#pragma once #include // ============================================================================ // Protocol Constants // ============================================================================ // Sync bytes (distinguishable from Feetech 0xFF 0xFF) constexpr uint8_t SYNC0 = 0xA5; constexpr uint8_t SYNC1 = 0x5A; // Packet structure: // [SYNC0][SYNC1][TAG 4 bytes][LENGTH 2 bytes][SEQ 2 bytes][PAYLOAD...][CRC16 2 bytes] // Total overhead: 12 bytes constexpr uint16_t MAX_PAYLOAD_SIZE = 6000; constexpr uint16_t PACKET_HEADER_SIZE = 10; // sync(2) + tag(4) + len(2) + seq(2) constexpr uint16_t PACKET_CRC_SIZE = 2; // ============================================================================ // Packet Tags (4 bytes each, human-readable) // ============================================================================ namespace Tag { // Identity & Config constexpr char IDENT[4] = {'I','D','N','T'}; // Identity request/response constexpr char CONFG[4] = {'C','O','N','F'}; // Config update // File Operations constexpr char FLIST[4] = {'F','L','S','T'}; // File list constexpr char FLOAD[4] = {'F','L','O','D'}; // File load constexpr char FSAVE[4] = {'F','S','A','V'}; // File save constexpr char FDELE[4] = {'F','D','E','L'}; // File delete constexpr char FPLAY[4] = {'F','P','L','Y'}; // Play animation file // Motor Control constexpr char MSET[4] = {'M','S','E','T'}; // Set motor positions constexpr char MPOS[4] = {'M','P','O','S'}; // Motor position stream constexpr char MSCAN[4] = {'M','S','C','N'}; // Scan for motors constexpr char MWRIT[4] = {'M','W','R','T'}; // Write motor register constexpr char MSTRM[4] = {'M','S','T','M'}; // Motor stream control // Sensors constexpr char IMU[4] = {'I','M','U','0'}; // ADXL acceleration data (x,y,z) constexpr char RADAR[4] = {'R','D','A','R'}; // Radar targets constexpr char FRAME[4] = {'F','R','M','E'}; // Animation frame events (frame, mode, status) // System constexpr char STATE[4] = {'S','T','A','T'}; // System state/heartbeat constexpr char MSGE[4] = {'M','S','G','E'}; // Log/debug message constexpr char BOOT[4] = {'B','O','O','T'}; // Enter bootloader constexpr char ACK[4] = {'A','C','K','!'}; // Acknowledge constexpr char NACK[4] = {'N','A','C','K'}; // Negative acknowledge } // ============================================================================ // Play Modes (for FPLAY command) // ============================================================================ enum PlayMode : uint8_t { PLAY_IDLE = 0x00, PLAY_ONCE = 0x01, PLAY_LOOP = 0x02, PLAY_REPEAT = 0x03 }; // ============================================================================ // Packet Buffer // ============================================================================ extern uint8_t g_rxBuffer[MAX_PAYLOAD_SIZE + PACKET_HEADER_SIZE + PACKET_CRC_SIZE]; extern uint16_t g_rxBufferLen; // ============================================================================ // CRC16-CCITT // ============================================================================ uint16_t crc16Update(uint16_t crc, const uint8_t* data, uint16_t len); uint16_t crc16Compute(const uint8_t* data, uint16_t len); // ============================================================================ // Packet Sending // ============================================================================ // Send a tagged packet with auto-incrementing sequence number void sendPacket(const char tag[4], const uint8_t* payload, uint16_t len); // Convenience: send string as MSGE packet void sendMessage(const String& msg); // Convenience: send ACK/NACK void sendAck(const char originalTag[4]); void sendNack(const char originalTag[4], const String& reason = ""); // ============================================================================ // Packet Receiving // ============================================================================ // Packet receive state machine - call from loop() // Returns true when a complete valid packet is ready bool receivePacket(); // Get received packet info (valid after receivePacket returns true) const char* getReceivedTag(); const uint8_t* getReceivedPayload(); uint16_t getReceivedPayloadLen(); uint16_t getReceivedSeq(); // Check if received tag matches bool tagMatches(const char* received, const char expected[4]); // ============================================================================ // Utility // ============================================================================ // Compare tags inline bool tagsEqual(const char a[4], const char b[4]) { return memcmp(a, b, 4) == 0; }