--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hp34comm.cpp Tue Sep 20 23:50:45 2016 +0200 @@ -0,0 +1,252 @@ +#include "hp34comm.h" +#include "mbed.h" +#include "CircularBuffer.h" + +/***** HP 34970A communication class ***/ + +#define HP_SERIAL_TX PC_7 // serial6 RX +#define HP_SERIAL_RX PA_1 // serial4 RX + +#ifdef DEBUG + +DigitalOut inrx(PC_0); +DigitalOut intx(PC_1); +DigitalOut ack(PC_3); +DigitalOut staterx(PC_2); +DigitalOut statetx(PH_1); + +#endif + + +HPSerial::HPSerial(): + ncmd(0), + serial_tx(NC, HP_SERIAL_TX), serial_rx(NC, HP_SERIAL_RX) { + + //pc.printf("HPSerial init\n"); + + for(uint8_t i=0; i<MAX_ERRS; i++) + errs[i] = 0; + reset(); + + serial_tx.baud(187500); + serial_tx.attach(this, &HPSerial::txIrq, Serial::RxIrq); //sic! + + serial_rx.baud(187500); + serial_rx.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::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_ack == true) + reset(0); + + else + if (tx_cmd == 0xFF) // still at the beginning of a packet, expect 0x99 as ack + if (val == 0x99) + { + tx_ack = true; +#ifdef DEBUG + ack = 1; + wait_us(2); + ack = 0; +#endif + } + else + reset(1); + + else // expect 0x00 as ack + if (val == 0x00) + { + tx_ack = true; +#ifdef DEBUG + ack = 1; + wait_us(2); + ack = 0; + wait_us(2); + ack = 1; + wait_us(2); + ack = 0; +#endif + } + else + reset(2); +} + +void HPSerial::pushCmd(TrState direction, 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++) + val.value[i] = payload[i]; + val.value[i] = 0x00; + 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; + if (tx_state == Rx) + tx_len = 0xFF; + else + tx_len = 0x00; // no payload: tx_cmd is the key stroke + } + else if (tx_len == 0xFF) { + // got a cmd, expect a payload size + tx_len = val; + tx_ack = false; + } + 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(tx_state, tx_cmd, head, 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::setstatedbg(void) { + /* + if (tx_state == Rx) + staterx = 1; + else + staterx = 0; + if (tx_state == Tx) + statetx = 1; + else + statetx = 0; + */ +} + +void HPSerial::rxIrq(void) { + uint8_t val; + if(serial_rx.readable()) { // no reason why we would end here without this condition, but hey +#ifdef DEBUG + inrx=1; +#endif + 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_state == Tx) // manage the acks + handleAck(val); + + else + handleChar(val); +#ifdef DEBUG + inrx=0; +#endif + } +} + +void HPSerial::txIrq(void) { + uint8_t val; + if(serial_tx.readable()) { // no reason why we would end here without this condition, but hey +#ifdef DEBUG + intx=1; +#endif + val = serial_tx.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 = Tx; + tx_ack = false; + setstatedbg(); + } + else + reset(5); + + else if (tx_state == Rx) // manage the acks + handleAck(val); + + else + handleChar(val); + } +#ifdef DEBUG + intx=0; +#endif +} + +void HPSerial::timeout(void) { + if (tx_state != Idle) { + reset(7); + } +}