From b11ae5cf86000bfce35b6ec511014d8f6b04416e Mon Sep 17 00:00:00 2001 From: root Date: Mon, 26 Oct 2020 22:55:18 +0000 Subject: add keypad --- keypad.c | 616 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 616 insertions(+) create mode 100644 keypad.c (limited to 'keypad.c') diff --git a/keypad.c b/keypad.c new file mode 100644 index 0000000..23a94bb --- /dev/null +++ b/keypad.c @@ -0,0 +1,616 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + + +#define GD_ADDR_US 0x00 +#define GD_ADDR_PANEL 0x11 + +#define GD_FN_POLL 0x01 + +#define GD_FN_PRESS_KEY 0x02 //Acked in the LCD data + +#define GD_FN_GET_LCD 0x03 +#define GD_FN_LCD 0x83 + +#define GD_FN_GET_PANEL_VER 0x04 +#define GD_FN_PANEL_VER 0x84 + +#define GD_FN_05 0x05 +#define GD_FN_05_RESP 0x85 + +#define GD_FN_06 0x06 +#define GD_FN_06_RESP 0x86 + + +#define GD_FN_ERR 0xf2 +#define GD_FN_ACK 0xfe + +#define GD_FN_BUSY 0x81 + + +#define GD_MAX_PKT_LEN 128 + + +#define GD_AK_RECEIVED 0x01 +#define GD_AK_DUPLICATE 0x02 + +#define GD_LCD_LINE_LEN 16 + +#define GD_TIMEOUT 2 + +// Packets are +// AA FN D0 D1 D2 CK + + +typedef struct { + union { + unsigned char pkt[GD_MAX_PKT_LEN]; + struct { + unsigned char address; + unsigned char fn; + unsigned char data[]; + }; + }; + size_t data_len; +} GD_PKT; + +typedef struct { + unsigned char line0[GD_LCD_LINE_LEN + 1]; + unsigned char line1[GD_LCD_LINE_LEN + 1]; + int cx, cy; + unsigned char flags; +} GD_LCD; + + + +static void endecode (unsigned char *p, size_t l) +{ + unsigned char ks[] = { 0x86, 0x93, 0xb5, 0x37, 0x12, 0xd6, 0xe4, 0x77}; + size_t i; + + for (i = 2; i < l; ++i) + p[i] ^= ks[i & 7]; +} + +static unsigned char checksum (unsigned char *p, size_t l) +{ + unsigned s = 0; + unsigned char q; + unsigned i; + + for (i = 0; i < l; ++i) + s += p[i]; + + s += 0xaa; + q = s & 0xff; + q += (s >> 8); + q += (s >> 16); + + return q; +} + + + + + +void hexdump_pkt (const char *prefix, GD_PKT *p) +{ + unsigned i, j, k; + unsigned char *d = p->pkt; + size_t l = p->data_len + 2; + + for (i = 0; i < l; i += 16) { + fprintf (stderr, "%s %04x ", prefix, i); + + for (j = 0; j < 16; ++j) { + k = i + j; + + if (k < l) + fprintf (stderr, " %02x", d[k]); + + else + fprintf (stderr, " "); + + if (j == 7) fprintf (stderr, " "); + } + + fprintf (stderr, " "); + + for (j = 0; j < 16; ++j) { + k = i + j; + + if (k < l) { + if ((d[k] > 32) && (d[k] < 127)) + fprintf (stderr, "%c", d[k]); + else + fprintf (stderr, "."); + } else + fprintf (stderr, " "); + + if (j == 7) fprintf (stderr, " "); + } + + fprintf (stderr, "\n"); + } + +} + +int send_pkt (int fd, GD_PKT *tx) +{ + unsigned char buf[GD_MAX_PKT_LEN]; + size_t len = tx->data_len + 2; + + //hexdump_pkt (" >", tx); + + memcpy (buf, tx->pkt, len); + endecode (buf, len); + buf[len] = checksum (buf, len) ; + len++; + + if (write (fd, buf, len) == len) + return 1; + + return -1; +} + + +int recv_pkt (int fd, GD_PKT *rx, int timeout) +{ + size_t len; + unsigned char sum; + + len = read_with_timeout (fd, rx->pkt, sizeof (rx->pkt), timeout); + + if (!len) return 0; + + if (len < 3) return -1; + + len--; + + sum = checksum (rx->pkt, len) ; + + if (rx->pkt[len] != sum) return -1; + + endecode (rx->pkt, len); + rx->data_len = len - 2; + + //hexdump_pkt (" <", rx); + + + return 1; + +} + +int gd_transact (int fd, GD_PKT *tx, GD_PKT *rx, unsigned char rx_addr, unsigned char rx_fn, int timeout) +{ + unsigned tries = 8; + + while (tries--) { + + if (send_pkt (fd, tx) != 1) + return -1; + + + if (recv_pkt (fd, rx, timeout) != 1) continue; + + if (rx->address != rx_addr) continue; + + if (rx->fn != rx_fn) continue; + + return 0; + } + + + return -1; +} + + +int gd_get_panel_ver (int fd, unsigned char a, int *v) +{ + GD_PKT o, i; + + o.address = GD_ADDR_US; + o.fn = GD_FN_GET_PANEL_VER; + o.data[0] = a; + o.data_len = 1; + + if (gd_transact (fd, &o, &i, GD_ADDR_PANEL, GD_FN_PANEL_VER, GD_TIMEOUT)) + return -1; + + + switch (i.data[2]) { + case 0: //? + *v = 2; + break; + + case 1: //Galaxy Dimension 48 + *v = 3; + break; + + case 2: + *v = 3; + break; + + case 3: + *v = 3; + break; + + default: + return -1; + } + + return 0; + +} + + +int gd_fn_05 (int fd, unsigned char a, unsigned char b, unsigned char c) +{ + GD_PKT o, i; + + o.address = GD_ADDR_US; + o.fn = GD_FN_05; + o.data[0] = a; + o.data[1] = b; + o.data[2] = c; + o.data_len = 3; + + if (gd_transact (fd, &o, &i, GD_ADDR_PANEL, GD_FN_05_RESP, GD_TIMEOUT)) + return -1; + + + return 0; + +} + + +int gd_fn_06 (int fd, unsigned char a, unsigned char b, unsigned char c, unsigned char *data, size_t len) +{ + GD_PKT o, i; + + o.address = GD_ADDR_US; + o.fn = GD_FN_06; + o.data[0] = len; + o.data[1] = a; + o.data[2] = b; + o.data[3] = c; + memcpy (&o.data[4], data, len); + o.data_len = 4 + len; + + if (gd_transact (fd, &o, &i, GD_ADDR_PANEL, GD_FN_06_RESP, GD_TIMEOUT)) + return -1; + + + return 0; +} + +void gd_to_ascii (unsigned char *c, size_t l) +{ + + for (; l; l--, c++) { + if (*c == 0xdb) *c = '+'; + + if (*c == 0xb0) *c = '-'; + } + +} + + + +void gd_extract_lcd (GD_PKT *i, GD_LCD *lcd) +{ + + memcpy (lcd->line0, &i->data[3], GD_LCD_LINE_LEN); + lcd->line0[GD_LCD_LINE_LEN] = 0; + memcpy (lcd->line1, &i->data[3 + GD_LCD_LINE_LEN], GD_LCD_LINE_LEN); + lcd->line1[GD_LCD_LINE_LEN] = 0; + + + gd_to_ascii (lcd->line0, GD_LCD_LINE_LEN); + gd_to_ascii (lcd->line1, GD_LCD_LINE_LEN); + + + + lcd->flags = i->data[2]; + lcd->cx = i->data[0] - 1; + + while (lcd->cx >= GD_LCD_LINE_LEN) { + lcd->cx -= GD_LCD_LINE_LEN; + lcd->cy++; + } + +} + + + + +int gd_fn_get_lcd (int fd, GD_LCD *lcd) +{ + GD_PKT o, i; + + o.address = GD_ADDR_US; + o.fn = GD_FN_GET_LCD; + o.data_len = 0; + + if (gd_transact (fd, &o, &i, GD_ADDR_PANEL, GD_FN_LCD, GD_TIMEOUT)) + return -1; + + if (lcd) + gd_extract_lcd (&i, lcd); + + return 0; + +} + +int gd_fn_key (int fd, char key, int dedup, GD_LCD *lcd) +{ + + int tries = 5; + GD_PKT o, i; + + + + switch (key) { + case '\e': + key = 0xd; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + key -= '0'; + break; + + case '*': + key = 0xe; + break; + + case '#': + key = 0xf; + break; + + case 'a': + case 'A': + key = 0xa; + break; + + case 'b': + case 'B': + key = 0xb; + break; + + case '\n': + key = 0xc; + break; + + default: + key = 0xd; + break; + } + + if (dedup) key |= 0x80; + + o.address = GD_ADDR_US; + o.fn = GD_FN_PRESS_KEY; + o.data[0] = key; + o.data_len = 1; + + do { + if (gd_transact (fd, &o, &i, GD_ADDR_PANEL, GD_FN_LCD, GD_TIMEOUT)) + return -1; + + } while ((! (i.data[2] & 0x80)) && (tries--)); + + if (!tries) return -1; + + + if (lcd) + gd_extract_lcd (&i, lcd); + + return 0; +} +int gd_fn_poll (int fd, GD_LCD *lcd) +{ + GD_PKT o, i; + + o.address = GD_ADDR_US; + o.fn = GD_FN_POLL; + o.data_len = 0; + + if (gd_transact (fd, &o, &i, GD_ADDR_PANEL, GD_FN_LCD, GD_TIMEOUT)) + return -1; + + if (lcd) + gd_extract_lcd (&i, lcd); + + return 0; +} + + +int gd_fn_key_press (int fd, char key, GD_LCD *lcd) +{ + static int alternate = 0; + int ret; + + ret = gd_fn_key (fd, key, alternate, lcd); + + alternate = !alternate; + + return ret; + +} + + + +int gd_init (int fd) +{ + int gv = 0; + + if (gd_get_panel_ver (fd, 0x30, &gv)) + return -1; + + + + if (gv == 2) { + + if (gd_fn_05 (fd, 0x18, 0x00, 0x07)) + return -1; + + } else if (gv == 3) { + if (gd_fn_05 (fd, 0x17, 0x00, 0x00)) + return -1; + + } + + + if (gd_fn_06 (fd, 0x18, 0x7f, 0x03, NULL, 0)) + return -1; + + if (gd_fn_06 (fd, 0x18, 0x7f, 0x02, NULL, 0)) + return -1; + + if (gd_fn_06 (fd, 0x18, 0x7f, 0x01, NULL, 0)) + return -1; + + + if (gd_get_panel_ver (fd, 0x30, &gv)) + return -1; + + { + unsigned char data[2] = {0x01, 0x00}; + + if (gd_fn_06 (fd, 0x18, 0x00, 0x00, data, sizeof (data))) + return -1; + } + + + + (void) gd_fn_get_lcd (fd, NULL); + + if (gd_fn_05 (fd, 0x18, 0x00, 0x00)) + return -1; + + if (gd_fn_05 (fd, 0x9c, 0x00, 0x01)) + return -1; + + if (gd_fn_05 (fd, 0x02, 0xff, 0xff)) + return -1; + + if (gd_fn_key_press (fd, '\e', NULL)) + return -1; + + if (gd_fn_key_press (fd, '\e', NULL)) + return -1; + + return 0; +} + +WINDOW *win; + +void curses_init (void) +{ + + initscr(); /* Start curses mode */ + raw(); /* Line buffering disabled */ + keypad (stdscr, TRUE); /* We get F1, F2 etc.. */ + noecho(); /* Don't echo() while we do getch */ + + + // printw ("fish"); + move (15, 1); + addstr ("q to quit"); + + refresh(); + + win = newwin (15, 20, 0, 0); + box (win, 0, 0); + + + wmove (win, 6, 3); + waddstr (win, "1 2 3 A->"); + wmove (win, 8, 3); + waddstr (win, "4 5 6 B<-"); + wmove (win, 10, 3); + waddstr (win, "7 8 9 Ent"); + wmove (win, 12, 3); + waddstr (win, "* 0 # Esc"); + + wrefresh (win); + + win = newwin (4, 18, 1, 1); + + box (win, 0, 0); + wrefresh (win); + timeout (0); + +} + + +void curses_end (void) +{ + endwin(); +} + + +void curses_show (GD_LCD *lcd) +{ + + wmove (win, 1, 1); + waddstr (win, (char *) lcd->line0); + wmove (win, 2, 1); + waddstr (win, (char *) lcd->line1); + wmove (win, lcd->cy + 1, lcd->cx + 1); + wrefresh (win); +} + + +int gd_keypad (int fd) +{ + GD_LCD l; + int ch; + + if (gd_init (fd)) { + printf ("Failed to init comms with panel\n"); + return -1; + } + + curses_init(); + + + + while ((ch = getch()) != 'q') { + + gd_fn_poll (fd, &l); + curses_show (&l); + + if (ch == KEY_LEFT) ch = 'a'; + + if (ch == KEY_RIGHT) ch = 'b'; + + if (ch != ERR && !gd_fn_key_press (fd, ch, &l)) + curses_show (&l); + } + + + curses_end(); + + + return 0; +} + + -- cgit v1.2.3