Sat, 29 Oct 2016 23:44:31 +0200
[full replacement] implement a state machine for Rx
#include "hp34comm.h" #include "mbed.h" #include "CircularBuffer.h" /***** HP 34970A communication class ***/ #ifdef DEBUG2 DigitalOut inrx(D9); DigitalOut intx(D5); DigitalOut ack(D6); DigitalOut staterx(A0); DigitalOut statetx(D10); #endif DigitalOut lled(LED1); 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) { return !cmdbuf.empty(); } bool HPSerial::pop(CMD& cmd) { return cmdbuf.pop(cmd); } bool HPSerial::cmd_buf_full(void) { return cmdbuf.full(); } unsigned int HPSerial::nerrors(uint8_t errorno) { return errs[errorno]; } void HPSerial::pushCmd(uint8_t cmd, uint8_t size, char *payload) { CMD val; uint8_t i; val.id = ncmd++; val.cmd = cmd; val.size = size; for(i=0; i<size; i++) val.value[i] = payload[i]; val.value[i] = 0x00; cmdbuf.push(val); } 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; } 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.readable()) { // no reason why we would end here without // this condition, but hey #ifdef DEBUG2 inrx=1; #endif lled = 1; val = serial.getc(); cur_state = run_state(cur_state, &rx_data, val); lled = 0; #ifdef DEBUG2 inrx=0; #endif } } void HPSerial::timeout(void) { cur_state = do_state_initial(&rx_data, 0x00); }