summaryrefslogtreecommitdiffstats
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
parent62bc1af6c6a1201db551e1ec523e757415464fd5 (diff)
downloadgalaxy_sia-b11ae5cf86000bfce35b6ec511014d8f6b04416e.tar.gz
galaxy_sia-b11ae5cf86000bfce35b6ec511014d8f6b04416e.tar.bz2
galaxy_sia-b11ae5cf86000bfce35b6ec511014d8f6b04416e.zip
add keypad
-rw-r--r--.gitignore2
-rw-r--r--Makefile14
-rw-r--r--keypad.c616
-rw-r--r--keypad.h4
-rw-r--r--net_keypad.c56
-rw-r--r--serial_arm.c2
-rw-r--r--serial_keypad.c62
-rw-r--r--util.c35
-rw-r--r--util.h1
9 files changed, 788 insertions, 4 deletions
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 <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;
+}
+
+
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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <termios.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#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);