From dc23bbaf5b9c19e07ee9211e32fc325710e8baff Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Tue, 23 Dec 2025 23:36:51 +0000 Subject: [PATCH] Reworking the communcation --- src/communication/commands.cpp | 16 + src/communication/commands.h | 10 +- src/communication/communication.cpp | 9 + src/communication/communication.h | 44 ++- src/communication/identificationPacket.h | 21 -- .../{identificationPacket.cpp => packets.cpp} | 7 +- src/communication/packets.h | 21 ++ src/communication/walkieTalkie.cpp | 104 +++++++ src/communication/walkieTalkie.h | 43 +++ src/main.cpp | 274 +++++++++++------- 10 files changed, 409 insertions(+), 140 deletions(-) create mode 100644 src/communication/commands.cpp delete mode 100644 src/communication/identificationPacket.h rename src/communication/{identificationPacket.cpp => packets.cpp} (75%) create mode 100644 src/communication/walkieTalkie.cpp create mode 100644 src/communication/walkieTalkie.h diff --git a/src/communication/commands.cpp b/src/communication/commands.cpp new file mode 100644 index 0000000..71c8c44 --- /dev/null +++ b/src/communication/commands.cpp @@ -0,0 +1,16 @@ +#include "commands.h" + +char* CommandToStr(Command id) { + switch(id) { + case CmdRequestID: + return (char*)"CmdRequestID"; + case CmdAckID: + return (char*)"CmdAckID"; + case CmdCreateWindow: + return (char*)"CmdCreateWindow"; + case CmdDestroyWindow: + return (char*)"CmdDestroyWindow"; + } + + return (char*)"CmdInvalid"; +} diff --git a/src/communication/commands.h b/src/communication/commands.h index f5ef139..ba3c204 100644 --- a/src/communication/commands.h +++ b/src/communication/commands.h @@ -4,11 +4,13 @@ #include typedef enum : uint8_t { - CmdRequestID = 0, - CmdAckID, - CmdCreateScreen, - CmdCreateWindow + CmdUnknown = 0, + CmdRequestID = 1, + CmdAckID = 2, + CmdCreateWindow = 3, + CmdDestroyWindow = 4 } Command; +char* CommandToStr(Command id); #endif diff --git a/src/communication/communication.cpp b/src/communication/communication.cpp index f8f6332..3ccb682 100644 --- a/src/communication/communication.cpp +++ b/src/communication/communication.cpp @@ -1 +1,10 @@ #include "communication.h" + +uint8_t CRC8(const uint8_t *data, size_t len) { + uint8_t crc = 0x00; + while (len--) { + crc = pgm_read_byte(&crc8_table[crc ^ *data++]); + } + + return crc; +} diff --git a/src/communication/communication.h b/src/communication/communication.h index 3478033..fd82690 100644 --- a/src/communication/communication.h +++ b/src/communication/communication.h @@ -1,6 +1,48 @@ #ifndef __COMMUNICATION__ #define __COMMUNICATION__ -int router(); +#include "pgmspace.h" +#include +#include + +const byte STX = 0x02; +const byte ETX = 0x03; +const byte ACK = 0x06; + +static const uint8_t crc8_table[256] PROGMEM = { + 0x00,0x07,0x0E,0x09,0x1C,0x1B,0x12,0x15, + 0x38,0x3F,0x36,0x31,0x24,0x23,0x2A,0x2D, + 0x70,0x77,0x7E,0x79,0x6C,0x6B,0x62,0x65, + 0x48,0x4F,0x46,0x41,0x54,0x53,0x5A,0x5D, + 0xE0,0xE7,0xEE,0xE9,0xFC,0xFB,0xF2,0xF5, + 0xD8,0xDF,0xD6,0xD1,0xC4,0xC3,0xCA,0xCD, + 0x90,0x97,0x9E,0x99,0x8C,0x8B,0x82,0x85, + 0xA8,0xAF,0xA6,0xA1,0xB4,0xB3,0xBA,0xBD, + 0xC7,0xC0,0xC9,0xCE,0xDB,0xDC,0xD5,0xD2, + 0xFF,0xF8,0xF1,0xF6,0xE3,0xE4,0xED,0xEA, + 0xB7,0xB0,0xB9,0xBE,0xAB,0xAC,0xA5,0xA2, + 0x8F,0x88,0x81,0x86,0x93,0x94,0x9D,0x9A, + 0x27,0x20,0x29,0x2E,0x3B,0x3C,0x35,0x32, + 0x1F,0x18,0x11,0x16,0x03,0x04,0x0D,0x0A, + 0x57,0x50,0x59,0x5E,0x4B,0x4C,0x45,0x42, + 0x6F,0x68,0x61,0x66,0x73,0x74,0x7D,0x7A, + 0x89,0x8E,0x87,0x80,0x95,0x92,0x9B,0x9C, + 0xB1,0xB6,0xBF,0xB8,0xAD,0xAA,0xA3,0xA4, + 0xF9,0xFE,0xF7,0xF0,0xE5,0xE2,0xEB,0xEC, + 0xC1,0xC6,0xCF,0xC8,0xDD,0xDA,0xD3,0xD4, + 0x69,0x6E,0x67,0x60,0x75,0x72,0x7B,0x7C, + 0x51,0x56,0x5F,0x58,0x4D,0x4A,0x43,0x44, + 0x19,0x1E,0x17,0x10,0x05,0x02,0x0B,0x0C, + 0x21,0x26,0x2F,0x28,0x3D,0x3A,0x33,0x34, + 0x4E,0x49,0x40,0x47,0x52,0x55,0x5C,0x5B, + 0x76,0x71,0x78,0x7F,0x6A,0x6D,0x64,0x63, + 0x3E,0x39,0x30,0x37,0x22,0x25,0x2C,0x2B, + 0x06,0x01,0x08,0x0F,0x1A,0x1D,0x14,0x13, + 0xAE,0xA9,0xA0,0xA7,0xB2,0xB5,0xBC,0xBB, + 0x96,0x91,0x98,0x9F,0x8A,0x8D,0x84,0x83, + 0xDE,0xD9,0xD0,0xD7,0xC2,0xC5,0xCC,0xCB, + 0xE6,0xE1,0xE8,0xEF,0xFA,0xFD,0xF4,0xF3 +}; +uint8_t CRC8(const uint8_t *data, size_t len); #endif diff --git a/src/communication/identificationPacket.h b/src/communication/identificationPacket.h deleted file mode 100644 index 6c59143..0000000 --- a/src/communication/identificationPacket.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __IDENTIFICATION_PACKET__ -#define __IDENTIFICATION_PACKET__ - -#include "packets.h" -#include -#include - -// eventually try this out with __attrubute__((packed)) -struct __attribute__((packed)) IdentificationPacket { - char StartMarker; - uint8_t DeviceID; - PacketType PktType; - char deviceName[32]; - char EndMarker; -}; - -void initIdentificationPacket(IdentificationPacket* packet, const char* name, - uint8_t id); -void sendIdentificationPacket(IdentificationPacket* packet); - -#endif diff --git a/src/communication/identificationPacket.cpp b/src/communication/packets.cpp similarity index 75% rename from src/communication/identificationPacket.cpp rename to src/communication/packets.cpp index 02aec1e..591a718 100644 --- a/src/communication/identificationPacket.cpp +++ b/src/communication/packets.cpp @@ -1,4 +1,4 @@ -#include "identificationPacket.h" +#include "packets.h" #include #include #include @@ -16,8 +16,3 @@ void initIdentificationPacket(IdentificationPacket* packet, const char* name, strncpy(packet->deviceName, name, strlen(name)); packet->deviceName[strlen(name)] = '\0'; } - -void sendIdentificationPacket(IdentificationPacket* packet) { - Serial.write((uint8_t*)packet, sizeof(*packet)); - Serial.flush(); -} diff --git a/src/communication/packets.h b/src/communication/packets.h index 8f84a25..44cd6bb 100644 --- a/src/communication/packets.h +++ b/src/communication/packets.h @@ -6,4 +6,25 @@ typedef uint8_t PacketType; const uint8_t identificationPacket = 0; +struct __attribute__((packed)) IdentificationPacket { + char StartMarker; + uint8_t DeviceID; + PacketType PktType; + char deviceName[32]; + char EndMarker; +}; + +void initIdentificationPacket(IdentificationPacket* packet, const char* name, + uint8_t id); + +struct __attribute__((packed)) NewWindowBody { + char StartMarker; + uint16_t x0; + uint16_t y0; + uint16_t width; + uint16_t height; + char title[32]; + char EndMarker; +}; + #endif diff --git a/src/communication/walkieTalkie.cpp b/src/communication/walkieTalkie.cpp new file mode 100644 index 0000000..39a7bf5 --- /dev/null +++ b/src/communication/walkieTalkie.cpp @@ -0,0 +1,104 @@ +#include "walkieTalkie.h" +#include "HardwareSerial.h" +#include "communication/commands.h" +#include "communication/communication.h" +#include +#include +#include + +namespace WalkieTalkie { + // ahem - maybe refactor this inferno! + size_t RecvData(Command *command, uint8_t *payload, uint16_t payloadMax) { + int16_t len = 0; + uint8_t crc = 0; + int16_t result = 0; + + while (Serial.available() > 0) { + uint8_t byte = Serial.read(); + switch(state) { + case WaitingSTX: + if (byte == STX) { + Serial2.println(F("First byte is STX")); + state = RecvCMD; + resetBuffer(); + } else { + Serial2.print(F("First byte is not STX: ")); + Serial2.println(byte); + } + break; + + case RecvCMD: + Serial2.println(F("Reading the command byte")); + + *command = Command(byte); + Serial2.print(" Command: "); + Serial2.println(byte); + + state = RecvLen; + resetBuffer(); + break; + + case RecvLen: + Serial2.println(F("Reading the len")); + buffer[bufferIndex++] = byte; + // we are currently using a int16_t for the len so: 2 bytes + if (bufferIndex > 1) { + len = buffer[0] | (buffer[1] << 8); + Serial2.print("Len: "); + Serial2.println(len); + state = RecvPayload; + resetBuffer(); + } + break; + + case RecvPayload: + Serial2.print("Reading payload: "); + Serial2.print(bufferIndex); + Serial2.print(" - "); + Serial2.println(byte); + buffer[bufferIndex++] = byte; + if (bufferIndex == len) { + // put the buffer data somewhere + memcpy(payload, buffer, len); + state = RecvCRC; + resetBuffer(); + } + break; + + case RecvCRC: + crc = byte; + Serial2.print("Reading CRC:"); + Serial2.println(crc); + + if (crc != CRC8(payload, len)) { + Serial2.print("CRC don't match. Expected: "); + Serial2.print(crc); + Serial2.print(", Got: "); + Serial2.println(CRC8(payload, len)); + + return -1; + break; + } + + state = RecvETX; + resetBuffer(); + break; + + case RecvETX: + Serial2.println("Reading ETX"); + if (byte != ETX) { + Serial2.print("Failure, last byte was: "); + Serial2.println(byte); + state = WaitingSTX; + return -1; + } else { + state = WaitingSTX; + return len; + } + break; + } + } + + return 0; + } +}; diff --git a/src/communication/walkieTalkie.h b/src/communication/walkieTalkie.h new file mode 100644 index 0000000..968a407 --- /dev/null +++ b/src/communication/walkieTalkie.h @@ -0,0 +1,43 @@ +#ifndef __WALKIE_TALKIE__ +#define __WALKIE_TALKIE__ + +#include "communication/communication.h" +#include "communication/commands.h" +#include +#include +#include + +namespace WalkieTalkie { + typedef enum { + WaitingSTX = 0, + RecvCMD = 1, + RecvLen = 2, + RecvPayload = 3, + RecvCRC = 4, + RecvETX = 5, + } RecvState; + + inline uint8_t buffer[4096]; + inline int16_t bufferIndex = 0; + inline RecvState state = WaitingSTX; + + inline static void resetBuffer() { + bufferIndex = 0; + } + + struct ACKPacket { + uint8_t StartMarker; + uint8_t ACK; + uint8_t EndMarker; + }; + + template + void SendData(PacketType *packet) { + Serial.write((uint8_t*)packet, sizeof(*packet)); + Serial.flush(); + } + + size_t RecvData(Command *command, uint8_t *payload, uint16_t payloadMax); +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index e0ed5d7..e2df5d5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,18 +7,17 @@ TODO: to have more ways to run analytics */ -#include "UIComponent.h" -#include "values.h" -#include "windowPool.h" -#include "UIScreen.h" -#include "UIDecorations.h" -#include "UIDimensions.h" -#include "communication/commands.h" -#include "communication/packets.h" -#include "communication/identificationPacket.h" #include "Arduino_GFX.h" #include "HardwareSerial.h" +#include "UIComponent.h" #include "UIDecorations.h" +#include "UIDimensions.h" +#include "UIScreen.h" +#include "communication/commands.h" +#include "communication/packets.h" +#include "communication/walkieTalkie.h" +#include "values.h" +#include "windowPool.h" // #include "UIDrawing.h" #include "UIString.h" // #include "UITable.h" @@ -56,20 +55,18 @@ Arduino_ESP32RGBPanel *panel = new Arduino_ESP32RGBPanel( Arduino_GFX *gfx = new Arduino_RGB_Display(TFT_HOR_RES, TFT_VER_RES, panel, 16); // HardwareSerial debugSerial(1); -Curses::Screen mainScreen( - gfx, - UIDimensions(0, 0, TFT_HOR_RES, TFT_VER_RES), - UIDecorations() -); +Curses::Screen mainScreen(gfx, UIDimensions(0, 0, TFT_HOR_RES, TFT_VER_RES), + UIDecorations()); // UIelements // UIDecorations *gearTextDecor = new UIDecorations(); -// UIString gearText(gfx, UIDimensions(0, 0, 0, 0), gearTextDecor, (char *)"Gear"); +// UIString gearText(gfx, UIDimensions(0, 0, 0, 0), gearTextDecor, (char +// *)"Gear"); // // UIElement mainWindow( -// gfx, +// gfx, // UIDimensions(0, 0, TFT_HOR_RES, TFT_VER_RES), -// gearTextDecor, +// gearTextDecor, // (char*)"MAIN WINDOW" // ); @@ -90,61 +87,64 @@ void setup() { mainScreen.Setup("Main Window"); // Grab a handle for the main window of the screen - UIElement* mainWindow = mainScreen.mainWindowHandle; + UIElement *mainWindow = mainScreen.mainWindowHandle; mainWindow->drawBox(); - int16_t childID = mainWindow->AddChild(STRING); - if (childID < 0) { - Serial2.println("Failed to add new window!"); - } else { - Serial2.print("Successfully added a new window: "); - Serial2.println(childID); - - UIElement* childComponent = mainWindow->GetChild(childID); - - childComponent->SetTitle((char*)"%s [%2d]", (const char*)"Child Window", childID); - childComponent->SetUIDecorations(UIDecorations()); - childComponent->SetUIDimensions(UIDimensions(20, 20, 300, 300)); - childComponent->SetDisplay(mainScreen.display); - - childComponent->drawBox(); - } - - childID = mainWindow->AddChild(STRING); - if (childID < 0) { - Serial2.println("Failed to add new window!"); - } else { - Serial2.print("Successfully added a new window: "); - Serial2.println(childID); - - UIElement* childComponent = mainWindow->GetChild(childID); - - childComponent->SetTitle((char*)"%s [%2d]", (const char*)"Second Child", childID); - childComponent->SetUIDecorations(UIDecorations()); - childComponent->SetUIDimensions(UIDimensions(330, 20, 300, 300)); - childComponent->SetDisplay(mainScreen.display); - - childComponent->drawBox(); - } - - mainWindow->RemoveChild(1); - - childID = mainWindow->AddChild(STRING); - if (childID < 0) { - Serial2.println("Failed to add new window!"); - } else { - Serial2.print("Successfully added a new window: "); - Serial2.println(childID); - - UIElement* childComponent = mainWindow->GetChild(childID); - - childComponent->SetTitle((char*)"%s [%2d]", (const char*)"Third Child", childID); - childComponent->SetUIDecorations(UIDecorations()); - childComponent->SetUIDimensions(UIDimensions(20, 20, 300, 300)); - childComponent->SetDisplay(mainScreen.display); - - childComponent->drawBox(); - } + // int16_t childID = mainWindow->AddChild(STRING); + // if (childID < 0) { + // Serial2.println("Failed to add new window!"); + // } else { + // Serial2.print("Successfully added a new window: "); + // Serial2.println(childID); + // + // UIElement *childComponent = mainWindow->GetChild(childID); + // + // childComponent->SetTitle((char *)"%s [%2d]", (const char *)"Child Window", + // childID); + // childComponent->SetUIDecorations(UIDecorations()); + // childComponent->SetUIDimensions(UIDimensions(20, 20, 300, 300)); + // childComponent->SetDisplay(mainScreen.display); + // + // childComponent->drawBox(); + // } + // + // childID = mainWindow->AddChild(STRING); + // if (childID < 0) { + // Serial2.println("Failed to add new window!"); + // } else { + // Serial2.print("Successfully added a new window: "); + // Serial2.println(childID); + // + // UIElement *childComponent = mainWindow->GetChild(childID); + // + // childComponent->SetTitle((char *)"%s [%2d]", (const char *)"Second Child", + // childID); + // childComponent->SetUIDecorations(UIDecorations()); + // childComponent->SetUIDimensions(UIDimensions(330, 20, 300, 300)); + // childComponent->SetDisplay(mainScreen.display); + // + // childComponent->drawBox(); + // } + // + // mainWindow->RemoveChild(1); + // + // childID = mainWindow->AddChild(STRING); + // if (childID < 0) { + // Serial2.println("Failed to add new window!"); + // } else { + // Serial2.print("Successfully added a new window: "); + // Serial2.println(childID); + // + // UIElement *childComponent = mainWindow->GetChild(childID); + // + // childComponent->SetTitle((char *)"%s [%2d]", (const char *)"Third Child", + // childID); + // childComponent->SetUIDecorations(UIDecorations()); + // childComponent->SetUIDimensions(UIDimensions(20, 20, 300, 300)); + // childComponent->SetDisplay(mainScreen.display); + // + // childComponent->drawBox(); + // } WindowPool::PrintInUse(); @@ -156,56 +156,114 @@ uint64_t lastDataRead = 0; bool gotAck = false; +struct header { + uint8_t StartMarker; + Command Cmd; + uint8_t EndMarker; +}; + +void PrintHeader(header *h) { + Serial2.println("HEADER:"); + Serial2.print(" StartMarker: "); + Serial2.println(h->StartMarker); + Serial2.print(" Command : "); + Serial2.println(CommandToStr(h->Cmd)); + Serial2.print(" EndMarker : "); + Serial2.println(h->EndMarker); + Serial2.println(); +} + +struct UIWindowPacket { + uint8_t StartMarker; + uint16_t x0; + uint16_t y0; + uint16_t width; + uint16_t height; + uint8_t EndMarker; +}; + uint64_t lastSent = 0; void loop(void) { uint64_t cur = millis(); - // if (!gotAck && (cur - lastSent) >= 1000) { - // // Send the packet again - // sendHello(); - // lastSent = cur; - // } - if (Serial.available() >= 1) { - uint8_t cmd = Serial.read(); - switch (cmd) { + // with this new way of reading data, we are just gonna read a payload + // and get a command + Command cmd = CmdUnknown; + uint8_t payload[256] = {0}; + + if (Serial.available() > 0) { + size_t resp = WalkieTalkie::RecvData(&cmd, payload, 256); + if (resp < 0) { + Serial2.println(F("Failed to receive data from serial")); + return; + } else if (resp == 0) { + Serial2.println(F("No data to receive")); + return; + } + + Serial2.print("Command: "); + Serial2.println(CommandToStr(cmd)); + Serial2.print("Response: "); + Serial2.println(resp); + + switch(cmd) { case CmdRequestID: - Serial2.println("Got identification request!"); - // gearText.Update("Connecting"); - IdentificationPacket papers; - initIdentificationPacket(&papers, ESLABS_DEVICE_NAME, ESLABS_DEVICE_ID); - sendIdentificationPacket(&papers); - break; - case CmdAckID: - Serial2.println("Got ack!"); - // gearText.Update("Connected"); - gotAck = true;; - break; - case NewWindow: - Serial2.println("Received request to create window"); - break; - case DestroyWindow: - Serial2.println("Received request to destroy window"); + initIdentificationPacket(&papers, ESLABS_DEVICE_NAME, ESLABS_DEVICE_ID); + WalkieTalkie::SendData(&papers); break; + default: + Serial2.print(F("Command `")); + Serial2.print(CommandToStr(cmd)); + Serial2.print(F("` has not been implemented yet.")); } } - - // // Request data here - // SendDataRequest(); + // // Try to use a state machine for this instead? Would it be better or just more + // // verbose and difficult to read? + // if (Serial.available() >= 1) { + // // Receive the header + // header h = {0}; + // int res = WalkieTalkie::RecvData(&h); + // if (res > 0) { + // PrintHeader(&h); + // } else { + // Serial2.println(F("Failed to read header")); + // return; + // } // - // // Receive data - // DataPacket telemetryPacket; - // int res = RecvDataPacket(&telemetryPacket); + // // Now we receive the body + // switch(h.Cmd) { + // case CmdRequestID: + // // We have no body to receive, we just return data + // break; + // case CmdCreateWindow: + // Serial2.println("Awaiting body..."); + // // We have to receive a body, should have plenty of data + // // + // UIWindowPacket windowData; + // size_t bytes = WalkieTalkie::RecvData(&windowData); + // if (bytes <= 0) { + // Serial2.println("Malformed data"); + // } // - // if (res == 0) { - // ui->Update(&telemetryPacket); + // Serial2.print("StartMarker: "); + // Serial2.println(windowData.StartMarker); + // Serial2.print("x0: "); + // Serial2.println(windowData.x0); + // Serial2.print("y0: "); + // Serial2.println(windowData.y0); + // Serial2.print("width: "); + // Serial2.println(windowData.width); + // Serial2.print("height: "); + // Serial2.println(windowData.height); + // // Serial2.print("title: "); + // // Serial2.println(windowData.title); + // Serial2.print("EndMarker: "); + // Serial2.println(windowData.EndMarker); // - // lastDataRead = millis(); - // } - // - // // If no data is received for 5 seconds, reset the display - // if (millis() - lastDataRead >= 5000) { - // Serial2.print("Resetting the display"); + // Serial2.println("Received body... Continuing"); + // break; + // } // } }