[full replacement] implement a state machine for Rx draft

Sat, 29 Oct 2016 23:44:31 +0200

author
David Douard <david.douard@logilab.fr>
date
Sat, 29 Oct 2016 23:44:31 +0200
changeset 18
4fd621551d55
parent 17
162fe523c37d
child 19
a52d60613cf7

[full replacement] implement a state machine for Rx

src/hp34comm.cpp file | annotate | diff | comparison | revisions
src/hp34comm.h file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
--- a/src/hp34comm.cpp	Wed Oct 26 22:41:16 2016 +0200
+++ b/src/hp34comm.cpp	Sat Oct 29 23:44:31 2016 +0200
@@ -15,19 +15,15 @@
 #endif
 
 DigitalOut lled(LED1);
-  
-HPSerial::HPSerial(PinName rx):
-  serial_rx(NC, rx),
-  ncmd(0) {
-  
-  //pc.printf("HPSerial init\n");
+
+
 
-  for(uint8_t i=0; i<MAX_ERRS; i++)
-    errs[i] = 0;
-  reset();
-  
-  serial_rx.baud(187500);
-  serial_rx.attach(this, &HPSerial::rxIrq, Serial::RxIrq);
+HPSerial::HPSerial(PinName tx, PinName rx):
+  serial(tx, rx)
+{
+  cur_state = do_state_initial(&rx_data, 0x00);
+  serial.baud(187500);
+  serial.attach(this, &HPSerial::rxIrq, Serial::RxIrq);
 }
 
 bool HPSerial::cmd_available(void) {
@@ -45,63 +41,11 @@
 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_cmd == 0xFF) // beginning of a packet, expect 0x99 as ack
-      if (val == 0x99)
-	{
-	  tx_ack = true;
-#ifdef DEBUG2
-	  ack = 1;
-	  wait_us(2);
-	  ack = 0;
-#endif
-	}
-      else 
-	reset(1);
-
-    else // expect 0x00 as ack
-      if (val == 0x00)
-	{
-	  tx_ack = true;
-#ifdef DEBUG2
-	  ack = 1;
-	  wait_us(2);
-	  ack = 0;
-#endif
-	}
-      else
-	reset(2);
-}
-
-void HPSerial::pushCmd(TrState direction, uint8_t cmd, uint8_t size, char *payload) {
+void HPSerial::pushCmd(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++)
@@ -110,114 +54,92 @@
   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;
-      tx_len = 0xFF;
-    }
-    else if (tx_len == 0xFF) {
-      if (val == 0x55) {
-	// packet was in fact a keystroke, tx_cmd is in fact the key
-	// stroke and no payload is expected 
-#ifdef DEBUG2
-      statetx = 1;
-#endif
-      pushCmd((TrState)Tx, tx_cmd, 0, (char*)buf);
-#ifdef DEBUG2
-      wait_us(2);
-      statetx = 0;
-#endif
-      reset();
-      } else {
-	// got a cmd, expect a payload size
-	tx_len = val;
-	tx_ack = false;
-      }
-    }
-    else if (tx_len == 0x55) {
-      // packet was in fact a keystroke, tx_cmd is in fact the key
-      // stroke and no payload is expected 
-#ifdef DEBUG2
-      statetx = 1;
-#endif
-      pushCmd((TrState)Tx, tx_cmd, 0, (char*)buf);
-#ifdef DEBUG2
-      wait_us(2);
-      statetx = 0;
-#endif
-      reset();
-    }
-    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((TrState)tx_state, tx_cmd, head, (char*)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::send_ack(uint8_t c) {
+  timeouter.attach(this, &HPSerial::timeout, 0.001); // if nothing else happen in the next ms, reset
+  serial.putc(c);
+}
+
+HPSerial::state_t HPSerial::do_state_initial(HPSerial::instance_data_t *data,
+				   uint8_t c)
+{
+  // go back to initial state
+  data->cmd = 0xFF;
+  data->size = 0;
+  data->received = 0;
+  timeouter.detach();
+  return HPSerial::STATE_IDLE;
+}
+
+HPSerial::state_t HPSerial::do_state_handcheck(HPSerial::instance_data_t *data,
+				     uint8_t c)
+{
+  // we are idle, incoming char is a handcheck
+  // knwon handcheck values are 0x66 and 0x33
+  switch (c) {
+  case 0x33:
+    send_ack(0xCC);
+    return HPSerial::STATE_PAYLOAD_SIZE;
+    break;
+  case 0x66:
+    send_ack(0x99);
+    return HPSerial::STATE_COMMAND;
+    break;
+  default:
+    return do_state_initial(data, 0x00);
+  }
 }
 
+HPSerial::state_t HPSerial::do_state_command(HPSerial::instance_data_t *data,
+					     uint8_t c)
+{
+  if (c == 0x55) { // EoT
+    return do_state_initial(data, 0x00);
+  }
 
+  data->cmd = c;
+  data->size = 0;
+  send_ack(0x00);
+  return HPSerial::STATE_PAYLOAD_SIZE;
+}
 
-void HPSerial::setstatedbg(void) {
-#ifdef DEBUG2
-    if (tx_state == Rx)
-      staterx = 1;
-    else
-      staterx = 0;
-    if (tx_state == Tx)
-      statetx = 1;
-    else
-      statetx = 0;
-#endif
+HPSerial::state_t HPSerial::do_state_payload_size(HPSerial::instance_data_t *data,
+						  uint8_t c)
+{
+  data->size = c;
+  data->received = 0;
+  send_ack(0x00);
+  return HPSerial::STATE_PAYLOAD;
 }
 
+HPSerial::state_t HPSerial::do_state_payload(HPSerial::instance_data_t *data,
+					uint8_t c)
+{
+  data->payload[data->received++] = c;
+  send_ack(0x00);
+  if (data->received >= data->size) {
+    pushCmd(data->cmd, data->size, data->payload);
+    return HPSerial::STATE_COMMAND;
+  }
+  return HPSerial::STATE_PAYLOAD;
+}
+
+HPSerial::state_t HPSerial::run_state(HPSerial::state_t cur_state,
+				      HPSerial::instance_data_t *data,
+				      uint8_t c)
+{
+  return (this->*(HPSerial::state_table[cur_state]))(data, c);
+};
+
 void HPSerial::rxIrq(void) {
   uint8_t val;
-  if(serial_rx.readable()) { // no reason why we would end here without this condition, but hey
+  if(serial.readable()) { // no reason why we would end here without
+			  // this condition, but hey
 #ifdef DEBUG2
     inrx=1;
 #endif
     lled = 1;
-    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_ack == false)  // manage the acks
-      handleAck(val);
-    else 
-      handleChar(val);
+    val = serial.getc();
+    cur_state = run_state(cur_state, &rx_data, val);
     lled = 0;
 #ifdef DEBUG2
     inrx=0;
@@ -227,7 +149,5 @@
 
 
 void HPSerial::timeout(void) {
-  if (tx_state != Idle) {
-    reset(7);
-  }
+  cur_state = do_state_initial(&rx_data, 0x00);
 }
--- a/src/hp34comm.h	Wed Oct 26 22:41:16 2016 +0200
+++ b/src/hp34comm.h	Sat Oct 29 23:44:31 2016 +0200
@@ -10,17 +10,13 @@
 #define MAX_BUFF 16
 #define BUF_SIZE 16
 
+
+
 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];
@@ -29,7 +25,7 @@
 
 
   
-  HPSerial(PinName rx);
+  HPSerial(PinName tx, PinName rx);
   
   bool cmd_available(void);
   bool pop(CMD& cmd);
@@ -38,26 +34,57 @@
 		     
   
 private:
-  void reset(uint8_t errorno=0xFF);
-  void handleAck(uint8_t val);
-  void pushCmd(TrState direction, uint8_t cmd, uint8_t size, char *payload);
-  void handleChar(uint8_t val);
-  void setstatedbg(void);    
+  void pushCmd(uint8_t cmd, uint8_t size, char *payload);
   void rxIrq(void);
   void timeout(void);
 
  private:
-  RawSerial serial_rx;
+  RawSerial serial;
   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;
+
+  // state machine stuff
+  typedef enum {STATE_IDLE,
+		STATE_HANDCHEKED,
+		STATE_COMMAND,
+		STATE_PAYLOAD_SIZE,
+		STATE_PAYLOAD,
+		NUM_STATES} state_t;
+
+  
+  typedef struct instance_data {
+    uint8_t cmd;
+    uint8_t size;
+    uint8_t received;
+    char payload[MAX_BUFF];
+  } instance_data_t;
+
+  state_t do_state_initial(instance_data_t *data, uint8_t c);
+  state_t do_state_handcheck(instance_data_t *data, uint8_t c);
+  state_t do_state_command(instance_data_t *data, uint8_t c);
+  state_t do_state_payload_size(instance_data_t *data, uint8_t c);
+  state_t do_state_payload(instance_data_t *data, uint8_t c);
+
+  void send_ack(uint8_t c);
+  
+  // pointer to "state method" (ie. one of the just above)
+  typedef state_t(HPSerial::*statemethod)(instance_data_t *data, uint8_t c);
+  statemethod const state_table[NUM_STATES] = {
+      &HPSerial::do_state_initial,
+      &HPSerial::do_state_handcheck,
+      &HPSerial::do_state_command,
+      &HPSerial::do_state_payload_size,
+      &HPSerial::do_state_payload,
+  };
+  
+  state_t run_state(state_t cur_state, instance_data_t *data, uint8_t c);
+
+  state_t cur_state;
+  instance_data rx_data;
 };
 
 #endif
--- a/src/main.cpp	Wed Oct 26 22:41:16 2016 +0200
+++ b/src/main.cpp	Sat Oct 29 23:44:31 2016 +0200
@@ -12,6 +12,8 @@
 #include "SSD1322.h"
 #include "hp34comm.h"
 
+#include "Keypad.h"
+
 #if (defined STM32L432xx)
 // display
 #define DSP_MOSI PA_7 //A6
@@ -21,6 +23,7 @@
 #define DSP_RST  PB_5 //D11
 #define DSP_DC   PB_4 //D12
 // UART for RX (CPU->DP) and TX (DP->CPU) combined
+#define HP_TX PA_9 // serial1 TX
 #define HP_RX PA_10 // serial1 RX
 // misc
 #define DBGPIN PA_12
@@ -67,6 +70,9 @@
 Timeout blinker;
 DigitalOut led(LED1);
 
+Keypad kpad(std::vector<int>({(int)PA_0, (int)PA_1}),
+	    std::vector<int>({(int)PA_8, (int)PA_11}));
+
 uint8_t curchar;
 uint8_t cmd;
 uint8_t nchars;
@@ -284,7 +290,7 @@
   wait(2);
   dsp->cls();
 
-  hp = new HPSerial(HP_RX);
+  hp = new HPSerial(HP_TX, HP_RX);
   //hp = NULL;
 }
 
@@ -530,26 +536,23 @@
 		}
 	      for (uint8_t i=0; i<7; i++)
 		err[i] = hp->nerrors(i);
-	      printf("CMD[%s:%d] %02X", (cmd.direction==HPSerial::Rx)?"Rx":"Tx", cmd.id,
-		     cmd.cmd);
+	      printf("CMD[%d] %02X", cmd.id, cmd.cmd);
 	      
-	      if (cmd.direction == HPSerial::Rx) {
-		if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C))
-		  printf(": '%s'\n", cmd.value);
-		else {
-		  printf(":");
-		  for (uint8_t i=0; i<cmd.size; i++)
-		    printf("%02x ", cmd.value[i]);
-		  printf("\n");	      
-		}
-		show(cmd.cmd, cmd.value, cmd.size);
+	      if ((cmd.cmd == 0x00) || (cmd.cmd == 0x0C))
+		printf(": '%s'\n", cmd.value);
+	      else {
+		printf(":");
+		for (uint8_t i=0; i<cmd.size; i++)
+		  printf("%02x ", cmd.value[i]);
+		printf("\n");	      
 	      }
-	      else
-		printf("\n");
+	      show(cmd.cmd, cmd.value, cmd.size);
+	    }
+	  else
+	    printf("\n");
 	  
-	      if (cmd.direction == HPSerial::Rx)
-		show(cmd.cmd, cmd.value, cmd.size);
-	    }
+	  show(cmd.cmd, cmd.value, cmd.size);
+	    
 	  led = 0;
 	}
       else

mercurial