HansonServo/protocol.h

137 lines
5.5 KiB
C++

#pragma once
#include <Arduino.h>
// ============================================================================
// 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
constexpr char FSTP[4] = {'F','S','T','P'}; // Stop animation
// 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 FACE[4] = {'F','A','C','E'}; // Face detection data (via WiFi)
constexpr char ALIV[4] = {'A','L','I','V'}; // Remote component alive/heartbeat
constexpr char FRAME[4] = {'F','R','M','E'}; // Animation frame events (frame, mode, status)
// Behaviors
constexpr char BHVR[4] = {'B','H','V','R'}; // Behavior control (activate/deactivate)
constexpr char BLST[4] = {'B','L','S','T'}; // Behavior list (list all behaviors and their states)
// Visemes
constexpr char VLST[4] = {'V','L','S','T'}; // List all visemes
constexpr char VADD[4] = {'V','A','D','D'}; // Add a new viseme
constexpr char VDEL[4] = {'V','D','E','L'}; // Delete a viseme
constexpr char VSET[4] = {'V','S','E','T'}; // Set viseme motor positions
constexpr char VSME[4] = {'V','S','M','E'}; // Trigger a viseme by ID
// Settings
constexpr char SSET[4] = {'S','S','E','T'}; // Settings set/dump (id + value pairs)
// 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;
}