123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- // simpleserial.c
- #include "simpleserial.h"
- #include <stdint.h>
- #include "hal.h"
- #define MAX_SS_CMDS 16
- static int num_commands = 0;
- #define MAX_SS_LEN 192
- //#define SS_VER_1_0 0
- //#define SS_VER_1_1 1
- //#define SS_VER_2_0 2
- // 0xA6 formerly
- #define CW_CRC 0x4D
- uint8_t ss_crc(uint8_t *buf, uint8_t len)
- {
- unsigned int k = 0;
- uint8_t crc = 0x00;
- while (len--) {
- crc ^= *buf++;
- for (k = 0; k < 8; k++) {
- crc = crc & 0x80 ? (crc << 1) ^ CW_CRC: crc << 1;
- }
- }
- return crc;
- }
- // [B_STUFF, CMD, SCMD, LEN, B_STUFF, DATA..., CRC, TERM]
- //#define SS_VER SS_VER_2_0
- #if SS_VER == SS_VER_2_0
- #error "SS_VER_2_0 is deprecated! Use SS_VER_2_1 instead."
- #elif SS_VER == SS_VER_2_1
- typedef struct ss_cmd
- {
- char c;
- unsigned int len;
- uint8_t (*fp)(uint8_t, uint8_t, uint8_t, uint8_t *);
- } ss_cmd;
- static ss_cmd commands[MAX_SS_CMDS];
- void ss_puts(char *x)
- {
- do {
- putch(*x);
- } while (*++x);
- }
- #define FRAME_BYTE 0x00
- uint8_t check_version(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t *data)
- {
- uint8_t ver = SS_VER;
- simpleserial_put('r', 1, &ver);
- return SS_ERR_OK;
- }
- uint8_t ss_get_commands(uint8_t cmd, uint8_t scmd, uint8_t len, uint8_t *data)
- {
- uint8_t cmd_chars[MAX_SS_CMDS];
- for (uint8_t i = 0; i < (num_commands & 0xFF); i++) {
- cmd_chars[i] = commands[i].c;
- }
- simpleserial_put('r', num_commands & 0xFF, (void *)cmd_chars);
- return 0x00;
- }
- uint8_t stuff_data(uint8_t *buf, uint8_t len)
- {
- uint8_t i = 1;
- uint8_t last = 0;
- for (; i < len; i++) {
- if (buf[i] == FRAME_BYTE) {
- buf[last] = i - last;
- last = i;
- }
- }
- return 0x00;
- }
- uint8_t unstuff_data(uint8_t *buf, uint8_t len)
- {
- uint8_t next = buf[0];
- buf[0] = 0x00;
- //len -= 1;
- uint8_t tmp = next;
- while ((next < len) && tmp != 0) {
- tmp = buf[next];
- buf[next] = FRAME_BYTE;
- next += tmp;
- }
- return next;
- }
- // Set up the SimpleSerial module by preparing internal commands
- // This just adds the "v" command for now...
- void simpleserial_init()
- {
- simpleserial_addcmd('v', 0, check_version);
- simpleserial_addcmd('w', 0, ss_get_commands);
- }
- int simpleserial_addcmd(char c, unsigned int len, uint8_t (*fp)(uint8_t, uint8_t, uint8_t, uint8_t*))
- {
- if(num_commands >= MAX_SS_CMDS) {
- putch('a');
- return 1;
- }
- if(len >= MAX_SS_LEN) {
- putch('b');
- return 1;
- }
- commands[num_commands].c = c;
- commands[num_commands].len = len;
- commands[num_commands].fp = fp;
- num_commands++;
- return 0;
- }
- void simpleserial_get(void)
- {
- uint8_t data_buf[MAX_SS_LEN];
- uint8_t err = 0;
- for (int i = 0; i < 4; i++) {
- data_buf[i] = getch(); //PTR, cmd, scmd, len
- if (data_buf[i] == FRAME_BYTE) {
- err = SS_ERR_FRAME_BYTE;
- goto ERROR;
- }
- }
- uint8_t next_frame = unstuff_data(data_buf, 4);
- // check for valid command
- uint8_t c = 0;
- for(c = 0; c < num_commands; c++)
- {
- if(commands[c].c == data_buf[1])
- break;
- }
- if (c == num_commands) {
- err = SS_ERR_CMD;
- goto ERROR;
- }
- //check that next frame not beyond end of message
- // account for cmd, scmd, len, data, crc, end of frame
- if ((data_buf[3] + 5) < next_frame) {
- err = SS_ERR_LEN;
- goto ERROR;
- }
- // read in data
- // eq to len + crc + frame end
- int i = 4;
- for (; i < data_buf[3] + 5; i++) {
- data_buf[i] = getch();
- if (data_buf[i] == FRAME_BYTE) {
- err = SS_ERR_FRAME_BYTE;
- goto ERROR;
- }
- }
- //check that final byte is the FRAME_BYTE
- data_buf[i] = getch();
- if (data_buf[i] != FRAME_BYTE) {
- err = SS_ERR_LEN;
- goto ERROR;
- }
- //fully unstuff data now
- unstuff_data(data_buf + next_frame, i - next_frame + 1);
- //calc crc excluding original frame offset and frame end and crc
- uint8_t crc = ss_crc(data_buf+1, i-2);
- if (crc != data_buf[i-1]) {
- err = SS_ERR_CRC;
- goto ERROR;
- }
- err = commands[c].fp(data_buf[1], data_buf[2], data_buf[3], data_buf+4);
- ERROR:
- simpleserial_put('e', 0x01, &err);
- return;
- }
- void simpleserial_put(char c, uint8_t size, uint8_t* output)
- {
- uint8_t data_buf[MAX_SS_LEN];
- data_buf[0] = 0x00;
- data_buf[1] = c;
- data_buf[2] = size;
- int i = 0;
- for (; i < size; i++) {
- data_buf[i + 3] = output[i];
- }
- data_buf[i + 3] = ss_crc(data_buf+1, size+2);
- data_buf[i + 4] = 0x00;
- stuff_data(data_buf, i + 5);
- for (int i = 0; i < size + 5; i++) {
- putch(data_buf[i]);
- }
- }
- #else
- typedef struct ss_cmd
- {
- char c;
- unsigned int len;
- uint8_t (*fp)(uint8_t*, uint8_t);
- uint8_t flags;
- } ss_cmd;
- static ss_cmd commands[MAX_SS_CMDS];
- // Callback function for "v" command.
- // This can exist in v1.0 as long as we don't actually send back an ack ("z")
- uint8_t check_version(uint8_t *v, uint8_t len)
- {
- return SS_VER;
- }
- uint8_t ss_num_commands(uint8_t *x, uint8_t len)
- {
- uint8_t ncmds = num_commands & 0xFF;
- simpleserial_put('r', 0x01, &ncmds);
- return 0x00;
- }
- typedef struct ss_cmd_repr {
- uint8_t c;
- uint8_t len;
- uint8_t flags;
- } ss_cmd_repr;
- uint8_t ss_get_commands(uint8_t *x, uint8_t len)
- {
- ss_cmd_repr repr_cmd_buf[MAX_SS_CMDS];
- for (uint8_t i = 0; i < (num_commands & 0xFF); i++) {
- repr_cmd_buf[i].c = commands[i].c;
- repr_cmd_buf[i].len = commands[i].len;
- repr_cmd_buf[i].flags = commands[i].flags;
- }
- simpleserial_put('r', num_commands * 0x03, (void *) repr_cmd_buf);
- return 0x00;
- }
- static char hex_lookup[16] =
- {
- '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
- int hex_decode(int len, char* ascii_buf, uint8_t* data_buf)
- {
- for(int i = 0; i < len; i++)
- {
- char n_hi = ascii_buf[2*i];
- char n_lo = ascii_buf[2*i+1];
- if(n_lo >= '0' && n_lo <= '9')
- data_buf[i] = n_lo - '0';
- else if(n_lo >= 'A' && n_lo <= 'F')
- data_buf[i] = n_lo - 'A' + 10;
- else if(n_lo >= 'a' && n_lo <= 'f')
- data_buf[i] = n_lo - 'a' + 10;
- else
- return 1;
- if(n_hi >= '0' && n_hi <= '9')
- data_buf[i] |= (n_hi - '0') << 4;
- else if(n_hi >= 'A' && n_hi <= 'F')
- data_buf[i] |= (n_hi - 'A' + 10) << 4;
- else if(n_hi >= 'a' && n_hi <= 'f')
- data_buf[i] |= (n_hi - 'a' + 10) << 4;
- else
- return 1;
- }
- return 0;
- }
- // Set up the SimpleSerial module by preparing internal commands
- // This just adds the "v" command for now...
- void simpleserial_init()
- {
- simpleserial_addcmd('v', 0, check_version);
- simpleserial_addcmd('w', 0, ss_get_commands);
- simpleserial_addcmd('y', 0, ss_num_commands);
- }
- int simpleserial_addcmd(char c, unsigned int len, uint8_t (*fp)(uint8_t*, uint8_t))
- {
- return simpleserial_addcmd_flags(c, len, fp, CMD_FLAG_NONE);
- }
- int simpleserial_addcmd_flags(char c, unsigned int len, uint8_t (*fp)(uint8_t*, uint8_t), uint8_t fl)
- {
- if(num_commands >= MAX_SS_CMDS)
- return 1;
- if(len >= MAX_SS_LEN)
- return 1;
- commands[num_commands].c = c;
- commands[num_commands].len = len;
- commands[num_commands].fp = fp;
- commands[num_commands].flags = fl;
- num_commands++;
- return 0;
- }
- void simpleserial_get(void)
- {
- char ascii_buf[2*MAX_SS_LEN];
- uint8_t data_buf[MAX_SS_LEN];
- char c;
- // Find which command we're receiving
- c = getch();
- int cmd;
- for(cmd = 0; cmd < num_commands; cmd++)
- {
- if(commands[cmd].c == c)
- break;
- }
- // If we didn't find a match, give up right away
- if(cmd == num_commands)
- return;
- // If flag CMD_FLAG_LEN is set, the next byte indicates the sent length
- if ((commands[cmd].flags & CMD_FLAG_LEN) != 0)
- {
- uint8_t l = 0;
- char buff[2];
- buff[0] = getch();
- buff[1] = getch();
- if (hex_decode(1, buff, &l))
- return;
- commands[cmd].len = l;
- }
- // Receive characters until we fill the ASCII buffer
- for(int i = 0; i < 2*commands[cmd].len; i++)
- {
- c = getch();
- // Check for early \n
- if(c == '\n' || c == '\r')
- return;
- ascii_buf[i] = c;
- }
- // Assert that last character is \n or \r
- c = getch();
- if(c != '\n' && c != '\r')
- return;
- // ASCII buffer is full: convert to bytes
- // Check for illegal characters here
- if(hex_decode(commands[cmd].len, ascii_buf, data_buf))
- return;
- // Callback
- uint8_t ret[1];
- ret[0] = commands[cmd].fp(data_buf, commands[cmd].len);
- // Acknowledge (if version is 1.1)
- #if SS_VER == SS_VER_1_1
- simpleserial_put('z', 1, ret);
- #endif
- }
- void simpleserial_put(char c, uint8_t size, uint8_t* output)
- {
- // Write first character
- putch(c);
- // Write each byte as two nibbles
- for(int i = 0; i < size; i++)
- {
- putch(hex_lookup[output[i] >> 4 ]);
- putch(hex_lookup[output[i] & 0xF]);
- }
- // Write trailing '\n'
- putch('\n');
- }
- #endif
|