Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: main.cpp
- 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();
+ }
+ }
+}
+