Sat, 29 Oct 2016 23:44:31 +0200
[full replacement] implement a state machine for Rx
src/hp34comm.cpp | file | annotate | diff | comparison | revisions | |
src/hp34comm.h | file | annotate | diff | comparison | revisions | |
src/main.cpp | file | annotate | diff | comparison | revisions |
--- a/src/hp34comm.cpp Wed Oct 26 22:41:16 2016 +0200 +++ b/src/hp34comm.cpp Sat Oct 29 23:44:31 2016 +0200 @@ -15,19 +15,15 @@ #endif DigitalOut lled(LED1); - -HPSerial::HPSerial(PinName rx): - serial_rx(NC, rx), - ncmd(0) { - - //pc.printf("HPSerial init\n"); + + - for(uint8_t i=0; i<MAX_ERRS; i++) - errs[i] = 0; - reset(); - - serial_rx.baud(187500); - serial_rx.attach(this, &HPSerial::rxIrq, Serial::RxIrq); +HPSerial::HPSerial(PinName tx, PinName rx): + serial(tx, rx) +{ + cur_state = do_state_initial(&rx_data, 0x00); + serial.baud(187500); + serial.attach(this, &HPSerial::rxIrq, Serial::RxIrq); } bool HPSerial::cmd_available(void) { @@ -45,63 +41,11 @@ unsigned int HPSerial::nerrors(uint8_t errorno) { return errs[errorno]; } - - - -void HPSerial::reset(uint8_t errorno) { - timeouter.detach(); - head = 0; - tx_state = Idle; - setstatedbg(); - tx_cmd = 0xFF; - tx_ack = false; - tx_len = 0xFF; - memset(buf, 0, BUF_SIZE); - if (errorno != 0xFF){ - errs[errorno]++; - } - -} -void HPSerial::handleAck(uint8_t val) { - if ((tx_state == Rx) & (tx_cmd == 0xFF) & (tx_ack == false) & (val == 0x66)) { - // special case: keypad does not acknwledge and takes precedence - // on the "bus" - tx_state = Tx; - setstatedbg(); - } else - if (tx_cmd == 0xFF) // beginning of a packet, expect 0x99 as ack - if (val == 0x99) - { - tx_ack = true; -#ifdef DEBUG2 - ack = 1; - wait_us(2); - ack = 0; -#endif - } - else - reset(1); - - else // expect 0x00 as ack - if (val == 0x00) - { - tx_ack = true; -#ifdef DEBUG2 - ack = 1; - wait_us(2); - ack = 0; -#endif - } - else - reset(2); -} - -void HPSerial::pushCmd(TrState direction, uint8_t cmd, uint8_t size, char *payload) { +void HPSerial::pushCmd(uint8_t cmd, uint8_t size, char *payload) { CMD val; uint8_t i; val.id = ncmd++; - val.direction = direction; val.cmd = cmd; val.size = size; for(i=0; i<size; i++) @@ -110,114 +54,92 @@ cmdbuf.push(val); } -void HPSerial::handleChar(uint8_t val) { - if (tx_ack == false) - reset(3); - else // remaining of the state machine - if (tx_cmd == 0xFF) { - // begin of transmission, expect a cmd - tx_cmd = val; - tx_ack = false; - tx_len = 0xFF; - } - else if (tx_len == 0xFF) { - if (val == 0x55) { - // packet was in fact a keystroke, tx_cmd is in fact the key - // stroke and no payload is expected -#ifdef DEBUG2 - statetx = 1; -#endif - pushCmd((TrState)Tx, tx_cmd, 0, (char*)buf); -#ifdef DEBUG2 - wait_us(2); - statetx = 0; -#endif - reset(); - } else { - // got a cmd, expect a payload size - tx_len = val; - tx_ack = false; - } - } - else if (tx_len == 0x55) { - // packet was in fact a keystroke, tx_cmd is in fact the key - // stroke and no payload is expected -#ifdef DEBUG2 - statetx = 1; -#endif - pushCmd((TrState)Tx, tx_cmd, 0, (char*)buf); -#ifdef DEBUG2 - wait_us(2); - statetx = 0; -#endif - reset(); - } - else if (tx_len > 0) { - // a payload char - buf[head++] = val; - tx_len--; - tx_ack = false; - } - else { // end of payload, manage sent content - uint8_t cur_state = tx_state; - pushCmd((TrState)tx_state, tx_cmd, head, (char*)buf); - - switch(val) { - case 0x66: // a new transmisson - reset(); - tx_state = cur_state; - setstatedbg(); - break; - case 0x55: - reset(); - break; - default: - reset(6); - break; - } - } +void HPSerial::send_ack(uint8_t c) { + timeouter.attach(this, &HPSerial::timeout, 0.001); // if nothing else happen in the next ms, reset + serial.putc(c); +} + +HPSerial::state_t HPSerial::do_state_initial(HPSerial::instance_data_t *data, + uint8_t c) +{ + // go back to initial state + data->cmd = 0xFF; + data->size = 0; + data->received = 0; + timeouter.detach(); + return HPSerial::STATE_IDLE; +} + +HPSerial::state_t HPSerial::do_state_handcheck(HPSerial::instance_data_t *data, + uint8_t c) +{ + // we are idle, incoming char is a handcheck + // knwon handcheck values are 0x66 and 0x33 + switch (c) { + case 0x33: + send_ack(0xCC); + return HPSerial::STATE_PAYLOAD_SIZE; + break; + case 0x66: + send_ack(0x99); + return HPSerial::STATE_COMMAND; + break; + default: + return do_state_initial(data, 0x00); + } } +HPSerial::state_t HPSerial::do_state_command(HPSerial::instance_data_t *data, + uint8_t c) +{ + if (c == 0x55) { // EoT + return do_state_initial(data, 0x00); + } + data->cmd = c; + data->size = 0; + send_ack(0x00); + return HPSerial::STATE_PAYLOAD_SIZE; +} -void HPSerial::setstatedbg(void) { -#ifdef DEBUG2 - if (tx_state == Rx) - staterx = 1; - else - staterx = 0; - if (tx_state == Tx) - statetx = 1; - else - statetx = 0; -#endif +HPSerial::state_t HPSerial::do_state_payload_size(HPSerial::instance_data_t *data, + uint8_t c) +{ + data->size = c; + data->received = 0; + send_ack(0x00); + return HPSerial::STATE_PAYLOAD; } +HPSerial::state_t HPSerial::do_state_payload(HPSerial::instance_data_t *data, + uint8_t c) +{ + data->payload[data->received++] = c; + send_ack(0x00); + if (data->received >= data->size) { + pushCmd(data->cmd, data->size, data->payload); + return HPSerial::STATE_COMMAND; + } + return HPSerial::STATE_PAYLOAD; +} + +HPSerial::state_t HPSerial::run_state(HPSerial::state_t cur_state, + HPSerial::instance_data_t *data, + uint8_t c) +{ + return (this->*(HPSerial::state_table[cur_state]))(data, c); +}; + void HPSerial::rxIrq(void) { uint8_t val; - if(serial_rx.readable()) { // no reason why we would end here without this condition, but hey + if(serial.readable()) { // no reason why we would end here without + // this condition, but hey #ifdef DEBUG2 inrx=1; #endif lled = 1; - val = serial_rx.getc(); - - timeouter.attach(this, &HPSerial::timeout, 0.001); // if nothing else happen in the next ms, reset - - if (tx_state == Idle) - if (val == 0x66) { - // no transmission in progress, expect a start of transmission - tx_state = Rx; - tx_ack = false; - setstatedbg(); - } - else { - reset(4); - } - else if (tx_ack == false) // manage the acks - handleAck(val); - else - handleChar(val); + val = serial.getc(); + cur_state = run_state(cur_state, &rx_data, val); lled = 0; #ifdef DEBUG2 inrx=0; @@ -227,7 +149,5 @@ void HPSerial::timeout(void) { - if (tx_state != Idle) { - reset(7); - } + cur_state = do_state_initial(&rx_data, 0x00); }
--- a/src/hp34comm.h Wed Oct 26 22:41:16 2016 +0200 +++ b/src/hp34comm.h Sat Oct 29 23:44:31 2016 +0200 @@ -10,17 +10,13 @@ #define MAX_BUFF 16 #define BUF_SIZE 16 + + class HPSerial { public: - enum TrState { - Idle = 0, - Tx, - Rx, - }; typedef struct _CMD { - TrState direction; uint8_t cmd; uint8_t size; char value[MAX_BUFF+1]; @@ -29,7 +25,7 @@ - HPSerial(PinName rx); + HPSerial(PinName tx, PinName rx); bool cmd_available(void); bool pop(CMD& cmd); @@ -38,26 +34,57 @@ private: - void reset(uint8_t errorno=0xFF); - void handleAck(uint8_t val); - void pushCmd(TrState direction, uint8_t cmd, uint8_t size, char *payload); - void handleChar(uint8_t val); - void setstatedbg(void); + void pushCmd(uint8_t cmd, uint8_t size, char *payload); void rxIrq(void); void timeout(void); private: - RawSerial serial_rx; + RawSerial serial; uint8_t buf[BUF_SIZE]; uint8_t head; - uint8_t tx_state; - uint8_t tx_cmd; - uint8_t tx_len; - bool tx_ack; CircularBuffer<CMD, 32> cmdbuf; unsigned long ncmd; unsigned int errs[MAX_ERRS]; Ticker timeouter; + + // state machine stuff + typedef enum {STATE_IDLE, + STATE_HANDCHEKED, + STATE_COMMAND, + STATE_PAYLOAD_SIZE, + STATE_PAYLOAD, + NUM_STATES} state_t; + + + typedef struct instance_data { + uint8_t cmd; + uint8_t size; + uint8_t received; + char payload[MAX_BUFF]; + } instance_data_t; + + state_t do_state_initial(instance_data_t *data, uint8_t c); + state_t do_state_handcheck(instance_data_t *data, uint8_t c); + state_t do_state_command(instance_data_t *data, uint8_t c); + state_t do_state_payload_size(instance_data_t *data, uint8_t c); + state_t do_state_payload(instance_data_t *data, uint8_t c); + + void send_ack(uint8_t c); + + // pointer to "state method" (ie. one of the just above) + typedef state_t(HPSerial::*statemethod)(instance_data_t *data, uint8_t c); + statemethod const state_table[NUM_STATES] = { + &HPSerial::do_state_initial, + &HPSerial::do_state_handcheck, + &HPSerial::do_state_command, + &HPSerial::do_state_payload_size, + &HPSerial::do_state_payload, + }; + + state_t run_state(state_t cur_state, instance_data_t *data, uint8_t c); + + state_t cur_state; + instance_data rx_data; }; #endif
--- a/src/main.cpp Wed Oct 26 22:41:16 2016 +0200 +++ b/src/main.cpp Sat Oct 29 23:44:31 2016 +0200 @@ -12,6 +12,8 @@ #include "SSD1322.h" #include "hp34comm.h" +#include "Keypad.h" + #if (defined STM32L432xx) // display #define DSP_MOSI PA_7 //A6 @@ -21,6 +23,7 @@ #define DSP_RST PB_5 //D11 #define DSP_DC PB_4 //D12 // UART for RX (CPU->DP) and TX (DP->CPU) combined +#define HP_TX PA_9 // serial1 TX #define HP_RX PA_10 // serial1 RX // misc #define DBGPIN PA_12 @@ -67,6 +70,9 @@ Timeout blinker; DigitalOut led(LED1); +Keypad kpad(std::vector<int>({(int)PA_0, (int)PA_1}), + std::vector<int>({(int)PA_8, (int)PA_11})); + uint8_t curchar; uint8_t cmd; uint8_t nchars; @@ -284,7 +290,7 @@ wait(2); dsp->cls(); - hp = new HPSerial(HP_RX); + hp = new HPSerial(HP_TX, HP_RX); //hp = NULL; } @@ -530,26 +536,23 @@ } for (uint8_t i=0; i<7; i++) err[i] = hp->nerrors(i); - printf("CMD[%s:%d] %02X", (cmd.direction==HPSerial::Rx)?"Rx":"Tx", cmd.id, - cmd.cmd); + printf("CMD[%d] %02X", cmd.id, cmd.cmd); - if (cmd.direction == HPSerial::Rx) { - if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C)) - printf(": '%s'\n", cmd.value); - else { - printf(":"); - for (uint8_t i=0; i<cmd.size; i++) - printf("%02x ", cmd.value[i]); - printf("\n"); - } - show(cmd.cmd, cmd.value, cmd.size); + if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C)) + printf(": '%s'\n", cmd.value); + else { + printf(":"); + for (uint8_t i=0; i<cmd.size; i++) + printf("%02x ", cmd.value[i]); + printf("\n"); } - else - printf("\n"); + show(cmd.cmd, cmd.value, cmd.size); + } + else + printf("\n"); - if (cmd.direction == HPSerial::Rx) - show(cmd.cmd, cmd.value, cmd.size); - } + show(cmd.cmd, cmd.value, cmd.size); + led = 0; } else