From 5a7b2f91491ea7288419e6c19e1d37e4c1c7cb74 Mon Sep 17 00:00:00 2001 From: Jean Jacques Avril Date: Sat, 4 Oct 2025 10:44:42 +0200 Subject: [PATCH] init --- .gitignore | 5 ++ .vscode/extensions.json | 10 +++ include/README | 37 +++++++++ lib/README | 46 +++++++++++ lib/hardware/hardware_serial.cpp | 128 +++++++++++++++++++++++++++++++ lib/hardware/hardware_serial.hpp | 87 +++++++++++++++++++++ platformio.ini | 28 +++++++ proto/hardware.options | 4 + proto/hardware.proto | 79 +++++++++++++++++++ src/main.cpp | 18 +++++ test/README | 11 +++ 11 files changed, 453 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 include/README create mode 100644 lib/README create mode 100644 lib/hardware/hardware_serial.cpp create mode 100644 lib/hardware/hardware_serial.hpp create mode 100644 platformio.ini create mode 100644 proto/hardware.options create mode 100644 proto/hardware.proto create mode 100644 src/main.cpp create mode 100644 test/README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/include/README b/include/README new file mode 100644 index 0000000..49819c0 --- /dev/null +++ b/include/README @@ -0,0 +1,37 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the convention is to give header files names that end with `.h'. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..9379397 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/lib/hardware/hardware_serial.cpp b/lib/hardware/hardware_serial.cpp new file mode 100644 index 0000000..78e79fc --- /dev/null +++ b/lib/hardware/hardware_serial.cpp @@ -0,0 +1,128 @@ +#include "hardware_serial.hpp" + +ProtoSerial::ProtoSerial() + : serial(nullptr), initialized(false), currentState(WAITING_FOR_LENGTH), + payloadLength(0), messageAvailable(false) { + receivedMessage = INCOMING_MESSAGE_INIT; +} + +ProtoSerial::~ProtoSerial() { + if (serial) { + delete serial; + } +} + +void ProtoSerial::begin(int rxPin, int txPin, long baud) { + if (serial) { + 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; + currentState = WAITING_FOR_LENGTH; + payloadLength = 0; + messageAvailable = false; +} + +bool ProtoSerial::sendMessage(const OutgoingMessage& message) { + if (!initialized || !serial) { + return false; + } + + 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)); + + // Encode the message + if (!pb_encode(&stream, OUTGOING_MESSAGE_FIELDS, &message)) { + // Encoding failed + return false; + } + + uint16_t messageLength = stream.bytes_written; + + // Send the length first (as two bytes, little-endian) + serial->write((uint8_t*)&messageLength, sizeof(messageLength)); + + // Send the actual payload + serial->write(buffer, messageLength); + + // Ensure data is sent + serial->flush(); + + return true; +} + +void ProtoSerial::update() { + if (!initialized || !serial) { + return; + } + + switch (currentState) { + case WAITING_FOR_LENGTH: { + if (serial->available() >= sizeof(payloadLength)) { + // Read the 2-byte length + serial->readBytes((uint8_t*)&payloadLength, sizeof(payloadLength)); + + // Protect against absurdly large lengths + if (payloadLength > sizeof(payloadBuffer) || payloadLength == 0) { + // Invalid length, reset + payloadLength = 0; + currentState = WAITING_FOR_LENGTH; + } else { + currentState = READING_PAYLOAD; + } + } + break; + } + + case READING_PAYLOAD: { + if (serial->available() >= payloadLength) { + // Read the payload + serial->readBytes(payloadBuffer, payloadLength); + + // Process the message + processReceivedMessage(payloadBuffer, payloadLength); + + // Reset for the next message + currentState = WAITING_FOR_LENGTH; + payloadLength = 0; + } + break; + } + } +} + +bool ProtoSerial::hasMessage() const { + return messageAvailable; +} + +const IncomingMessage& ProtoSerial::getMessage() const { + return receivedMessage; +} + +void ProtoSerial::clearMessage() { + messageAvailable = false; + receivedMessage = INCOMING_MESSAGE_INIT; +} + +void ProtoSerial::processReceivedMessage(uint8_t* buffer, uint16_t length) { + // Reset the message + receivedMessage = INCOMING_MESSAGE_INIT; + + // Create a stream from the buffer + pb_istream_t stream = pb_istream_from_buffer(buffer, length); + + // Decode the message + if (pb_decode(&stream, INCOMING_MESSAGE_FIELDS, &receivedMessage)) { + messageAvailable = true; + } else { + // Decoding failed, do not set messageAvailable + } +} \ No newline at end of file diff --git a/lib/hardware/hardware_serial.hpp b/lib/hardware/hardware_serial.hpp new file mode 100644 index 0000000..7d627f5 --- /dev/null +++ b/lib/hardware/hardware_serial.hpp @@ -0,0 +1,87 @@ +#pragma once +#ifdef ESP32 +#include +typedef HardwareSerial SerialType; +#define SERIAL_TYPE HardwareSerial +#elif defined(ESP8266) +#include +typedef SoftwareSerial SerialType; +#define SERIAL_TYPE SoftwareSerial +#else +#error "Unsupported platform. Only ESP32 and ESP8266 are supported." +#endif + +#include +#include +#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_default +#define OUTGOING_MESSAGE_INIT hardware_ControlToSensorMessage_init_default +#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_default +#define OUTGOING_MESSAGE_INIT hardware_SensorToControlMessage_init_default +#else +#error "Must define either HARDWARE_SERIAL_ROLE_CONTROL or HARDWARE_SERIAL_ROLE_SENSOR" +#endif + +class ProtoSerial { +public: + ProtoSerial(); + ~ProtoSerial(); + + // Initialize with RX and TX pins + void begin(int rxPin, int txPin, long baud = 9600); + + // Send a message + bool sendMessage(const OutgoingMessage& message); + + // Check for incoming messages (non-blocking) + void update(); + + // Check if a message has been received + bool hasMessage() const; + + // Get the received message (only valid if hasMessage() returns true) + const IncomingMessage& getMessage() const; + + // Clear the received message + void clearMessage(); + +private: + SerialType* serial; + bool initialized; + + // Receive state machine + enum RxState { + WAITING_FOR_LENGTH, + READING_PAYLOAD + }; + RxState currentState; + uint16_t payloadLength; + uint8_t payloadBuffer[64]; // Max message size + some buffer + IncomingMessage receivedMessage; + bool messageAvailable; + + // Helper methods + void processReceivedMessage(uint8_t* buffer, uint16_t length); +}; + diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..895464d --- /dev/null +++ b/platformio.ini @@ -0,0 +1,28 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = esp8285 + +[env] +framework = arduino +monitor_speed = 9600 +board_build.filesystem = littlefs +lib_deps = + miguelbalboa/MFRC522@^1.4.12 + adafruit/Adafruit NeoPixel@^1.15.1 + nanopb/Nanopb@^0.4.91 +custom_nanopb_protos = + + + custom_nanopb_options = + --error-on-unmatched +[env:esp8285] +platform = espressif8266 +board = esp8285 \ No newline at end of file diff --git a/proto/hardware.options b/proto/hardware.options new file mode 100644 index 0000000..9e8624e --- /dev/null +++ b/proto/hardware.options @@ -0,0 +1,4 @@ +# Nanopb options for hardware.proto + +# LED configuration +hardware.FadeParams.colors max_count:5 \ No newline at end of file diff --git a/proto/hardware.proto b/proto/hardware.proto new file mode 100644 index 0000000..1f74a55 --- /dev/null +++ b/proto/hardware.proto @@ -0,0 +1,79 @@ +syntax = "proto3"; + +package hardware; + +// LED animation types +enum LedAnimation { + LED_ANIMATION_STATIC = 0; + LED_ANIMATION_PULSE = 1; + LED_ANIMATION_FADE = 2; + LED_ANIMATION_FLICKER = 3; +} + +// Hardware configuration +message HardwareConfig { + uint32 hold_duration_ms = 1; + bool override = 2; + uint32 relay_pin = 3; + uint32 sensor_rx_pin = 4; + uint32 sensor_tx_pin = 5; + LedConfig on_open_led = 6; + LedConfig default_led = 7; + LedConfig on_invalid_led = 8; + bool enable_serial_sensor = 9; + // repeated char sensor_api_key = 10; + // bool enable_ws_sensor = 11; +} + +// LED configuration +message LedConfig { + // General properties that apply to all animations + uint32 brightness = 1; // 0-255 + uint32 duration_ms = 2; // 0 for indefinite + + oneof animation_params { + StaticParams static_params = 3; + PulseParams pulse_params = 4; + FadeParams fade_params = 5; + FlickerParams flicker_params = 6; + } +} + +// Define the specific parameters for each animation type +message StaticParams { + uint32 color = 1; +} +message PulseParams { + uint32 color = 1; + uint32 speed_ms = 2; +} +message FadeParams { + repeated uint32 colors = 1; // Fade between these colors + uint32 speed_ms = 2; +} +message FlickerParams { + uint32 color = 1; + uint32 intensity = 2; // e.g., 0-100 +} + +message RfidReading { + uint32 card_id = 1; +} + +message SensorToControlMessage { + uint32 sensor_id = 1; + oneof payload { + RfidReading rfid_reading = 2; + // Add other sensor message types as needed + } +} + + + +message ControlToSensorMessage { + uint32 control_id = 1; + oneof payload { + LedConfig led_config = 2; + // Add other control message types as needed + } +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..cb9fbba --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,18 @@ +#include + +// put function declarations here: +int myFunction(int, int); + +void setup() { + // put your setup code here, to run once: + int result = myFunction(2, 3); +} + +void loop() { + // put your main code here, to run repeatedly: +} + +// put function definitions here: +int myFunction(int x, int y) { + return x + y; +} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html