src/hp34comm.cpp

changeset 5
f1c85c2500f2
child 8
55021f3f1929
--- /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);
+  }
+}

mercurial