summaryrefslogtreecommitdiffstats
path: root/keypad.c
diff options
context:
space:
mode:
authorroot <root@nolonger-other.tetra.james.local>2020-10-26 22:55:18 +0000
committerfishsoupisgood <github@madingley.org>2020-10-26 23:04:50 +0000
commitb11ae5cf86000bfce35b6ec511014d8f6b04416e (patch)
treed4f4caf8ecb8b14e62858d46d781af6886eb1b73 /keypad.c
parent62bc1af6c6a1201db551e1ec523e757415464fd5 (diff)
downloadgalaxy_tools-b11ae5cf86000bfce35b6ec511014d8f6b04416e.tar.gz
galaxy_tools-b11ae5cf86000bfce35b6ec511014d8f6b04416e.tar.bz2
galaxy_tools-b11ae5cf86000bfce35b6ec511014d8f6b04416e.zip
add keypad
Diffstat (limited to 'keypad.c')
-rw-r--r--keypad.c616
1 files changed, 616 insertions, 0 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <ncurses.h>
+
+#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;
+}
+
+