src/hp34comm.h~

changeset 5
f1c85c2500f2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hp34comm.h~	Tue Sep 20 23:50:45 2016 +0200
@@ -0,0 +1,270 @@
+#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

mercurial