From 62bc1af6c6a1201db551e1ec523e757415464fd5 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 25 Oct 2020 13:26:29 +0000 Subject: tidy up, make less awful --- sia.c | 253 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 sia.c (limited to 'sia.c') diff --git a/sia.c b/sia.c new file mode 100644 index 0000000..3c47c8b --- /dev/null +++ b/sia.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include +#include "util.h" + + +#include "sia.h" + + + +int sia_fn_valid (SIA_Block *s) +{ + switch (s->function) { + + case SIA_FN_ACCOUNT_ID: + case SIA_FN_ORIGIN_ID: + case SIA_FN_END_OF_DATA: + case SIA_FN_WAIT: + case SIA_FN_ABORT: + case SIA_FN_RES_3: + case SIA_FN_RES_4: + case SIA_FN_RES_5: + case SIA_FN_ACK_AND_STANDBY: + case SIA_FN_ACK_AND_DISCONNECT: + case SIA_FN_ACKNOLEDGE: + case SIA_FN_ALT_ACKNOLEDGE: + case SIA_FN_REJECT: + case SIA_FN_ALT_REJECT: + case SIA_FN_REMOTE_LOGIN: + case SIA_FN_CONFIGURATION: + case SIA_FN_ASCII: + case SIA_FN_CONTROL: + case SIA_FN_ENVIRONMENTAL: + case SIA_FN_VIDEO: + case SIA_FN_LISTEN_IN: + case SIA_FN_NEW_EVENT: + case SIA_FN_OLD_EVENT: + case SIA_FN_PROGRAM: + case SIA_FN_VCHN_REQUEST: + case SIA_FN_EXTENDED: + case SIA_FN_VCHN_FRAME: + return 1; + } + + return 0; +} + +int sia_fn_permits_ack (unsigned char fn) +{ + switch (fn) { + case SIA_FN_ALT_REJECT: + case SIA_FN_REJECT: + case SIA_FN_ALT_ACKNOLEDGE: + case SIA_FN_ACKNOLEDGE: + case SIA_FN_CONFIGURATION: + case SIA_FN_CONTROL: + case SIA_FN_EXTENDED: + return 0; + } + + return 1; +} + + +unsigned int sia_data_length (SIA_Block *s) +{ + return s->length; +} + +unsigned int sia_length (SIA_Block *s) +{ + return sia_data_length (s) + 3; +} + +int sia_parity_valid (SIA_Block *s) +{ + unsigned char parity = 0xff; + + unsigned i, l = sia_length (s); + + for (i = 0; i < l; ++i) + parity ^= s->block[i]; + + + return !parity; +} + + +void sia_set_parity (SIA_Block *s) +{ + unsigned char parity = 0xff; + unsigned i, l = sia_length (s) - 1; + + for (i = 0; i < l; ++i) + parity ^= s->block[i]; + + s->block[l] = parity; +} + + +ssize_t sia_write (int fd, SIA_Block *s) +{ + ssize_t rc, l = sia_length (s); + + sia_set_parity (s); + + rc = write (fd, s->block, l); + + if (rc == l) return 1; + + if (rc > 0) rc = 0; + + return rc; +} + + +ssize_t sia_acknoledge (int fd) +{ + SIA_Block b; + + b.length = 0; + b.request_ack = 0; + b.reverse_channel = 0; + b.function = SIA_FN_ACKNOLEDGE; + + return sia_write (fd, &b); +} + +/* Zero on success, 1 on error */ +int sia_ack_if_needed (int fd, SIA_Block *s) +{ + if (!s->request_ack) return 0; + + if (!sia_fn_permits_ack (s->function)) + return 0; + + return ! (sia_acknoledge (fd) == 1); +} + + + +/* Returns 0 for need more data, number of bytes consumed for success, -1 for parse error */ +/* On tcp/ip the form appears to be to drop the connexion on parse error*/ +/* On serial drain the buffer as comms is bursty */ + +int sia_parse (unsigned char *buf, unsigned len, SIA_Block *b) +{ + unsigned calc_len; + + if (len < 2) return 0; + + if (len > SIA_MAX_BLOCK_LENGTH) len = SIA_MAX_BLOCK_LENGTH; + + memcpy (b->block, buf, len); + + if (!sia_fn_valid (b)) return -1; + + calc_len = sia_length (b); + + if (len < calc_len) return 0; + + + if (!sia_parity_valid (b)) return -1; + + return calc_len; +} + + +/*Returns 0 for success, -1 for error */ +int sia_rx_with_timeout (int fd, SIA_Block *b, int timeout) +{ + unsigned char buf[SIA_MAX_BLOCK_LENGTH]; + unsigned ptr = 0; + int rc; + + struct timeval tv = {0}; + + tv.tv_sec = timeout; + + while (tv.tv_sec || tv.tv_usec) { + fd_set rfds; + FD_ZERO (&rfds); + FD_SET (fd, &rfds); + + rc = select (fd + 1, &rfds, NULL, NULL, &tv); + + if (rc <= 0) return -1; + + rc = read (fd, &buf[ptr], 1); + + if (rc <= 0) + return -1; + + ptr++; + + switch (sia_parse (buf, ptr, b)) { + case -1: + return -1; + + case 0: + break; + + default: + return 0; + } + } + + return 0; +} + +int sia_rx_with_timeout_ignore_log (int fd, SIA_Block *b, int timeout) +{ + int ret; + + do { + ret = sia_rx_with_timeout (fd, b, timeout); + + if (ret < 0) return ret; + } while ((b->function == SIA_FN_ACCOUNT_ID) || (b->function == SIA_FN_NEW_EVENT) || (b->function == SIA_FN_OLD_EVENT) || (b->function == SIA_FN_ASCII)); + + return ret; +} + + +int sia_login (int fd, SIA_Block *b) +{ + const char *pin = "543210"; //JMM: Oh yes! and there's no way to change it from the panel, you need the £3k bit of software to do that + + b->reverse_channel = 0; + b->request_ack = 1; + b->function = SIA_FN_REMOTE_LOGIN; + b->length = strlen (pin); + memcpy (b->data, pin, b->length); + + if (fd_drain (fd)) + return -1; + + if (sia_write (fd, b) != 1) + return -1; + + if (sia_rx_with_timeout_ignore_log (fd, b, SIA_TIMEOUT)) + return -1; + + + if (b->function != SIA_FN_CONFIGURATION) + return -1; + + return 0; +} + + -- cgit v1.2.3