Wed, 21 Sep 2016 20:09:21 +0200
[SSD1322] add a copy_to_lcd method that accepts an area
#ifndef HP34COMM_H #define HP34COMM_H /***** 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) { 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]++; pulse(errorno+1); } } void 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 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; 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 setstatedbg(void) { /* if (tx_state == Rx) staterx = 1; else staterx = 0; if (tx_state == Tx) statetx = 1; else statetx = 0; */ } void 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 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 timeout(void) { if (tx_state != Idle) { reset(7); } } 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]; Ticker timeouter; }; #endif