impl main func
This commit is contained in:
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"array": "cpp",
|
||||||
|
"deque": "cpp",
|
||||||
|
"list": "cpp",
|
||||||
|
"string": "cpp",
|
||||||
|
"unordered_map": "cpp",
|
||||||
|
"unordered_set": "cpp",
|
||||||
|
"vector": "cpp",
|
||||||
|
"string_view": "cpp",
|
||||||
|
"initializer_list": "cpp",
|
||||||
|
"ranges": "cpp"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
|
|
||||||
//#define DEBUG_RFID
|
// #define DEBUG_RFID
|
||||||
#ifdef DEBUG_RFID
|
#ifdef DEBUG_RFID
|
||||||
#define LOG(msg) Serial.println(msg)
|
#define LOG(msg) Serial.println(msg)
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -1,102 +1,153 @@
|
|||||||
#include "hardware_serial.hpp"
|
#include "hardware_serial.hpp"
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
// #define DEBUG_PROTO
|
||||||
|
#ifdef DEBUG_PROTO
|
||||||
|
#define LOG(msg) Serial.println(msg)
|
||||||
|
#else
|
||||||
|
#define LOG(msg)
|
||||||
|
#endif
|
||||||
|
|
||||||
ProtoSerial::ProtoSerial()
|
ProtoSerial::ProtoSerial()
|
||||||
: serial(nullptr), initialized(false), currentState(WAITING_FOR_LENGTH),
|
: serial(nullptr), initialized(false), lastError{0}, callback(nullptr),
|
||||||
payloadLength(0), messageAvailable(false) {
|
currentState(WAITING_FOR_SYNC_START), payloadLength(0), messageAvailable(false),
|
||||||
|
lastUpdate(0), lastByteTime(0) {
|
||||||
receivedMessage = INCOMING_MESSAGE_INIT;
|
receivedMessage = INCOMING_MESSAGE_INIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtoSerial::~ProtoSerial() {
|
ProtoSerial::~ProtoSerial() {
|
||||||
if (serial) {
|
// No delete needed; serial is caller-managed
|
||||||
delete serial;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtoSerial::begin(int rxPin, int txPin, long baud) {
|
void ProtoSerial::begin(SerialType& serialPort) {
|
||||||
if (serial) {
|
serial = &serialPort;
|
||||||
delete serial;
|
|
||||||
}
|
|
||||||
#ifdef ESP32
|
|
||||||
serial = new HardwareSerial(1); // Use UART 1
|
|
||||||
serial->begin(baud, SERIAL_8N1, rxPin, txPin);
|
|
||||||
#elif defined(ESP8266)
|
|
||||||
serial = new SoftwareSerial(rxPin, txPin);
|
|
||||||
serial->begin(baud);
|
|
||||||
#endif
|
|
||||||
initialized = true;
|
initialized = true;
|
||||||
currentState = WAITING_FOR_LENGTH;
|
currentState = WAITING_FOR_SYNC_START;
|
||||||
payloadLength = 0;
|
payloadLength = 0;
|
||||||
messageAvailable = false;
|
messageAvailable = false;
|
||||||
|
lastError[0] = '\0';
|
||||||
|
lastUpdate = 0;
|
||||||
|
lastByteTime = 0;
|
||||||
|
snprintf(lastError, sizeof(lastError), "Initialized ProtoSerial");
|
||||||
|
LOG(lastError);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProtoSerial::sendMessage(const OutgoingMessage& message) {
|
bool ProtoSerial::sendMessage(const OutgoingMessage& message) {
|
||||||
if (!initialized || !serial) {
|
if (!initialized || !serial || !serial->availableForWrite()) {
|
||||||
|
snprintf(lastError, sizeof(lastError), "Serial not initialized or not ready");
|
||||||
|
LOG(lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t buffer[OUTGOING_MESSAGE_SIZE];
|
uint8_t buffer[OUTGOING_MESSAGE_SIZE];
|
||||||
|
|
||||||
// Create a stream that writes to our buffer
|
|
||||||
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||||
|
|
||||||
// Encode the message
|
// Encode the message
|
||||||
if (!pb_encode(&stream, OUTGOING_MESSAGE_FIELDS, &message)) {
|
if (!pb_encode(&stream, OUTGOING_MESSAGE_FIELDS, &message)) {
|
||||||
// Encoding failed
|
snprintf(lastError, sizeof(lastError), "Failed to encode message");
|
||||||
|
LOG(lastError);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t messageLength = stream.bytes_written;
|
uint16_t messageLength = stream.bytes_written;
|
||||||
|
if (messageLength > sizeof(buffer)) {
|
||||||
|
snprintf(lastError, sizeof(lastError), "Encoded message too large: %u", messageLength);
|
||||||
|
LOG(lastError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Send the length first (as two bytes, little-endian)
|
// Send framing: sync start, length, payload, CRC, sync end
|
||||||
|
serial->write(SYNC_START);
|
||||||
serial->write((uint8_t*)&messageLength, sizeof(messageLength));
|
serial->write((uint8_t*)&messageLength, sizeof(messageLength));
|
||||||
|
|
||||||
// Send the actual payload
|
|
||||||
serial->write(buffer, messageLength);
|
serial->write(buffer, messageLength);
|
||||||
|
uint8_t crc = calculate_crc8(buffer, messageLength);
|
||||||
// Ensure data is sent
|
serial->write(crc);
|
||||||
|
serial->write(SYNC_END);
|
||||||
serial->flush();
|
serial->flush();
|
||||||
|
|
||||||
|
dumpHex(buffer, messageLength, "Sent");
|
||||||
|
snprintf(lastError, sizeof(lastError), "Sent message, length: %u, CRC: 0x%02X", messageLength, crc);
|
||||||
|
LOG(lastError);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtoSerial::update() {
|
void ProtoSerial::update() {
|
||||||
if (!initialized || !serial) {
|
if (!initialized || !serial) {
|
||||||
|
snprintf(lastError, sizeof(lastError), "Serial not initialized");
|
||||||
|
LOG(lastError);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Throttle updates to ~100Hz
|
||||||
|
unsigned long now = millis();
|
||||||
|
if (now - lastUpdate < 10) return;
|
||||||
|
lastUpdate = now;
|
||||||
|
|
||||||
|
// Timeout if no data received for 1 second
|
||||||
|
if (currentState != WAITING_FOR_SYNC_START && now - lastByteTime > 1000) {
|
||||||
|
snprintf(lastError, sizeof(lastError), "Receive timeout");
|
||||||
|
LOG(lastError);
|
||||||
|
currentState = WAITING_FOR_SYNC_START;
|
||||||
|
payloadLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (serial->available()) {
|
||||||
|
lastByteTime = now;
|
||||||
switch (currentState) {
|
switch (currentState) {
|
||||||
|
case WAITING_FOR_SYNC_START: {
|
||||||
|
uint8_t byte = serial->read();
|
||||||
|
if (byte == SYNC_START) {
|
||||||
|
currentState = WAITING_FOR_LENGTH;
|
||||||
|
LOG("Received SYNC_START");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case WAITING_FOR_LENGTH: {
|
case WAITING_FOR_LENGTH: {
|
||||||
if (serial->available() >= sizeof(payloadLength)) {
|
if (serial->available() >= sizeof(payloadLength)) {
|
||||||
// Read the 2-byte length
|
|
||||||
serial->readBytes((uint8_t*)&payloadLength, sizeof(payloadLength));
|
serial->readBytes((uint8_t*)&payloadLength, sizeof(payloadLength));
|
||||||
|
|
||||||
// Protect against absurdly large lengths
|
|
||||||
if (payloadLength > sizeof(payloadBuffer) || payloadLength == 0) {
|
if (payloadLength > sizeof(payloadBuffer) || payloadLength == 0) {
|
||||||
// Invalid length, reset
|
snprintf(lastError, sizeof(lastError), "Invalid payload length: %u", payloadLength);
|
||||||
|
LOG(lastError);
|
||||||
|
currentState = WAITING_FOR_SYNC_START;
|
||||||
payloadLength = 0;
|
payloadLength = 0;
|
||||||
currentState = WAITING_FOR_LENGTH;
|
|
||||||
} else {
|
} else {
|
||||||
currentState = READING_PAYLOAD;
|
currentState = READING_PAYLOAD;
|
||||||
|
snprintf(lastError, sizeof(lastError), "Received length: %u", payloadLength);
|
||||||
|
LOG(lastError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case READING_PAYLOAD: {
|
case READING_PAYLOAD: {
|
||||||
if (serial->available() >= payloadLength) {
|
if (serial->available() >= payloadLength) {
|
||||||
// Read the payload
|
|
||||||
serial->readBytes(payloadBuffer, payloadLength);
|
serial->readBytes(payloadBuffer, payloadLength);
|
||||||
|
currentState = READING_CRC;
|
||||||
// Process the message
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case READING_CRC: {
|
||||||
|
if (serial->available() >= 1) {
|
||||||
|
uint8_t received_crc = serial->read();
|
||||||
|
uint8_t expected_crc = calculate_crc8(payloadBuffer, payloadLength);
|
||||||
|
if (received_crc != expected_crc) {
|
||||||
|
snprintf(lastError, sizeof(lastError), "CRC mismatch: received 0x%02X, expected 0x%02X", received_crc, expected_crc);
|
||||||
|
LOG(lastError);
|
||||||
|
} else if (serial->available() >= 1 && serial->read() != SYNC_END) {
|
||||||
|
snprintf(lastError, sizeof(lastError), "Missing SYNC_END");
|
||||||
|
LOG(lastError);
|
||||||
|
} else {
|
||||||
|
dumpHex(payloadBuffer, payloadLength, "Received");
|
||||||
processReceivedMessage(payloadBuffer, payloadLength);
|
processReceivedMessage(payloadBuffer, payloadLength);
|
||||||
|
snprintf(lastError, sizeof(lastError), "Received valid message, length: %u", payloadLength);
|
||||||
// Reset for the next message
|
LOG(lastError);
|
||||||
currentState = WAITING_FOR_LENGTH;
|
}
|
||||||
|
currentState = WAITING_FOR_SYNC_START;
|
||||||
payloadLength = 0;
|
payloadLength = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProtoSerial::hasMessage() const {
|
bool ProtoSerial::hasMessage() const {
|
||||||
@@ -110,19 +161,57 @@ const IncomingMessage& ProtoSerial::getMessage() const {
|
|||||||
void ProtoSerial::clearMessage() {
|
void ProtoSerial::clearMessage() {
|
||||||
messageAvailable = false;
|
messageAvailable = false;
|
||||||
receivedMessage = INCOMING_MESSAGE_INIT;
|
receivedMessage = INCOMING_MESSAGE_INIT;
|
||||||
|
snprintf(lastError, sizeof(lastError), "Message cleared");
|
||||||
|
LOG(lastError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtoSerial::setCallback(Callback cb) {
|
||||||
|
callback = cb;
|
||||||
|
snprintf(lastError, sizeof(lastError), "Callback set");
|
||||||
|
LOG(lastError);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtoSerial::processReceivedMessage(uint8_t* buffer, uint16_t length) {
|
void ProtoSerial::processReceivedMessage(uint8_t* buffer, uint16_t length) {
|
||||||
// Reset the message
|
|
||||||
receivedMessage = INCOMING_MESSAGE_INIT;
|
receivedMessage = INCOMING_MESSAGE_INIT;
|
||||||
|
|
||||||
// Create a stream from the buffer
|
|
||||||
pb_istream_t stream = pb_istream_from_buffer(buffer, length);
|
pb_istream_t stream = pb_istream_from_buffer(buffer, length);
|
||||||
|
|
||||||
// Decode the message
|
|
||||||
if (pb_decode(&stream, INCOMING_MESSAGE_FIELDS, &receivedMessage)) {
|
if (pb_decode(&stream, INCOMING_MESSAGE_FIELDS, &receivedMessage)) {
|
||||||
|
if (receivedMessage.which_payload == 0) {
|
||||||
|
snprintf(lastError, sizeof(lastError), "Invalid message: which_payload not set");
|
||||||
|
LOG(lastError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
messageAvailable = true;
|
messageAvailable = true;
|
||||||
|
if (callback) {
|
||||||
|
callback(receivedMessage);
|
||||||
|
}
|
||||||
|
snprintf(lastError, sizeof(lastError), "Message decoded successfully");
|
||||||
|
LOG(lastError);
|
||||||
} else {
|
} else {
|
||||||
// Decoding failed, do not set messageAvailable
|
snprintf(lastError, sizeof(lastError), "Failed to decode message");
|
||||||
|
LOG(lastError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t ProtoSerial::calculate_crc8(const uint8_t* data, uint16_t len) {
|
||||||
|
uint8_t crc = 0x00;
|
||||||
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
|
crc ^= data[i];
|
||||||
|
for (uint8_t j = 0; j < 8; j++) {
|
||||||
|
if (crc & 0x80) crc = (crc << 1) ^ 0x31; // CRC-8 polynomial
|
||||||
|
else crc <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProtoSerial::dumpHex(const uint8_t* data, uint16_t len, const char* label) {
|
||||||
|
#ifdef DEBUG_PROTO
|
||||||
|
Serial.print(label);
|
||||||
|
Serial.print(": ");
|
||||||
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
|
if (i % 16 == 0) Serial.println();
|
||||||
|
Serial.printf("%02X ", data[i]);
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
typedef HardwareSerial SerialType;
|
typedef HardwareSerial SerialType;
|
||||||
#define SERIAL_TYPE HardwareSerial
|
#define SERIAL_TYPE HardwareSerial
|
||||||
#elif defined(ESP8266)
|
#elif defined(ESP8266)
|
||||||
#include <SoftwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
typedef SoftwareSerial SerialType;
|
typedef HardwareSerial SerialType;
|
||||||
#define SERIAL_TYPE SoftwareSerial
|
#define SERIAL_TYPE HardwareSerial
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform. Only ESP32 and ESP8266 are supported."
|
#error "Unsupported platform. Only ESP32 and ESP8266 are supported."
|
||||||
#endif
|
#endif
|
||||||
@@ -28,8 +29,8 @@ typedef hardware_ControlToSensorMessage OutgoingMessage;
|
|||||||
#define OUTGOING_MESSAGE_SIZE hardware_ControlToSensorMessage_size
|
#define OUTGOING_MESSAGE_SIZE hardware_ControlToSensorMessage_size
|
||||||
#define INCOMING_MESSAGE_FIELDS hardware_SensorToControlMessage_fields
|
#define INCOMING_MESSAGE_FIELDS hardware_SensorToControlMessage_fields
|
||||||
#define OUTGOING_MESSAGE_FIELDS hardware_ControlToSensorMessage_fields
|
#define OUTGOING_MESSAGE_FIELDS hardware_ControlToSensorMessage_fields
|
||||||
#define INCOMING_MESSAGE_INIT hardware_SensorToControlMessage_init_default
|
#define INCOMING_MESSAGE_INIT hardware_SensorToControlMessage_init_zero
|
||||||
#define OUTGOING_MESSAGE_INIT hardware_ControlToSensorMessage_init_default
|
#define OUTGOING_MESSAGE_INIT hardware_ControlToSensorMessage_init_zero
|
||||||
#elif defined(HARDWARE_SERIAL_ROLE_SENSOR)
|
#elif defined(HARDWARE_SERIAL_ROLE_SENSOR)
|
||||||
typedef hardware_ControlToSensorMessage IncomingMessage;
|
typedef hardware_ControlToSensorMessage IncomingMessage;
|
||||||
typedef hardware_SensorToControlMessage OutgoingMessage;
|
typedef hardware_SensorToControlMessage OutgoingMessage;
|
||||||
@@ -37,51 +38,132 @@ typedef hardware_SensorToControlMessage OutgoingMessage;
|
|||||||
#define OUTGOING_MESSAGE_SIZE hardware_SensorToControlMessage_size
|
#define OUTGOING_MESSAGE_SIZE hardware_SensorToControlMessage_size
|
||||||
#define INCOMING_MESSAGE_FIELDS hardware_ControlToSensorMessage_fields
|
#define INCOMING_MESSAGE_FIELDS hardware_ControlToSensorMessage_fields
|
||||||
#define OUTGOING_MESSAGE_FIELDS hardware_SensorToControlMessage_fields
|
#define OUTGOING_MESSAGE_FIELDS hardware_SensorToControlMessage_fields
|
||||||
#define INCOMING_MESSAGE_INIT hardware_ControlToSensorMessage_init_default
|
#define INCOMING_MESSAGE_INIT hardware_ControlToSensorMessage_init_zero
|
||||||
#define OUTGOING_MESSAGE_INIT hardware_SensorToControlMessage_init_default
|
#define OUTGOING_MESSAGE_INIT hardware_ControlToSensorMessage_init_zero
|
||||||
#else
|
#else
|
||||||
#error "Must define either HARDWARE_SERIAL_ROLE_CONTROL or HARDWARE_SERIAL_ROLE_SENSOR"
|
#error "Must define either HARDWARE_SERIAL_ROLE_CONTROL or HARDWARE_SERIAL_ROLE_SENSOR"
|
||||||
#endif
|
#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 {
|
class ProtoSerial {
|
||||||
public:
|
public:
|
||||||
|
using Callback = void (*)(const IncomingMessage&); ///< Callback for received messages.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Constructor.
|
||||||
|
*/
|
||||||
ProtoSerial();
|
ProtoSerial();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor. No-op (serial is managed by caller).
|
||||||
|
*/
|
||||||
~ProtoSerial();
|
~ProtoSerial();
|
||||||
|
|
||||||
// Initialize with RX and TX pins
|
/**
|
||||||
void begin(int rxPin, int txPin, long baud = 9600);
|
* @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);
|
||||||
|
|
||||||
// Send a message
|
/**
|
||||||
|
* @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);
|
bool sendMessage(const OutgoingMessage& message);
|
||||||
|
|
||||||
// Check for incoming messages (non-blocking)
|
/**
|
||||||
|
* @brief Checks for incoming messages (non-blocking).
|
||||||
|
*/
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
// Check if a message has been received
|
/**
|
||||||
|
* @brief Checks if a message is available.
|
||||||
|
* @return True if a message is ready to be read.
|
||||||
|
*/
|
||||||
bool hasMessage() const;
|
bool hasMessage() const;
|
||||||
|
|
||||||
// Get the received message (only valid if hasMessage() returns true)
|
/**
|
||||||
|
* @brief Gets the received message.
|
||||||
|
* @return Reference to the received message (valid only if hasMessage() is true).
|
||||||
|
*/
|
||||||
const IncomingMessage& getMessage() const;
|
const IncomingMessage& getMessage() const;
|
||||||
|
|
||||||
// Clear the received message
|
/**
|
||||||
|
* @brief Clears the received message.
|
||||||
|
*/
|
||||||
void clearMessage();
|
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:
|
private:
|
||||||
SerialType* serial;
|
SerialType* serial; ///< Serial interface (pointer to caller-provided SerialType).
|
||||||
bool initialized;
|
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
|
// Receive state machine
|
||||||
enum RxState {
|
enum RxState {
|
||||||
WAITING_FOR_LENGTH,
|
WAITING_FOR_SYNC_START, ///< Waiting for start byte (0xAA).
|
||||||
READING_PAYLOAD
|
WAITING_FOR_LENGTH, ///< Waiting for 2-byte length.
|
||||||
|
READING_PAYLOAD, ///< Reading payload bytes.
|
||||||
|
READING_CRC ///< Reading CRC-8 byte.
|
||||||
};
|
};
|
||||||
RxState currentState;
|
RxState currentState; ///< Current state of receive state machine.
|
||||||
uint16_t payloadLength;
|
uint16_t payloadLength; ///< Length of incoming payload.
|
||||||
uint8_t payloadBuffer[64]; // Max message size + some buffer
|
uint8_t payloadBuffer[INCOMING_MESSAGE_SIZE + 10]; ///< Buffer for payload (plus overhead).
|
||||||
IncomingMessage receivedMessage;
|
IncomingMessage receivedMessage; ///< Decoded incoming message.
|
||||||
bool messageAvailable;
|
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
|
// 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);
|
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);
|
||||||
|
};
|
||||||
+53
-42
@@ -1,6 +1,7 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <hardware_led.hpp>
|
#include <hardware_led.hpp>
|
||||||
#include <hardware_rfid.hpp>
|
#include <hardware_rfid.hpp>
|
||||||
|
#include <hardware_serial.hpp>
|
||||||
#include "hardware.pb.h"
|
#include "hardware.pb.h"
|
||||||
|
|
||||||
// Demo for HardwareLed
|
// Demo for HardwareLed
|
||||||
@@ -9,14 +10,24 @@ HardwareLed<2> led; // Assuming NeoPixel on pin 2 (D2 on ESP8266)
|
|||||||
// Demo for HardwareRfid
|
// Demo for HardwareRfid
|
||||||
HardwareRfid rfid(4, 5); // SS=D2 (GPIO4), RST=D1 (GPIO5)
|
HardwareRfid rfid(4, 5); // SS=D2 (GPIO4), RST=D1 (GPIO5)
|
||||||
|
|
||||||
|
// Demo for HardwareSerial
|
||||||
|
ProtoSerial serial;
|
||||||
|
|
||||||
hardware_LedConfig configs[4];
|
hardware_LedConfig configs[4];
|
||||||
unsigned long lastChange = 0;
|
unsigned long lastChange = 0;
|
||||||
int currentConfig = 0;
|
int currentConfig = 0;
|
||||||
|
|
||||||
void onRfidTag(const hardware_SensorToControlMessage& msg) {
|
void onRfidTag(const hardware_SensorToControlMessage& msg) {
|
||||||
Serial.println("Callback onRfidTag triggered");
|
serial.sendMessage(msg);
|
||||||
Serial.print("RFID Tag detected: 0x");
|
// Serial.println("Callback onRfidTag triggered");
|
||||||
Serial.println(msg.payload.rfid_reading.card_id, HEX);
|
// Serial.print("RFID Tag detected: 0x");
|
||||||
|
// Serial.println(msg.payload.rfid_reading.card_id, HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSerialMessage(const IncomingMessage& msg) {
|
||||||
|
if (msg.which_payload == hardware_ControlToSensorMessage_led_config_tag) {
|
||||||
|
led.set(msg.payload.led_config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
@@ -24,54 +35,54 @@ void setup() {
|
|||||||
led.begin();
|
led.begin();
|
||||||
rfid.begin();
|
rfid.begin();
|
||||||
rfid.setCallback(onRfidTag);
|
rfid.setCallback(onRfidTag);
|
||||||
|
serial.begin(Serial);
|
||||||
|
serial.setCallback(onSerialMessage);
|
||||||
|
|
||||||
// Static config
|
// // Static config
|
||||||
configs[0] = {0};
|
// configs[0] = {0};
|
||||||
configs[0].brightness = 128;
|
// configs[0].brightness = 128;
|
||||||
configs[0].duration_ms = 0;
|
// configs[0].duration_ms = 0;
|
||||||
configs[0].which_animation_params = 3;
|
// configs[0].which_animation_params = 3;
|
||||||
configs[0].animation_params.static_params.color = 0x00FF00; // Green
|
// configs[0].animation_params.static_params.color = 0x00FF00; // Green
|
||||||
|
|
||||||
// Pulse config
|
// // Pulse config
|
||||||
configs[1] = {0};
|
// configs[1] = {0};
|
||||||
configs[1].brightness = 128;
|
// configs[1].brightness = 128;
|
||||||
configs[1].duration_ms = 0;
|
// configs[1].duration_ms = 0;
|
||||||
configs[1].which_animation_params = 4;
|
// configs[1].which_animation_params = 4;
|
||||||
configs[1].animation_params.pulse_params.color = 0xFF0000; // Red
|
// configs[1].animation_params.pulse_params.color = 0xFF0000; // Red
|
||||||
configs[1].animation_params.pulse_params.speed_ms = 500;
|
// configs[1].animation_params.pulse_params.speed_ms = 500;
|
||||||
|
|
||||||
// Fade config
|
// // Fade config
|
||||||
configs[2] = {0};
|
// configs[2] = {0};
|
||||||
configs[2].brightness = 128;
|
// configs[2].brightness = 128;
|
||||||
configs[2].duration_ms = 0;
|
// configs[2].duration_ms = 0;
|
||||||
configs[2].which_animation_params = 5;
|
// configs[2].which_animation_params = 5;
|
||||||
configs[2].animation_params.fade_params.colors_count = 3;
|
// configs[2].animation_params.fade_params.colors_count = 3;
|
||||||
configs[2].animation_params.fade_params.colors[0] = 0xFF0000; // Red
|
// configs[2].animation_params.fade_params.colors[0] = 0xFF0000; // Red
|
||||||
configs[2].animation_params.fade_params.colors[1] = 0x00FF00; // Green
|
// configs[2].animation_params.fade_params.colors[1] = 0x00FF00; // Green
|
||||||
configs[2].animation_params.fade_params.colors[2] = 0x0000FF; // Blue
|
// configs[2].animation_params.fade_params.colors[2] = 0x0000FF; // Blue
|
||||||
configs[2].animation_params.fade_params.speed_ms = 1000;
|
// configs[2].animation_params.fade_params.speed_ms = 1000;
|
||||||
|
|
||||||
// Flicker config
|
// // Flicker config
|
||||||
configs[3] = {0};
|
// configs[3] = {0};
|
||||||
configs[3].brightness = 128;
|
// configs[3].brightness = 128;
|
||||||
configs[3].duration_ms = 0;
|
// configs[3].duration_ms = 0;
|
||||||
configs[3].which_animation_params = 6;
|
// configs[3].which_animation_params = 6;
|
||||||
configs[3].animation_params.flicker_params.color = 0xFFFFFF; // White
|
// configs[3].animation_params.flicker_params.color = 0xFFFFFF; // White
|
||||||
configs[3].animation_params.flicker_params.intensity = 50;
|
// configs[3].animation_params.flicker_params.intensity = 50;
|
||||||
|
|
||||||
led.set(configs[0]);
|
// led.set(configs[0]);
|
||||||
Serial.println("Starting with static green");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
led.update();
|
led.update();
|
||||||
rfid.update();
|
rfid.update();
|
||||||
|
serial.update();
|
||||||
|
|
||||||
if (millis() - lastChange >= 10000) {
|
// if (millis() - lastChange >= 10000) {
|
||||||
lastChange = millis();
|
// lastChange = millis();
|
||||||
currentConfig = (currentConfig + 1) % 4;
|
// currentConfig = (currentConfig + 1) % 4;
|
||||||
led.set(configs[currentConfig]);
|
// led.set(configs[currentConfig]);
|
||||||
Serial.print("Switched to config ");
|
// }
|
||||||
Serial.println(currentConfig);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user