From b11ae5cf86000bfce35b6ec511014d8f6b04416e Mon Sep 17 00:00:00 2001 From: root Date: Mon, 26 Oct 2020 22:55:18 +0000 Subject: add keypad --- .gitignore | 2 + Makefile | 14 +- keypad.c | 616 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ keypad.h | 4 + net_keypad.c | 56 ++++++ serial_arm.c | 2 +- serial_keypad.c | 62 ++++++ util.c | 35 ++++ util.h | 1 + 9 files changed, 788 insertions(+), 4 deletions(-) create mode 100644 keypad.c create mode 100644 keypad.h create mode 100644 net_keypad.c create mode 100644 serial_keypad.c diff --git a/.gitignore b/.gitignore index fa6e66e..ae0d207 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ serial_rx net_rx serial_arm net_arm +serial_keypad +net_keypad *.orig diff --git a/Makefile b/Makefile index 3264523..68f78bf 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,22 @@ -CFLAGS=-Wall +CFLAGS=-Wall ${CURSES_CFLAGS} +CURSES_CFLAGS=$(shell pkg-config --cflags ncurses) +CURSES_LIBS=$(shell pkg-config --libs ncurses) -all: net_rx net_arm serial_rx serial_arm +all: net_rx net_arm serial_rx serial_arm serial_keypad net_keypad net_rx:util.o sia.o net_rx.o net_arm:util.o sia.o net_arm.o arm.c serial_rx:util.o sia.o serial_rx.o serial_arm:util.o sia.o serial_arm.o arm.c +serial_keypad:util.o keypad.o serial_keypad.o + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${CURSES_LIBS} ${LIBS} + +net_keypad:util.o keypad.o net_keypad.o + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ $^ ${CURSES_LIBS} ${LIBS} + tidy: - astyle -A3 -s2 --attach-extern-c -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd sia.c sia.h util.c util.h serial_rx.c net_rx.c serial_arm.c net_arm.c arm.c + astyle -A3 -s2 --attach-extern-c -L -c -w -Y -m0 -f -p -H -U -k3 -xj -xd sia.c sia.h util.c util.h serial_rx.c net_rx.c serial_arm.c net_arm.c arm.c keypad.c net_keypad.c serial_keypad.c clean: /bin/rm -f *.o 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; +} + + diff --git a/keypad.h b/keypad.h new file mode 100644 index 0000000..c14e2f9 --- /dev/null +++ b/keypad.h @@ -0,0 +1,4 @@ +#ifndef _keypad_h_ +#define _keypad_h_ +extern int gd_keypad(int); +#endif /* _keypad_h_ */ diff --git a/net_keypad.c b/net_keypad.c new file mode 100644 index 0000000..9169b80 --- /dev/null +++ b/net_keypad.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "keypad.h" + + + + +static int usage (const char *name) +{ + fprintf (stderr, "Usage:\n"); + fprintf (stderr, "%s -h host [-p port]\n", name); + fprintf (stderr, "\n"); + + return -1; +} + + +int main (int argc, char *argv[]) +{ + unsigned opt; + const char *host = NULL; + unsigned port = 10001; + int fd; + + while ((opt = getopt (argc, argv, "h:p:z:USPRBFTAD")) != -1) { + switch (opt) { + case 'h': + host = optarg; + break; + + case 'p': + port = atoi (optarg); + break; + + default: /* '?' */ + return usage (argv[0]); + } + } + + if (!host) return (usage (argv[0])); + + fd = open_tcp_client (host, port); + + if (fd < 0) { + perror ("open tcp port"); + return -1; + } + + return gd_keypad (fd); +} diff --git a/serial_arm.c b/serial_arm.c index d1a5149..4ed28b9 100644 --- a/serial_arm.c +++ b/serial_arm.c @@ -15,7 +15,7 @@ static int usage (const char *name) { fprintf (stderr, "Usage:\n"); - fprintf (stderr, "%s -h host [-p port] [-z zone] [-U|-S|-P|-R|-B|-F|-T|-A|-D]\n", name); + fprintf (stderr, "%s -p device [ -b baud ] [-z zone] [-U|-S|-P|-R|-B|-F|-T|-A|-D]\n", name); fprintf (stderr, "\n"); fprintf (stderr, " -U Unset system/zone\n"); fprintf (stderr, " -S Set system/zone\n"); diff --git a/serial_keypad.c b/serial_keypad.c new file mode 100644 index 0000000..91939e6 --- /dev/null +++ b/serial_keypad.c @@ -0,0 +1,62 @@ +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "keypad.h" + + + + +static int usage (const char *name) +{ + fprintf (stderr, "Usage:\n"); + fprintf (stderr, "%s -p device [ -b baud ]\n", name); + fprintf (stderr, "\n"); + + return -1; +} + + +int main (int argc, char *argv[]) +{ + unsigned opt; + const char *port = NULL; + unsigned baud = 9600; + int fd; + + while ((opt = getopt (argc, argv, "h:p:z:USPRBFTAD")) != -1) { + switch (opt) { + case 'p': + port = optarg; + break; + + case 'b': + baud = atoi (optarg); + break; + + default: /* '?' */ + return usage (argv[0]); + } + } + + if (!port) return (usage (argv[0])); + + fd = open_tty (port, baud); + + set_blocking (fd); + + + if (fd < 0) { + perror ("open tcp port"); + return -1; + } + + + return gd_keypad (fd); +} + + diff --git a/util.c b/util.c index 95268b4..ab9afcc 100644 --- a/util.c +++ b/util.c @@ -45,6 +45,41 @@ int fd_can_read (int fd) return 0; } +ssize_t read_with_timeout (int fd, void *_b, size_t len, unsigned timeout) +{ + struct timeval tv = {0}; + unsigned char *b = _b; + fd_set rfds; + ssize_t red, ret = 0; + + tv.tv_sec = timeout / 10; + tv.tv_usec = (timeout % 10) * 100000; + + while (tv.tv_sec || tv.tv_usec) { + FD_ZERO (&rfds); + FD_SET (fd, &rfds); + + if (select (fd + 1, &rfds, NULL, NULL, &tv) == 1) { + + red = read (fd, &b[ret], 1); + + if (red == 1) + ret++; + + if (red <= 0) { + if (ret) return ret; + + return red; + } + + if (ret == len) return ret; + + } + } + + return ret; +} + int fd_drain (int fd) { char c; diff --git a/util.h b/util.h index 9bee282..55f6e38 100644 --- a/util.h +++ b/util.h @@ -5,6 +5,7 @@ extern void set_nonblocking (int fd); extern void set_blocking (int fd); extern int fd_can_read (int fd); +extern ssize_t read_with_timeout (int fd, void *_b, size_t len, unsigned timeout); extern int fd_drain (int fd); extern int open_tty (const char *path, int baud); extern int open_tcp_client (const char *host, unsigned port); -- cgit v1.2.3