diff --git a/.gitignore b/.gitignore index 1caed0bc6..a20a9d40f 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,6 @@ data/ # Misc. Data tests/ -venv/ \ No newline at end of file +venv/ + +Doxyfile \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 12d7d847e..9356a4952 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,18 @@ { "files.associations": { "limits": "c", - "type_traits": "c" + "type_traits": "c", + "array": "cpp", + "deque": "cpp", + "list": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "string_view": "cpp", + "format": "cpp", + "initializer_list": "cpp", + "span": "cpp" }, "C_Cpp.dimInactiveRegions": true, "dotnet.defaultSolution": "disable", diff --git a/Doxyfile b/Doxyfile index c05228416..2e9f261f9 100644 --- a/Doxyfile +++ b/Doxyfile @@ -2451,4 +2451,4 @@ GENERATE_LEGEND = YES # plantuml temporary files. # The default value is: YES. -DOT_CLEANUP = YES +DOT_CLEANUP = YES \ No newline at end of file diff --git a/library.properties b/library.properties index 9ef6dc4a2..5cf33a228 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit WipperSnapper -version=1.0.0-beta.110 +version=1.0.0-beta.112 author=Adafruit maintainer=Adafruit sentence=Arduino application for Adafruit.io WipperSnapper @@ -7,4 +7,4 @@ paragraph=Arduino application for Adafruit.io WipperSnapper category=Communication url=https://github.com/adafruit/Adafruit_Wippersnapper_Arduino architectures=* -depends=OmronD6T - Community Fork, SdFat - Adafruit Fork, Adafruit NeoPixel, Adafruit SPIFlash, ArduinoJson, Adafruit DotStar, Adafruit HDC302x, Adafruit INA219, Adafruit INA260 Library, Adafruit INA237 and INA238 Library, Adafruit LTR329 and LTR303, Adafruit LTR390 Library, Adafruit MCP3421, Adafruit NAU7802 Library, Adafruit SleepyDog Library, Adafruit TMP117, Adafruit TinyUSB Library, Adafruit AHTX0, Adafruit BME280 Library, Adafruit BMP280 Library, Adafruit BMP3XX Library, Adafruit DPS310, Adafruit DS248x, Adafruit SCD30, Adafruit SGP30 Sensor, Adafruit SGP40 Sensor, Sensirion I2C SCD4x, Sensirion I2C SEN5X, Sensirion I2C SEN66, arduino-sht, Adafruit Si7021 Library, Adafruit MQTT Library, Adafruit MS8607, Adafruit MCP9808 Library, Adafruit MCP9600 Library, Adafruit MPL115A2, Adafruit MPRLS Library, Adafruit TSL2591 Library, Adafruit_VL53L0X, Adafruit VL53L1X, STM32duino VL53L4CD, STM32duino VL53L4CX, Adafruit_VL6180X, Adafruit PM25 AQI Sensor, Adafruit VCNL4020 Library, Adafruit VCNL4040, Adafruit VCNL4200 Library, Adafruit VEML7700 Library, Adafruit LC709203F, Adafruit LPS2X, Adafruit LPS28, Adafruit LPS35HW, Adafruit seesaw Library, Adafruit BME680 Library, Adafruit MAX1704X, Adafruit ADT7410 Library, Adafruit HTS221, Adafruit HTU21DF Library, Adafruit HTU31D Library, Adafruit PCT2075, hp_BH1750, ENS160 - Adafruit Fork, Adafruit BusIO, Adafruit Unified Sensor, Sensirion Core, Adafruit GFX Library, Adafruit LED Backpack Library, Adafruit LiquidCrystal, Adafruit SH110X, Adafruit SSD1306 +depends=OmronD6T - Community Fork, SdFat - Adafruit Fork, Adafruit NeoPixel, Adafruit SPIFlash, ArduinoJson, Adafruit DotStar, Adafruit HDC302x, Adafruit INA219, Adafruit INA260 Library, Adafruit INA237 and INA238 Library, Adafruit LTR329 and LTR303, Adafruit LTR390 Library, Adafruit MCP3421, Adafruit NAU7802 Library, Adafruit SleepyDog Library, Adafruit TMP117, Adafruit TinyUSB Library, Adafruit AHTX0, Adafruit BME280 Library, Adafruit BMP280 Library, Adafruit BMP3XX Library, Adafruit DPS310, Adafruit DS248x, Adafruit SCD30, Adafruit SGP30 Sensor, Adafruit SGP40 Sensor, Sensirion I2C SCD4x, Sensirion I2C SEN5X, Sensirion I2C SEN66, arduino-sht, Adafruit Si7021 Library, Adafruit MQTT Library, Adafruit MS8607, Adafruit MCP9808 Library, Adafruit MCP9600 Library, Adafruit MPL115A2, Adafruit MPRLS Library, Adafruit TSL2591 Library, Adafruit_VL53L0X, Adafruit VL53L1X, STM32duino VL53L4CD, STM32duino VL53L4CX, Adafruit_VL6180X, Adafruit PM25 AQI Sensor, Adafruit VCNL4020 Library, Adafruit VCNL4040, Adafruit VCNL4200 Library, Adafruit VEML7700 Library, Adafruit LC709203F, Adafruit LPS2X, Adafruit LPS28, Adafruit LPS35HW, Adafruit seesaw Library, Adafruit BME680 Library, Adafruit MAX1704X, Adafruit ADT7410 Library, Adafruit HTS221, Adafruit HTU21DF Library, Adafruit HTU31D Library, Adafruit PCT2075, hp_BH1750, ENS160 - Adafruit Fork, Adafruit BusIO, Adafruit Unified Sensor, Sensirion Core, Adafruit GFX Library, Adafruit LED Backpack Library, Adafruit LiquidCrystal, Adafruit SH110X, Adafruit SSD1306, Adafruit EPD diff --git a/platformio.ini b/platformio.ini index 28f065116..25bbc006b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -90,9 +90,9 @@ lib_deps = https://github.com/tyeth/omron-devhub_d6t-arduino.git https://github.com/pstolarz/OneWireNg.git ; COMMENT OUT FOR RP2040/RP2350 BOARDS - https://github.com/milesburton/Arduino-Temperature-Control-Library.git + ;https://github.com/milesburton/Arduino-Temperature-Control-Library.git ; AND UNCOMMENT FOR RP2040/RP2350 BOARDS - ; https://github.com/pstolarz/Arduino-Temperature-Control-Library.git + https://github.com/pstolarz/Arduino-Temperature-Control-Library.git https://github.com/Sensirion/arduino-sht.git https://github.com/Sensirion/arduino-i2c-scd4x.git https://github.com/Sensirion/arduino-i2c-sen5x.git @@ -100,6 +100,7 @@ lib_deps = https://github.com/adafruit/WiFiNINA.git https://github.com/Starmbi/hp_BH1750.git https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git + Adafruit EPD @@ -265,7 +266,7 @@ extends = common:esp32 board = adafruit_magtag29_esp32s2 build_flags = -DARDUINO_MAGTAG29_ESP32S2 -DBOARD_HAS_PSRAM ;set partition to tinyuf2-partitions-4MB.csv as of idf 5.1 -board_build.partitions = tinyuf2-partitions-4MB.csv +board_build.partitions = tinyuf2-partitions-4MB-noota.csv extra_scripts = pre:rename_usb_config.py ; Adafruit Metro ESP32-S2 diff --git a/src/Wippersnapper.cpp b/src/Wippersnapper.cpp index 0a948feaa..8cf7c9b7d 100644 --- a/src/Wippersnapper.cpp +++ b/src/Wippersnapper.cpp @@ -69,6 +69,9 @@ Wippersnapper::Wippersnapper() { // DallasSemi (OneWire) WS._ds18x20Component = new ws_ds18x20(); + + // Display controller + WS._displayController = new DisplayController(); }; /**************************************************************************/ @@ -1655,6 +1658,124 @@ void cbSignalUARTReq(char *data, uint16_t len) { WS_DEBUG_PRINTLN("ERROR: Unable to decode UART Signal message"); } +/*! + @brief Deserializes a DisplayRequest message and sends it to the display + component. + @param stream + Incoming data stream from buffer. + @param field + Protobuf message's tag type. + @param arg + Optional arguments from decoder calling function. + @returns True if decoded successfully, False otherwise. +*/ +bool cbDecodeDisplayMsg(pb_istream_t *stream, const pb_field_t *field, + void **arg) { + if (field->tag == wippersnapper_signal_v1_DisplayRequest_display_add_tag) { + + // Decode message into a DisplayAddRequest + wippersnapper_display_v1_DisplayAddOrReplace msgAddReq = + wippersnapper_display_v1_DisplayAddOrReplace_init_zero; + if (!ws_pb_decode(stream, + wippersnapper_display_v1_DisplayAddOrReplace_fields, + &msgAddReq)) { + WS_DEBUG_PRINTLN("ERROR: Failure decoding DisplayAddOrReplace message!"); + return false; + } + + // Attempt to add or replace a display component + bool did_add = + WS._displayController->Handle_Display_AddOrReplace(&msgAddReq); + + // Create a DisplayResponse message + wippersnapper_signal_v1_DisplayResponse msgResp = + wippersnapper_signal_v1_DisplayResponse_init_zero; + msgResp.which_payload = + wippersnapper_signal_v1_DisplayResponse_display_added_tag; + msgResp.payload.display_added.did_add = did_add; + strncpy(msgResp.payload.display_added.name, msgAddReq.name, + sizeof(msgResp.payload.display_added.name)); + + // Encode and publish response back to broker + memset(WS._buffer_outgoing, 0, sizeof(WS._buffer_outgoing)); + pb_ostream_t ostream = pb_ostream_from_buffer(WS._buffer_outgoing, + sizeof(WS._buffer_outgoing)); + if (!ws_pb_encode(&ostream, wippersnapper_signal_v1_DisplayResponse_fields, + &msgResp)) { + WS_DEBUG_PRINTLN("ERROR: Unable to encode display response message!"); + return false; + } + + size_t msgSz; + pb_get_encoded_size(&msgSz, wippersnapper_signal_v1_DisplayResponse_fields, + &msgResp); + WS_DEBUG_PRINT("Publishing DisplayResponse Message..."); + if (!WS._mqtt->publish(WS._topic_signal_display_device, WS._buffer_outgoing, + msgSz, 1)) { + WS_DEBUG_PRINTLN("ERROR: Failed to DisplayResponse Response!"); + } else { + WS_DEBUG_PRINTLN("Published!"); + } + } else if (field->tag == + wippersnapper_signal_v1_DisplayRequest_display_write_tag) { + // Decode message into a DisplayAddRequest + wippersnapper_display_v1_DisplayWrite msgWrite = + wippersnapper_display_v1_DisplayWrite_init_zero; + if (!ws_pb_decode(stream, wippersnapper_display_v1_DisplayWrite_fields, + &msgWrite)) { + WS_DEBUG_PRINTLN("ERROR: Failure decoding DisplayWrite message!"); + return false; + } + // Attempt to write to a display + WS._displayController->Handle_Display_Write(&msgWrite); + } else if (field->tag == + wippersnapper_signal_v1_DisplayRequest_display_remove_tag) { + // Decode message into a DisplayRemoveRequest + wippersnapper_display_v1_DisplayRemove msgRemove = + wippersnapper_display_v1_DisplayRemove_init_zero; + if (!ws_pb_decode(stream, wippersnapper_display_v1_DisplayRemove_fields, + &msgRemove)) { + WS_DEBUG_PRINTLN("ERROR: Failure decoding DisplayRemove message!"); + return false; + } + // Attempt to remove a display + WS._displayController->Handle_Display_Remove(&msgRemove); + } else { + WS_DEBUG_PRINTLN("ERROR: Display message type not found!"); + return false; + } + return true; +} + +/*! + @brief Called when the device receives a new message from the + /display/ topic. + @param data + Incoming data from MQTT broker. + @param len + Length of incoming data. +*/ +void cbDisplayMessage(char *data, uint16_t len) { + WS_DEBUG_PRINTLN("* NEW MESSAGE [Topic: Display]: "); + WS_DEBUG_PRINT(len); + WS_DEBUG_PRINTLN(" bytes."); + // zero-out current buffer + memset(WS._buffer, 0, sizeof(WS._buffer)); + // copy mqtt data into buffer + memcpy(WS._buffer, data, len); + WS.bufSize = len; + + // Set up the payload callback, which will set up the callbacks for + // each oneof payload field once the field tag is known + WS.msgSignalDisplay.cb_payload.funcs.decode = cbDecodeDisplayMsg; + + // Decode pixel message from buffer + pb_istream_t istream = pb_istream_from_buffer(WS._buffer, WS.bufSize); + if (!ws_pb_decode(&istream, wippersnapper_signal_v1_DisplayRequest_fields, + &WS.msgSignalDisplay)) + WS_DEBUG_PRINTLN("ERROR: Unable to decode display message"); +} + /****************************************************************************/ /*! @brief Handles MQTT messages on signal topic until timeout. @@ -2344,6 +2465,63 @@ bool Wippersnapper::generateWSTopics() { WS_DEBUG_PRINTLN("FATAL ERROR: Failed to allocate memory for UART topic!"); return false; } + + // /display topic // + + // Pre-determine topic size + topicLen = strlen(WS._config.aio_user) + strlen("/") + strlen(_device_uid) + + strlen("/wprsnpr/") + strlen(TOPIC_SIGNALS) + strlen("broker") + + strlen(TOPIC_DISPLAY) + 1; + +// Pre-allocate memory for topic +#ifdef USE_PSRAM + WS._topic_signal_display_brkr = (char *)ps_malloc(topicLen); +#else + WS._topic_signal_display_brkr = (char *)malloc(topicLen); +#endif + + // Generate the topic + if (WS._topic_signal_display_brkr != NULL) { + snprintf(WS._topic_signal_display_brkr, topicLen, "%s/wprsnpr/%s%sbroker%s", + WS._config.aio_user, _device_uid, TOPIC_SIGNALS, TOPIC_DISPLAY); + } else { + WS_DEBUG_PRINTLN( + "FATAL ERROR: Failed to allocate memory for DISPLAY topic!"); + return false; + } + + // Subscribe to signal's DISPLAY sub-topic and set callback + _topic_signal_display_sub = + new Adafruit_MQTT_Subscribe(WS._mqtt, WS._topic_signal_display_brkr, 1); + WS_DEBUG_PRINTLN("Subscribing to DISPLAY topic: "); + WS_DEBUG_PRINTLN(WS._topic_signal_display_brkr); + WS._mqtt->subscribe(_topic_signal_display_sub); + WS_DEBUG_PRINTLN("Subscribed to DISPLAY topic!"); + _topic_signal_display_sub->setCallback(cbDisplayMessage); + + // Calculate length of the topic for device-to-broker DISPLAY topic + topicLen = strlen(WS._config.aio_user) + strlen("/") + strlen(_device_uid) + + strlen("/wprsnpr/") + strlen(TOPIC_SIGNALS) + strlen("device") + + strlen(TOPIC_DISPLAY) + 1; + +// Allocate memory for dynamic MQTT topic +#ifdef USE_PSRAM + WS._topic_signal_display_device = (char *)ps_malloc(topicLen); +#else + WS._topic_signal_display_device = (char *)malloc(topicLen); +#endif + + // Generate the topic if memory was allocated successfully + if (WS._topic_signal_display_device != NULL) { + snprintf(WS._topic_signal_display_device, topicLen, + "%s/wprsnpr/%s%sdevice%s", WS._config.aio_user, _device_uid, + TOPIC_SIGNALS, TOPIC_DISPLAY); + } else { + WS_DEBUG_PRINTLN( + "FATAL ERROR: Failed to allocate memory for DISPLAY topic!"); + return false; + } + return true; } @@ -2837,6 +3015,14 @@ void Wippersnapper::connect() { WS._ui_helper->build_scr_monitor(); #endif + WS.pinCfgCompleted = true; + + // Initialize Digital IO class + WS._digitalGPIO = new Wippersnapper_DigitalGPIO(20); + // Initialize Analog IO class + WS._analogIO = new Wippersnapper_AnalogIO(5, 3.3); + WS._boardStatus = WS_BOARD_DEF_OK; + // Configure hardware while (!WS.pinCfgCompleted) { WS_DEBUG_PRINTLN( diff --git a/src/Wippersnapper.h b/src/Wippersnapper.h index dc3152d01..e7af45ab7 100644 --- a/src/Wippersnapper.h +++ b/src/Wippersnapper.h @@ -127,6 +127,7 @@ #include "display/ws_display_ui_helper.h" #endif +#include "components/display/controller.h" #include "components/ds18x20/ws_ds18x20.h" #include "components/pixels/ws_pixels.h" #include "components/pwm/ws_pwm.h" @@ -142,7 +143,7 @@ #endif #define WS_VERSION \ - "1.0.0-beta.110" ///< WipperSnapper app. version (semver-formatted) + "1.0.0-beta.112" ///< WipperSnapper app. version (semver-formatted) // Reserved Adafruit IO MQTT topics #define TOPIC_IO_THROTTLE "/throttle" ///< Adafruit IO Throttle MQTT Topic @@ -153,6 +154,7 @@ #define TOPIC_INFO "/info/" ///< Registration sub-topic #define TOPIC_SIGNALS "/signals/" ///< Signals sub-topic #define TOPIC_I2C "/i2c" ///< I2C sub-topic +#define TOPIC_DISPLAY "/display" ///< Display sub-topic (EPD, OLED, TFT, etc.) #define MQTT_TOPIC_PIXELS_DEVICE \ "/signals/device/pixel" ///< Pixels device->broker topic #define MQTT_TOPIC_PIXELS_BROKER \ @@ -245,6 +247,7 @@ class ws_pwm; class ws_ds18x20; class ws_pixels; class ws_uart; +class DisplayController; /**************************************************************************/ /*! @@ -368,6 +371,8 @@ class Wippersnapper { ws_servo *_servoComponent; ///< Instance of servo class ws_ds18x20 *_ds18x20Component; ///< Instance of DS18x20 class ws_uart *_uartComponent; ///< Instance of UART class + DisplayController + *_displayController; ///< Instance of display controller class // TODO: does this really need to be global? uint8_t _macAddr[6]; /*!< Unique network iface identifier */ @@ -404,6 +409,10 @@ class Wippersnapper { char *_topic_signal_pixels_device = NULL; /*!< Topic carries pixel messages */ char *_topic_signal_uart_brkr = NULL; /*!< Topic carries UART messages */ char *_topic_signal_uart_device = NULL; /*!< Topic carries UART messages */ + char *_topic_signal_display_brkr = + NULL; /*!< Topic carries messages from a device to a broker. */ + char *_topic_signal_display_device = + NULL; /*!< Topic carries messages from a broker to a device. */ wippersnapper_signal_v1_CreateSignalRequest _incomingSignalMsg; /*!< Incoming signal message from broker */ @@ -430,6 +439,9 @@ class Wippersnapper { wippersnapper_signal_v1_UARTRequest msgSignalUART; ///< UARTReq wrapper message + wippersnapper_signal_v1_DisplayRequest + msgSignalDisplay; ///< DisplayRequest wrapper message + char *throttleMessage; /*!< Pointer to throttle message data. */ int throttleTime; /*!< Total amount of time to throttle the device, in milliseconds. */ @@ -490,6 +502,8 @@ class Wippersnapper { *_topic_signal_pixels_sub; /*!< Subscribes to pixel device topic. */ Adafruit_MQTT_Subscribe *_topic_signal_uart_sub; /*!< Subscribes to signal's UART topic. */ + Adafruit_MQTT_Subscribe *_topic_signal_display_sub; /*!< Subscription callback + for display topic. */ Adafruit_MQTT_Subscribe *_err_sub; /*!< Subscription to Adafruit IO Error topic. */ diff --git a/src/components/display/controller.cpp b/src/components/display/controller.cpp new file mode 100644 index 000000000..476e898fd --- /dev/null +++ b/src/components/display/controller.cpp @@ -0,0 +1,121 @@ +/*! + * @file src/components/display/controller.cpp + * + * Implementation for the display API controller. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Copyright (c) Brent Rubell 2025 for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ +#include "controller.h" + +/*! + @brief Constructs a new DisplayController object +*/ +DisplayController::DisplayController() {} + +/*! + @brief Destructor +*/ +DisplayController::~DisplayController() { + // Clean up all display hardware instances + for (DisplayHardware *hw_instance : _hw_instances) { + delete hw_instance; + } + _hw_instances.clear(); +} + +/*! + @brief Handles a Display_AddOrReplace message. + @param msgAdd + Pointer to a DisplayAddOrReplace message structure. + @return True if the display was added or replaced successfully, false + otherwise. +*/ +bool DisplayController::Handle_Display_AddOrReplace( + wippersnapper_display_v1_DisplayAddOrReplace *msgAdd) { + DisplayHardware *display = new DisplayHardware(msgAdd->name); + WS_DEBUG_PRINT("[display] Adding or replacing display: "); + WS_DEBUG_PRINTLN(msgAdd->name); + + // Configure display type + display->setType(msgAdd->type); + + // Attempt to initialize display hardware instance + bool did_begin = false; + if (msgAdd->which_config == + wippersnapper_display_v1_DisplayAddOrReplace_epd_config_tag) { + did_begin = display->beginEPD(&msgAdd->config.epd_config, + &msgAdd->interface_type.spi_epd); + } else { + WS_DEBUG_PRINTLN("[display] Unsupported display configuration type!"); + return false; + } + + // Check if the display began successfully + if (!did_begin) { + WS_DEBUG_PRINTLN("[display] Failed to initialize display!"); + delete display; // Clean up if initialization failed + return false; + } + + _hw_instances.push_back(display); // Store the display instance + WS_DEBUG_PRINTLN("[display] Display added or replaced successfully!"); + return true; +} + +/*! + @brief Handles a Display_Remove message. + @param msgRemove + Pointer to a DisplayRemove message structure. + @return True if the display was removed successfully, false otherwise. +*/ +bool DisplayController::Handle_Display_Remove( + wippersnapper_display_v1_DisplayRemove *msgRemove) { + // Find the display instance by name + for (auto it = _hw_instances.begin(); it != _hw_instances.end(); ++it) { + if (strcmp((*it)->getName(), msgRemove->name) == 0) { + delete *it; + _hw_instances.erase(it); + WS_DEBUG_PRINTLN("[display] Display removed successfully!"); + return true; + } + } + WS_DEBUG_PRINTLN("[display] Could not remove display, not found!"); + return false; +} + +/*! + @brief Handles a Display_Write message. + @param msgWrite + Pointer to a DisplayWrite message structure. + @return True if the display write was successful, false otherwise. +*/ +bool DisplayController::Handle_Display_Write( + wippersnapper_display_v1_DisplayWrite *msgWrite) { + // Get the driver instance for the display + DisplayHardware *display = nullptr; + for (auto &hw_instance : _hw_instances) { + if (strcmp(hw_instance->getName(), msgWrite->name) == 0) { + display = hw_instance; + break; + } + } + + // Early-out if driver instance not found + if (!display) { + WS_DEBUG_PRINTLN("[display] Failed to write, driver not found!"); + return false; + } + + // Write the message to the display + WS_DEBUG_PRINT("[display] Writing message to display: "); + WS_DEBUG_PRINTLN(msgWrite->message); + display->writeMessage(msgWrite->message); + return true; +} \ No newline at end of file diff --git a/src/components/display/controller.h b/src/components/display/controller.h new file mode 100644 index 000000000..f4c087e30 --- /dev/null +++ b/src/components/display/controller.h @@ -0,0 +1,44 @@ +/*! + * @file src/components/display/controller.h + * + * Controller for the display API + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Copyright (c) Brent Rubell 2025 for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ +#ifndef WS_DISPLAY_CONTROLLER_H +#define WS_DISPLAY_CONTROLLER_H +#include "Wippersnapper.h" +#include "hardware.h" + +class Wippersnapper_V2; ///< Forward declaration +class DisplayHardware; ///< Forward declaration + +/**************************************************************************/ +/*! + @brief Routes messages using the display.proto API to the + appropriate hardware and model classes, controls and tracks + the state of displays. +*/ +/**************************************************************************/ +class DisplayController { +public: + DisplayController(); + ~DisplayController(); + bool Handle_Display_AddOrReplace( + wippersnapper_display_v1_DisplayAddOrReplace *msgAdd); + bool Handle_Display_Remove(wippersnapper_display_v1_DisplayRemove *msgRemove); + bool Handle_Display_Write(wippersnapper_display_v1_DisplayWrite *msgWrite); + +private: + std::vector + _hw_instances; ///< Holds pointers to DisplayHardware instances +}; +extern Wippersnapper Ws; ///< Global WS instance +#endif \ No newline at end of file diff --git a/src/components/display/drivers/dispDrvBase.h b/src/components/display/drivers/dispDrvBase.h new file mode 100644 index 000000000..c7d624836 --- /dev/null +++ b/src/components/display/drivers/dispDrvBase.h @@ -0,0 +1,82 @@ +/*! + * @file src/components/display/drivers/dispDrvBase.h + * + * Abstract base class for display drivers. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Copyright (c) Brent Rubell 2025 for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ +#ifndef WS_DISP_DRV_BASE_H +#define WS_DISP_DRV_BASE_H + +#include "Adafruit_ThinkInk.h" +#include "Wippersnapper.h" + +/*! + @brief Abstract base class for display drivers. + This class provides a common interface for all display drivers, + allowing them to be used interchangeably. +*/ +class dispDrvBase { +public: + /*! + @brief Constructor for the base display driver for E-Ink displays. + @param dc + Data/Command pin for the display. + @param rst + Reset pin for the display. + @param cs + Chip Select pin for the display. + @param sram_cs + Optional SRAM Chip Select pin for E-Ink displays that support it. + @param busy + Optional Busy pin for the display. + */ + dispDrvBase(int16_t dc, int16_t rst, int16_t cs, int16_t sram_cs = -1, + int16_t busy = -1) + : _pin_dc(dc), _pin_rst(rst), _pin_cs(cs), _pin_sram_cs(sram_cs), + _pin_busy(busy) {} + + /*! + @brief Destructor for the base display driver. + This destructor is virtual to allow derived classes to clean up + resources properly. + */ + virtual ~dispDrvBase() {} + + /*! + @brief Attempts to initialize a ThinkInk EPD driver. + @param mode + The ThinkInk mode to use for the display. + @param reset + Whether to reset the display before initialization. + @return True if the display was initialized successfully, false otherwise. + */ + virtual bool begin(thinkinkmode_t mode, bool reset = true); + + /*! + @brief Writes a message to the display. + @param message + The message to write to the display. + @note MUST be implemented by derived classes. + */ + virtual void writeMessage(const char *message) = 0; + +protected: + int16_t _pin_dc; ///< Data/Command pin + int16_t _pin_rst; ///< Reset pin + int16_t _pin_cs; ///< Chip Select pin + int16_t _pin_busy; ///< Optional Busy pin + int16_t _pin_sram_cs; ///< Optional EPD SRAM chip select pin + uint8_t _text_sz = 1; ///< Text size for displaying a message + int16_t _height; ///< Height of the display + int16_t _width; ///< Width of the display +}; + +#endif // WS_DISP_DRV_BASE_H \ No newline at end of file diff --git a/src/components/display/drivers/dispDrvThinkInkGrayscale4Eaamfgn.h b/src/components/display/drivers/dispDrvThinkInkGrayscale4Eaamfgn.h new file mode 100644 index 000000000..6fcbb1cfe --- /dev/null +++ b/src/components/display/drivers/dispDrvThinkInkGrayscale4Eaamfgn.h @@ -0,0 +1,139 @@ +/*! + * @file src/components/display/drivers/dispDrvThinkInkGrayscale4Eaamfgn.h + * + * Driver for ThinkInk 2.9" Grayscale 4-level EAAMFGN display (present on the + * 2025 version of the Adafruit MagTag) + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Copyright (c) Brent Rubell 2025 for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ +#ifndef WS_DRV_THINKINK_GRAYSCALE4_EAAMFGN_H +#define WS_DRV_THINKINK_GRAYSCALE4_EAAMFGN_H + +#include "dispDrvBase.h" + +/*! + @brief Driver for a ThinkInk 2.9" Grayscale 4-level EAAMFGN display. +*/ +class drvDispThinkInkGrayscale4Eaamfgn : public dispDrvBase { +public: + /*! + @brief Constructor for the ThinkInk Grayscale 4-level EAAMFGN display + driver. + @param dc + Data/Command pin for the display. + @param rst + Reset pin for the display. + @param cs + Chip Select pin for the display. + @param sram_cs + Optional SRAM Chip Select pin for E-Ink displays that support it. + @param busy + Optional Busy pin for the display. + */ + drvDispThinkInkGrayscale4Eaamfgn(int16_t dc, int16_t rst, int16_t cs, + int16_t sram_cs = -1, int16_t busy = -1) + : dispDrvBase(dc, rst, cs, sram_cs, busy), _display(nullptr) {} + + ~drvDispThinkInkGrayscale4Eaamfgn() { + if (_display) { + delete _display; + _display = nullptr; + } + } + + /*! + @brief Attempts to initialize the ThinkInk Grayscale 4-level EAAMFGN + display driver. + @param mode + The ThinkInk mode to use for the display. + @param reset + Whether to reset the display before initialization. + @return True if the display was initialized successfully, false otherwise. + */ + bool begin(thinkinkmode_t mode, bool reset = true) override { + _display = new ThinkInk_290_Grayscale4_EAAMFGN(_pin_dc, _pin_rst, _pin_cs, + _pin_sram_cs, _pin_busy); + if (!_display) + return false; // Allocation failed + + // Initialize the display + _display->begin(mode); + // Configure display settings + _text_sz = 3; + _display->setTextSize(_text_sz); + _display->setTextColor(EPD_BLACK); + _display->setTextWrap(false); + _height = _display->height(); + _width = _display->width(); + // Clear the display buffer + _display->clearBuffer(); + _display->display(); + + return true; + } + + /*! + @brief Writes a message to the display. + @param message + The message to write to the display. + @note This method overrides the base class method to provide specific + functionality for the Think Ink Grayscale 4 EAAMGFGN driver. + */ + virtual void writeMessage(const char *message) override { + if (_display == nullptr) + return; + + // Start with a fresh display buffer + _display->clearBuffer(); + int16_t y_idx = 0; + _display->setCursor(0, y_idx); + + // Calculate the line height based on the text size (NOTE: base height is + // 8px) + int16_t line_height = 8 * _text_sz; + uint16_t c_idx = 0; + size_t msg_size = strlen(message); + for (size_t i = 0; i < msg_size && c_idx < msg_size; i++) { + if (y_idx + line_height > _height) + break; + if (message[i] == '\\' && i + 1 < msg_size && + (message[i + 1] == 'n' || message[i + 1] == 'r')) { + // Handle \r\n sequence as a single newline + if (message[i + 1] == 'r' && i + 3 < msg_size && + message[i + 2] == '\\' && message[i + 3] == 'n') { + // Skip to the next line + if (y_idx + line_height > _height) + break; + y_idx += line_height; + _display->setCursor(0, y_idx); + i += 3; + } else if (message[i + 1] == 'n') { + // Skip to the next line + if (y_idx + line_height > _height) + break; + y_idx += line_height; + _display->setCursor(0, y_idx); + i++; + } + } else if (message[i] == 0xC2 && message[i + 1] == 0xB0) { + _display->write(char(248)); + i++; + } else { + _display->print(message[i]); + } + } + _display->display(); + } + +private: + ThinkInk_290_Grayscale4_EAAMFGN *_display; +}; + +#endif // WS_DRV_THINKINK_GRAYSCALE4_EAAMFGN_H \ No newline at end of file diff --git a/src/components/display/drivers/dispDrvThinkInkGrayscale4T5.h b/src/components/display/drivers/dispDrvThinkInkGrayscale4T5.h new file mode 100644 index 000000000..ed266e00b --- /dev/null +++ b/src/components/display/drivers/dispDrvThinkInkGrayscale4T5.h @@ -0,0 +1,140 @@ +/*! + * @file src/components/display/drivers/dispDrvThinkInkGrayscale4T5.h + * + * Driver for ThinkInk 2.9" Grayscale 4-level T5 display (present on the + * pre-2025 version of the Adafruit MagTag) + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Copyright (c) Brent Rubell 2025 for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ +#ifndef WS_DRV_THINKINK_GRAYSCALE4_T5_H +#define WS_DRV_THINKINK_GRAYSCALE4_T5_H + +#include "dispDrvBase.h" + +/*! + @brief Driver for a ThinkInk 2.9" Grayscale 4-level T5 display (pre-2025 + version of the Adafruit MagTag). +*/ +class dispDrvThinkInkGrayscale4T5 : public dispDrvBase { +public: + /*! + @brief Constructor for the ThinkInk Grayscale 4-level EAAMFGN display + driver. + @param dc + Data/Command pin for the display. + @param rst + Reset pin for the display. + @param cs + Chip Select pin for the display. + @param sram_cs + Optional SRAM Chip Select pin for E-Ink displays that support it. + @param busy + Optional Busy pin for the display. + */ + dispDrvThinkInkGrayscale4T5(int16_t dc, int16_t rst, int16_t cs, + int16_t sram_cs = -1, int16_t busy = -1) + : dispDrvBase(dc, rst, cs, sram_cs, busy), _display(nullptr) {} + + ~dispDrvThinkInkGrayscale4T5() { + if (_display) { + delete _display; + _display = nullptr; + } + } + + /*! + @brief Attempts to initialize the ThinkInk Grayscale 4-level EAAMFGN + display driver. + @param mode + The ThinkInk mode to use for the display. + @param reset + Whether to reset the display before initialization. + @return True if the display was initialized successfully, false otherwise. + */ + bool begin(thinkinkmode_t mode, bool reset = true) override { + _display = new ThinkInk_290_Grayscale4_T5(_pin_dc, _pin_rst, _pin_cs, + _pin_sram_cs, _pin_busy); + if (!_display) + return false; // Allocation failed + + // Initialize the display + _display->begin(mode); + // Configure display settings + _text_sz = 3; + _display->setTextSize(_text_sz); + _display->setTextColor(EPD_BLACK); + _display->setTextWrap(false); + _height = _display->height(); + _width = _display->width(); + // Clear the display buffer + _display->clearBuffer(); + _display->display(); + + return true; + } + + /*! + @brief Writes a message to the display. + @param message + The message to write to the display. + @note This method overrides the base class method to provide specific + functionality for the Think Ink Grayscale 4 EAAMGFGN driver. + */ + virtual void writeMessage(const char *message) override { + if (_display == nullptr) + return; + + // Start with a fresh display buffer + _display->clearBuffer(); + int16_t y_idx = 0; + _display->setCursor(0, y_idx); + + // Calculate the line height based on the text size (NOTE: base height is + // 8px) + int16_t line_height = 8 * _text_sz; + uint16_t c_idx = 0; + size_t msg_size = strlen(message); + for (size_t i = 0; i < msg_size && c_idx < msg_size; i++) { + if (y_idx + line_height > _height) + break; + if (message[i] == '\\' && i + 1 < msg_size && + (message[i + 1] == 'n' || message[i + 1] == 'r')) { + // Handle \r\n sequence as a single newline + if (message[i + 1] == 'r' && i + 3 < msg_size && + message[i + 2] == '\\' && message[i + 3] == 'n') { + // Skip to the next line + if (y_idx + line_height > _height) + break; + y_idx += line_height; + _display->setCursor(0, y_idx); + i += 3; + } else if (message[i + 1] == 'n') { + // Skip to the next line + if (y_idx + line_height > _height) + break; + y_idx += line_height; + _display->setCursor(0, y_idx); + i++; + } + } else if (message[i] == 0xC2 && message[i + 1] == 0xB0) { + _display->write(char(248)); + i++; + } else { + _display->print(message[i]); + } + } + _display->display(); + } + +private: + ThinkInk_290_Grayscale4_T5 *_display; +}; + +#endif // WS_DRV_THINKINK_GRAYSCALE4_T5_H \ No newline at end of file diff --git a/src/components/display/hardware.cpp b/src/components/display/hardware.cpp new file mode 100644 index 000000000..13f8248da --- /dev/null +++ b/src/components/display/hardware.cpp @@ -0,0 +1,287 @@ +/*! + * @file src/components/display/hardware.cpp + * + * Implementation for the display hardware. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Copyright (c) Brent Rubell 2025 for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ +#include "controller.h" + +/*! + @brief Lambda function to create a dispDrvBase instance +*/ +using FnCreateDispDrv = + std::function; + +// Factory for creating a new display drivers +// NOTE: When you add a new display driver, make sure to add it to the factory! +static const std::map FactoryDrvDisp = { + {"thinkink-gs4-eaamfgn", + [](int16_t dc, int16_t rst, int16_t cs, int16_t sram_cs, + int16_t busy) -> dispDrvBase * { + return new drvDispThinkInkGrayscale4Eaamfgn(dc, rst, cs, sram_cs, busy); + }}, + {"thinkink-gs4-t5", + [](int16_t dc, int16_t rst, int16_t cs, int16_t sram_cs, + int16_t busy) -> dispDrvBase * { + return new dispDrvThinkInkGrayscale4T5(dc, rst, cs, sram_cs, busy); + }}}; + +/*! + @brief Creates a new display driver instance based on the driver name. + @param driver_name + The name of the display driver to create. + @param dc + Data/Command pin number. + @param rst + Reset pin number. + @param cs + Chip Select pin number. + @param sram_cs + Optional SRAM Chip Select pin number (default: -1). + @param busy + Optional Busy pin number (default: -1). + @return Pointer to the created display driver instance, or nullptr if the + driver name is not recognized. +*/ +dispDrvBase *CreateDrvDisp(const char *driver_name, int16_t dc, int16_t rst, + int16_t cs, int16_t sram_cs = -1, + int16_t busy = -1) { + auto it = FactoryDrvDisp.find(driver_name); + if (it == FactoryDrvDisp.end()) + return nullptr; + + return it->second(dc, rst, cs, sram_cs, busy); +} + +/*! + @brief Constructs a new DisplayHardware object + @param name + The name of the hardware instance. +*/ +DisplayHardware::DisplayHardware(const char *name) { + strncpy(_name, name, sizeof(_name) - 1); + _name[sizeof(_name) - 1] = '\0'; + _type = wippersnapper_display_v1_DisplayType_DISPLAY_TYPE_UNSPECIFIED; +} + +/*! + @brief Destructor +*/ +DisplayHardware::~DisplayHardware() { + if (_drvDisp) { + delete _drvDisp; + _drvDisp = nullptr; + } +} + +/*! + @brief Sets the hardware's display type. + @param type + The display type to set. +*/ +void DisplayHardware::setType(wippersnapper_display_v1_DisplayType type) { + _type = type; +} + +/*! + @brief Gets the hardware's display type. + @return The current display type. +*/ +wippersnapper_display_v1_DisplayType DisplayHardware::getType() { + return _type; +} + +/*! + @brief Configures the EPD display with the provided configuration. + @param config + Pointer to the EPD configuration structure. + @param spi_config + Pointer to the SPI configuration structure for EPD. + @return True if configuration was successful, False otherwise. +*/ +bool DisplayHardware::beginEPD( + wippersnapper_display_v1_EPDConfig *config, + wippersnapper_display_v1_EpdSpiConfig *spi_config) { + // Validate pointers + if (config == nullptr || spi_config == nullptr) { + WS_DEBUG_PRINTLN("[display] EPD config or SPI config is null!"); + return false; + } + + // Validate mode is a correct EPD mode + if (config->mode == wippersnapper_display_v1_EPDMode_EPD_MODE_UNSPECIFIED) { + WS_DEBUG_PRINTLN("[display] Unsupported EPD mode!"); + return false; + } + + // If we already have a display driver assigned to this hardware instance, + // clean it up! + if (_drvDisp) { + delete _drvDisp; + _drvDisp = nullptr; + } + + // Parse all SPI bus pins + // Check length + if (strlen(spi_config->pin_dc) < 2 || strlen(spi_config->pin_rst) < 2 || + strlen(spi_config->pin_cs) < 2) { + WS_DEBUG_PRINTLN("[display] Invalid SPI pin len!"); + return false; + } + // SPI pins must start with 'D' + if (spi_config->pin_dc[0] != 'D' || spi_config->pin_rst[0] != 'D' || + spi_config->pin_cs[0] != 'D') { + WS_DEBUG_PRINTLN("[display] SPI pins must start with 'D'!"); + return false; + } + + // Parse and assign pins + int16_t srcs = -1, busy = -1; + int16_t dc = (int16_t)atoi(spi_config->pin_dc + 1); + int16_t rst = (int16_t)atoi(spi_config->pin_rst + 1); + int16_t cs = (int16_t)atoi(spi_config->pin_cs + 1); + + // Optionally parse SRAM CS and BUSY pins + if (strlen(spi_config->pin_sram_cs) >= 2 && + spi_config->pin_sram_cs[0] == 'D') { + srcs = (int16_t)atoi(spi_config->pin_sram_cs + 1); + } + if (strlen(spi_config->pin_busy) >= 2 && spi_config->pin_busy[0] == 'D') { + busy = (int16_t)atoi(spi_config->pin_busy + 1); + } + + // Configure SPI bus + if (spi_config->bus != 0) { + WS_DEBUG_PRINTLN( + "[display] ERROR: Non-default SPI buses are currently not supported!"); + return false; + } + + // For "magtag" component name, attempt to autodetect the driver type + if (strncmp(_name, "magtag", 6) == 0) { + if (detect_ssd1680(cs, dc, rst)) { + // Detected SSD1680, use EAAMFGN driver + strncpy(_name, "thinkink-gs4-eaamfgn", sizeof(_name) - 1); + _name[sizeof(_name) - 1] = '\0'; + } else { + // Did not detect SSD1680, use IL0373 driver + strncpy(_name, "thinkink-gs4-t5", sizeof(_name) - 1); + _name[sizeof(_name) - 1] = '\0'; + } + } + + // Create display driver object using the factory function + _drvDisp = CreateDrvDisp(_name, dc, rst, cs, srcs, busy); + if (!_drvDisp) { + WS_DEBUG_PRINTLN("[display] Failed to create display driver!"); + return false; // Failed to create display driver + } + + // Configure EPD mode + thinkinkmode_t epd_mode = THINKINK_MONO; + if (config->mode == wippersnapper_display_v1_EPDMode_EPD_MODE_GRAYSCALE4) { + epd_mode = THINKINK_GRAYSCALE4; + WS_DEBUG_PRINTLN("[display] EPD mode: GRAYSCALE4"); + } + + if (!_drvDisp->begin(epd_mode)) { + WS_DEBUG_PRINTLN("[display] Failed to begin display driver!"); + delete _drvDisp; + _drvDisp = nullptr; + return false; + } + + return true; // Configuration successful +} + +/*! + @brief Gets the name of the display hardware instance. + @return The name of the display hardware instance. +*/ +const char *DisplayHardware::getName() { return _name; } + +/*! + @brief Writes a message to the display. + @param message + The message to display. +*/ +void DisplayHardware::writeMessage(const char *message) { + if (!_drvDisp) + return; + _drvDisp->writeMessage(message); +} + +/*! + @brief Detects if an SSD1680 EPD is connected using bit-banged SPI. + @param cs + Chip Select pin number. + @param dc + Data/Command pin number. + @param rst + Reset pin number. + @return True if an SSD1680 is detected, False otherwise (IL0373 or different + EPD). +*/ +bool DisplayHardware::detect_ssd1680(uint8_t cs, uint8_t dc, uint8_t rst) { + // note: for a complete implementation reference, see + // https://github.com/adafruit/circuitpython/commit/f4316cb2491c815b128acca47f1bb75519fe306e + // Configure SPI pins to bit-bang + pinMode(MOSI, OUTPUT); + pinMode(SCK, OUTPUT); + pinMode(cs, OUTPUT); + pinMode(dc, OUTPUT); + pinMode(rst, OUTPUT); + + // Begin transaction by pulling cs and dc LOW + digitalWrite(cs, LOW); + digitalWrite(dc, LOW); + digitalWrite(SCK, LOW); + digitalWrite(rst, HIGH); + + // Write to read register 0x71 + uint8_t cmd = 0x71; + for (int i = 0; i < 8; i++) { + digitalWrite(MOSI, (cmd & (1 << (7 - i))) != 0); + digitalWrite(SCK, HIGH); + digitalWrite(SCK, LOW); + } + + // Set DC high to indicate data and switch MOSI to input with PUR in case + // SSD1680 does not send data back + digitalWrite(dc, HIGH); + delayMicroseconds(1); + pinMode(MOSI, INPUT_PULLUP); + delayMicroseconds(1); + + // Read response from register + uint8_t status = 0; + for (int i = 0; i < 8; i++) { + status <<= 1; + if (digitalRead(MOSI)) { + status |= 1; + } + digitalWrite(SCK, HIGH); + delayMicroseconds(1); + digitalWrite(SCK, LOW); + delayMicroseconds(1); + } + + // End transaction by pulling CS high + digitalWrite(cs, HIGH); + + // Put back MOSI pin as an output + pinMode(MOSI, OUTPUT); + + WS_DEBUG_PRINT("[display] Bitbang read 0x71: 0x"); + WS_DEBUG_PRINTLN(status, HEX); + + return status == 0xFF; +} \ No newline at end of file diff --git a/src/components/display/hardware.h b/src/components/display/hardware.h new file mode 100644 index 000000000..f8f5dad61 --- /dev/null +++ b/src/components/display/hardware.h @@ -0,0 +1,57 @@ +/*! + * @file src/components/display/hardware.h + * + * Hardware interface for display components. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Copyright (c) Brent Rubell 2025 for Adafruit Industries. + * + * BSD license, all text here must be included in any redistribution. + * + */ +#ifndef WS_DISPLAY_HARDWARE_H +#define WS_DISPLAY_HARDWARE_H +#include "Wippersnapper.h" +#include "drivers/dispDrvBase.h" +#include "drivers/dispDrvThinkInkGrayscale4Eaamfgn.h" +#include "drivers/dispDrvThinkInkGrayscale4T5.h" +#include +#include + +/*! + @brief Interface for interacting with display hardware (TFT, eInk, + OLED, etc.) + This class provides methods to initialize, write to, and + manage the state of display hardware. +*/ +class DisplayHardware { +public: + DisplayHardware(const char *name); + ~DisplayHardware(); + + // + // API for configuring the display hardware // + // + const char *getName(); + void setType(wippersnapper_display_v1_DisplayType type); + wippersnapper_display_v1_DisplayType getType(); + bool beginEPD(wippersnapper_display_v1_EPDConfig *config, + wippersnapper_display_v1_EpdSpiConfig *spi_config); + + // + // API for Adafruit_GFX that abstracts hardware functionality + // NOTE: These methods are meant to be implemented within dispDrvBase and + // exposed within dispDrv driver instances + // + void writeMessage(const char *message); + +private: + bool detect_ssd1680(uint8_t cs, uint8_t dc, uint8_t rst); + char _name[64]; ///< Identifies the hardware instance + wippersnapper_display_v1_DisplayType _type; ///< Display type + dispDrvBase *_drvDisp = nullptr; ///< Base display driver +}; +#endif // WS_DISPLAY_HARDWARE_H \ No newline at end of file diff --git a/src/components/register/Wippersnapper_Register.cpp b/src/components/register/Wippersnapper_Register.cpp index 522818997..4ad9ec5c4 100644 --- a/src/components/register/Wippersnapper_Register.cpp +++ b/src/components/register/Wippersnapper_Register.cpp @@ -77,6 +77,7 @@ bool Wippersnapper::encodePubRegistrationReq() { /****************************************************************************/ void Wippersnapper::pollRegistrationResp() { // Blocking loop, WDT reset upon failure. + WS._boardStatus = WS_BOARD_DEF_OK; while (WS._boardStatus != WS_BOARD_DEF_OK) { WS_DEBUG_PRINT("Polling for registration message response..."); WS_DEBUG_PRINTLN(WS._boardStatus); diff --git a/src/provisioning/sdcard/ws_sdcard.cpp b/src/provisioning/sdcard/ws_sdcard.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/provisioning/sdcard/ws_sdcard.h b/src/provisioning/sdcard/ws_sdcard.h new file mode 100644 index 000000000..e69de29bb diff --git a/src/wippersnapper/description/v1/description.pb.c b/src/wippersnapper/description/v1/description.pb.c index af570fc40..638affe37 100644 --- a/src/wippersnapper/description/v1/description.pb.c +++ b/src/wippersnapper/description/v1/description.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/description/v1/description.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/description/v1/description.pb.h b/src/wippersnapper/description/v1/description.pb.h index 208fbd01c..9af63f69c 100644 --- a/src/wippersnapper/description/v1/description.pb.h +++ b/src/wippersnapper/description/v1/description.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_DESCRIPTION_V1_WIPPERSNAPPER_DESCRIPTION_V1_DESCRIPTION_PB_H_INCLUDED #define PB_WIPPERSNAPPER_DESCRIPTION_V1_WIPPERSNAPPER_DESCRIPTION_V1_DESCRIPTION_PB_H_INCLUDED diff --git a/src/wippersnapper/display/v1/display.pb.c b/src/wippersnapper/display/v1/display.pb.c new file mode 100644 index 000000000..9e1339aec --- /dev/null +++ b/src/wippersnapper/display/v1/display.pb.c @@ -0,0 +1,36 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ + +#include "wippersnapper/display/v1/display.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(wippersnapper_display_v1_EpdSpiConfig, wippersnapper_display_v1_EpdSpiConfig, AUTO) + + +PB_BIND(wippersnapper_display_v1_EPDConfig, wippersnapper_display_v1_EPDConfig, AUTO) + + +PB_BIND(wippersnapper_display_v1_EPDWriteOptions, wippersnapper_display_v1_EPDWriteOptions, AUTO) + + +PB_BIND(wippersnapper_display_v1_DisplayAddOrReplace, wippersnapper_display_v1_DisplayAddOrReplace, AUTO) + + +PB_BIND(wippersnapper_display_v1_DisplayRemove, wippersnapper_display_v1_DisplayRemove, AUTO) + + +PB_BIND(wippersnapper_display_v1_DisplayWrite, wippersnapper_display_v1_DisplayWrite, 2) + + +PB_BIND(wippersnapper_display_v1_DisplayAddedorReplaced, wippersnapper_display_v1_DisplayAddedorReplaced, AUTO) + + +PB_BIND(wippersnapper_display_v1_DisplayRemoved, wippersnapper_display_v1_DisplayRemoved, AUTO) + + + + + + diff --git a/src/wippersnapper/display/v1/display.pb.h b/src/wippersnapper/display/v1/display.pb.h new file mode 100644 index 000000000..b72968763 --- /dev/null +++ b/src/wippersnapper/display/v1/display.pb.h @@ -0,0 +1,243 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ + +#ifndef PB_WIPPERSNAPPER_DISPLAY_V1_WIPPERSNAPPER_DISPLAY_V1_DISPLAY_PB_H_INCLUDED +#define PB_WIPPERSNAPPER_DISPLAY_V1_WIPPERSNAPPER_DISPLAY_V1_DISPLAY_PB_H_INCLUDED +#include +#include "nanopb/nanopb.pb.h" +#include "wippersnapper/i2c/v1/i2c.pb.h" + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +typedef enum _wippersnapper_display_v1_DisplayType { + wippersnapper_display_v1_DisplayType_DISPLAY_TYPE_UNSPECIFIED = 0, + wippersnapper_display_v1_DisplayType_DISPLAY_TYPE_OLED = 1, + wippersnapper_display_v1_DisplayType_DISPLAY_TYPE_EPD = 2 +} wippersnapper_display_v1_DisplayType; + +typedef enum _wippersnapper_display_v1_EPDMode { + wippersnapper_display_v1_EPDMode_EPD_MODE_UNSPECIFIED = 0, + wippersnapper_display_v1_EPDMode_EPD_MODE_GRAYSCALE4 = 1, + wippersnapper_display_v1_EPDMode_EPD_MODE_MONO = 2 +} wippersnapper_display_v1_EPDMode; + +typedef enum _wippersnapper_display_v1_EPDColors { + wippersnapper_display_v1_EPDColors_EPD_COLORS_UNSPECIFIED = 0, + wippersnapper_display_v1_EPDColors_EPD_COLORS_WHITE = 1, + wippersnapper_display_v1_EPDColors_EPD_COLORS_BLACK = 2, + wippersnapper_display_v1_EPDColors_EPD_COLORS_RED = 3, + wippersnapper_display_v1_EPDColors_EPD_COLORS_GRAY = 4, + wippersnapper_display_v1_EPDColors_EPD_COLORS_DARK = 5, + wippersnapper_display_v1_EPDColors_EPD_COLORS_LIGHT = 6, + wippersnapper_display_v1_EPDColors_EPD_COLORS_YELLOW = 7 +} wippersnapper_display_v1_EPDColors; + +/* Struct definitions */ +typedef struct _wippersnapper_display_v1_DisplayAddedorReplaced { + char name[64]; + bool did_add; +} wippersnapper_display_v1_DisplayAddedorReplaced; + +typedef struct _wippersnapper_display_v1_DisplayRemove { + char name[64]; +} wippersnapper_display_v1_DisplayRemove; + +typedef struct _wippersnapper_display_v1_DisplayRemoved { + char name[64]; + bool did_remove; +} wippersnapper_display_v1_DisplayRemoved; + +typedef struct _wippersnapper_display_v1_EPDConfig { + wippersnapper_display_v1_EPDMode mode; +} wippersnapper_display_v1_EPDConfig; + +typedef struct _wippersnapper_display_v1_EPDWriteOptions { + int32_t text_size; + wippersnapper_display_v1_EPDColors color; +} wippersnapper_display_v1_EPDWriteOptions; + +typedef struct _wippersnapper_display_v1_EpdSpiConfig { + int32_t bus; + char pin_dc[6]; + char pin_rst[6]; + char pin_cs[6]; + char pin_sram_cs[6]; + char pin_busy[6]; +} wippersnapper_display_v1_EpdSpiConfig; + +typedef struct _wippersnapper_display_v1_DisplayAddOrReplace { + wippersnapper_display_v1_DisplayType type; + char name[64]; + pb_size_t which_interface_type; + union { + wippersnapper_display_v1_EpdSpiConfig spi_epd; + } interface_type; + pb_size_t which_config; + union { + wippersnapper_display_v1_EPDConfig epd_config; + } config; +} wippersnapper_display_v1_DisplayAddOrReplace; + +typedef struct _wippersnapper_display_v1_DisplayWrite { + char name[64]; + char message[1024]; + pb_size_t which_options; + union { + wippersnapper_display_v1_EPDWriteOptions epd_options; + } options; +} wippersnapper_display_v1_DisplayWrite; + + +/* Helper constants for enums */ +#define _wippersnapper_display_v1_DisplayType_MIN wippersnapper_display_v1_DisplayType_DISPLAY_TYPE_UNSPECIFIED +#define _wippersnapper_display_v1_DisplayType_MAX wippersnapper_display_v1_DisplayType_DISPLAY_TYPE_EPD +#define _wippersnapper_display_v1_DisplayType_ARRAYSIZE ((wippersnapper_display_v1_DisplayType)(wippersnapper_display_v1_DisplayType_DISPLAY_TYPE_EPD+1)) + +#define _wippersnapper_display_v1_EPDMode_MIN wippersnapper_display_v1_EPDMode_EPD_MODE_UNSPECIFIED +#define _wippersnapper_display_v1_EPDMode_MAX wippersnapper_display_v1_EPDMode_EPD_MODE_MONO +#define _wippersnapper_display_v1_EPDMode_ARRAYSIZE ((wippersnapper_display_v1_EPDMode)(wippersnapper_display_v1_EPDMode_EPD_MODE_MONO+1)) + +#define _wippersnapper_display_v1_EPDColors_MIN wippersnapper_display_v1_EPDColors_EPD_COLORS_UNSPECIFIED +#define _wippersnapper_display_v1_EPDColors_MAX wippersnapper_display_v1_EPDColors_EPD_COLORS_YELLOW +#define _wippersnapper_display_v1_EPDColors_ARRAYSIZE ((wippersnapper_display_v1_EPDColors)(wippersnapper_display_v1_EPDColors_EPD_COLORS_YELLOW+1)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializer values for message structs */ +#define wippersnapper_display_v1_EpdSpiConfig_init_default {0, "", "", "", "", ""} +#define wippersnapper_display_v1_EPDConfig_init_default {_wippersnapper_display_v1_EPDMode_MIN} +#define wippersnapper_display_v1_EPDWriteOptions_init_default {0, _wippersnapper_display_v1_EPDColors_MIN} +#define wippersnapper_display_v1_DisplayAddOrReplace_init_default {_wippersnapper_display_v1_DisplayType_MIN, "", 0, {wippersnapper_display_v1_EpdSpiConfig_init_default}, 0, {wippersnapper_display_v1_EPDConfig_init_default}} +#define wippersnapper_display_v1_DisplayRemove_init_default {""} +#define wippersnapper_display_v1_DisplayWrite_init_default {"", "", 0, {wippersnapper_display_v1_EPDWriteOptions_init_default}} +#define wippersnapper_display_v1_DisplayAddedorReplaced_init_default {"", 0} +#define wippersnapper_display_v1_DisplayRemoved_init_default {"", 0} +#define wippersnapper_display_v1_EpdSpiConfig_init_zero {0, "", "", "", "", ""} +#define wippersnapper_display_v1_EPDConfig_init_zero {_wippersnapper_display_v1_EPDMode_MIN} +#define wippersnapper_display_v1_EPDWriteOptions_init_zero {0, _wippersnapper_display_v1_EPDColors_MIN} +#define wippersnapper_display_v1_DisplayAddOrReplace_init_zero {_wippersnapper_display_v1_DisplayType_MIN, "", 0, {wippersnapper_display_v1_EpdSpiConfig_init_zero}, 0, {wippersnapper_display_v1_EPDConfig_init_zero}} +#define wippersnapper_display_v1_DisplayRemove_init_zero {""} +#define wippersnapper_display_v1_DisplayWrite_init_zero {"", "", 0, {wippersnapper_display_v1_EPDWriteOptions_init_zero}} +#define wippersnapper_display_v1_DisplayAddedorReplaced_init_zero {"", 0} +#define wippersnapper_display_v1_DisplayRemoved_init_zero {"", 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define wippersnapper_display_v1_DisplayAddedorReplaced_name_tag 1 +#define wippersnapper_display_v1_DisplayAddedorReplaced_did_add_tag 2 +#define wippersnapper_display_v1_DisplayRemove_name_tag 1 +#define wippersnapper_display_v1_DisplayRemoved_name_tag 1 +#define wippersnapper_display_v1_DisplayRemoved_did_remove_tag 2 +#define wippersnapper_display_v1_EPDConfig_mode_tag 1 +#define wippersnapper_display_v1_EPDWriteOptions_text_size_tag 1 +#define wippersnapper_display_v1_EPDWriteOptions_color_tag 2 +#define wippersnapper_display_v1_EpdSpiConfig_bus_tag 1 +#define wippersnapper_display_v1_EpdSpiConfig_pin_dc_tag 2 +#define wippersnapper_display_v1_EpdSpiConfig_pin_rst_tag 3 +#define wippersnapper_display_v1_EpdSpiConfig_pin_cs_tag 4 +#define wippersnapper_display_v1_EpdSpiConfig_pin_sram_cs_tag 5 +#define wippersnapper_display_v1_EpdSpiConfig_pin_busy_tag 6 +#define wippersnapper_display_v1_DisplayAddOrReplace_type_tag 1 +#define wippersnapper_display_v1_DisplayAddOrReplace_name_tag 2 +#define wippersnapper_display_v1_DisplayAddOrReplace_spi_epd_tag 3 +#define wippersnapper_display_v1_DisplayAddOrReplace_epd_config_tag 4 +#define wippersnapper_display_v1_DisplayWrite_name_tag 1 +#define wippersnapper_display_v1_DisplayWrite_message_tag 2 +#define wippersnapper_display_v1_DisplayWrite_epd_options_tag 3 + +/* Struct field encoding specification for nanopb */ +#define wippersnapper_display_v1_EpdSpiConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT32, bus, 1) \ +X(a, STATIC, SINGULAR, STRING, pin_dc, 2) \ +X(a, STATIC, SINGULAR, STRING, pin_rst, 3) \ +X(a, STATIC, SINGULAR, STRING, pin_cs, 4) \ +X(a, STATIC, SINGULAR, STRING, pin_sram_cs, 5) \ +X(a, STATIC, SINGULAR, STRING, pin_busy, 6) +#define wippersnapper_display_v1_EpdSpiConfig_CALLBACK NULL +#define wippersnapper_display_v1_EpdSpiConfig_DEFAULT NULL + +#define wippersnapper_display_v1_EPDConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, mode, 1) +#define wippersnapper_display_v1_EPDConfig_CALLBACK NULL +#define wippersnapper_display_v1_EPDConfig_DEFAULT NULL + +#define wippersnapper_display_v1_EPDWriteOptions_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT32, text_size, 1) \ +X(a, STATIC, SINGULAR, UENUM, color, 2) +#define wippersnapper_display_v1_EPDWriteOptions_CALLBACK NULL +#define wippersnapper_display_v1_EPDWriteOptions_DEFAULT NULL + +#define wippersnapper_display_v1_DisplayAddOrReplace_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, type, 1) \ +X(a, STATIC, SINGULAR, STRING, name, 2) \ +X(a, STATIC, ONEOF, MESSAGE, (interface_type,spi_epd,interface_type.spi_epd), 3) \ +X(a, STATIC, ONEOF, MESSAGE, (config,epd_config,config.epd_config), 4) +#define wippersnapper_display_v1_DisplayAddOrReplace_CALLBACK NULL +#define wippersnapper_display_v1_DisplayAddOrReplace_DEFAULT NULL +#define wippersnapper_display_v1_DisplayAddOrReplace_interface_type_spi_epd_MSGTYPE wippersnapper_display_v1_EpdSpiConfig +#define wippersnapper_display_v1_DisplayAddOrReplace_config_epd_config_MSGTYPE wippersnapper_display_v1_EPDConfig + +#define wippersnapper_display_v1_DisplayRemove_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, name, 1) +#define wippersnapper_display_v1_DisplayRemove_CALLBACK NULL +#define wippersnapper_display_v1_DisplayRemove_DEFAULT NULL + +#define wippersnapper_display_v1_DisplayWrite_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, name, 1) \ +X(a, STATIC, SINGULAR, STRING, message, 2) \ +X(a, STATIC, ONEOF, MESSAGE, (options,epd_options,options.epd_options), 3) +#define wippersnapper_display_v1_DisplayWrite_CALLBACK NULL +#define wippersnapper_display_v1_DisplayWrite_DEFAULT NULL +#define wippersnapper_display_v1_DisplayWrite_options_epd_options_MSGTYPE wippersnapper_display_v1_EPDWriteOptions + +#define wippersnapper_display_v1_DisplayAddedorReplaced_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, name, 1) \ +X(a, STATIC, SINGULAR, BOOL, did_add, 2) +#define wippersnapper_display_v1_DisplayAddedorReplaced_CALLBACK NULL +#define wippersnapper_display_v1_DisplayAddedorReplaced_DEFAULT NULL + +#define wippersnapper_display_v1_DisplayRemoved_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, name, 1) \ +X(a, STATIC, SINGULAR, BOOL, did_remove, 2) +#define wippersnapper_display_v1_DisplayRemoved_CALLBACK NULL +#define wippersnapper_display_v1_DisplayRemoved_DEFAULT NULL + +extern const pb_msgdesc_t wippersnapper_display_v1_EpdSpiConfig_msg; +extern const pb_msgdesc_t wippersnapper_display_v1_EPDConfig_msg; +extern const pb_msgdesc_t wippersnapper_display_v1_EPDWriteOptions_msg; +extern const pb_msgdesc_t wippersnapper_display_v1_DisplayAddOrReplace_msg; +extern const pb_msgdesc_t wippersnapper_display_v1_DisplayRemove_msg; +extern const pb_msgdesc_t wippersnapper_display_v1_DisplayWrite_msg; +extern const pb_msgdesc_t wippersnapper_display_v1_DisplayAddedorReplaced_msg; +extern const pb_msgdesc_t wippersnapper_display_v1_DisplayRemoved_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define wippersnapper_display_v1_EpdSpiConfig_fields &wippersnapper_display_v1_EpdSpiConfig_msg +#define wippersnapper_display_v1_EPDConfig_fields &wippersnapper_display_v1_EPDConfig_msg +#define wippersnapper_display_v1_EPDWriteOptions_fields &wippersnapper_display_v1_EPDWriteOptions_msg +#define wippersnapper_display_v1_DisplayAddOrReplace_fields &wippersnapper_display_v1_DisplayAddOrReplace_msg +#define wippersnapper_display_v1_DisplayRemove_fields &wippersnapper_display_v1_DisplayRemove_msg +#define wippersnapper_display_v1_DisplayWrite_fields &wippersnapper_display_v1_DisplayWrite_msg +#define wippersnapper_display_v1_DisplayAddedorReplaced_fields &wippersnapper_display_v1_DisplayAddedorReplaced_msg +#define wippersnapper_display_v1_DisplayRemoved_fields &wippersnapper_display_v1_DisplayRemoved_msg + +/* Maximum encoded size of messages (where known) */ +#define wippersnapper_display_v1_EpdSpiConfig_size 46 +#define wippersnapper_display_v1_EPDConfig_size 2 +#define wippersnapper_display_v1_EPDWriteOptions_size 13 +#define wippersnapper_display_v1_DisplayAddOrReplace_size 119 +#define wippersnapper_display_v1_DisplayRemove_size 65 +#define wippersnapper_display_v1_DisplayWrite_size 1106 +#define wippersnapper_display_v1_DisplayAddedorReplaced_size 67 +#define wippersnapper_display_v1_DisplayRemoved_size 67 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/wippersnapper/ds18x20/v1/ds18x20.pb.c b/src/wippersnapper/ds18x20/v1/ds18x20.pb.c index 483c432c9..2033a041d 100644 --- a/src/wippersnapper/ds18x20/v1/ds18x20.pb.c +++ b/src/wippersnapper/ds18x20/v1/ds18x20.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/ds18x20/v1/ds18x20.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/ds18x20/v1/ds18x20.pb.h b/src/wippersnapper/ds18x20/v1/ds18x20.pb.h index 715616f73..ba86dbb96 100644 --- a/src/wippersnapper/ds18x20/v1/ds18x20.pb.h +++ b/src/wippersnapper/ds18x20/v1/ds18x20.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_DS18X20_V1_WIPPERSNAPPER_DS18X20_V1_DS18X20_PB_H_INCLUDED #define PB_WIPPERSNAPPER_DS18X20_V1_WIPPERSNAPPER_DS18X20_V1_DS18X20_PB_H_INCLUDED diff --git a/src/wippersnapper/i2c/v1/i2c.pb.c b/src/wippersnapper/i2c/v1/i2c.pb.c index e1e4dde04..80c5b8c7e 100644 --- a/src/wippersnapper/i2c/v1/i2c.pb.c +++ b/src/wippersnapper/i2c/v1/i2c.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/i2c/v1/i2c.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/i2c/v1/i2c.pb.h b/src/wippersnapper/i2c/v1/i2c.pb.h index 8b5b0f53b..b2718e279 100644 --- a/src/wippersnapper/i2c/v1/i2c.pb.h +++ b/src/wippersnapper/i2c/v1/i2c.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_I2C_V1_WIPPERSNAPPER_I2C_V1_I2C_PB_H_INCLUDED #define PB_WIPPERSNAPPER_I2C_V1_WIPPERSNAPPER_I2C_V1_I2C_PB_H_INCLUDED diff --git a/src/wippersnapper/pin/v1/pin.pb.c b/src/wippersnapper/pin/v1/pin.pb.c index 8ed37f9d0..11ba4661a 100644 --- a/src/wippersnapper/pin/v1/pin.pb.c +++ b/src/wippersnapper/pin/v1/pin.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/pin/v1/pin.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/pin/v1/pin.pb.h b/src/wippersnapper/pin/v1/pin.pb.h index 14b1a99fe..28b37e0bb 100644 --- a/src/wippersnapper/pin/v1/pin.pb.h +++ b/src/wippersnapper/pin/v1/pin.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_PIN_V1_WIPPERSNAPPER_PIN_V1_PIN_PB_H_INCLUDED #define PB_WIPPERSNAPPER_PIN_V1_WIPPERSNAPPER_PIN_V1_PIN_PB_H_INCLUDED diff --git a/src/wippersnapper/pixels/v1/pixels.pb.c b/src/wippersnapper/pixels/v1/pixels.pb.c index e5bcca7f3..cc1697451 100644 --- a/src/wippersnapper/pixels/v1/pixels.pb.c +++ b/src/wippersnapper/pixels/v1/pixels.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/pixels/v1/pixels.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/pixels/v1/pixels.pb.h b/src/wippersnapper/pixels/v1/pixels.pb.h index b8a7f6813..8bb1815f4 100644 --- a/src/wippersnapper/pixels/v1/pixels.pb.h +++ b/src/wippersnapper/pixels/v1/pixels.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_PIXELS_V1_WIPPERSNAPPER_PIXELS_V1_PIXELS_PB_H_INCLUDED #define PB_WIPPERSNAPPER_PIXELS_V1_WIPPERSNAPPER_PIXELS_V1_PIXELS_PB_H_INCLUDED diff --git a/src/wippersnapper/pwm/v1/pwm.pb.c b/src/wippersnapper/pwm/v1/pwm.pb.c index 36cf1c440..2cf59f201 100644 --- a/src/wippersnapper/pwm/v1/pwm.pb.c +++ b/src/wippersnapper/pwm/v1/pwm.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/pwm/v1/pwm.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/pwm/v1/pwm.pb.h b/src/wippersnapper/pwm/v1/pwm.pb.h index d223d7a1c..12713219f 100644 --- a/src/wippersnapper/pwm/v1/pwm.pb.h +++ b/src/wippersnapper/pwm/v1/pwm.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_PWM_V1_WIPPERSNAPPER_PWM_V1_PWM_PB_H_INCLUDED #define PB_WIPPERSNAPPER_PWM_V1_WIPPERSNAPPER_PWM_V1_PWM_PB_H_INCLUDED diff --git a/src/wippersnapper/servo/v1/servo.pb.c b/src/wippersnapper/servo/v1/servo.pb.c index eb9b45e93..bc08aa6ba 100644 --- a/src/wippersnapper/servo/v1/servo.pb.c +++ b/src/wippersnapper/servo/v1/servo.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/servo/v1/servo.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/servo/v1/servo.pb.h b/src/wippersnapper/servo/v1/servo.pb.h index 61b3b809a..b9b62fe13 100644 --- a/src/wippersnapper/servo/v1/servo.pb.h +++ b/src/wippersnapper/servo/v1/servo.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_SERVO_V1_WIPPERSNAPPER_SERVO_V1_SERVO_PB_H_INCLUDED #define PB_WIPPERSNAPPER_SERVO_V1_WIPPERSNAPPER_SERVO_V1_SERVO_PB_H_INCLUDED diff --git a/src/wippersnapper/signal/v1/signal.pb.c b/src/wippersnapper/signal/v1/signal.pb.c index 0f0278ac0..67dc1ade0 100644 --- a/src/wippersnapper/signal/v1/signal.pb.c +++ b/src/wippersnapper/signal/v1/signal.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/signal/v1/signal.pb.h" #if PB_PROTO_HEADER_VERSION != 40 @@ -48,4 +48,10 @@ PB_BIND(wippersnapper_signal_v1_PWMRequest, wippersnapper_signal_v1_PWMRequest, PB_BIND(wippersnapper_signal_v1_PWMResponse, wippersnapper_signal_v1_PWMResponse, AUTO) +PB_BIND(wippersnapper_signal_v1_DisplayRequest, wippersnapper_signal_v1_DisplayRequest, 2) + + +PB_BIND(wippersnapper_signal_v1_DisplayResponse, wippersnapper_signal_v1_DisplayResponse, AUTO) + + diff --git a/src/wippersnapper/signal/v1/signal.pb.h b/src/wippersnapper/signal/v1/signal.pb.h index e459607f3..77f6843a2 100644 --- a/src/wippersnapper/signal/v1/signal.pb.h +++ b/src/wippersnapper/signal/v1/signal.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_SIGNAL_V1_WIPPERSNAPPER_SIGNAL_V1_SIGNAL_PB_H_INCLUDED #define PB_WIPPERSNAPPER_SIGNAL_V1_WIPPERSNAPPER_SIGNAL_V1_SIGNAL_PB_H_INCLUDED @@ -12,6 +12,7 @@ #include "wippersnapper/ds18x20/v1/ds18x20.pb.h" #include "wippersnapper/pixels/v1/pixels.pb.h" #include "wippersnapper/uart/v1/uart.pb.h" +#include "wippersnapper/display/v1/display.pb.h" #if PB_PROTO_HEADER_VERSION != 40 #error Regenerate this file with the current version of nanopb generator. @@ -28,6 +29,25 @@ typedef struct _wippersnapper_signal_v1_CreateSignalRequest { } payload; } wippersnapper_signal_v1_CreateSignalRequest; +typedef struct _wippersnapper_signal_v1_DisplayRequest { + pb_callback_t cb_payload; + pb_size_t which_payload; + union { + wippersnapper_display_v1_DisplayAddOrReplace display_add; + wippersnapper_display_v1_DisplayRemove display_remove; + wippersnapper_display_v1_DisplayWrite display_write; + } payload; +} wippersnapper_signal_v1_DisplayRequest; + +typedef struct _wippersnapper_signal_v1_DisplayResponse { + pb_callback_t cb_payload; + pb_size_t which_payload; + union { + wippersnapper_display_v1_DisplayAddedorReplaced display_added; + wippersnapper_display_v1_DisplayRemoved display_removed; + } payload; +} wippersnapper_signal_v1_DisplayResponse; + typedef struct _wippersnapper_signal_v1_Ds18x20Request { pb_callback_t cb_payload; pb_size_t which_payload; @@ -173,6 +193,8 @@ extern "C" { #define wippersnapper_signal_v1_SignalResponse_init_default {0, {0}} #define wippersnapper_signal_v1_PWMRequest_init_default {{{NULL}, NULL}, 0, {wippersnapper_pwm_v1_PWMAttachRequest_init_default}} #define wippersnapper_signal_v1_PWMResponse_init_default {{{NULL}, NULL}, 0, {wippersnapper_pwm_v1_PWMAttachResponse_init_default}} +#define wippersnapper_signal_v1_DisplayRequest_init_default {{{NULL}, NULL}, 0, {wippersnapper_display_v1_DisplayAddOrReplace_init_default}} +#define wippersnapper_signal_v1_DisplayResponse_init_default {{{NULL}, NULL}, 0, {wippersnapper_display_v1_DisplayAddedorReplaced_init_default}} #define wippersnapper_signal_v1_UARTRequest_init_zero {{{NULL}, NULL}, 0, {wippersnapper_uart_v1_UARTDeviceAttachRequest_init_zero}} #define wippersnapper_signal_v1_UARTResponse_init_zero {{{NULL}, NULL}, 0, {wippersnapper_uart_v1_UARTDeviceAttachResponse_init_zero}} #define wippersnapper_signal_v1_Ds18x20Request_init_zero {{{NULL}, NULL}, 0, {wippersnapper_ds18x20_v1_Ds18x20InitRequest_init_zero}} @@ -187,11 +209,18 @@ extern "C" { #define wippersnapper_signal_v1_SignalResponse_init_zero {0, {0}} #define wippersnapper_signal_v1_PWMRequest_init_zero {{{NULL}, NULL}, 0, {wippersnapper_pwm_v1_PWMAttachRequest_init_zero}} #define wippersnapper_signal_v1_PWMResponse_init_zero {{{NULL}, NULL}, 0, {wippersnapper_pwm_v1_PWMAttachResponse_init_zero}} +#define wippersnapper_signal_v1_DisplayRequest_init_zero {{{NULL}, NULL}, 0, {wippersnapper_display_v1_DisplayAddOrReplace_init_zero}} +#define wippersnapper_signal_v1_DisplayResponse_init_zero {{{NULL}, NULL}, 0, {wippersnapper_display_v1_DisplayAddedorReplaced_init_zero}} /* Field tags (for use in manual encoding/decoding) */ #define wippersnapper_signal_v1_CreateSignalRequest_pin_configs_tag 6 #define wippersnapper_signal_v1_CreateSignalRequest_pin_events_tag 7 #define wippersnapper_signal_v1_CreateSignalRequest_pin_event_tag 15 +#define wippersnapper_signal_v1_DisplayRequest_display_add_tag 1 +#define wippersnapper_signal_v1_DisplayRequest_display_remove_tag 2 +#define wippersnapper_signal_v1_DisplayRequest_display_write_tag 3 +#define wippersnapper_signal_v1_DisplayResponse_display_added_tag 1 +#define wippersnapper_signal_v1_DisplayResponse_display_removed_tag 2 #define wippersnapper_signal_v1_Ds18x20Request_req_ds18x20_init_tag 1 #define wippersnapper_signal_v1_Ds18x20Request_req_ds18x20_deinit_tag 2 #define wippersnapper_signal_v1_Ds18x20Response_resp_ds18x20_init_tag 1 @@ -360,6 +389,24 @@ X(a, STATIC, ONEOF, MSG_W_CB, (payload,attach_response,payload.attach_respo #define wippersnapper_signal_v1_PWMResponse_DEFAULT NULL #define wippersnapper_signal_v1_PWMResponse_payload_attach_response_MSGTYPE wippersnapper_pwm_v1_PWMAttachResponse +#define wippersnapper_signal_v1_DisplayRequest_FIELDLIST(X, a) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,display_add,payload.display_add), 1) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,display_remove,payload.display_remove), 2) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,display_write,payload.display_write), 3) +#define wippersnapper_signal_v1_DisplayRequest_CALLBACK NULL +#define wippersnapper_signal_v1_DisplayRequest_DEFAULT NULL +#define wippersnapper_signal_v1_DisplayRequest_payload_display_add_MSGTYPE wippersnapper_display_v1_DisplayAddOrReplace +#define wippersnapper_signal_v1_DisplayRequest_payload_display_remove_MSGTYPE wippersnapper_display_v1_DisplayRemove +#define wippersnapper_signal_v1_DisplayRequest_payload_display_write_MSGTYPE wippersnapper_display_v1_DisplayWrite + +#define wippersnapper_signal_v1_DisplayResponse_FIELDLIST(X, a) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,display_added,payload.display_added), 1) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,display_removed,payload.display_removed), 2) +#define wippersnapper_signal_v1_DisplayResponse_CALLBACK NULL +#define wippersnapper_signal_v1_DisplayResponse_DEFAULT NULL +#define wippersnapper_signal_v1_DisplayResponse_payload_display_added_MSGTYPE wippersnapper_display_v1_DisplayAddedorReplaced +#define wippersnapper_signal_v1_DisplayResponse_payload_display_removed_MSGTYPE wippersnapper_display_v1_DisplayRemoved + extern const pb_msgdesc_t wippersnapper_signal_v1_UARTRequest_msg; extern const pb_msgdesc_t wippersnapper_signal_v1_UARTResponse_msg; extern const pb_msgdesc_t wippersnapper_signal_v1_Ds18x20Request_msg; @@ -374,6 +421,8 @@ extern const pb_msgdesc_t wippersnapper_signal_v1_CreateSignalRequest_msg; extern const pb_msgdesc_t wippersnapper_signal_v1_SignalResponse_msg; extern const pb_msgdesc_t wippersnapper_signal_v1_PWMRequest_msg; extern const pb_msgdesc_t wippersnapper_signal_v1_PWMResponse_msg; +extern const pb_msgdesc_t wippersnapper_signal_v1_DisplayRequest_msg; +extern const pb_msgdesc_t wippersnapper_signal_v1_DisplayResponse_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define wippersnapper_signal_v1_UARTRequest_fields &wippersnapper_signal_v1_UARTRequest_msg @@ -390,6 +439,8 @@ extern const pb_msgdesc_t wippersnapper_signal_v1_PWMResponse_msg; #define wippersnapper_signal_v1_SignalResponse_fields &wippersnapper_signal_v1_SignalResponse_msg #define wippersnapper_signal_v1_PWMRequest_fields &wippersnapper_signal_v1_PWMRequest_msg #define wippersnapper_signal_v1_PWMResponse_fields &wippersnapper_signal_v1_PWMResponse_msg +#define wippersnapper_signal_v1_DisplayRequest_fields &wippersnapper_signal_v1_DisplayRequest_msg +#define wippersnapper_signal_v1_DisplayResponse_fields &wippersnapper_signal_v1_DisplayResponse_msg /* Maximum encoded size of messages (where known) */ #define wippersnapper_signal_v1_UARTRequest_size 58 @@ -412,6 +463,8 @@ union wippersnapper_signal_v1_CreateSignalRequest_payload_size_union {char f6[(6 #define wippersnapper_signal_v1_SignalResponse_size 2 #define wippersnapper_signal_v1_PWMRequest_size 82 #define wippersnapper_signal_v1_PWMResponse_size 11 +#define wippersnapper_signal_v1_DisplayRequest_size 1109 +#define wippersnapper_signal_v1_DisplayResponse_size 69 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/wippersnapper/uart/v1/uart.pb.c b/src/wippersnapper/uart/v1/uart.pb.c index a605be6ef..27928dd4f 100644 --- a/src/wippersnapper/uart/v1/uart.pb.c +++ b/src/wippersnapper/uart/v1/uart.pb.c @@ -1,5 +1,5 @@ /* Automatically generated nanopb constant definitions */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #include "wippersnapper/uart/v1/uart.pb.h" #if PB_PROTO_HEADER_VERSION != 40 diff --git a/src/wippersnapper/uart/v1/uart.pb.h b/src/wippersnapper/uart/v1/uart.pb.h index af9364c2a..867abee65 100644 --- a/src/wippersnapper/uart/v1/uart.pb.h +++ b/src/wippersnapper/uart/v1/uart.pb.h @@ -1,5 +1,5 @@ /* Automatically generated nanopb header */ -/* Generated by nanopb-0.4.5-dev at Fri Jun 6 19:48:16 2025. */ +/* Generated by nanopb-0.4.5-dev at Wed Aug 20 17:46:06 2025. */ #ifndef PB_WIPPERSNAPPER_UART_V1_WIPPERSNAPPER_UART_V1_UART_PB_H_INCLUDED #define PB_WIPPERSNAPPER_UART_V1_WIPPERSNAPPER_UART_V1_UART_PB_H_INCLUDED