169 lines
5.9 KiB
C++
169 lines
5.9 KiB
C++
#pragma once
|
|
|
|
#ifdef ESP32
|
|
#include <HardwareSerial.h>
|
|
typedef HardwareSerial SerialType;
|
|
#define SERIAL_TYPE HardwareSerial
|
|
#elif defined(ESP8266)
|
|
#include <HardwareSerial.h>
|
|
typedef HardwareSerial SerialType;
|
|
#define SERIAL_TYPE HardwareSerial
|
|
#else
|
|
#error "Unsupported platform. Only ESP32 and ESP8266 are supported."
|
|
#endif
|
|
|
|
#include <pb_encode.h>
|
|
#include <pb_decode.h>
|
|
#include "hardware.pb.h"
|
|
|
|
// Define the role of this device
|
|
// Uncomment one of the following defines to set the role
|
|
//#define HARDWARE_SERIAL_ROLE_CONTROL
|
|
#define HARDWARE_SERIAL_ROLE_SENSOR
|
|
|
|
// Based on role, define the message types
|
|
#if defined(HARDWARE_SERIAL_ROLE_CONTROL)
|
|
typedef hardware_SensorToControlMessage IncomingMessage;
|
|
typedef hardware_ControlToSensorMessage OutgoingMessage;
|
|
#define INCOMING_MESSAGE_SIZE hardware_SensorToControlMessage_size
|
|
#define OUTGOING_MESSAGE_SIZE hardware_ControlToSensorMessage_size
|
|
#define INCOMING_MESSAGE_FIELDS hardware_SensorToControlMessage_fields
|
|
#define OUTGOING_MESSAGE_FIELDS hardware_ControlToSensorMessage_fields
|
|
#define INCOMING_MESSAGE_INIT hardware_SensorToControlMessage_init_zero
|
|
#define OUTGOING_MESSAGE_INIT hardware_ControlToSensorMessage_init_zero
|
|
#elif defined(HARDWARE_SERIAL_ROLE_SENSOR)
|
|
typedef hardware_ControlToSensorMessage IncomingMessage;
|
|
typedef hardware_SensorToControlMessage OutgoingMessage;
|
|
#define INCOMING_MESSAGE_SIZE hardware_ControlToSensorMessage_size
|
|
#define OUTGOING_MESSAGE_SIZE hardware_SensorToControlMessage_size
|
|
#define INCOMING_MESSAGE_FIELDS hardware_ControlToSensorMessage_fields
|
|
#define OUTGOING_MESSAGE_FIELDS hardware_SensorToControlMessage_fields
|
|
#define INCOMING_MESSAGE_INIT hardware_ControlToSensorMessage_init_zero
|
|
#define OUTGOING_MESSAGE_INIT hardware_ControlToSensorMessage_init_zero
|
|
#else
|
|
#error "Must define either HARDWARE_SERIAL_ROLE_CONTROL or HARDWARE_SERIAL_ROLE_SENSOR"
|
|
#endif
|
|
|
|
/**
|
|
* @class ProtoSerial
|
|
* @brief Manages serial communication with Protocol Buffers for ESP32/ESP8266.
|
|
* Supports length-prefixed messages with CRC-8 checksum and sync bytes.
|
|
* Configured for SENSOR or CONTROL role via HARDWARE_SERIAL_ROLE_* macros.
|
|
* On ESP8266, uses UART0 (Serial, RX=GPIO3, TX=GPIO1). On ESP32, uses caller-provided UART.
|
|
*/
|
|
class ProtoSerial {
|
|
public:
|
|
using Callback = void (*)(const IncomingMessage&); ///< Callback for received messages.
|
|
|
|
/**
|
|
* @brief Constructor.
|
|
*/
|
|
ProtoSerial();
|
|
|
|
/**
|
|
* @brief Destructor. No-op (serial is managed by caller).
|
|
*/
|
|
~ProtoSerial();
|
|
|
|
/**
|
|
* @brief Initializes serial communication with a caller-provided serial port.
|
|
* @param serialPort Reference to a configured SerialType (e.g., Serial for ESP8266, HardwareSerial for ESP32).
|
|
*/
|
|
void begin(SerialType& serialPort);
|
|
|
|
/**
|
|
* @brief Sends a Protocol Buffers message with sync bytes and CRC-8.
|
|
* @param message The message to send (OutgoingMessage type).
|
|
* @return True if sent successfully, false otherwise.
|
|
*/
|
|
bool sendMessage(const OutgoingMessage& message);
|
|
|
|
/**
|
|
* @brief Checks for incoming messages (non-blocking).
|
|
*/
|
|
void update();
|
|
|
|
/**
|
|
* @brief Checks if a message is available.
|
|
* @return True if a message is ready to be read.
|
|
*/
|
|
bool hasMessage() const;
|
|
|
|
/**
|
|
* @brief Gets the received message.
|
|
* @return Reference to the received message (valid only if hasMessage() is true).
|
|
*/
|
|
const IncomingMessage& getMessage() const;
|
|
|
|
/**
|
|
* @brief Clears the received message.
|
|
*/
|
|
void clearMessage();
|
|
|
|
/**
|
|
* @brief Sets the callback for received messages.
|
|
* @param cb Callback function to handle incoming messages.
|
|
*/
|
|
void setCallback(Callback cb);
|
|
|
|
/**
|
|
* @brief Checks if the serial interface is initialized.
|
|
* @return True if initialized.
|
|
*/
|
|
bool isInitialized() const { return initialized; }
|
|
|
|
/**
|
|
* @brief Gets the last error message (for debugging).
|
|
* @return Last error string or empty if none.
|
|
*/
|
|
const char* getLastError() const { return lastError; }
|
|
|
|
private:
|
|
SerialType* serial; ///< Serial interface (pointer to caller-provided SerialType).
|
|
bool initialized; ///< Tracks initialization state.
|
|
char lastError[64]; ///< Last error message (fixed-size to avoid heap issues).
|
|
Callback callback; ///< Callback for received messages.
|
|
|
|
// Framing constants
|
|
static const uint8_t SYNC_START = 0xAA; ///< Start byte for message framing.
|
|
static const uint8_t SYNC_END = 0xBB; ///< End byte for message framing.
|
|
|
|
// Receive state machine
|
|
enum RxState {
|
|
WAITING_FOR_SYNC_START, ///< Waiting for start byte (0xAA).
|
|
WAITING_FOR_LENGTH, ///< Waiting for 2-byte length.
|
|
READING_PAYLOAD, ///< Reading payload bytes.
|
|
READING_CRC ///< Reading CRC-8 byte.
|
|
};
|
|
RxState currentState; ///< Current state of receive state machine.
|
|
uint16_t payloadLength; ///< Length of incoming payload.
|
|
uint8_t payloadBuffer[INCOMING_MESSAGE_SIZE + 10]; ///< Buffer for payload (plus overhead).
|
|
IncomingMessage receivedMessage; ///< Decoded incoming message.
|
|
bool messageAvailable; ///< True if a message is ready.
|
|
unsigned long lastUpdate; ///< Timestamp of last update (for throttling).
|
|
unsigned long lastByteTime; ///< Timestamp of last byte received (for timeout).
|
|
|
|
// Helper methods
|
|
/**
|
|
* @brief Processes a received payload and decodes it.
|
|
* @param buffer Payload buffer.
|
|
* @param length Payload length.
|
|
*/
|
|
void processReceivedMessage(uint8_t* buffer, uint16_t length);
|
|
|
|
/**
|
|
* @brief Calculates CRC-8 for a buffer.
|
|
* @param data Buffer to compute CRC over.
|
|
* @param len Length of buffer.
|
|
* @return CRC-8 value.
|
|
*/
|
|
uint8_t calculate_crc8(const uint8_t* data, uint16_t len);
|
|
|
|
/**
|
|
* @brief Logs a hex dump of a buffer (debug only).
|
|
* @param data Buffer to dump.
|
|
* @param len Length of buffer.
|
|
* @param label Label for the dump.
|
|
*/
|
|
void dumpHex(const uint8_t* data, uint16_t len, const char* label);
|
|
}; |