Tue, 13 Sep 2016 21:32:48 +0200
another attempt using a more complete support of the protocol and async serial stuff
src/main.cpp | file | annotate | diff | comparison | revisions |
--- a/src/main.cpp Fri Sep 09 23:42:39 2016 +0200 +++ b/src/main.cpp Tue Sep 13 21:32:48 2016 +0200 @@ -1,21 +1,27 @@ #include "stdio.h" + #include "mbed.h" #include "string" +#include "CircularBuffer.h" + #include "Terminal6x8.h" #include "Mono19x27.h" #include "Mono15x22.h" #include "Arial12x12.h" -#include "BufferedSerial.h" - #include "SSD1322.h" Serial pc(USBTX, USBRX); -BufferedSerial hp(NC, PA_1, 64, 0); // serial4 + +//BufferedSerial hp(NC, PA_1, 64, 0); // serial4 +#define HP_SERIAL_TX PC_7 // serial6 RX +#define HP_SERIAL_RX PA_1 // serial4 RX SSD1322 dsp(SPI_8, 10000000, PB_15, PB_14, PB_13, PB_12, D11, D12, "SSD1322", 256, 64); -#define MAX_BUFF 14 +#define BUF_SIZE 32 +#define MAX_BUFF 15 +#define MAX_ERRS 10 uint8_t curchar; uint8_t cmd; uint8_t nchars; @@ -137,6 +143,202 @@ {} #endif + + +/***** HP 34970A communication class ***/ + +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]; + unsigned long id; + } CMD; + + + + 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 cmd_available(void) { + return !cmdbuf.empty(); + } + + bool pop(CMD& cmd) { + return cmdbuf.pop(cmd); + } + + bool cmd_buf_full(void) { + return cmdbuf.full(); + } + + unsigned int nerrors(uint8_t errorno) { + return errs[errorno]; + } + + + +private: + void reset(uint8_t errorno=0xFF) { + head = 0; + tx_state = Idle; + tx_cmd = 0xFF; + tx_ack = false; + tx_len = 0xFF; + memset(buf, 0, BUF_SIZE); + if (errorno != 0xFF) + errs[errorno]++; + } + + void handleAck(uint8_t val) { + 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; + else + reset(1); + + else // expect 0x00 as ack + if (val == 0x00) + tx_ack = true; + else + reset(2); + } + + void 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 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) { + // 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 { + uint8_t cur_state = tx_state; + pushCmd(tx_state, tx_cmd, head, buf); + reset(); + + if (val != 0x55) { // not an end of transmission + // should be another cmd I think + tx_cmd = val; + tx_state = cur_state; + } + } + } + + + void rxIrq(void) { + uint8_t val; + if(serial_rx.readable()) { // no reason why we would end here without this condition, but hey + val = serial_rx.getc(); + + if (tx_state == Idle) + if (val == 0x66) { + // no transmission in progress, expect a start of transmission + tx_state = Rx; + tx_ack = false; + } + else + reset(4); + + else if (tx_state == Tx) // manage the acks + handleAck(val); + + else + handleChar(val); + } + } + + void txIrq(void) { + uint8_t val; + if(serial_tx.readable()) { // no reason why we would end here without this condition, but hey + val = serial_tx.getc(); + + if (tx_state == Idle) + if (val == 0x66) { + // no transmission in progress, expect a start of transmission + tx_state = Tx; + tx_ack = false; + } + else + reset(5); + + else if (tx_state == Rx) // manage the acks + handleAck(val); + + else + handleChar(val); + } + } + +private: + RawSerial serial_tx; + RawSerial serial_rx; + 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]; +}; + + +HPSerial hp; +Ticker dsp_refresher; +volatile bool must_refresh; + +void copy_to_lcd(void); void test_dsp(); void setup() { @@ -147,8 +349,6 @@ pc.printf("\n\nSystem Core Clock = %.3f MHZ\r\n", (float)SystemCoreClock/1000000); - hp.baud(187500); - // myLCD.set_font((unsigned char*) Terminal6x8); // myLCD.claim(stdout); // send stdout to the LCD display // myLCD.claim(stderr); // send stderr to the LCD display @@ -161,6 +361,7 @@ cmd = 0xFF; curchar = 0; nchars = 0; + dsp.printf("HP34970A"); dsp.set_font(Terminal6x8); @@ -173,14 +374,17 @@ dsp.copy_to_lcd(); wait(2); dsp.cls(); + + dsp_refresher.attach(©_to_lcd, 0.1); test_dsp(); wait(2); dsp.cls(); + } -void go_msg() { - dsp.set_font((unsigned char*) Arial12x12); - dsp.locate(0, 38); +void copy_to_lcd(void) { + if (must_refresh) + dsp.copy_to_lcd(); } void show(uint8_t cmd, char *txt, uint8_t nchar=0) { @@ -188,6 +392,8 @@ uint16_t bgcolor, fgcolor; char *oldv; + must_refresh = false; + len = MAX_BUFF; for (i=0; i<sizeof(table)/sizeof(table[0]); ++i) { @@ -266,8 +472,8 @@ } } } - dsp.copy_to_lcd(); - + must_refresh = true; + //dsp.copy_to_lcd(); } void test_dsp() @@ -275,92 +481,32 @@ show(0x00, "8g8g8g8g8g8g8", 13); // main dsp show(0x0C, "888", 3); // channel dsp show(0x0A, "\xFF\xFF\xFF\xFF", 4); // flags - dsp.copy_to_lcd(); } void loop() { // run over and over - if (hp.readable()) { - uint8_t val = hp.getc(); - DebugPulse(3); - // 0xFF: idle - // 0xFE: frame finished - // 0x66: Start of transmission received - pc.printf(" VAL=0x%X\tCMD=0x%X\n", val, cmd); - if (cmd == 0xFF) { - if ((val == 0x66) || (val == 0x99)) { - cmd = val; - } else if ((val == 0x00) || (val == 0x55)){ - // probably an ACK for a keypad related event - } else { - // display "junk" byte - //DebugPulse(); - show(0xFF, "", 0); - dsp.printf("%02X:> %02x", cmd, val); - } - - } else if (cmd == 0xFE ) { - if ((val == 0x66) || (val == 0x99)) { - cmd = val; - } else if (val == 0x55) { - cmd = 0xFF; - } else if (val == 0x00){ - // probably an ACK for a keypad related event - } else { - // display "junk" byte - DebugPulse(); - show(0xFF, "", 5); - dsp.printf("%02X=> %02x", cmd, val); - } + if (hp.cmd_available()) + { + HPSerial::CMD cmd; + if (hp.pop(cmd)) + { + pc.printf("CMD[%s:%d %d/%d/%d/%d/%d/%d] %X\n", (cmd.direction==HPSerial::Rx)?"Rx":"Tx", cmd.id, + hp.nerrors(0), + hp.nerrors(1), + hp.nerrors(2), + hp.nerrors(3), + hp.nerrors(4), + hp.nerrors(5), + cmd.cmd); - } else if (cmd == 0x66) { // waiting for the display command - if ((val == 0x0C) || (val == 0x00) || (val == 0x01) || (val == 0x02) || (val == 0x0A)) { - cmd = val; - nchars = 0; - } else { - cmd = 0xFE; - // display unknown cmd byte - DebugPulse(); - show(0xFF, "", 10); - dsp.printf("%02X-> %02x", cmd, val); - } - - } else if (cmd == 0x99) { // waiting for a 0x00, it's the DP that sent a keypress event - if (val != 0x00) { - show(0xFF, "", 0); - dsp.printf("%02X kp %02X", cmd, val); - } - cmd = 0xFF; - - } else if (nchars == 0) { // waiting for the number of chars to display - if (val>MAX_BUFF) { - // display warning - //dsp(); - //dsp << cmd << " got len " << val; - //DebugPulse(); - show(0xFF, "", 0); - dsp.printf("%02X len %d", cmd, val); - cmd = 0xFE; // weird - } else { - nchars = val; - curchar = 0; - } - - } else { // a character to display - buffer[curchar] = val; - curchar++; - if (curchar == nchars) { - buffer[curchar] = 0x00; - show(cmd, buffer, nchars); - nchars = 0; - curchar = 0; - cmd = 0xFE; - } - } - - DebugPulse(4); - - } + if (cmd.direction == HPSerial::Rx) { + if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C)) + pc.printf(" data=%s\n", cmd.value); + show(cmd.cmd, cmd.value, cmd.size); + + } + } + } } int main()