Patricio Silva / Mbed 2 deprecated c3auto

Dependencies:   mbed

Revision:
0:57215055833e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Oct 23 14:07:50 2019 +0000
@@ -0,0 +1,374 @@
+#include "mbed.h"
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Conf IO
+DigitalOut led1(LED1); // HeartBeat
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Timers
+Ticker timer100ms;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Comunicación Serial
+
+#define RXBUFFERSIZE 256
+#define TXBUFFERSIZE 256
+#define RXCMDTIME 50000
+#define TXCMDTIME 50000
+// Header
+const uint8_t header[7] = {0x55, 0x4E, 0x45, 0x52, 0x00, 0x00, 0x3A};
+
+Serial pc(USBTX, USBRX); // tx, rx
+
+//////////////////////////////////////////
+// Tipos de dato
+//////////////////////////////////////////
+
+/*
+ * Indices de lectura y escritura del buffer circular
+ * checksum y marcas de tiempo para el envio por puerto serie
+ * empty indica si la cola esta vacia o llena cuando indexR=indexW
+ */
+typedef struct{
+  uint8_t indexR;
+  uint8_t indexW;
+  uint8_t buf[RXBUFFERSIZE];
+  uint8_t chksum;
+  bool empty;
+  uint64_t cmdTime;
+  uint8_t chksumHeader;
+} _txbuffer;
+
+/*
+ * Indices de lectura y escritura del buffer circular
+ * marcas de tiempo, indice de comando y tamaño del comando
+ */
+typedef struct{
+  uint8_t indexR;
+  uint8_t indexW;
+  uint8_t buf[RXBUFFERSIZE];
+  uint64_t cmdTime;
+  uint8_t cmdIndex;
+  uint8_t stage;
+  bool cmd;
+  uint8_t chksum;
+  uint16_t payloadSize;
+} _rxbuffer;
+
+
+///////////////////////////////
+// Variables
+////////////////////////////////
+
+// defino los buffer
+_txbuffer TX;
+_rxbuffer RX;
+
+
+///////////////////////////////
+// Prototipos Serial
+///////////////////////////////
+
+void serialSetup(uint16_t);
+
+
+/* Escribe en el puerto serie los datos del buffer
+ * en cualquier escribo solo de a 1 byte por llamada
+ */
+void serialSubmit();
+
+
+/* Carga al buffer lo recibido por puerto serie
+ */
+void serialReceive();
+
+
+/*  Busca si hay un frame en el buffer que esté correcto y verifica el checksum
+ *  Si hay un header mueve el indice RX.cmdIndex a la posicion donde comienza el comando
+ *  y setea a true el flag RX.cmd. Mueve RX.indexR a esa posición para liberar el espacio
+ *  ocupado por el header. No procesa un nuevo comando hasta que no se ha procesado el anterior
+ *  notificandolo con clearCmd()
+ */
+void getFrame();
+
+
+/*
+ * Escribe en el buffer de salida un frame con un tamaño de comando+payload+checksum = s
+ * retorna true cuando termina de escribir, falso si no hay suficiente espacio (y restablece los indices)
+ */
+bool serialEnqueueHeader(uint16_t);
+
+
+/* Escribe el byte en el buffer de salida, retorna falso si no hay lugar suficiente para hacerlo
+ */
+bool serialEnqueueData(uint8_t);
+
+
+/* Encola el checksum
+ */
+bool serialEnqueueChksum();
+
+/* Borra el comando actual para que se pueda recibir el siguiente
+ */
+void cleanCmd();
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Prototipos de Utilidades
+void heartBeat();
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Funciones
+
+
+/*
+ * Señal de activo, dos parpadeos de 100ms cada dos segundos
+ */
+void heartBeat(){
+  static int count = 0;
+  switch (count++){
+    case 0:
+    case 2:
+        led1 = 0;
+        break;
+    case 1:
+    case 3:
+        led1 = 1;
+        break;
+    case 20:
+        count = 0;
+        break;
+    }
+}
+
+
+
+void serialSetup(uint16_t br){
+    RX.indexR=0;
+    RX.indexW=0;
+    RX.stage=0;
+    RX.cmd=false;
+    TX.indexR=0;
+    TX.indexW=0;
+    TX.empty=true;
+    // Calculo el checksum del header
+    TX.chksumHeader = header[0];
+    for (uint8_t i = 1 ; i < 4 ; i++){
+        TX.chksumHeader ^= header[i];
+    }
+    pc.baud(19200);
+    pc.attach(&serialReceive);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+// Funciones para el manejo del protocolo
+////////////////////////////////////////////////////////////////////////
+
+// Carga al buffer lo recibido por puerto serie
+void serialReceive(){
+  while (pc.readable() && (uint8_t)(RX.indexW+1) != RX.indexR){
+    RX.buf[RX.indexW++] = pc.getc();;
+  }
+}
+
+
+
+/* Escribe en el puerto serie los datos del buffer
+ * en cualquier escribo solo de a 1 byte por llamada
+ */
+void serialSubmit(){
+    if(TX.indexR!=TX.indexW){
+      pc.putc(TX.buf[TX.indexR++]);
+    }
+  TX.empty = (TX.indexR==TX.indexW);
+}
+
+
+
+/*  Busca si hay un frame en el buffer que esté correcto y verifica el checksum
+ *  Si hay un header mueve el indice RX.cmdIndex a la posicion donde comienza el comando
+ *  y setea a true el flag RX.cmd. Mueve RX.indexR a esa posición para liberar el espacio
+ *  ocupado por el header
+ */
+void getFrame(){
+  uint8_t index;
+  
+  // No logré completar el comando dentro de la ventana de tiempo, considero vacio el buffer de entrada
+  if(RX.stage > 0 && RX.cmdTime+RXCMDTIME < us_ticker_read()){
+    RX.indexR = RX.indexW;
+    RX.stage = 0;
+    return;
+  }
+
+  // mientras hay bytes disponibles en el buffer, proceso desde donde quedé
+  index = RX.indexR+RX.stage;
+  while (index != RX.indexW){
+    switch (RX.stage){
+      case 0:
+          RX.cmdTime = us_ticker_read();
+      case 1:
+      case 2:
+      case 3:{
+          if(RX.buf[index] == header[RX.stage]){
+            RX.stage++;
+            index++;
+          }else{ // No coincide con un header, descarto hasta acá y empiezo de nuevo en el proximo ciclo
+            RX.indexR +=RX.stage;
+            RX.stage=0;
+            return;
+          }
+          break;
+      }
+      case 4:{
+          RX.payloadSize = RX.buf[index];
+          RX.stage++;
+          index++;
+          break;
+      }
+      case 5:{
+          RX.payloadSize += RX.buf[index]*256;
+          RX.stage++;
+          index++;
+          break;
+      }
+      case 6:{
+          if (RX.buf[index] == header[RX.stage]){ // Llego al separador ":", marco la posicion sigiente como cmdIndex
+            RX.stage++;
+            index++;
+          }else{
+            RX.indexR += 3; // Continuo desde la direccion de tamaño del payload
+            RX.stage = 0;
+            return;
+          }
+          break;
+      }
+      case 7:{
+          // empiezo a incrementar index hasta alcanzar el fin de trama (RX.indexR+RX.payloadSize+7)
+          // No avanzo si aún hay un comando por ejecutar
+          if(!RX.cmd && index == (uint8_t)(RX.indexR+RX.payloadSize+6)){ // alcance la posicion del checksum
+            // Calculo checksum y comparo
+            RX.chksum = RX.buf[RX.indexR];
+            for (uint16_t i = 1 ; i < RX.payloadSize+6 ; i++){
+              RX.chksum ^= RX.buf[(uint8_t)(RX.indexR+i)];
+             }
+            if(RX.buf[(uint8_t)(RX.indexR+RX.payloadSize+6)] == RX.chksum){
+              RX.cmd = true;
+              RX.cmdIndex = RX.indexR+7;
+              RX.indexR = RX.cmdIndex;
+              TX.cmdTime = us_ticker_read(); // marca de tiempo para responder el comando
+              RX.stage = 0;
+              return;
+            }else{
+              RX.indexR += 3; // checksum incorrecto, continuo procesando desde la direccion de tamaño del payload
+              RX.stage = 0;
+            }
+            return;
+          }else{
+            index++;
+          }
+          break;
+      }
+      default:{
+          RX.stage = 0;
+          return;
+      }
+    }
+  }
+}
+
+
+ 
+/*
+ * Escribe en el buffer de salida un frame con un tamaño de comando+payload+checksum = s
+ * retorna true cuando termina de escribir, falso si no hay suficiente espacio (y restablece los indices)
+ */
+bool serialEnqueueHeader(uint16_t s){
+  uint8_t index = TX.indexW;
+  // Inicializo chechsum
+  TX.chksum = TX.chksumHeader;
+
+  // escribo la cabecera
+  for (uint8_t i = 0 ; i < 4 ; i++){
+      if(TX.indexR != TX.indexW || TX.empty){
+        TX.buf[TX.indexW++] = header[i];
+      }else{
+        TX.indexW = index;
+        return false;
+      }
+  }
+  // Escribo el tamaño
+  if(TX.indexR != TX.indexW || TX.empty){
+    TX.buf[TX.indexW++] = (uint8_t)s;
+    TX.chksum ^= (uint8_t)s;
+  }else{
+    TX.indexW = index;
+    return false;
+  }
+  if(TX.indexR != TX.indexW || TX.empty){
+    TX.buf[TX.indexW++] = (uint8_t)(s/256);
+    TX.chksum ^= (uint8_t)(s/256);
+  }else{
+    TX.indexW = index;
+    return false;
+  }
+  // escribo el separador
+  if(TX.indexR != TX.indexW || TX.empty){
+    TX.buf[TX.indexW++] = header[6];
+    TX.chksum ^= header[6];
+  }else{
+    TX.indexW = index;
+    return false;
+  }
+  return true;
+}
+
+// Escribe el byte en el buffer de salida, retorna falso si no hay lugar suficiente para hacerlo
+bool serialEnqueueData(uint8_t d){
+  if(TX.indexR != TX.indexW || TX.empty){
+    TX.buf[TX.indexW++] = d;
+    TX.chksum ^= d;
+    return true;
+  }else{
+    TX.indexW--;
+    return false;
+  }
+}
+
+// Encola el checksum
+bool serialEnqueueChksum(){
+  return serialEnqueueData(TX.chksum);
+}
+
+
+/* 
+ * Borra el comando actual para que getFrame pueda recibir el siguiente
+ * Necesario por cada overflow de us_ticker_read()
+ */
+void cleanCmd(){
+    RX.cmd = false;
+    RX.cmdTime = 0;
+    RX.indexR = RX.cmdIndex+RX.payloadSize;
+    TX.cmdTime = 0;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// MAIN
+
+
+int main(){
+    uint32_t maxUsTicker = us_ticker_read();
+    timer100ms.attach(&heartBeat, 0.1);
+    serialSetup(19200);
+    while(1){
+        // Overflow de us_ticker_read(), reseteo todo lo que utiliza este dato
+        if(maxUsTicker > us_ticker_read()){
+            maxUsTicker = us_ticker_read();
+            cleanCmd();
+        }
+    }
+}
+