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.
Revision 0:57215055833e, committed 2019-10-23
- Comitter:
- elpatosilva
- Date:
- Wed Oct 23 14:07:50 2019 +0000
- Commit message:
- first commit
Changed in this revision
main.cpp | Show annotated file Show diff for this revision Revisions of this file |
mbed.bld | Show annotated file Show diff for this revision Revisions of this file |
--- /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(); + } + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Oct 23 14:07:50 2019 +0000 @@ -0,0 +1,1 @@ +https://os.mbed.com/users/mbed_official/code/mbed/builds/3a7713b1edbc \ No newline at end of file