From 66fc39df2b94fd45af00c5d122ebb62d7ae39b2e Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 6 May 2025 11:50:25 -0400 Subject: [PATCH 01/26] Add I2C_Output PB, add new outputbase driver class, add i2c output to i2c model and controller bridge --- src/components/i2c/controller.cpp | 4 + src/components/i2c/controller.h | 16 +- src/components/i2c/drivers/drvOutputBase.h | 58 ++++++ src/components/i2c/model.cpp | 86 +++++++- src/components/i2c/model.h | 29 ++- src/protos/i2c.pb.c | 3 + src/protos/i2c.pb.h | 56 ++++- src/protos/i2c_output.pb.c | 27 +++ src/protos/i2c_output.pb.h | 232 +++++++++++++++++++++ src/protos/signal.pb.h | 11 +- src/protos/uart.pb.c | 1 + src/protos/uart.pb.h | 137 ++++++++---- 12 files changed, 598 insertions(+), 62 deletions(-) create mode 100644 src/components/i2c/drivers/drvOutputBase.h create mode 100644 src/protos/i2c_output.pb.c create mode 100644 src/protos/i2c_output.pb.h diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index e14344d91..60b72534a 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -382,6 +382,7 @@ drvBase *CreateI2CDriverByName(const char *driver_name, TwoWire *i2c, I2cController::I2cController() { _i2c_bus_alt = nullptr; _i2c_model = new I2cModel(); + _i2c_output_model = new I2cOutputModel(); _i2c_bus_default = new I2cHardware(); } @@ -394,6 +395,9 @@ I2cController::~I2cController() { if (_i2c_model) delete _i2c_model; + if (_i2c_output_model) + delete _i2c_output_model; + if (_i2c_bus_default) delete _i2c_bus_default; } diff --git a/src/components/i2c/controller.h b/src/components/i2c/controller.h index cb2a9d2ab..9d355c7f6 100644 --- a/src/components/i2c/controller.h +++ b/src/components/i2c/controller.h @@ -20,7 +20,7 @@ // I2C Drivers #include "drivers/drvAdt7410.h" #include "drivers/drvAhtx0.h" -#include "drivers/drvBase.h" ///< Base driver class +#include "drivers/drvBase.h" ///< Base i2c input driver class #include "drivers/drvBh1750.h" #include "drivers/drvBme280.h" #include "drivers/drvBme680.h" @@ -45,6 +45,7 @@ #include "drivers/drvMprls.h" #include "drivers/drvMs8607.h" #include "drivers/drvNau7802.h" +#include "drivers/drvOutputBase.h" ///< Base i2c output driver class #include "drivers/drvPct2075.h" #include "drivers/drvPm25.h" #include "drivers/drvScd30.h" @@ -69,6 +70,7 @@ class Wippersnapper_V2; ///< Forward declaration class I2cModel; ///< Forward declaration +class I2cOutputModel; ///< Forward declaration class I2cHardware; ///< Forward declaration /**************************************************************************/ @@ -84,7 +86,6 @@ class I2cController { void update(); // Routing // bool Handle_I2cDeviceAddOrReplace(pb_istream_t *stream); - // TODO [Online]: These are for Online mode and not yet implemented bool Handle_I2cBusScan(pb_istream_t *stream); bool Handle_I2cDeviceRemove(pb_istream_t *stream); // Publishing // @@ -98,10 +99,13 @@ class I2cController { bool RemoveDriver(uint32_t address); private: - I2cModel *_i2c_model; ///< Pointer to an I2C model object - I2cHardware *_i2c_bus_default; ///< Pointer to the default I2C bus - I2cHardware *_i2c_bus_alt; ///< Pointer to an alternative I2C bus - std::vector _i2c_drivers; ///< Vector of ptrs to I2C device drivers + I2cModel *_i2c_model; ///< Pointer to an I2C model object + I2cOutputModel *_i2c_output_model; ///< Pointer to an I2C output model object + I2cHardware *_i2c_bus_default; ///< Pointer to the default I2C bus + I2cHardware *_i2c_bus_alt; ///< Pointer to an alternative I2C bus + std::vector _i2c_drivers; ///< Vector of ptrs to I2C input drivers + std::vector + _i2c_drivers_output; ///< Vector of ptrs to I2C output drivers }; extern Wippersnapper_V2 WsV2; ///< Wippersnapper V2 instance #endif // WS_I2C_CONTROLLER_H \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h new file mode 100644 index 000000000..f10d05b7c --- /dev/null +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -0,0 +1,58 @@ +/*! + * @file drvOutputBase.h + * + * Base implementation for I2C output device 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. + * + * MIT license, all text here must be included in any redistribution. + * + */ + +#ifndef DRV_OUTPUT_BASE_H +#define DRV_OUTPUT_BASE_H +#include "drvBase.h" + +/**************************************************************************/ +/*! + @brief Base class for I2C Output Drivers. +*/ +/**************************************************************************/ +class drvOutputBase : public drvBase { + +public: + /*******************************************************************************/ + /*! + @brief Instantiates an I2C output device. + @param i2c + The I2C hardware interface, default is Wire. + @param address + The I2C device's unique address. + @param mux_channel + An optional channel number used to address a device on a I2C + MUX. + @param driver_name + The name of the driver. + */ + /*******************************************************************************/ + drvOutputBase(TwoWire *i2c, uint16_t address, uint32_t mux_channel, + const char *driver_name) + : drvBase(i2c, address, mux_channel, driver_name) { + // TODO + } + + /*******************************************************************************/ + /*! + @brief Destructor for an I2C output device. + */ + /*******************************************************************************/ + virtual ~drvOutputBase() {} + +protected: + // TODO +}; +#endif // DRV_OUTPUT_BASE_H \ No newline at end of file diff --git a/src/components/i2c/model.cpp b/src/components/i2c/model.cpp index 200148d38..0bd6ff97b 100644 --- a/src/components/i2c/model.cpp +++ b/src/components/i2c/model.cpp @@ -1,7 +1,7 @@ /*! * @file src/components/i2c/model.cpp * - * Model for the i2c.proto message. + * Model for the i2c.proto and i2c_output.proto messages. * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing @@ -413,4 +413,86 @@ bool I2cModel::EncodeI2cDeviceEvent() { /**********************************************************************/ wippersnapper_i2c_I2cDeviceEvent *I2cModel::GetI2cDeviceEvent() { return &_msg_i2c_device_event; -} \ No newline at end of file +} + +/*! + @brief I2cOutputModel constructor +*/ +I2cOutputModel::I2cOutputModel() { + memset(&_msg_i2c_output_add, 0, sizeof(_msg_i2c_output_add)); + memset(&_msg_led_backpack_write, 0, sizeof(_msg_led_backpack_write)); + memset(&_msg_char_lcd_write, 0, sizeof(_msg_char_lcd_write)); +} + +/*! + @brief I2cOutputModel destructor +*/ +I2cOutputModel::~I2cOutputModel() { + memset(&_msg_i2c_output_add, 0, sizeof(_msg_i2c_output_add)); + memset(&_msg_led_backpack_write, 0, sizeof(_msg_led_backpack_write)); + memset(&_msg_char_lcd_write, 0, sizeof(_msg_char_lcd_write)); +} + +/*! + @brief Decodes a I2cOutputAdd message from an input stream. + @param stream + A pointer to the pb_istream_t stream. + @returns True if the I2cOutputAdd message was decoded successfully, + False otherwise. +*/ +bool I2cOutputModel::DecodeI2cOutputAdd(pb_istream_t *stream) { + memset(&_msg_i2c_output_add, 0, sizeof(_msg_i2c_output_add)); + return pb_decode(stream, wippersnapper_i2c_output_I2cOutputAdd_fields, + &_msg_i2c_output_add); +} + +/*! + @brief Decodes a LedBackpackWrite message from an input stream. + @param stream + A pointer to the pb_istream_t stream. + @returns True if the LedBackpackWrite message was decoded successfully, + False otherwise. +*/ +bool I2cOutputModel::DecodeLedBackpackWrite(pb_istream_t *stream) { + memset(&_msg_led_backpack_write, 0, sizeof(_msg_led_backpack_write)); + return pb_decode(stream, wippersnapper_i2c_output_LedBackpackWrite_fields, + &_msg_led_backpack_write); +} + +/*! + @brief Decodes a CharLCDWrite message from an input stream. + @param stream + A pointer to the pb_istream_t stream. + @returns True if the CharLCDWrite message was decoded successfully, + False otherwise. +*/ +bool I2cOutputModel::DecodeCharLCDWrite(pb_istream_t *stream) { + memset(&_msg_char_lcd_write, 0, sizeof(_msg_char_lcd_write)); + return pb_decode(stream, wippersnapper_i2c_output_CharLCDWrite_fields, + &_msg_char_lcd_write); +} + +/*! + @brief Returns a pointer to the I2cOutputAdd message. + @returns Pointer to the I2cOutputAdd message. +*/ +wippersnapper_i2c_output_I2cOutputAdd *I2cOutputModel::GetI2cOutputAddMsg() { + return &_msg_i2c_output_add; +} + +/*! + @brief Returns a pointer to the LedBackpackWrite message. + @returns Pointer to the LedBackpackWrite message. +*/ +wippersnapper_i2c_output_LedBackpackWrite * +I2cOutputModel::GetLedBackpackWriteMsg() { + return &_msg_led_backpack_write; +} + +/*! + @brief Returns a pointer to the CharLCDWrite message. + @returns Pointer to the CharLCDWrite message. +*/ +wippersnapper_i2c_output_CharLCDWrite *I2cOutputModel::GetCharLCDWriteMsg() { + return &_msg_char_lcd_write; +} diff --git a/src/components/i2c/model.h b/src/components/i2c/model.h index 328783b7f..8b2056222 100644 --- a/src/components/i2c/model.h +++ b/src/components/i2c/model.h @@ -1,7 +1,8 @@ /*! * @file src/components/i2c/model.h * - * Provides high-level interfaces for messages within i2c.proto. + * Provides high-level interfaces for messages within i2c.proto and + * i2c_output.proto. * * Adafruit invests time and resources providing this open source code, * please support Adafruit and open-source hardware by purchasing @@ -16,6 +17,7 @@ #define WS_I2C_MODEL_H #include "Wippersnapper_V2.h" #include +#include #define MAX_DEVICE_EVENTS \ 15 ///< Maximum number of SensorEvents within I2cDeviceEvent #define MAX_I2C_SCAN_DEVICES 120 ///< Maximum number of devices found on the bus @@ -71,4 +73,29 @@ class I2cModel { wippersnapper_i2c_I2cDeviceRemoved _msg_i2c_device_removed; wippersnapper_i2c_I2cDeviceEvent _msg_i2c_device_event; }; + +/**************************************************************************/ +/*! + @brief Provides an interface for creating, encoding, and parsing + messages from i2c_output.proto. +*/ +/**************************************************************************/ +class I2cOutputModel { +public: + I2cOutputModel(); + ~I2cOutputModel(); + // Decoders + bool DecodeI2cOutputAdd(pb_istream_t *stream); + bool DecodeLedBackpackWrite(pb_istream_t *stream); + bool DecodeCharLCDWrite(pb_istream_t *stream); + // Getters + wippersnapper_i2c_output_I2cOutputAdd *GetI2cOutputAddMsg(); + wippersnapper_i2c_output_LedBackpackWrite *GetLedBackpackWriteMsg(); + wippersnapper_i2c_output_CharLCDWrite *GetCharLCDWriteMsg(); + +private: + wippersnapper_i2c_output_I2cOutputAdd _msg_i2c_output_add; + wippersnapper_i2c_output_LedBackpackWrite _msg_led_backpack_write; + wippersnapper_i2c_output_CharLCDWrite _msg_char_lcd_write; +}; #endif // WS_I2C_MODEL_H \ No newline at end of file diff --git a/src/protos/i2c.pb.c b/src/protos/i2c.pb.c index 88655b887..14ee91854 100644 --- a/src/protos/i2c.pb.c +++ b/src/protos/i2c.pb.c @@ -33,6 +33,9 @@ PB_BIND(wippersnapper_i2c_I2cDeviceRemoved, wippersnapper_i2c_I2cDeviceRemoved, PB_BIND(wippersnapper_i2c_I2cDeviceEvent, wippersnapper_i2c_I2cDeviceEvent, 2) +PB_BIND(wippersnapper_i2c_I2cDeviceOutputWrite, wippersnapper_i2c_I2cDeviceOutputWrite, AUTO) + + diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index b344a0029..96a1b9111 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -4,6 +4,7 @@ #ifndef PB_WIPPERSNAPPER_I2C_I2C_PB_H_INCLUDED #define PB_WIPPERSNAPPER_I2C_I2C_PB_H_INCLUDED #include +#include "i2c_output.pb.h" #include "sensor.pb.h" #if PB_PROTO_HEADER_VERSION != 40 @@ -81,6 +82,10 @@ typedef struct _wippersnapper_i2c_I2cDeviceAddOrReplace { float i2c_device_period; /* * The desired period to update the I2c device's sensor(s), in seconds. */ pb_size_t i2c_device_sensor_types_count; wippersnapper_sensor_SensorType i2c_device_sensor_types[15]; /* * SI Types for each sensor on the I2c device. */ + bool is_persistent; /* * Offline-Mode ONLY - True if the device exits in the config file, False otherwise. * */ + bool is_output; /* * Required by the device to determine if the device is an output device.* */ + bool has_i2c_output_add; + wippersnapper_i2c_output_I2cOutputAdd i2c_output_add; /* * Optional - If the I2C device is an output device, fill this field. * */ } wippersnapper_i2c_I2cDeviceAddOrReplace; /* * @@ -115,9 +120,20 @@ typedef struct _wippersnapper_i2c_I2cDeviceEvent { bool has_i2c_device_description; wippersnapper_i2c_I2cDeviceDescriptor i2c_device_description; /* * The I2c device's address and metadata. */ pb_size_t i2c_device_events_count; - wippersnapper_sensor_SensorEvent i2c_device_events[15]; /* * A, optionally repeated, SensorEvent from a sensor. */ + wippersnapper_sensor_SensorEvent i2c_device_events[15]; /* * Required, but optionally repeated, SensorEvent from a sensor. */ } wippersnapper_i2c_I2cDeviceEvent; +/* * + I2cDeviceOutputWrite represents a request to write to an I2C output device. */ +typedef struct _wippersnapper_i2c_I2cDeviceOutputWrite { + bool has_i2c_device_description; + wippersnapper_i2c_I2cDeviceDescriptor i2c_device_description; /* * Required - The I2c device's address and metadata. */ + bool has_led_backpack_write; + wippersnapper_i2c_output_LedBackpackWrite led_backpack_write; /* * Optional - If the I2C device is a LED backpack, fill this field. * */ + bool has_char_lcd_write; + wippersnapper_i2c_output_CharLCDWrite char_lcd_write; /* * Optional - If the I2C device is a character LCD, fill this field. * */ +} wippersnapper_i2c_I2cDeviceOutputWrite; + #ifdef __cplusplus extern "C" { @@ -146,25 +162,28 @@ extern "C" { + /* Initializer values for message structs */ #define wippersnapper_i2c_I2cDeviceDescriptor_init_default {"", "", 0, 0, 0} #define wippersnapper_i2c_I2cBusDescriptor_init_default {"", ""} #define wippersnapper_i2c_I2cBusScan_init_default {0, 0, false, wippersnapper_i2c_I2cBusDescriptor_init_default, 0, 0} #define wippersnapper_i2c_I2cBusScanned_init_default {0, {wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default}, _wippersnapper_i2c_I2cBusStatus_MIN} -#define wippersnapper_i2c_I2cDeviceAddOrReplace_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, "", 0, 0, {_wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN}} +#define wippersnapper_i2c_I2cDeviceAddOrReplace_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, "", 0, 0, {_wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN}, 0, 0, false, wippersnapper_i2c_output_I2cOutputAdd_init_default} #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, _wippersnapper_i2c_I2cBusStatus_MIN, _wippersnapper_i2c_I2cDeviceStatus_MIN} #define wippersnapper_i2c_I2cDeviceRemove_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default} #define wippersnapper_i2c_I2cDeviceRemoved_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0} #define wippersnapper_i2c_I2cDeviceEvent_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0, {wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default}} +#define wippersnapper_i2c_I2cDeviceOutputWrite_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, false, wippersnapper_i2c_output_LedBackpackWrite_init_default, false, wippersnapper_i2c_output_CharLCDWrite_init_default} #define wippersnapper_i2c_I2cDeviceDescriptor_init_zero {"", "", 0, 0, 0} #define wippersnapper_i2c_I2cBusDescriptor_init_zero {"", ""} #define wippersnapper_i2c_I2cBusScan_init_zero {0, 0, false, wippersnapper_i2c_I2cBusDescriptor_init_zero, 0, 0} #define wippersnapper_i2c_I2cBusScanned_init_zero {0, {wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero}, _wippersnapper_i2c_I2cBusStatus_MIN} -#define wippersnapper_i2c_I2cDeviceAddOrReplace_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, "", 0, 0, {_wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN}} +#define wippersnapper_i2c_I2cDeviceAddOrReplace_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, "", 0, 0, {_wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN}, 0, 0, false, wippersnapper_i2c_output_I2cOutputAdd_init_zero} #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, _wippersnapper_i2c_I2cBusStatus_MIN, _wippersnapper_i2c_I2cDeviceStatus_MIN} #define wippersnapper_i2c_I2cDeviceRemove_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero} #define wippersnapper_i2c_I2cDeviceRemoved_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0} #define wippersnapper_i2c_I2cDeviceEvent_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0, {wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero}} +#define wippersnapper_i2c_I2cDeviceOutputWrite_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, false, wippersnapper_i2c_output_LedBackpackWrite_init_zero, false, wippersnapper_i2c_output_CharLCDWrite_init_zero} /* Field tags (for use in manual encoding/decoding) */ #define wippersnapper_i2c_I2cDeviceDescriptor_i2c_bus_sda_tag 1 @@ -185,6 +204,9 @@ extern "C" { #define wippersnapper_i2c_I2cDeviceAddOrReplace_i2c_device_name_tag 2 #define wippersnapper_i2c_I2cDeviceAddOrReplace_i2c_device_period_tag 3 #define wippersnapper_i2c_I2cDeviceAddOrReplace_i2c_device_sensor_types_tag 4 +#define wippersnapper_i2c_I2cDeviceAddOrReplace_is_persistent_tag 5 +#define wippersnapper_i2c_I2cDeviceAddOrReplace_is_output_tag 6 +#define wippersnapper_i2c_I2cDeviceAddOrReplace_i2c_output_add_tag 7 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_i2c_device_description_tag 1 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_i2c_bus_status_tag 2 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_i2c_device_status_tag 3 @@ -193,6 +215,9 @@ extern "C" { #define wippersnapper_i2c_I2cDeviceRemoved_did_remove_tag 2 #define wippersnapper_i2c_I2cDeviceEvent_i2c_device_description_tag 1 #define wippersnapper_i2c_I2cDeviceEvent_i2c_device_events_tag 2 +#define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_tag 1 +#define wippersnapper_i2c_I2cDeviceOutputWrite_led_backpack_write_tag 2 +#define wippersnapper_i2c_I2cDeviceOutputWrite_char_lcd_write_tag 3 /* Struct field encoding specification for nanopb */ #define wippersnapper_i2c_I2cDeviceDescriptor_FIELDLIST(X, a) \ @@ -231,10 +256,14 @@ X(a, STATIC, SINGULAR, UENUM, i2c_bus_status, 2) X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) \ X(a, STATIC, SINGULAR, STRING, i2c_device_name, 2) \ X(a, STATIC, SINGULAR, FLOAT, i2c_device_period, 3) \ -X(a, STATIC, REPEATED, UENUM, i2c_device_sensor_types, 4) +X(a, STATIC, REPEATED, UENUM, i2c_device_sensor_types, 4) \ +X(a, STATIC, SINGULAR, BOOL, is_persistent, 5) \ +X(a, STATIC, SINGULAR, BOOL, is_output, 6) \ +X(a, STATIC, OPTIONAL, MESSAGE, i2c_output_add, 7) #define wippersnapper_i2c_I2cDeviceAddOrReplace_CALLBACK NULL #define wippersnapper_i2c_I2cDeviceAddOrReplace_DEFAULT NULL #define wippersnapper_i2c_I2cDeviceAddOrReplace_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor +#define wippersnapper_i2c_I2cDeviceAddOrReplace_i2c_output_add_MSGTYPE wippersnapper_i2c_output_I2cOutputAdd #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_FIELDLIST(X, a) \ X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) \ @@ -265,6 +294,16 @@ X(a, STATIC, REPEATED, MESSAGE, i2c_device_events, 2) #define wippersnapper_i2c_I2cDeviceEvent_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor #define wippersnapper_i2c_I2cDeviceEvent_i2c_device_events_MSGTYPE wippersnapper_sensor_SensorEvent +#define wippersnapper_i2c_I2cDeviceOutputWrite_FIELDLIST(X, a) \ +X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) \ +X(a, STATIC, OPTIONAL, MESSAGE, led_backpack_write, 2) \ +X(a, STATIC, OPTIONAL, MESSAGE, char_lcd_write, 3) +#define wippersnapper_i2c_I2cDeviceOutputWrite_CALLBACK NULL +#define wippersnapper_i2c_I2cDeviceOutputWrite_DEFAULT NULL +#define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor +#define wippersnapper_i2c_I2cDeviceOutputWrite_led_backpack_write_MSGTYPE wippersnapper_i2c_output_LedBackpackWrite +#define wippersnapper_i2c_I2cDeviceOutputWrite_char_lcd_write_MSGTYPE wippersnapper_i2c_output_CharLCDWrite + extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceDescriptor_msg; extern const pb_msgdesc_t wippersnapper_i2c_I2cBusDescriptor_msg; extern const pb_msgdesc_t wippersnapper_i2c_I2cBusScan_msg; @@ -274,6 +313,7 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceAddedOrReplaced_msg; extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceRemove_msg; extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceRemoved_msg; extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceEvent_msg; +extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define wippersnapper_i2c_I2cDeviceDescriptor_fields &wippersnapper_i2c_I2cDeviceDescriptor_msg @@ -285,20 +325,26 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceEvent_msg; #define wippersnapper_i2c_I2cDeviceRemove_fields &wippersnapper_i2c_I2cDeviceRemove_msg #define wippersnapper_i2c_I2cDeviceRemoved_fields &wippersnapper_i2c_I2cDeviceRemoved_msg #define wippersnapper_i2c_I2cDeviceEvent_fields &wippersnapper_i2c_I2cDeviceEvent_msg +#define wippersnapper_i2c_I2cDeviceOutputWrite_fields &wippersnapper_i2c_I2cDeviceOutputWrite_msg /* Maximum encoded size of messages (where known) */ #define WIPPERSNAPPER_I2C_I2C_PB_H_MAX_SIZE wippersnapper_i2c_I2cBusScanned_size #define wippersnapper_i2c_I2cBusDescriptor_size 32 #define wippersnapper_i2c_I2cBusScan_size 42 #define wippersnapper_i2c_I2cBusScanned_size 6242 -#define wippersnapper_i2c_I2cDeviceAddOrReplace_size 103 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 #define wippersnapper_i2c_I2cDeviceRemove_size 52 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 +#if defined(wippersnapper_i2c_output_I2cOutputAdd_size) +#define wippersnapper_i2c_I2cDeviceAddOrReplace_size (113 + wippersnapper_i2c_output_I2cOutputAdd_size) +#endif #if defined(wippersnapper_sensor_SensorEvent_size) #define wippersnapper_i2c_I2cDeviceEvent_size (142 + 15*wippersnapper_sensor_SensorEvent_size) #endif +#if defined(wippersnapper_i2c_output_LedBackpackWrite_size) && defined(wippersnapper_i2c_output_CharLCDWrite_size) +#define wippersnapper_i2c_I2cDeviceOutputWrite_size (64 + wippersnapper_i2c_output_LedBackpackWrite_size + wippersnapper_i2c_output_CharLCDWrite_size) +#endif #ifdef __cplusplus } /* extern "C" */ diff --git a/src/protos/i2c_output.pb.c b/src/protos/i2c_output.pb.c new file mode 100644 index 000000000..c7ec07df2 --- /dev/null +++ b/src/protos/i2c_output.pb.c @@ -0,0 +1,27 @@ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.4.8 */ + +#include "i2c_output.pb.h" +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +PB_BIND(wippersnapper_i2c_output_LedBackpackConfig, wippersnapper_i2c_output_LedBackpackConfig, AUTO) + + +PB_BIND(wippersnapper_i2c_output_CharLCDConfig, wippersnapper_i2c_output_CharLCDConfig, AUTO) + + +PB_BIND(wippersnapper_i2c_output_I2cOutputAdd, wippersnapper_i2c_output_I2cOutputAdd, AUTO) + + +PB_BIND(wippersnapper_i2c_output_LedBackpackWrite, wippersnapper_i2c_output_LedBackpackWrite, AUTO) + + +PB_BIND(wippersnapper_i2c_output_CharLCDWrite, wippersnapper_i2c_output_CharLCDWrite, AUTO) + + + + + + diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h new file mode 100644 index 000000000..0071d9163 --- /dev/null +++ b/src/protos/i2c_output.pb.h @@ -0,0 +1,232 @@ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.4.8 */ + +#ifndef PB_WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_INCLUDED +#define PB_WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_INCLUDED +#include + +#if PB_PROTO_HEADER_VERSION != 40 +#error Regenerate this file with the current version of nanopb generator. +#endif + +/* Enum definitions */ +/* * + I2cOutputType defines the category of I2C output device. */ +typedef enum _wippersnapper_i2c_output_I2cOutputType { + wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_UNSPECIFIED = 0, /* * Unspecified output type. * */ + wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_LED_BACKPACK = 1, /* * LED backpack output type. * */ + wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_CHAR_LCD = 2 /* * Character LCD output type. * */ +} wippersnapper_i2c_output_I2cOutputType; + +/* * + LedBackpackBlinkRate represents supported, OPTIONAL, blink rates for LED backpack displays */ +typedef enum _wippersnapper_i2c_output_LedBackpackBlinkRate { + wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_UNSPECIFIED = 0, /* * No blinking. * */ + wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_OFF = 1, /* * No blinking. * */ + wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_2HZ = 2, /* * 2 Hz blink rate. * */ + wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_1HZ = 3, /* * 1 Hz blink rate. * */ + wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ = 4 /* * 0.5 Hz blink rate. * */ +} wippersnapper_i2c_output_LedBackpackBlinkRate; + +/* * + LedBackpackAlignment represents all text alignment option for LED backpack displays */ +typedef enum _wippersnapper_i2c_output_LedBackpackAlignment { + wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_UNSPECIFIED = 0, /* * Unspecified alignment option. * */ + wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_LEFT = 1, /* * (Default) Left-aligned. * */ + wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_RIGHT = 2 /* * Right-aligned. * */ +} wippersnapper_i2c_output_LedBackpackAlignment; + +/* Struct definitions */ +/* * + LedBackpackConfig represents the configuration for a LED backpack display. */ +typedef struct _wippersnapper_i2c_output_LedBackpackConfig { + int32_t brightness; /* * Desired brightness of the LED backpack, from 0 (off) to 15 (full brightness). * */ + wippersnapper_i2c_output_LedBackpackAlignment alignment; /* * Desired text alignment for the LED backpack. * */ +} wippersnapper_i2c_output_LedBackpackConfig; + +/* * + CharLCDConfig represents the configuration for a character LCD display. */ +typedef struct _wippersnapper_i2c_output_CharLCDConfig { + uint32_t rows; /* * Number of rows for the character LCD. * */ + uint32_t columns; /* * Number of columns for the character LCD. * */ + bool backlight_enable; /* * Backlight state for the character LCD. * */ + pb_callback_t backlight_color; /* * Backlight color for the character LCD, in Hex. * */ +} wippersnapper_i2c_output_CharLCDConfig; + +/* * + I2cOutputAdd represents a request from the broker to add an I2C output device to a device. */ +typedef struct _wippersnapper_i2c_output_I2cOutputAdd { + wippersnapper_i2c_output_I2cOutputType type; /* * The type of I2C output device. * */ + pb_size_t which_config; + union { + wippersnapper_i2c_output_LedBackpackConfig led_backpack_config; /* * Configuration for LED backpack. * */ + wippersnapper_i2c_output_CharLCDConfig char_lcd_config; /* * Configuration for character LCD. * */ + } config; +} wippersnapper_i2c_output_I2cOutputAdd; + +/* * + LedBackpackWrite represents a request from the broker to write a message to a LED backpack. */ +typedef struct _wippersnapper_i2c_output_LedBackpackWrite { + pb_size_t which_message; + union { + pb_callback_t text; /* * Text to write to the LED backpack. * */ + int32_t number_int; /* * Number to write to the LED backpack. * */ + float number_float; /* * Float to write to the LED backpack. * */ + } message; + int32_t brightness; /* * Optionally adjusts the brightness from 0 (off) to 15 (full brightness). * */ + wippersnapper_i2c_output_LedBackpackBlinkRate blink_rate; /* * Optionally sets the blink rate for the LED backpack. * */ + bool enable_scroll_marquee; /* * Optionally enables automatic text scrolling * */ + float scroll_marquee_speed; /* * Speed for the scrolling marquee. * */ + bool enable_ampm_dot; /* * Enable AM/PM dot. * */ +} wippersnapper_i2c_output_LedBackpackWrite; + +/* * + CharLCDWrite represents a request from the broker to write to a character LCD. */ +typedef struct _wippersnapper_i2c_output_CharLCDWrite { + pb_size_t which_message; + union { + pb_callback_t text; /* * Text to write to the character LCD. * */ + int32_t number_int; /* * Number to write to the character LCD. * */ + float number_float; /* * Float to write to the character LCD. * */ + } message; + bool enable_backlight; /* * Enable backlight for the character LCD. * */ + pb_callback_t backlight_color; /* * Backlight color for the character LCD, in Hex. * */ + bool enable_scroll; /* * Enable automatic scrolling for the character LCD. * */ +} wippersnapper_i2c_output_CharLCDWrite; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Helper constants for enums */ +#define _wippersnapper_i2c_output_I2cOutputType_MIN wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_UNSPECIFIED +#define _wippersnapper_i2c_output_I2cOutputType_MAX wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_CHAR_LCD +#define _wippersnapper_i2c_output_I2cOutputType_ARRAYSIZE ((wippersnapper_i2c_output_I2cOutputType)(wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_CHAR_LCD+1)) + +#define _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_UNSPECIFIED +#define _wippersnapper_i2c_output_LedBackpackBlinkRate_MAX wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ +#define _wippersnapper_i2c_output_LedBackpackBlinkRate_ARRAYSIZE ((wippersnapper_i2c_output_LedBackpackBlinkRate)(wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ+1)) + +#define _wippersnapper_i2c_output_LedBackpackAlignment_MIN wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_UNSPECIFIED +#define _wippersnapper_i2c_output_LedBackpackAlignment_MAX wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_RIGHT +#define _wippersnapper_i2c_output_LedBackpackAlignment_ARRAYSIZE ((wippersnapper_i2c_output_LedBackpackAlignment)(wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_RIGHT+1)) + +#define wippersnapper_i2c_output_LedBackpackConfig_alignment_ENUMTYPE wippersnapper_i2c_output_LedBackpackAlignment + + +#define wippersnapper_i2c_output_I2cOutputAdd_type_ENUMTYPE wippersnapper_i2c_output_I2cOutputType + +#define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_ENUMTYPE wippersnapper_i2c_output_LedBackpackBlinkRate + + + +/* Initializer values for message structs */ +#define wippersnapper_i2c_output_LedBackpackConfig_init_default {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} +#define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, 0, {{NULL}, NULL}} +#define wippersnapper_i2c_output_I2cOutputAdd_init_default {_wippersnapper_i2c_output_I2cOutputType_MIN, 0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} +#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {{{NULL}, NULL}}, 0, {{NULL}, NULL}, 0} +#define wippersnapper_i2c_output_LedBackpackConfig_init_zero {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} +#define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, 0, {{NULL}, NULL}} +#define wippersnapper_i2c_output_I2cOutputAdd_init_zero {_wippersnapper_i2c_output_I2cOutputType_MIN, 0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} +#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {{{NULL}, NULL}}, 0, {{NULL}, NULL}, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define wippersnapper_i2c_output_LedBackpackConfig_brightness_tag 1 +#define wippersnapper_i2c_output_LedBackpackConfig_alignment_tag 2 +#define wippersnapper_i2c_output_CharLCDConfig_rows_tag 1 +#define wippersnapper_i2c_output_CharLCDConfig_columns_tag 2 +#define wippersnapper_i2c_output_CharLCDConfig_backlight_enable_tag 3 +#define wippersnapper_i2c_output_CharLCDConfig_backlight_color_tag 4 +#define wippersnapper_i2c_output_I2cOutputAdd_type_tag 1 +#define wippersnapper_i2c_output_I2cOutputAdd_led_backpack_config_tag 2 +#define wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag 3 +#define wippersnapper_i2c_output_LedBackpackWrite_text_tag 1 +#define wippersnapper_i2c_output_LedBackpackWrite_number_int_tag 2 +#define wippersnapper_i2c_output_LedBackpackWrite_number_float_tag 3 +#define wippersnapper_i2c_output_LedBackpackWrite_brightness_tag 4 +#define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_tag 5 +#define wippersnapper_i2c_output_LedBackpackWrite_enable_scroll_marquee_tag 6 +#define wippersnapper_i2c_output_LedBackpackWrite_scroll_marquee_speed_tag 7 +#define wippersnapper_i2c_output_LedBackpackWrite_enable_ampm_dot_tag 8 +#define wippersnapper_i2c_output_CharLCDWrite_text_tag 1 +#define wippersnapper_i2c_output_CharLCDWrite_number_int_tag 2 +#define wippersnapper_i2c_output_CharLCDWrite_number_float_tag 3 +#define wippersnapper_i2c_output_CharLCDWrite_enable_backlight_tag 4 +#define wippersnapper_i2c_output_CharLCDWrite_backlight_color_tag 5 +#define wippersnapper_i2c_output_CharLCDWrite_enable_scroll_tag 6 + +/* Struct field encoding specification for nanopb */ +#define wippersnapper_i2c_output_LedBackpackConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, INT32, brightness, 1) \ +X(a, STATIC, SINGULAR, UENUM, alignment, 2) +#define wippersnapper_i2c_output_LedBackpackConfig_CALLBACK NULL +#define wippersnapper_i2c_output_LedBackpackConfig_DEFAULT NULL + +#define wippersnapper_i2c_output_CharLCDConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, rows, 1) \ +X(a, STATIC, SINGULAR, UINT32, columns, 2) \ +X(a, STATIC, SINGULAR, BOOL, backlight_enable, 3) \ +X(a, CALLBACK, SINGULAR, STRING, backlight_color, 4) +#define wippersnapper_i2c_output_CharLCDConfig_CALLBACK pb_default_field_callback +#define wippersnapper_i2c_output_CharLCDConfig_DEFAULT NULL + +#define wippersnapper_i2c_output_I2cOutputAdd_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UENUM, type, 1) \ +X(a, STATIC, ONEOF, MESSAGE, (config,led_backpack_config,config.led_backpack_config), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (config,char_lcd_config,config.char_lcd_config), 3) +#define wippersnapper_i2c_output_I2cOutputAdd_CALLBACK NULL +#define wippersnapper_i2c_output_I2cOutputAdd_DEFAULT NULL +#define wippersnapper_i2c_output_I2cOutputAdd_config_led_backpack_config_MSGTYPE wippersnapper_i2c_output_LedBackpackConfig +#define wippersnapper_i2c_output_I2cOutputAdd_config_char_lcd_config_MSGTYPE wippersnapper_i2c_output_CharLCDConfig + +#define wippersnapper_i2c_output_LedBackpackWrite_FIELDLIST(X, a) \ +X(a, CALLBACK, ONEOF, STRING, (message,text,message.text), 1) \ +X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ +X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ +X(a, STATIC, SINGULAR, INT32, brightness, 4) \ +X(a, STATIC, SINGULAR, UENUM, blink_rate, 5) \ +X(a, STATIC, SINGULAR, BOOL, enable_scroll_marquee, 6) \ +X(a, STATIC, SINGULAR, FLOAT, scroll_marquee_speed, 7) \ +X(a, STATIC, SINGULAR, BOOL, enable_ampm_dot, 8) +#define wippersnapper_i2c_output_LedBackpackWrite_CALLBACK pb_default_field_callback +#define wippersnapper_i2c_output_LedBackpackWrite_DEFAULT NULL + +#define wippersnapper_i2c_output_CharLCDWrite_FIELDLIST(X, a) \ +X(a, CALLBACK, ONEOF, STRING, (message,text,message.text), 1) \ +X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ +X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ +X(a, STATIC, SINGULAR, BOOL, enable_backlight, 4) \ +X(a, CALLBACK, SINGULAR, STRING, backlight_color, 5) \ +X(a, STATIC, SINGULAR, BOOL, enable_scroll, 6) +#define wippersnapper_i2c_output_CharLCDWrite_CALLBACK pb_default_field_callback +#define wippersnapper_i2c_output_CharLCDWrite_DEFAULT NULL + +extern const pb_msgdesc_t wippersnapper_i2c_output_LedBackpackConfig_msg; +extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDConfig_msg; +extern const pb_msgdesc_t wippersnapper_i2c_output_I2cOutputAdd_msg; +extern const pb_msgdesc_t wippersnapper_i2c_output_LedBackpackWrite_msg; +extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDWrite_msg; + +/* Defines for backwards compatibility with code written before nanopb-0.4.0 */ +#define wippersnapper_i2c_output_LedBackpackConfig_fields &wippersnapper_i2c_output_LedBackpackConfig_msg +#define wippersnapper_i2c_output_CharLCDConfig_fields &wippersnapper_i2c_output_CharLCDConfig_msg +#define wippersnapper_i2c_output_I2cOutputAdd_fields &wippersnapper_i2c_output_I2cOutputAdd_msg +#define wippersnapper_i2c_output_LedBackpackWrite_fields &wippersnapper_i2c_output_LedBackpackWrite_msg +#define wippersnapper_i2c_output_CharLCDWrite_fields &wippersnapper_i2c_output_CharLCDWrite_msg + +/* Maximum encoded size of messages (where known) */ +/* wippersnapper_i2c_output_CharLCDConfig_size depends on runtime parameters */ +/* wippersnapper_i2c_output_I2cOutputAdd_size depends on runtime parameters */ +/* wippersnapper_i2c_output_LedBackpackWrite_size depends on runtime parameters */ +/* wippersnapper_i2c_output_CharLCDWrite_size depends on runtime parameters */ +#define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_LedBackpackConfig_size +#define wippersnapper_i2c_output_LedBackpackConfig_size 13 + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index 3262a6c05..6b28ca32b 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -10,6 +10,7 @@ #include "ds18x20.pb.h" #include "error.pb.h" #include "i2c.pb.h" +#include "i2c_output.pb.h" #include "pixels.pb.h" #include "pwm.pb.h" #include "servo.pb.h" @@ -62,6 +63,7 @@ typedef struct _wippersnapper_signal_BrokerToDevice { wippersnapper_i2c_I2cBusScan i2c_bus_scan; wippersnapper_i2c_I2cDeviceAddOrReplace i2c_device_add_replace; wippersnapper_i2c_I2cDeviceRemove i2c_device_remove; + wippersnapper_i2c_I2cDeviceOutputWrite i2c_device_output_write; /* error.proto */ wippersnapper_error_Error error; } payload; @@ -138,6 +140,7 @@ extern "C" { #define wippersnapper_signal_BrokerToDevice_i2c_bus_scan_tag 90 #define wippersnapper_signal_BrokerToDevice_i2c_device_add_replace_tag 91 #define wippersnapper_signal_BrokerToDevice_i2c_device_remove_tag 92 +#define wippersnapper_signal_BrokerToDevice_i2c_device_output_write_tag 93 #define wippersnapper_signal_BrokerToDevice_error_tag 100 #define wippersnapper_signal_DeviceToBroker_digitalio_event_tag 10 #define wippersnapper_signal_DeviceToBroker_analogio_event_tag 20 @@ -181,6 +184,7 @@ X(a, STATIC, ONEOF, MSG_W_CB, (payload,uart_remove,payload.uart_remove), 8 X(a, STATIC, ONEOF, MSG_W_CB, (payload,i2c_bus_scan,payload.i2c_bus_scan), 90) \ X(a, STATIC, ONEOF, MSG_W_CB, (payload,i2c_device_add_replace,payload.i2c_device_add_replace), 91) \ X(a, STATIC, ONEOF, MSG_W_CB, (payload,i2c_device_remove,payload.i2c_device_remove), 92) \ +X(a, STATIC, ONEOF, MSG_W_CB, (payload,i2c_device_output_write,payload.i2c_device_output_write), 93) \ X(a, STATIC, ONEOF, MSG_W_CB, (payload,error,payload.error), 100) #define wippersnapper_signal_BrokerToDevice_CALLBACK NULL #define wippersnapper_signal_BrokerToDevice_DEFAULT NULL @@ -209,6 +213,7 @@ X(a, STATIC, ONEOF, MSG_W_CB, (payload,error,payload.error), 100) #define wippersnapper_signal_BrokerToDevice_payload_i2c_bus_scan_MSGTYPE wippersnapper_i2c_I2cBusScan #define wippersnapper_signal_BrokerToDevice_payload_i2c_device_add_replace_MSGTYPE wippersnapper_i2c_I2cDeviceAddOrReplace #define wippersnapper_signal_BrokerToDevice_payload_i2c_device_remove_MSGTYPE wippersnapper_i2c_I2cDeviceRemove +#define wippersnapper_signal_BrokerToDevice_payload_i2c_device_output_write_MSGTYPE wippersnapper_i2c_I2cDeviceOutputWrite #define wippersnapper_signal_BrokerToDevice_payload_error_MSGTYPE wippersnapper_error_Error #define wippersnapper_signal_DeviceToBroker_FIELDLIST(X, a) \ @@ -251,13 +256,13 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; #define wippersnapper_signal_DeviceToBroker_fields &wippersnapper_signal_DeviceToBroker_msg /* Maximum encoded size of messages (where known) */ -#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[106];}; +#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceAddOrReplace_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f91[(7 + wippersnapper_i2c_I2cDeviceAddOrReplace_size)]; char f93[(7 + wippersnapper_i2c_I2cDeviceOutputWrite_size)]; char f0[83];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; #endif -#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) +#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceAddOrReplace_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) #define WIPPERSNAPPER_SIGNAL_SIGNAL_PB_H_MAX_SIZE wippersnapper_signal_BrokerToDevice_size #define wippersnapper_signal_BrokerToDevice_size (0 + sizeof(union wippersnapper_signal_BrokerToDevice_payload_size_union)) #endif diff --git a/src/protos/uart.pb.c b/src/protos/uart.pb.c index 827e9c1d6..435d0c1f2 100644 --- a/src/protos/uart.pb.c +++ b/src/protos/uart.pb.c @@ -22,3 +22,4 @@ PB_BIND(wippersnapper_uart_UARTEvent, wippersnapper_uart_UARTEvent, AUTO) + diff --git a/src/protos/uart.pb.h b/src/protos/uart.pb.h index 6c4e07eaa..e8ec44f22 100644 --- a/src/protos/uart.pb.h +++ b/src/protos/uart.pb.h @@ -10,46 +10,78 @@ #error Regenerate this file with the current version of nanopb generator. #endif +/* Enum definitions */ +/* * + SerialConfig contains the configuration (data, parity, and stop bits) for a serial bus. */ +typedef enum _wippersnapper_uart_SerialConfig { + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_UNSPECIFIED = 0, /* Config was not specified by IO. */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8N1 = 1, /* 8 data bits, no parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_5N1 = 2, /* 5 data bits, no parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_6N1 = 3, /* 6 data bits, no parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_7N1 = 4, /* 7 data bits, no parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_5N2 = 5, /* 5 data bits, no parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_6N2 = 6, /* 6 data bits, no parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_7N2 = 7, /* 7 data bits, no parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8N2 = 8, /* 8 data bits, no parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_5E1 = 9, /* 5 data bits, even parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_6E1 = 10, /* 6 data bits, even parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_7E1 = 11, /* 7 data bits, even parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8E1 = 12, /* 8 data bits, even parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_5E2 = 13, /* 5 data bits, even parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_6E2 = 14, /* 6 data bits, even parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_7E2 = 15, /* 7 data bits, even parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8E2 = 16, /* 8 data bits, even parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_5O1 = 17, /* 5 data bits, odd parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_6O1 = 18, /* 6 data bits, odd parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_7O1 = 19, /* 7 data bits, odd parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8O1 = 20, /* 8 data bits, odd parity, 1 stop bit */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_5O2 = 21, /* 5 data bits, odd parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_6O2 = 22, /* 6 data bits, odd parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_7O2 = 23, /* 7 data bits, odd parity, 2 stop bits */ + wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8O2 = 24 /* 8 data bits, odd parity, 2 stop bits */ +} wippersnapper_uart_SerialConfig; + /* Struct definitions */ /* * UARTBusData represents a message to configure a UART bus for communication with a device. NOTE: This message is never sent directly, it is packed inside UARTAdd. */ typedef struct _wippersnapper_uart_UARTBusData { - int32_t baudrate; /* * The baudrate to use for UART communication (may be a common baud rate such as: -1200bps, 2400bps, 4800bps, 19200bps, 38400bps, 57600bps, or 115200bps). */ - char pin_rx[6]; /* * The pin on which to receive UART stream data. */ - char pin_tx[6]; /* * The pin on which to transmit UART stream data. */ - bool is_invert; /* * Inverts the UART signal on RX and TX pins. Defaults to False. */ + pb_callback_t bus_id; /* * The ID of the Serial bus (i.e: Serial, Serial1, "SoftwareSerial"). */ + uint32_t baud_rate; /* * The desired baudrate, in bits per second. */ + wippersnapper_uart_SerialConfig config; /* * Configures the data, parity, and stop bits. */ + pb_callback_t rx_pin; /* * Optional: The pin on which to receive on. */ + pb_callback_t tx_pin; /* * Optional: The pin on which to transmit with. */ + bool invert; /* * Optional: Inverts the UART signal on RX and TX pins. Defaults to False. */ + float timeout; /* * Optional: The timeout, in milliseconds, for the UART bus. */ } wippersnapper_uart_UARTBusData; /* * UARTAdd represents a message sent from IO to a device - to configure the UART bus (if not already configured) and attach a device. */ + to configure a UART bus for communication with a driver. */ typedef struct _wippersnapper_uart_UARTAdd { - bool has_bus_info; - wippersnapper_uart_UARTBusData bus_info; /* * The UART bus configuration. */ - pb_callback_t device_id; /* * The unique identifier of the device to attach to the UART bus, from Adafruit_WipperSnapper_Components. */ - int32_t polling_interval; /* * The polling interval, in milliseconds, to use for the device. */ + bool has_config; + wippersnapper_uart_UARTBusData config; /* * The UART bus configuration. */ + pb_callback_t driver; /* * The unique identifier of the UART driver. */ } wippersnapper_uart_UARTAdd; /* * UARTAdded represents a message sent from a device to IO to confirm that a device has been attached to the UART bus. */ typedef struct _wippersnapper_uart_UARTAdded { - pb_callback_t device_id; /* * The unique identifier of the device to attach to the UART bus, from Adafruit_WipperSnapper_Components. */ - bool is_success; /* * True if the UARTInit was successful, False otherwise. */ + pb_callback_t driver; /* * The unique identifier of the UART driver. */ + bool success; /* * True if the UART bus was successfully initialized, False otherwise. */ } wippersnapper_uart_UARTAdded; /* UARTRemove represents a message sent from IO to a device - to detach a device from the UART bus. */ + to detach a driver from the UART bus and deinitialize the bus. */ typedef struct _wippersnapper_uart_UARTRemove { - pb_callback_t device_id; /* * The unique identifier of the device to detach from the UART bus. */ + pb_callback_t driver; /* * The unique identifier of the UART driver. */ } wippersnapper_uart_UARTRemove; /* * UARTEvent represents incoming data from a UART sensor. */ typedef struct _wippersnapper_uart_UARTEvent { - pb_callback_t device_id; /* * Unique identifier of the device to attach to the UART bus, from Adafruit_WipperSnapper_Components. */ + pb_callback_t driver; /* * The unique identifier of the UART driver. */ pb_callback_t sensor_events; /* * An optionally repeated event from a sensor. */ } wippersnapper_uart_UARTEvent; @@ -58,62 +90,78 @@ typedef struct _wippersnapper_uart_UARTEvent { extern "C" { #endif +/* Helper constants for enums */ +#define _wippersnapper_uart_SerialConfig_MIN wippersnapper_uart_SerialConfig_SERIAL_CONFIG_UNSPECIFIED +#define _wippersnapper_uart_SerialConfig_MAX wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8O2 +#define _wippersnapper_uart_SerialConfig_ARRAYSIZE ((wippersnapper_uart_SerialConfig)(wippersnapper_uart_SerialConfig_SERIAL_CONFIG_8O2+1)) + +#define wippersnapper_uart_UARTBusData_config_ENUMTYPE wippersnapper_uart_SerialConfig + + + + + + /* Initializer values for message structs */ -#define wippersnapper_uart_UARTBusData_init_default {0, "", "", 0} -#define wippersnapper_uart_UARTAdd_init_default {false, wippersnapper_uart_UARTBusData_init_default, {{NULL}, NULL}, 0} +#define wippersnapper_uart_UARTBusData_init_default {{{NULL}, NULL}, 0, _wippersnapper_uart_SerialConfig_MIN, {{NULL}, NULL}, {{NULL}, NULL}, 0, 0} +#define wippersnapper_uart_UARTAdd_init_default {false, wippersnapper_uart_UARTBusData_init_default, {{NULL}, NULL}} #define wippersnapper_uart_UARTAdded_init_default {{{NULL}, NULL}, 0} #define wippersnapper_uart_UARTRemove_init_default {{{NULL}, NULL}} #define wippersnapper_uart_UARTEvent_init_default {{{NULL}, NULL}, {{NULL}, NULL}} -#define wippersnapper_uart_UARTBusData_init_zero {0, "", "", 0} -#define wippersnapper_uart_UARTAdd_init_zero {false, wippersnapper_uart_UARTBusData_init_zero, {{NULL}, NULL}, 0} +#define wippersnapper_uart_UARTBusData_init_zero {{{NULL}, NULL}, 0, _wippersnapper_uart_SerialConfig_MIN, {{NULL}, NULL}, {{NULL}, NULL}, 0, 0} +#define wippersnapper_uart_UARTAdd_init_zero {false, wippersnapper_uart_UARTBusData_init_zero, {{NULL}, NULL}} #define wippersnapper_uart_UARTAdded_init_zero {{{NULL}, NULL}, 0} #define wippersnapper_uart_UARTRemove_init_zero {{{NULL}, NULL}} #define wippersnapper_uart_UARTEvent_init_zero {{{NULL}, NULL}, {{NULL}, NULL}} /* Field tags (for use in manual encoding/decoding) */ -#define wippersnapper_uart_UARTBusData_baudrate_tag 1 -#define wippersnapper_uart_UARTBusData_pin_rx_tag 2 -#define wippersnapper_uart_UARTBusData_pin_tx_tag 3 -#define wippersnapper_uart_UARTBusData_is_invert_tag 4 -#define wippersnapper_uart_UARTAdd_bus_info_tag 1 -#define wippersnapper_uart_UARTAdd_device_id_tag 2 -#define wippersnapper_uart_UARTAdd_polling_interval_tag 3 -#define wippersnapper_uart_UARTAdded_device_id_tag 1 -#define wippersnapper_uart_UARTAdded_is_success_tag 2 -#define wippersnapper_uart_UARTRemove_device_id_tag 1 -#define wippersnapper_uart_UARTEvent_device_id_tag 1 +#define wippersnapper_uart_UARTBusData_bus_id_tag 1 +#define wippersnapper_uart_UARTBusData_baud_rate_tag 2 +#define wippersnapper_uart_UARTBusData_config_tag 3 +#define wippersnapper_uart_UARTBusData_rx_pin_tag 4 +#define wippersnapper_uart_UARTBusData_tx_pin_tag 5 +#define wippersnapper_uart_UARTBusData_invert_tag 6 +#define wippersnapper_uart_UARTBusData_timeout_tag 7 +#define wippersnapper_uart_UARTAdd_config_tag 1 +#define wippersnapper_uart_UARTAdd_driver_tag 2 +#define wippersnapper_uart_UARTAdded_driver_tag 1 +#define wippersnapper_uart_UARTAdded_success_tag 2 +#define wippersnapper_uart_UARTRemove_driver_tag 1 +#define wippersnapper_uart_UARTEvent_driver_tag 1 #define wippersnapper_uart_UARTEvent_sensor_events_tag 2 /* Struct field encoding specification for nanopb */ #define wippersnapper_uart_UARTBusData_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, INT32, baudrate, 1) \ -X(a, STATIC, SINGULAR, STRING, pin_rx, 2) \ -X(a, STATIC, SINGULAR, STRING, pin_tx, 3) \ -X(a, STATIC, SINGULAR, BOOL, is_invert, 4) -#define wippersnapper_uart_UARTBusData_CALLBACK NULL +X(a, CALLBACK, SINGULAR, STRING, bus_id, 1) \ +X(a, STATIC, SINGULAR, UINT32, baud_rate, 2) \ +X(a, STATIC, SINGULAR, UENUM, config, 3) \ +X(a, CALLBACK, SINGULAR, STRING, rx_pin, 4) \ +X(a, CALLBACK, SINGULAR, STRING, tx_pin, 5) \ +X(a, STATIC, SINGULAR, BOOL, invert, 6) \ +X(a, STATIC, SINGULAR, FLOAT, timeout, 7) +#define wippersnapper_uart_UARTBusData_CALLBACK pb_default_field_callback #define wippersnapper_uart_UARTBusData_DEFAULT NULL #define wippersnapper_uart_UARTAdd_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, bus_info, 1) \ -X(a, CALLBACK, SINGULAR, STRING, device_id, 2) \ -X(a, STATIC, SINGULAR, INT32, polling_interval, 3) +X(a, STATIC, OPTIONAL, MESSAGE, config, 1) \ +X(a, CALLBACK, SINGULAR, STRING, driver, 2) #define wippersnapper_uart_UARTAdd_CALLBACK pb_default_field_callback #define wippersnapper_uart_UARTAdd_DEFAULT NULL -#define wippersnapper_uart_UARTAdd_bus_info_MSGTYPE wippersnapper_uart_UARTBusData +#define wippersnapper_uart_UARTAdd_config_MSGTYPE wippersnapper_uart_UARTBusData #define wippersnapper_uart_UARTAdded_FIELDLIST(X, a) \ -X(a, CALLBACK, SINGULAR, STRING, device_id, 1) \ -X(a, STATIC, SINGULAR, BOOL, is_success, 2) +X(a, CALLBACK, SINGULAR, STRING, driver, 1) \ +X(a, STATIC, SINGULAR, BOOL, success, 2) #define wippersnapper_uart_UARTAdded_CALLBACK pb_default_field_callback #define wippersnapper_uart_UARTAdded_DEFAULT NULL #define wippersnapper_uart_UARTRemove_FIELDLIST(X, a) \ -X(a, CALLBACK, SINGULAR, STRING, device_id, 1) +X(a, CALLBACK, SINGULAR, STRING, driver, 1) #define wippersnapper_uart_UARTRemove_CALLBACK pb_default_field_callback #define wippersnapper_uart_UARTRemove_DEFAULT NULL #define wippersnapper_uart_UARTEvent_FIELDLIST(X, a) \ -X(a, CALLBACK, SINGULAR, STRING, device_id, 1) \ +X(a, CALLBACK, SINGULAR, STRING, driver, 1) \ X(a, CALLBACK, REPEATED, MESSAGE, sensor_events, 2) #define wippersnapper_uart_UARTEvent_CALLBACK pb_default_field_callback #define wippersnapper_uart_UARTEvent_DEFAULT NULL @@ -133,12 +181,11 @@ extern const pb_msgdesc_t wippersnapper_uart_UARTEvent_msg; #define wippersnapper_uart_UARTEvent_fields &wippersnapper_uart_UARTEvent_msg /* Maximum encoded size of messages (where known) */ +/* wippersnapper_uart_UARTBusData_size depends on runtime parameters */ /* wippersnapper_uart_UARTAdd_size depends on runtime parameters */ /* wippersnapper_uart_UARTAdded_size depends on runtime parameters */ /* wippersnapper_uart_UARTRemove_size depends on runtime parameters */ /* wippersnapper_uart_UARTEvent_size depends on runtime parameters */ -#define WIPPERSNAPPER_UART_UART_PB_H_MAX_SIZE wippersnapper_uart_UARTBusData_size -#define wippersnapper_uart_UARTBusData_size 27 #ifdef __cplusplus } /* extern "C" */ From b8ad718d08ea2eb66cbf81a3f9cb130c4faf89b1 Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 6 May 2025 13:06:30 -0400 Subject: [PATCH 02/26] detect i2c output device --- src/components/i2c/controller.cpp | 3 +++ src/components/i2c/model.cpp | 29 ++++++++--------------------- src/components/i2c/model.h | 5 +---- 3 files changed, 12 insertions(+), 25 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 60b72534a..def01ae19 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -740,6 +740,9 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { wippersnapper_i2c_I2cDeviceDescriptor device_descriptor = _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_description; + // Is this an i2c output device? + bool is_output = _i2c_model->GetI2cDeviceAddOrReplaceMsg()->is_output; + // TODO [Online]: Handle Replace messages by implementing the Remove handler // first...then proceed to adding a new device diff --git a/src/components/i2c/model.cpp b/src/components/i2c/model.cpp index 0bd6ff97b..04cd118d7 100644 --- a/src/components/i2c/model.cpp +++ b/src/components/i2c/model.cpp @@ -272,6 +272,14 @@ I2cModel::GetI2cDeviceAddOrReplaceMsg() { return &_msg_i2c_device_add_replace; } +/*! + @brief Returns a pointer to the I2cOutputAdd message. + @returns Pointer to the I2cOutputAdd message. +*/ +wippersnapper_i2c_output_I2cOutputAdd *I2cModel::GetI2cOutputAddMsg() { + return &_msg_i2c_device_add_replace.i2c_output_add; +} + /***************************************************************************/ /*! @brief Encodes a I2cDeviceAddedOrReplaced message. @@ -433,19 +441,6 @@ I2cOutputModel::~I2cOutputModel() { memset(&_msg_char_lcd_write, 0, sizeof(_msg_char_lcd_write)); } -/*! - @brief Decodes a I2cOutputAdd message from an input stream. - @param stream - A pointer to the pb_istream_t stream. - @returns True if the I2cOutputAdd message was decoded successfully, - False otherwise. -*/ -bool I2cOutputModel::DecodeI2cOutputAdd(pb_istream_t *stream) { - memset(&_msg_i2c_output_add, 0, sizeof(_msg_i2c_output_add)); - return pb_decode(stream, wippersnapper_i2c_output_I2cOutputAdd_fields, - &_msg_i2c_output_add); -} - /*! @brief Decodes a LedBackpackWrite message from an input stream. @param stream @@ -472,14 +467,6 @@ bool I2cOutputModel::DecodeCharLCDWrite(pb_istream_t *stream) { &_msg_char_lcd_write); } -/*! - @brief Returns a pointer to the I2cOutputAdd message. - @returns Pointer to the I2cOutputAdd message. -*/ -wippersnapper_i2c_output_I2cOutputAdd *I2cOutputModel::GetI2cOutputAddMsg() { - return &_msg_i2c_output_add; -} - /*! @brief Returns a pointer to the LedBackpackWrite message. @returns Pointer to the LedBackpackWrite message. diff --git a/src/components/i2c/model.h b/src/components/i2c/model.h index 8b2056222..ebd0d6a81 100644 --- a/src/components/i2c/model.h +++ b/src/components/i2c/model.h @@ -45,6 +45,7 @@ class I2cModel { // Getters wippersnapper_i2c_I2cDeviceRemove *GetI2cDeviceRemoveMsg(); wippersnapper_i2c_I2cDeviceAddOrReplace *GetI2cDeviceAddOrReplaceMsg(); + wippersnapper_i2c_output_I2cOutputAdd *GetI2cOutputAddMsg(); wippersnapper_i2c_I2cDeviceAddedOrReplaced *GetMsgI2cDeviceAddedOrReplaced(); wippersnapper_i2c_I2cDeviceEvent *GetI2cDeviceEvent(); wippersnapper_i2c_I2cBusScan *GetI2cBusScanMsg(); @@ -85,16 +86,12 @@ class I2cOutputModel { I2cOutputModel(); ~I2cOutputModel(); // Decoders - bool DecodeI2cOutputAdd(pb_istream_t *stream); bool DecodeLedBackpackWrite(pb_istream_t *stream); bool DecodeCharLCDWrite(pb_istream_t *stream); // Getters - wippersnapper_i2c_output_I2cOutputAdd *GetI2cOutputAddMsg(); wippersnapper_i2c_output_LedBackpackWrite *GetLedBackpackWriteMsg(); wippersnapper_i2c_output_CharLCDWrite *GetCharLCDWriteMsg(); - private: - wippersnapper_i2c_output_I2cOutputAdd _msg_i2c_output_add; wippersnapper_i2c_output_LedBackpackWrite _msg_led_backpack_write; wippersnapper_i2c_output_CharLCDWrite _msg_char_lcd_write; }; From 54cc000e408d5a6b8a5ca59e83fae7d3fe7739cb Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 6 May 2025 14:53:35 -0400 Subject: [PATCH 03/26] Add drv for QuadAlphaNum LED backpack --- platformio.ini | 1 + src/components/i2c/controller.cpp | 98 +++++++++++++++---- src/components/i2c/controller.h | 12 +-- .../i2c/drivers/drvOutQuadAlphaNum.h | 69 +++++++++++++ src/components/i2c/model.cpp | 2 - 5 files changed, 157 insertions(+), 25 deletions(-) create mode 100644 src/components/i2c/drivers/drvOutQuadAlphaNum.h diff --git a/platformio.ini b/platformio.ini index ad5932606..e68c95709 100644 --- a/platformio.ini +++ b/platformio.ini @@ -89,6 +89,7 @@ lib_deps = https://github.com/adafruit/RTClib.git https://github.com/bblanchon/ArduinoStreamUtils.git https://github.com/Sensirion/arduino-i2c-scd4x.git + https://github.com/adafruit/Adafruit_LED_Backpack.git ; Common build environment for ESP32 platform [common:esp32] diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index def01ae19..404acb2ac 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -14,7 +14,6 @@ */ #include "controller.h" -/*******************************************************************************/ /*! @brief Lambda function to create a drvBase driver instance @param i2c @@ -26,13 +25,12 @@ @param driver_name The i2c driver's name. */ -/*******************************************************************************/ -using FnCreateI2CDriver = +using FnCreateI2CSensorDriver = std::function; -// Factory for creating a new I2C drivers -// NOTE: When you add a new driver, make sure to add it to the factory! -static const std::map I2cFactory = { +// Factory for creating a new I2C SENSOR drivers +// NOTE: When you add a new SENSOR driver, make sure to add it to the factory! +static const std::map I2cFactorySensor = { {"bme280", [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, const char *driver_name) -> drvBase * { @@ -344,7 +342,29 @@ static const std::map I2cFactory = { return new drvVl6180x(i2c, addr, mux_channel, driver_name); }}}; ///< I2C driver factory -/***********************************************************************/ +/*! + @brief Lambda function to create a drvOutputBase instance + @param i2c + The desired I2C interface. + @param addr + The desired i2c device address. + @param mux_channel + The desired I2C multiplexer channel. + @param driver_name + The i2c output driver's name. +*/ +using FnCreateI2cOutputDrv = + std::function; + +// Factory for creating a new i2c OUTPUT driver +// NOTE: When adding a new OUTPUT driver, make sure to add it to the map below! +static const std::map I2cFactoryOutput = { + {"quadalphanum", + [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, + const char *driver_name) -> drvOutputBase * { + return new drvOutQuadAlphaNum(i2c, addr, mux_channel, driver_name); + }}}; ///< I2C output driver factory + /*! @brief Creates an I2C driver by name @param driver_name @@ -359,12 +379,39 @@ static const std::map I2cFactory = { The I2cDeviceStatus message. @returns A pointer to the I2C driver. */ -/***********************************************************************/ -drvBase *CreateI2CDriverByName(const char *driver_name, TwoWire *i2c, - uint16_t addr, uint32_t i2c_mux_channel, - wippersnapper_i2c_I2cDeviceStatus &status) { - auto it = I2cFactory.find(driver_name); - if (it == I2cFactory.end()) { +drvBase *CreateI2cSensorDrv(const char *driver_name, TwoWire *i2c, + uint16_t addr, uint32_t i2c_mux_channel, + wippersnapper_i2c_I2cDeviceStatus &status) { + auto it = I2cFactorySensor.find(driver_name); + if (it == I2cFactorySensor.end()) { + status = + wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_FAIL_UNSUPPORTED_SENSOR; + return nullptr; + } + + status = wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_SUCCESS; + return it->second(i2c, addr, i2c_mux_channel, driver_name); +} + +/*! + @brief Creates an I2C driver by name + @param driver_name + The name of the I2C driver. + @param i2c + The I2C bus. + @param addr + The I2C device address. + @param i2c_mux_channel + The I2C MUX channel. + @param status + The I2cDeviceStatus message. + @returns A pointer to the I2C driver. +*/ +drvOutputBase *CreateI2cOutputDrv(const char *driver_name, TwoWire *i2c, + uint16_t addr, uint32_t i2c_mux_channel, + wippersnapper_i2c_I2cDeviceStatus &status) { + auto it = I2cFactoryOutput.find(driver_name); + if (it == I2cFactoryOutput.end()) { status = wippersnapper_i2c_I2cDeviceStatus_I2C_DEVICE_STATUS_FAIL_UNSUPPORTED_SENSOR; return nullptr; @@ -380,7 +427,6 @@ drvBase *CreateI2CDriverByName(const char *driver_name, TwoWire *i2c, */ /***********************************************************************/ I2cController::I2cController() { - _i2c_bus_alt = nullptr; _i2c_model = new I2cModel(); _i2c_output_model = new I2cOutputModel(); _i2c_bus_default = new I2cHardware(); @@ -411,6 +457,7 @@ I2cController::~I2cController() { */ /***********************************************************************/ bool I2cController::RemoveDriver(uint32_t address) { + // Safely remove the i2c sensor drivers from the vector and free memory for (drvBase *driver : _i2c_drivers) { if (driver == nullptr) continue; @@ -425,6 +472,23 @@ bool I2cController::RemoveDriver(uint32_t address) { delete driver; return true; } + + // Safely remove the i2c output drivers from the vector and free memory + for (drvOutputBase *driver : _i2c_drivers_output) { + if (driver == nullptr) + continue; + + if (driver->GetAddress() != address) + continue; + + auto it = std::find(_i2c_drivers_output.begin(), _i2c_drivers_output.end(), + driver); + if (it != _i2c_drivers_output.end()) { + _i2c_drivers_output.erase(it); + } + delete driver; + return true; + } return false; } @@ -810,9 +874,9 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { bus = _i2c_bus_default->GetBus(); } - drvBase *drv = CreateI2CDriverByName( - device_name, bus, device_descriptor.i2c_device_address, - device_descriptor.i2c_mux_channel, device_status); + drvBase *drv = + CreateI2cSensorDrv(device_name, bus, device_descriptor.i2c_device_address, + device_descriptor.i2c_mux_channel, device_status); if (drv == nullptr) { WS_DEBUG_PRINTLN("[i2c] ERROR: I2C driver type not found or unsupported!"); if (WsV2._sdCardV2->isModeOffline()) { diff --git a/src/components/i2c/controller.h b/src/components/i2c/controller.h index 9d355c7f6..ba168df33 100644 --- a/src/components/i2c/controller.h +++ b/src/components/i2c/controller.h @@ -20,6 +20,7 @@ // I2C Drivers #include "drivers/drvAdt7410.h" #include "drivers/drvAhtx0.h" +#include "drivers/drvOutQuadAlphaNum.h" #include "drivers/drvBase.h" ///< Base i2c input driver class #include "drivers/drvBh1750.h" #include "drivers/drvBme280.h" @@ -99,13 +100,12 @@ class I2cController { bool RemoveDriver(uint32_t address); private: - I2cModel *_i2c_model; ///< Pointer to an I2C model object - I2cOutputModel *_i2c_output_model; ///< Pointer to an I2C output model object - I2cHardware *_i2c_bus_default; ///< Pointer to the default I2C bus - I2cHardware *_i2c_bus_alt; ///< Pointer to an alternative I2C bus + I2cModel *_i2c_model = nullptr; ///< Pointer to an I2C model object + I2cOutputModel *_i2c_output_model = nullptr; ///< Pointer to an I2C output model object + I2cHardware *_i2c_bus_default = nullptr; ///< Pointer to the default I2C bus + I2cHardware *_i2c_bus_alt = nullptr; ///< Pointer to an alternative I2C bus std::vector _i2c_drivers; ///< Vector of ptrs to I2C input drivers - std::vector - _i2c_drivers_output; ///< Vector of ptrs to I2C output drivers + std::vector _i2c_drivers_output; ///< Vector of ptrs to I2C output drivers }; extern Wippersnapper_V2 WsV2; ///< Wippersnapper V2 instance #endif // WS_I2C_CONTROLLER_H \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h new file mode 100644 index 000000000..f9b3d461e --- /dev/null +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -0,0 +1,69 @@ +/*! + * @file drvQuadAlphaNum.h + * + * Device driver for Quad Alphanumeric Displays w/I2C Backpack + * + * 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 for Adafruit Industries 2025 + * + * MIT license, all text here must be included in any redistribution. + * + */ + +#ifndef DRV_OUT_QUAD_ALPHANUM_H +#define DRV_OUT_QUAD_ALPHANUM_H + +#include "drvOutputBase.h" +#include + +/*! + @brief Class that provides a driver interface for Quad Alphanumeric + Displays w/I2C Backpack +*/ +class drvOutQuadAlphaNum : public drvOutputBase { +public: + /*! + @brief Constructor for a quad alphanumeric display.. + @param i2c + The I2C interface. + @param sensorAddress + 7-bit device address. + @param mux_channel + The I2C multiplexer channel. + @param driver_name + The name of the driver. + */ + drvOutQuadAlphaNum(TwoWire *i2c, uint16_t sensorAddress, uint32_t mux_channel, + const char *driver_name) + : drvOutputBase(i2c, sensorAddress, mux_channel, driver_name) { + // Initialization handled by drvBase constructor + } + + /*! + @brief Destructor for a quad alphanumeric display. + */ + ~drvOutQuadAlphaNum() { + if (_alpha4) { + delete _alpha4; + _alpha4 = nullptr; + } + } + + /*! + @brief Initializes the drvOutQuadAlphaNum sensor and begins I2C. + @returns True if initialized successfully, False otherwise. + */ + bool begin() override { + _alpha4 = new Adafruit_AlphaNum4(); + return _alpha4->begin(_address, _i2c); + } + +protected: + Adafruit_AlphaNum4 *_alpha4 = + nullptr; ///< ptr to a 4-digit alphanumeric display object +}; + +#endif // DRV_OUT_QUAD_ALPHANUM_H \ No newline at end of file diff --git a/src/components/i2c/model.cpp b/src/components/i2c/model.cpp index 04cd118d7..0bde0397e 100644 --- a/src/components/i2c/model.cpp +++ b/src/components/i2c/model.cpp @@ -427,7 +427,6 @@ wippersnapper_i2c_I2cDeviceEvent *I2cModel::GetI2cDeviceEvent() { @brief I2cOutputModel constructor */ I2cOutputModel::I2cOutputModel() { - memset(&_msg_i2c_output_add, 0, sizeof(_msg_i2c_output_add)); memset(&_msg_led_backpack_write, 0, sizeof(_msg_led_backpack_write)); memset(&_msg_char_lcd_write, 0, sizeof(_msg_char_lcd_write)); } @@ -436,7 +435,6 @@ I2cOutputModel::I2cOutputModel() { @brief I2cOutputModel destructor */ I2cOutputModel::~I2cOutputModel() { - memset(&_msg_i2c_output_add, 0, sizeof(_msg_i2c_output_add)); memset(&_msg_led_backpack_write, 0, sizeof(_msg_led_backpack_write)); memset(&_msg_char_lcd_write, 0, sizeof(_msg_char_lcd_write)); } From 8f19c0830d91a0c14af32835a5de870786a399c0 Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 6 May 2025 15:58:13 -0400 Subject: [PATCH 04/26] Add handler for Write message --- src/Wippersnapper_V2.cpp | 6 +++ src/components/i2c/controller.cpp | 11 +++++ src/components/i2c/controller.h | 1 + .../i2c/drivers/drvOutQuadAlphaNum.h | 42 +++++++++++++++++++ src/components/i2c/drivers/drvOutputBase.h | 34 ++++++++++++--- 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/src/Wippersnapper_V2.cpp b/src/Wippersnapper_V2.cpp index 209f7464f..897132427 100644 --- a/src/Wippersnapper_V2.cpp +++ b/src/Wippersnapper_V2.cpp @@ -401,6 +401,12 @@ bool cbDecodeBrokerToDevice(pb_istream_t *stream, const pb_field_t *field, return false; } break; + case wippersnapper_signal_BrokerToDevice_i2c_device_output_write_tag: + WS_DEBUG_PRINTLN("-> I2C Device Output Write Message Type"); + if (!WsV2._i2c_controller->Handle_I2cDeviceOutputWrite(stream)) { + return false; + } + break; case wippersnapper_signal_BrokerToDevice_pixels_add_tag: WS_DEBUG_PRINTLN("-> Pixels Add Message Type"); if (!WsV2._pixels_controller->Handle_Pixels_Add(stream)) { diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 404acb2ac..86e92ff6c 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -775,6 +775,17 @@ bool I2cController::Handle_I2cBusScan(pb_istream_t *stream) { return true; } +/*! + @brief Handler for an I2cDeviceOutputWrite message + @param stream + A pointer to the pb_istream_t stream. + @returns True if the callback was successfully executed by the driver, False otherwise. +*/ +bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { + // todo! + return false; +} + /***********************************************************************/ /*! @brief Implements handling for a I2cDeviceAddOrReplace message diff --git a/src/components/i2c/controller.h b/src/components/i2c/controller.h index ba168df33..5b0b7196d 100644 --- a/src/components/i2c/controller.h +++ b/src/components/i2c/controller.h @@ -89,6 +89,7 @@ class I2cController { bool Handle_I2cDeviceAddOrReplace(pb_istream_t *stream); bool Handle_I2cBusScan(pb_istream_t *stream); bool Handle_I2cDeviceRemove(pb_istream_t *stream); + bool Handle_I2cDeviceOutputWrite(pb_istream_t *stream); // Publishing // bool PublishI2cDeviceAddedorReplaced( const wippersnapper_i2c_I2cDeviceDescriptor &device_descriptor, diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index f9b3d461e..6fa233bd1 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -61,6 +61,48 @@ class drvOutQuadAlphaNum : public drvOutputBase { return _alpha4->begin(_address, _i2c); } + /*! + @brief Writes the first four characters of a message to the quad + alphanumeric display. + @param message + The message to be displayed. + */ + void WriteMessage(const char *message) { + if (_alpha4 == nullptr) { + return; + } + for (size_t i = 0; i < 4; i++) { + _alpha4->writeDigitAscii(i, message[i]); + } + _alpha4->writeDisplay(); + } + + /*! + @brief Writes a floating point value to the quad alphanumeric display. + @param value + The value to be displayed. Only the first four digits are + displayed. + */ + void WriteValue(float value) { + if (_alpha4 == nullptr) { + return; + } + // TODO! + } + + /*! + @brief Writes an integer value to the quad alphanumeric display. + @param value + The value to be displayed. Only the first four digits are + displayed. + */ + void WriteValue(int32_t value) { + if (_alpha4 == nullptr) { + return; + } + // TODO! +} + protected: Adafruit_AlphaNum4 *_alpha4 = nullptr; ///< ptr to a 4-digit alphanumeric display object diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index f10d05b7c..36d93d20c 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -17,15 +17,12 @@ #define DRV_OUTPUT_BASE_H #include "drvBase.h" -/**************************************************************************/ /*! @brief Base class for I2C Output Drivers. */ -/**************************************************************************/ class drvOutputBase : public drvBase { public: - /*******************************************************************************/ /*! @brief Instantiates an I2C output device. @param i2c @@ -38,20 +35,45 @@ class drvOutputBase : public drvBase { @param driver_name The name of the driver. */ - /*******************************************************************************/ drvOutputBase(TwoWire *i2c, uint16_t address, uint32_t mux_channel, const char *driver_name) : drvBase(i2c, address, mux_channel, driver_name) { // TODO } - /*******************************************************************************/ /*! @brief Destructor for an I2C output device. */ - /*******************************************************************************/ virtual ~drvOutputBase() {} + /*! + @brief Initializes the I2C output device and begins I2C. + @returns True if initialized successfully, False otherwise. + */ + virtual void WriteMessage(const char *message) { + // noop + } + + /*! + @brief Writes a floating point value to the quad alphanumeric display. + @param value + The value to be displayed. Only the first four digits are + displayed. + */ + virtual void WriteValue(float value) { + // noop + } + + /*! + @brief Writes a floating point value to the quad alphanumeric display. + @param value + The value to be displayed. Only the first four digits are + displayed. + */ + virtual void WriteValue(int32_t value) { + // noop + } + protected: // TODO }; From d54d4ad8b7d4951a415611c8811b14b3c62ea971 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 7 May 2025 13:04:38 -0400 Subject: [PATCH 05/26] Handle initial configuration and begin for outputs --- src/components/i2c/controller.cpp | 88 +++++++++++++++---- .../i2c/drivers/drvOutQuadAlphaNum.h | 36 ++++++-- src/components/i2c/drivers/drvOutputBase.h | 13 ++- src/protos/i2c_output.pb.c | 1 - src/protos/i2c_output.pb.h | 28 ++---- 5 files changed, 120 insertions(+), 46 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 86e92ff6c..4dade10b7 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -13,6 +13,8 @@ * */ #include "controller.h" +#include "drivers/drvBase.h" +#include "drivers/drvOutputBase.h" /*! @brief Lambda function to create a drvBase driver instance @@ -779,7 +781,8 @@ bool I2cController::Handle_I2cBusScan(pb_istream_t *stream) { @brief Handler for an I2cDeviceOutputWrite message @param stream A pointer to the pb_istream_t stream. - @returns True if the callback was successfully executed by the driver, False otherwise. + @returns True if the callback was successfully executed by the driver, + False otherwise. */ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { // todo! @@ -885,10 +888,27 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { bus = _i2c_bus_default->GetBus(); } - drvBase *drv = - CreateI2cSensorDrv(device_name, bus, device_descriptor.i2c_device_address, - device_descriptor.i2c_mux_channel, device_status); - if (drv == nullptr) { + // Attempt to create the driver + bool did_init = false; + drvBase *drv = nullptr; + drvOutputBase *drv_out = nullptr; + if (!is_output) { + drv = CreateI2cSensorDrv(device_name, bus, + device_descriptor.i2c_device_address, + device_descriptor.i2c_mux_channel, device_status); + if (drv != nullptr) { + did_init = true; + } + } else { + drv_out = CreateI2cOutputDrv( + device_name, bus, device_descriptor.i2c_device_address, + device_descriptor.i2c_mux_channel, device_status); + if (drv_out != nullptr) { + did_init = true; + } + } + + if (!did_init) { WS_DEBUG_PRINTLN("[i2c] ERROR: I2C driver type not found or unsupported!"); if (WsV2._sdCardV2->isModeOffline()) { WsV2.haltErrorV2("[i2c] Driver failed to initialize!\n\tDid you set " @@ -901,22 +921,58 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { // Attempt to initialize the driver if (did_set_mux_ch) { - drv->SetMuxAddress(device_descriptor.i2c_mux_address); + if (!is_output) { + drv->SetMuxAddress(device_descriptor.i2c_mux_address); + } else { + drv_out->SetMuxAddress(device_descriptor.i2c_mux_address); + } WS_DEBUG_PRINTLN("[i2c] Set driver to use MUX"); } if (use_alt_bus) { - drv->EnableAltI2CBus(_i2c_model->GetI2cDeviceAddOrReplaceMsg() - ->i2c_device_description.i2c_bus_scl, - _i2c_model->GetI2cDeviceAddOrReplaceMsg() - ->i2c_device_description.i2c_bus_sda); + if (!is_output) { + drv->EnableAltI2CBus(_i2c_model->GetI2cDeviceAddOrReplaceMsg() + ->i2c_device_description.i2c_bus_scl, + _i2c_model->GetI2cDeviceAddOrReplaceMsg() + ->i2c_device_description.i2c_bus_sda); + } else { + drv_out->EnableAltI2CBus(_i2c_model->GetI2cDeviceAddOrReplaceMsg() + ->i2c_device_description.i2c_bus_scl, + _i2c_model->GetI2cDeviceAddOrReplaceMsg() + ->i2c_device_description.i2c_bus_sda); + } WS_DEBUG_PRINTLN("[i2c] Set driver to use Alt I2C bus"); } // Configure the driver - drv->EnableSensorReads( - _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_sensor_types, - _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_sensor_types_count); - drv->SetSensorPeriod( - _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_period); + + if (!is_output) { + // Configure Input-driver settings + drv->EnableSensorReads( + _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_sensor_types, + _i2c_model->GetI2cDeviceAddOrReplaceMsg() + ->i2c_device_sensor_types_count); + drv->SetSensorPeriod( + _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_period); + } else { + // Configure Output-driver settings + pb_size_t config = + _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_output_add.which_config; + if (config == + wippersnapper_i2c_output_I2cOutputAdd_led_backpack_config_tag) { + // TODO: Configure LED Backpack + wippersnapper_i2c_output_LedBackpackConfig cfg = + _i2c_model->GetI2cDeviceAddOrReplaceMsg() + ->i2c_output_add.config.led_backpack_config; + drv_out->ConfigureLEDBackpack(cfg.brightness, cfg.alignment); + } else if (config == + wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag) { + // TODO: Configure Char LCD + } else { + WS_DEBUG_PRINTLN( + "[i2c] ERROR: Unknown config specified for output driver!"); + return false; + } + } + if (!drv->begin()) { if (WsV2._sdCardV2->isModeOffline()) { WsV2.haltErrorV2("[i2c] Driver failed to initialize!\n\tDid you set " @@ -1035,4 +1091,4 @@ void I2cController::update() { cur_time = millis(); drv->SetSensorPeriodPrv(cur_time); } -} \ No newline at end of file +} diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index 6fa233bd1..74261cc03 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -19,6 +19,10 @@ #include "drvOutputBase.h" #include +#define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 +#define LED_BACKPACK_ALIGNMENT_LEFT 1 +#define LED_BACKPACK_ALIGNMENT_RIGHT 2 + /*! @brief Class that provides a driver interface for Quad Alphanumeric Displays w/I2C Backpack @@ -58,7 +62,25 @@ class drvOutQuadAlphaNum : public drvOutputBase { */ bool begin() override { _alpha4 = new Adafruit_AlphaNum4(); - return _alpha4->begin(_address, _i2c); + bool did_begin = _alpha4->begin(_address, _i2c); + _alpha4->setBrightness(_brightness); + } + + /*! + @brief Configures a LED backpack. + @param brightness + The brightness of the LED backpack. + @param alignment + The alignment of the LED backpack. +*/ + void ConfigureLEDBackpack(int32_t brightness, uint32_t alignment) { + if (alignment == LED_BACKPACK_ALIGNMENT_RIGHT) { + _alignment = LED_BACKPACK_ALIGNMENT_RIGHT; + } else { + // default: left alignment + _alignment = LED_BACKPACK_ALIGNMENT_LEFT; + } + _brightness = brightness; } /*! @@ -96,16 +118,18 @@ class drvOutQuadAlphaNum : public drvOutputBase { The value to be displayed. Only the first four digits are displayed. */ - void WriteValue(int32_t value) { - if (_alpha4 == nullptr) { - return; + void WriteValue(int32_t value) { + if (_alpha4 == nullptr) { + return; + } + // TODO! } - // TODO! -} protected: Adafruit_AlphaNum4 *_alpha4 = nullptr; ///< ptr to a 4-digit alphanumeric display object + int32_t _brightness; + uint32_t _alignment; }; #endif // DRV_OUT_QUAD_ALPHANUM_H \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 36d93d20c..618f36a93 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -70,7 +70,18 @@ class drvOutputBase : public drvBase { The value to be displayed. Only the first four digits are displayed. */ - virtual void WriteValue(int32_t value) { + virtual void WriteValue(int32_t value) { + // noop + } + + /*! + @brief Configures a LED backpack. + @param brightness + The brightness of the LED backpack. + @param alignment + The alignment of the LED backpack. + */ + virtual void ConfigureLEDBackpack(int32_t brightness, uint32_t alignment) { // noop } diff --git a/src/protos/i2c_output.pb.c b/src/protos/i2c_output.pb.c index c7ec07df2..dfd0fc075 100644 --- a/src/protos/i2c_output.pb.c +++ b/src/protos/i2c_output.pb.c @@ -24,4 +24,3 @@ PB_BIND(wippersnapper_i2c_output_CharLCDWrite, wippersnapper_i2c_output_CharLCDW - diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h index 0071d9163..9c47288b7 100644 --- a/src/protos/i2c_output.pb.h +++ b/src/protos/i2c_output.pb.h @@ -10,14 +10,6 @@ #endif /* Enum definitions */ -/* * - I2cOutputType defines the category of I2C output device. */ -typedef enum _wippersnapper_i2c_output_I2cOutputType { - wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_UNSPECIFIED = 0, /* * Unspecified output type. * */ - wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_LED_BACKPACK = 1, /* * LED backpack output type. * */ - wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_CHAR_LCD = 2 /* * Character LCD output type. * */ -} wippersnapper_i2c_output_I2cOutputType; - /* * LedBackpackBlinkRate represents supported, OPTIONAL, blink rates for LED backpack displays */ typedef enum _wippersnapper_i2c_output_LedBackpackBlinkRate { @@ -56,7 +48,6 @@ typedef struct _wippersnapper_i2c_output_CharLCDConfig { /* * I2cOutputAdd represents a request from the broker to add an I2C output device to a device. */ typedef struct _wippersnapper_i2c_output_I2cOutputAdd { - wippersnapper_i2c_output_I2cOutputType type; /* * The type of I2C output device. * */ pb_size_t which_config; union { wippersnapper_i2c_output_LedBackpackConfig led_backpack_config; /* * Configuration for LED backpack. * */ @@ -100,10 +91,6 @@ extern "C" { #endif /* Helper constants for enums */ -#define _wippersnapper_i2c_output_I2cOutputType_MIN wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_UNSPECIFIED -#define _wippersnapper_i2c_output_I2cOutputType_MAX wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_CHAR_LCD -#define _wippersnapper_i2c_output_I2cOutputType_ARRAYSIZE ((wippersnapper_i2c_output_I2cOutputType)(wippersnapper_i2c_output_I2cOutputType_I2C_OUTPUT_TYPE_CHAR_LCD+1)) - #define _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_UNSPECIFIED #define _wippersnapper_i2c_output_LedBackpackBlinkRate_MAX wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ #define _wippersnapper_i2c_output_LedBackpackBlinkRate_ARRAYSIZE ((wippersnapper_i2c_output_LedBackpackBlinkRate)(wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ+1)) @@ -115,7 +102,6 @@ extern "C" { #define wippersnapper_i2c_output_LedBackpackConfig_alignment_ENUMTYPE wippersnapper_i2c_output_LedBackpackAlignment -#define wippersnapper_i2c_output_I2cOutputAdd_type_ENUMTYPE wippersnapper_i2c_output_I2cOutputType #define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_ENUMTYPE wippersnapper_i2c_output_LedBackpackBlinkRate @@ -124,12 +110,12 @@ extern "C" { /* Initializer values for message structs */ #define wippersnapper_i2c_output_LedBackpackConfig_init_default {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} #define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, 0, {{NULL}, NULL}} -#define wippersnapper_i2c_output_I2cOutputAdd_init_default {_wippersnapper_i2c_output_I2cOutputType_MIN, 0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} +#define wippersnapper_i2c_output_I2cOutputAdd_init_default {0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} #define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} #define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {{{NULL}, NULL}}, 0, {{NULL}, NULL}, 0} #define wippersnapper_i2c_output_LedBackpackConfig_init_zero {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} #define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, 0, {{NULL}, NULL}} -#define wippersnapper_i2c_output_I2cOutputAdd_init_zero {_wippersnapper_i2c_output_I2cOutputType_MIN, 0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} +#define wippersnapper_i2c_output_I2cOutputAdd_init_zero {0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} #define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} #define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {{{NULL}, NULL}}, 0, {{NULL}, NULL}, 0} @@ -140,9 +126,8 @@ extern "C" { #define wippersnapper_i2c_output_CharLCDConfig_columns_tag 2 #define wippersnapper_i2c_output_CharLCDConfig_backlight_enable_tag 3 #define wippersnapper_i2c_output_CharLCDConfig_backlight_color_tag 4 -#define wippersnapper_i2c_output_I2cOutputAdd_type_tag 1 -#define wippersnapper_i2c_output_I2cOutputAdd_led_backpack_config_tag 2 -#define wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag 3 +#define wippersnapper_i2c_output_I2cOutputAdd_led_backpack_config_tag 1 +#define wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag 2 #define wippersnapper_i2c_output_LedBackpackWrite_text_tag 1 #define wippersnapper_i2c_output_LedBackpackWrite_number_int_tag 2 #define wippersnapper_i2c_output_LedBackpackWrite_number_float_tag 3 @@ -174,9 +159,8 @@ X(a, CALLBACK, SINGULAR, STRING, backlight_color, 4) #define wippersnapper_i2c_output_CharLCDConfig_DEFAULT NULL #define wippersnapper_i2c_output_I2cOutputAdd_FIELDLIST(X, a) \ -X(a, STATIC, SINGULAR, UENUM, type, 1) \ -X(a, STATIC, ONEOF, MESSAGE, (config,led_backpack_config,config.led_backpack_config), 2) \ -X(a, STATIC, ONEOF, MESSAGE, (config,char_lcd_config,config.char_lcd_config), 3) +X(a, STATIC, ONEOF, MESSAGE, (config,led_backpack_config,config.led_backpack_config), 1) \ +X(a, STATIC, ONEOF, MESSAGE, (config,char_lcd_config,config.char_lcd_config), 2) #define wippersnapper_i2c_output_I2cOutputAdd_CALLBACK NULL #define wippersnapper_i2c_output_I2cOutputAdd_DEFAULT NULL #define wippersnapper_i2c_output_I2cOutputAdd_config_led_backpack_config_MSGTYPE wippersnapper_i2c_output_LedBackpackConfig From 9340fff7686c324ec7b30f28d03726d921c61cf8 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 7 May 2025 14:31:30 -0400 Subject: [PATCH 06/26] Added options file, new protos/ --- src/components/i2c/controller.cpp | 31 ++++++++++++++++++++++++++++++- src/components/i2c/model.cpp | 27 ++++++++++++++++++++++++++- src/components/i2c/model.h | 4 ++++ src/protos/i2c.pb.h | 4 +--- src/protos/i2c_output.pb.h | 24 ++++++++++++------------ src/protos/signal.pb.h | 6 +++--- 6 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 4dade10b7..a5ed930c7 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -785,7 +785,36 @@ bool I2cController::Handle_I2cBusScan(pb_istream_t *stream) { False otherwise. */ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { - // todo! + WS_DEBUG_PRINTLN("[i2c] Decoding I2cDeviceOutputWrite message..."); + // Attempt to decode an I2cDeviceOutputWrite message + if (!_i2c_model->DecodeI2cDeviceOutputWrite(stream)) { + WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to decode I2cDeviceOutputWrite " + "message!"); + return false; + } + wippersnapper_i2c_I2cDeviceDescriptor descriptor = _i2c_model->GetI2cDeviceOutputWriteMsg()->i2c_device_description; + + // Get the driver + drvOutputBase *driver = nullptr; + for (auto *drv : _i2c_drivers_output) { + if (drv == nullptr) + continue; + + if (drv->GetAddress() != descriptor.i2c_device_address) + continue; + + driver = drv; + break; + } + + // Optionally configure the I2C MUX + uint32_t mux_channel = driver->GetMuxChannel(); + WS_DEBUG_PRINTLN(mux_channel); + if (driver->HasMux()) { + ConfigureMuxChannel(mux_channel, driver->HasAltI2CBus()); + } + + return false; } diff --git a/src/components/i2c/model.cpp b/src/components/i2c/model.cpp index 0bde0397e..b2fb0264b 100644 --- a/src/components/i2c/model.cpp +++ b/src/components/i2c/model.cpp @@ -28,7 +28,8 @@ I2cModel::I2cModel() { memset(&_msg_i2c_device_remove, 0, sizeof(_msg_i2c_device_remove)); memset(&_msg_i2c_device_removed, 0, sizeof(_msg_i2c_device_removed)); memset(&_msg_i2c_device_event, 0, sizeof(_msg_i2c_device_event)); - // no-op + memset(&_msg_i2c_device_output_write, 0, + sizeof(_msg_i2c_device_output_write)); } /***********************************************************************/ @@ -45,6 +46,8 @@ I2cModel::~I2cModel() { memset(&_msg_i2c_device_remove, 0, sizeof(_msg_i2c_device_remove)); memset(&_msg_i2c_device_removed, 0, sizeof(_msg_i2c_device_removed)); memset(&_msg_i2c_device_event, 0, sizeof(_msg_i2c_device_event)); + memset(&_msg_i2c_device_output_write, 0, + sizeof(_msg_i2c_device_output_write)); } /***************************************************************************/ @@ -423,6 +426,28 @@ wippersnapper_i2c_I2cDeviceEvent *I2cModel::GetI2cDeviceEvent() { return &_msg_i2c_device_event; } +/*! + @brief Decodes a I2cDeviceOutputWrite message from an input stream. + @param stream + A pointer to the pb_istream_t stream. + @returns True if the I2cDeviceOutputWrite message was decoded successfully, + False otherwise. +*/ +bool I2cModel::DecodeI2cDeviceOutputWrite(pb_istream_t *stream) { + memset(&_msg_i2c_device_output_write, 0, + sizeof(_msg_i2c_device_output_write)); + return pb_decode(stream, wippersnapper_i2c_I2cDeviceOutputWrite_fields, + &_msg_i2c_device_output_write); +} + +/*! + @brief Returns a pointer to the I2cDeviceOutputWrite message. + @returns Pointer to the I2cDeviceOutputWrite message. +*/ +wippersnapper_i2c_I2cDeviceOutputWrite *I2cModel::GetI2cDeviceOutputWriteMsg() { + return &_msg_i2c_device_output_write; +} + /*! @brief I2cOutputModel constructor */ diff --git a/src/components/i2c/model.h b/src/components/i2c/model.h index ebd0d6a81..838ce759c 100644 --- a/src/components/i2c/model.h +++ b/src/components/i2c/model.h @@ -36,6 +36,7 @@ class I2cModel { bool DecodeI2cDeviceAddReplace(pb_istream_t *stream); bool DecodeI2cDeviceRemove(pb_istream_t *stream); bool DecodeI2cBusScan(pb_istream_t *stream); + bool DecodeI2cDeviceOutputWrite(pb_istream_t *stream); // Encoders bool encodeMsgI2cDeviceAddedorReplaced( wippersnapper_i2c_I2cDeviceDescriptor i2c_device_description, @@ -50,6 +51,7 @@ class I2cModel { wippersnapper_i2c_I2cDeviceEvent *GetI2cDeviceEvent(); wippersnapper_i2c_I2cBusScan *GetI2cBusScanMsg(); wippersnapper_i2c_I2cBusScanned *GetI2cBusScannedMsg(); + wippersnapper_i2c_I2cDeviceOutputWrite *GetI2cDeviceOutputWriteMsg(); // I2cBusScanned Message API void ClearI2cBusScanned(); bool AddDeviceToBusScan(const char *bus_scl, const char *bus_sda, @@ -73,6 +75,7 @@ class I2cModel { wippersnapper_i2c_I2cDeviceRemove _msg_i2c_device_remove; wippersnapper_i2c_I2cDeviceRemoved _msg_i2c_device_removed; wippersnapper_i2c_I2cDeviceEvent _msg_i2c_device_event; + wippersnapper_i2c_I2cDeviceOutputWrite _msg_i2c_device_output_write; }; /**************************************************************************/ @@ -91,6 +94,7 @@ class I2cOutputModel { // Getters wippersnapper_i2c_output_LedBackpackWrite *GetLedBackpackWriteMsg(); wippersnapper_i2c_output_CharLCDWrite *GetCharLCDWriteMsg(); + private: wippersnapper_i2c_output_LedBackpackWrite _msg_led_backpack_write; wippersnapper_i2c_output_CharLCDWrite _msg_char_lcd_write; diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index 96a1b9111..0de0b47c4 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -332,13 +332,11 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cBusDescriptor_size 32 #define wippersnapper_i2c_I2cBusScan_size 42 #define wippersnapper_i2c_I2cBusScanned_size 6242 +#define wippersnapper_i2c_I2cDeviceAddOrReplace_size 141 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 #define wippersnapper_i2c_I2cDeviceRemove_size 52 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 -#if defined(wippersnapper_i2c_output_I2cOutputAdd_size) -#define wippersnapper_i2c_I2cDeviceAddOrReplace_size (113 + wippersnapper_i2c_output_I2cOutputAdd_size) -#endif #if defined(wippersnapper_sensor_SensorEvent_size) #define wippersnapper_i2c_I2cDeviceEvent_size (142 + 15*wippersnapper_sensor_SensorEvent_size) #endif diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h index 9c47288b7..b57f2a0ca 100644 --- a/src/protos/i2c_output.pb.h +++ b/src/protos/i2c_output.pb.h @@ -42,7 +42,7 @@ typedef struct _wippersnapper_i2c_output_CharLCDConfig { uint32_t rows; /* * Number of rows for the character LCD. * */ uint32_t columns; /* * Number of columns for the character LCD. * */ bool backlight_enable; /* * Backlight state for the character LCD. * */ - pb_callback_t backlight_color; /* * Backlight color for the character LCD, in Hex. * */ + char backlight_color[15]; /* * Backlight color for the character LCD, in Hex. * */ } wippersnapper_i2c_output_CharLCDConfig; /* * @@ -81,7 +81,7 @@ typedef struct _wippersnapper_i2c_output_CharLCDWrite { float number_float; /* * Float to write to the character LCD. * */ } message; bool enable_backlight; /* * Enable backlight for the character LCD. * */ - pb_callback_t backlight_color; /* * Backlight color for the character LCD, in Hex. * */ + char backlight_color[20]; /* * Backlight color for the character LCD, in Hex. * */ bool enable_scroll; /* * Enable automatic scrolling for the character LCD. * */ } wippersnapper_i2c_output_CharLCDWrite; @@ -109,15 +109,15 @@ extern "C" { /* Initializer values for message structs */ #define wippersnapper_i2c_output_LedBackpackConfig_init_default {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} -#define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, 0, {{NULL}, NULL}} +#define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_default {0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} #define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {{{NULL}, NULL}}, 0, {{NULL}, NULL}, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {{{NULL}, NULL}}, 0, "", 0} #define wippersnapper_i2c_output_LedBackpackConfig_init_zero {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} -#define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, 0, {{NULL}, NULL}} +#define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_zero {0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} #define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {{{NULL}, NULL}}, 0, {{NULL}, NULL}, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {{{NULL}, NULL}}, 0, "", 0} /* Field tags (for use in manual encoding/decoding) */ #define wippersnapper_i2c_output_LedBackpackConfig_brightness_tag 1 @@ -154,8 +154,8 @@ X(a, STATIC, SINGULAR, UENUM, alignment, 2) X(a, STATIC, SINGULAR, UINT32, rows, 1) \ X(a, STATIC, SINGULAR, UINT32, columns, 2) \ X(a, STATIC, SINGULAR, BOOL, backlight_enable, 3) \ -X(a, CALLBACK, SINGULAR, STRING, backlight_color, 4) -#define wippersnapper_i2c_output_CharLCDConfig_CALLBACK pb_default_field_callback +X(a, STATIC, SINGULAR, STRING, backlight_color, 4) +#define wippersnapper_i2c_output_CharLCDConfig_CALLBACK NULL #define wippersnapper_i2c_output_CharLCDConfig_DEFAULT NULL #define wippersnapper_i2c_output_I2cOutputAdd_FIELDLIST(X, a) \ @@ -183,7 +183,7 @@ X(a, CALLBACK, ONEOF, STRING, (message,text,message.text), 1) \ X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ X(a, STATIC, SINGULAR, BOOL, enable_backlight, 4) \ -X(a, CALLBACK, SINGULAR, STRING, backlight_color, 5) \ +X(a, STATIC, SINGULAR, STRING, backlight_color, 5) \ X(a, STATIC, SINGULAR, BOOL, enable_scroll, 6) #define wippersnapper_i2c_output_CharLCDWrite_CALLBACK pb_default_field_callback #define wippersnapper_i2c_output_CharLCDWrite_DEFAULT NULL @@ -202,11 +202,11 @@ extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDWrite_msg; #define wippersnapper_i2c_output_CharLCDWrite_fields &wippersnapper_i2c_output_CharLCDWrite_msg /* Maximum encoded size of messages (where known) */ -/* wippersnapper_i2c_output_CharLCDConfig_size depends on runtime parameters */ -/* wippersnapper_i2c_output_I2cOutputAdd_size depends on runtime parameters */ /* wippersnapper_i2c_output_LedBackpackWrite_size depends on runtime parameters */ /* wippersnapper_i2c_output_CharLCDWrite_size depends on runtime parameters */ -#define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_LedBackpackConfig_size +#define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_I2cOutputAdd_size +#define wippersnapper_i2c_output_CharLCDConfig_size 30 +#define wippersnapper_i2c_output_I2cOutputAdd_size 32 #define wippersnapper_i2c_output_LedBackpackConfig_size 13 #ifdef __cplusplus diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index 6b28ca32b..b07af7c06 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -256,13 +256,13 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; #define wippersnapper_signal_DeviceToBroker_fields &wippersnapper_signal_DeviceToBroker_msg /* Maximum encoded size of messages (where known) */ -#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceAddOrReplace_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f91[(7 + wippersnapper_i2c_I2cDeviceAddOrReplace_size)]; char f93[(7 + wippersnapper_i2c_I2cDeviceOutputWrite_size)]; char f0[83];}; +#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f93[(7 + wippersnapper_i2c_I2cDeviceOutputWrite_size)]; char f0[145];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; #endif -#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceAddOrReplace_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) +#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) #define WIPPERSNAPPER_SIGNAL_SIGNAL_PB_H_MAX_SIZE wippersnapper_signal_BrokerToDevice_size #define wippersnapper_signal_BrokerToDevice_size (0 + sizeof(union wippersnapper_signal_BrokerToDevice_payload_size_union)) #endif From 888a3c0158febc51334d45647205438c4d646be7 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 7 May 2025 15:09:34 -0400 Subject: [PATCH 07/26] Fixed options files --- src/components/i2c/controller.cpp | 13 ++++++++++- src/components/i2c/drivers/drvOutputBase.h | 12 ++++++++++ src/protos/i2c.pb.h | 4 +--- src/protos/i2c_output.pb.h | 26 +++++++++++----------- src/protos/signal.pb.h | 6 ++--- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index a5ed930c7..170c218fe 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -813,9 +813,20 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { if (driver->HasMux()) { ConfigureMuxChannel(mux_channel, driver->HasAltI2CBus()); } + + // Determine which driver cb function to use + if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_led_backpack_write) { + // TODO + WS_DEBUG_PRINTLN("[i2c] LED backpack write!"); + } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_char_lcd_write) { + WS_DEBUG_PRINTLN("[i2c] Char LCD write not implemented yet!"); + } else { + WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine I2C Output Write type!"); + return false; + } - return false; + return true; } /***********************************************************************/ diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 618f36a93..c1d6252c7 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -16,6 +16,8 @@ #ifndef DRV_OUTPUT_BASE_H #define DRV_OUTPUT_BASE_H #include "drvBase.h" +#include +#include /*! @brief Base class for I2C Output Drivers. @@ -85,6 +87,16 @@ class drvOutputBase : public drvBase { // noop } + /*! + @brief High-level fn, executes a call to the appropriate driver function(s) + based on the message data type to write. + @param msg_backpack_write + Pointer to a wippersnapper_i2c_output_LedBackpackWrite message. + */ + void LedBackpackWrite(wippersnapper_i2c_output_LedBackpackWrite *msg_backpack_write) { + + } + protected: // TODO }; diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index 0de0b47c4..014dc9ac4 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -335,14 +335,12 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cDeviceAddOrReplace_size 141 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 +#define wippersnapper_i2c_I2cDeviceOutputWrite_size 145 #define wippersnapper_i2c_I2cDeviceRemove_size 52 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 #if defined(wippersnapper_sensor_SensorEvent_size) #define wippersnapper_i2c_I2cDeviceEvent_size (142 + 15*wippersnapper_sensor_SensorEvent_size) #endif -#if defined(wippersnapper_i2c_output_LedBackpackWrite_size) && defined(wippersnapper_i2c_output_CharLCDWrite_size) -#define wippersnapper_i2c_I2cDeviceOutputWrite_size (64 + wippersnapper_i2c_output_LedBackpackWrite_size + wippersnapper_i2c_output_CharLCDWrite_size) -#endif #ifdef __cplusplus } /* extern "C" */ diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h index b57f2a0ca..e42a9b5ed 100644 --- a/src/protos/i2c_output.pb.h +++ b/src/protos/i2c_output.pb.h @@ -60,7 +60,7 @@ typedef struct _wippersnapper_i2c_output_I2cOutputAdd { typedef struct _wippersnapper_i2c_output_LedBackpackWrite { pb_size_t which_message; union { - pb_callback_t text; /* * Text to write to the LED backpack. * */ + char text[20]; /* * Text to write to the LED backpack. * */ int32_t number_int; /* * Number to write to the LED backpack. * */ float number_float; /* * Float to write to the LED backpack. * */ } message; @@ -76,7 +76,7 @@ typedef struct _wippersnapper_i2c_output_LedBackpackWrite { typedef struct _wippersnapper_i2c_output_CharLCDWrite { pb_size_t which_message; union { - pb_callback_t text; /* * Text to write to the character LCD. * */ + char text[20]; /* * Text to write to the character LCD. * */ int32_t number_int; /* * Number to write to the character LCD. * */ float number_float; /* * Float to write to the character LCD. * */ } message; @@ -111,13 +111,13 @@ extern "C" { #define wippersnapper_i2c_output_LedBackpackConfig_init_default {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} #define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_default {0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {{{NULL}, NULL}}, 0, "", 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {""}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {""}, 0, "", 0} #define wippersnapper_i2c_output_LedBackpackConfig_init_zero {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} #define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_zero {0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {{{NULL}, NULL}}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {{{NULL}, NULL}}, 0, "", 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {""}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {""}, 0, "", 0} /* Field tags (for use in manual encoding/decoding) */ #define wippersnapper_i2c_output_LedBackpackConfig_brightness_tag 1 @@ -167,7 +167,7 @@ X(a, STATIC, ONEOF, MESSAGE, (config,char_lcd_config,config.char_lcd_confi #define wippersnapper_i2c_output_I2cOutputAdd_config_char_lcd_config_MSGTYPE wippersnapper_i2c_output_CharLCDConfig #define wippersnapper_i2c_output_LedBackpackWrite_FIELDLIST(X, a) \ -X(a, CALLBACK, ONEOF, STRING, (message,text,message.text), 1) \ +X(a, STATIC, ONEOF, STRING, (message,text,message.text), 1) \ X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ X(a, STATIC, SINGULAR, INT32, brightness, 4) \ @@ -175,17 +175,17 @@ X(a, STATIC, SINGULAR, UENUM, blink_rate, 5) \ X(a, STATIC, SINGULAR, BOOL, enable_scroll_marquee, 6) \ X(a, STATIC, SINGULAR, FLOAT, scroll_marquee_speed, 7) \ X(a, STATIC, SINGULAR, BOOL, enable_ampm_dot, 8) -#define wippersnapper_i2c_output_LedBackpackWrite_CALLBACK pb_default_field_callback +#define wippersnapper_i2c_output_LedBackpackWrite_CALLBACK NULL #define wippersnapper_i2c_output_LedBackpackWrite_DEFAULT NULL #define wippersnapper_i2c_output_CharLCDWrite_FIELDLIST(X, a) \ -X(a, CALLBACK, ONEOF, STRING, (message,text,message.text), 1) \ +X(a, STATIC, ONEOF, STRING, (message,text,message.text), 1) \ X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ X(a, STATIC, SINGULAR, BOOL, enable_backlight, 4) \ X(a, STATIC, SINGULAR, STRING, backlight_color, 5) \ X(a, STATIC, SINGULAR, BOOL, enable_scroll, 6) -#define wippersnapper_i2c_output_CharLCDWrite_CALLBACK pb_default_field_callback +#define wippersnapper_i2c_output_CharLCDWrite_CALLBACK NULL #define wippersnapper_i2c_output_CharLCDWrite_DEFAULT NULL extern const pb_msgdesc_t wippersnapper_i2c_output_LedBackpackConfig_msg; @@ -202,12 +202,12 @@ extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDWrite_msg; #define wippersnapper_i2c_output_CharLCDWrite_fields &wippersnapper_i2c_output_CharLCDWrite_msg /* Maximum encoded size of messages (where known) */ -/* wippersnapper_i2c_output_LedBackpackWrite_size depends on runtime parameters */ -/* wippersnapper_i2c_output_CharLCDWrite_size depends on runtime parameters */ -#define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_I2cOutputAdd_size +#define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_CharLCDWrite_size #define wippersnapper_i2c_output_CharLCDConfig_size 30 +#define wippersnapper_i2c_output_CharLCDWrite_size 46 #define wippersnapper_i2c_output_I2cOutputAdd_size 32 #define wippersnapper_i2c_output_LedBackpackConfig_size 13 +#define wippersnapper_i2c_output_LedBackpackWrite_size 43 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index b07af7c06..79e519ce3 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -256,13 +256,13 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; #define wippersnapper_signal_DeviceToBroker_fields &wippersnapper_signal_DeviceToBroker_msg /* Maximum encoded size of messages (where known) */ -#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f93[(7 + wippersnapper_i2c_I2cDeviceOutputWrite_size)]; char f0[145];}; +#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[149];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; #endif -#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) && defined(wippersnapper_i2c_I2cDeviceOutputWrite_size) +#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) #define WIPPERSNAPPER_SIGNAL_SIGNAL_PB_H_MAX_SIZE wippersnapper_signal_BrokerToDevice_size #define wippersnapper_signal_BrokerToDevice_size (0 + sizeof(union wippersnapper_signal_BrokerToDevice_payload_size_union)) #endif From 263fbfae2ad1ea2e74f5975d355277c2da024346 Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 8 May 2025 11:48:02 -0400 Subject: [PATCH 08/26] Implement WriteX funcs for each value type and link within drvOutputBase --- src/components/i2c/controller.cpp | 4 + .../i2c/drivers/drvOutQuadAlphaNum.h | 78 +++++++++++++++---- src/components/i2c/drivers/drvOutputBase.h | 37 ++++++++- src/protos/i2c.pb.h | 2 +- src/protos/i2c_output.pb.h | 29 +++---- src/protos/signal.pb.h | 2 +- 6 files changed, 119 insertions(+), 33 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 170c218fe..fd2438202 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -818,6 +818,10 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_led_backpack_write) { // TODO WS_DEBUG_PRINTLN("[i2c] LED backpack write!"); + if (!driver->LedBackpackWrite(&_i2c_model->GetI2cDeviceOutputWriteMsg()->led_backpack_write)) { + WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to LED backpack!"); + return false; + } } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_char_lcd_write) { WS_DEBUG_PRINTLN("[i2c] Char LCD write not implemented yet!"); } else { diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index 74261cc03..1ccb5309f 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -18,10 +18,12 @@ #include "drvOutputBase.h" #include +#include #define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 #define LED_BACKPACK_ALIGNMENT_LEFT 1 #define LED_BACKPACK_ALIGNMENT_RIGHT 2 +#define LED_MAX_CHARS 4 /*! @brief Class that provides a driver interface for Quad Alphanumeric @@ -64,6 +66,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { _alpha4 = new Adafruit_AlphaNum4(); bool did_begin = _alpha4->begin(_address, _i2c); _alpha4->setBrightness(_brightness); + return did_begin; } /*! @@ -83,6 +86,18 @@ class drvOutQuadAlphaNum : public drvOutputBase { _brightness = brightness; } + /*! + @brief Sets the brightness of the LED backpack. + @param b + The brightness value, from 0 (off) to 15 (full brightness). + */ + void SetLedBackpackBrightness(uint8_t b) { + if (_alpha4 == nullptr) { + return; + } + _alpha4->setBrightness(b); + } + /*! @brief Writes the first four characters of a message to the quad alphanumeric display. @@ -90,12 +105,46 @@ class drvOutQuadAlphaNum : public drvOutputBase { The message to be displayed. */ void WriteMessage(const char *message) { - if (_alpha4 == nullptr) { + if (_alpha4 == nullptr || message == nullptr) { return; } - for (size_t i = 0; i < 4; i++) { - _alpha4->writeDigitAscii(i, message[i]); + // Clear before writing + _alpha4->clear(); + + // Calculate the number of characters to display + size_t len_display = min(strlen(message), (size_t)LED_MAX_CHARS); + + // Set the starting position based on alignment + int pos_start; + if (_alignment == LED_BACKPACK_ALIGNMENT_LEFT) { + pos_start = 0; // start at the leftmost position of the display + } else { + // Exclude decimal points from the character count because those get + // displayed on a "special" segment of the LED display + int seg_chars = 0; + for (size_t i = 0; i < len_display; i++) { + if (message[i] != '.') { + seg_chars++; + } + } + // start at the rightmost position of the display + pos_start = LED_MAX_CHARS - seg_chars; + } + + // Write to the display's buffer + int cur_idx = pos_start; + for (size_t i = 0; i < len_display; i++) { + // Look-ahead for a decimal point to attach to the current character + bool display_dot = false; + if (i + 1 < len_display && message[i + 1] == '.') { + display_dot = true; + i++; + } + // Write the character to the display buffer + _alpha4->writeDigitAscii(cur_idx, message[i], display_dot); + cur_idx++; } + // Issue the buffered data in RAM to the display _alpha4->writeDisplay(); } @@ -106,10 +155,9 @@ class drvOutQuadAlphaNum : public drvOutputBase { displayed. */ void WriteValue(float value) { - if (_alpha4 == nullptr) { - return; - } - // TODO! + char message[LED_MAX_CHARS + 1]; + snprintf(message, sizeof(message), "%.4f", value); + WriteMessage(message); } /*! @@ -119,17 +167,19 @@ class drvOutQuadAlphaNum : public drvOutputBase { displayed. */ void WriteValue(int32_t value) { - if (_alpha4 == nullptr) { - return; - } - // TODO! + char message[LED_MAX_CHARS + 1]; + snprintf(message, sizeof(message), "%ld", value); + WriteMessage(message); } protected: Adafruit_AlphaNum4 *_alpha4 = - nullptr; ///< ptr to a 4-digit alphanumeric display object - int32_t _brightness; - uint32_t _alignment; + nullptr; ///< ptr to a 4-digit alphanumeric display object + int32_t _brightness; ///< Brightness of the LED backpack, from 0 (off) to 15 + ///< (full brightness) + uint32_t _alignment = + LED_BACKPACK_ALIGNMENT_RIGHT; ///< Determines L/R alignment of the message + ///< displayed }; #endif // DRV_OUT_QUAD_ALPHANUM_H \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index c1d6252c7..1ccf6a508 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -88,16 +88,45 @@ class drvOutputBase : public drvBase { } /*! - @brief High-level fn, executes a call to the appropriate driver function(s) - based on the message data type to write. + @brief Sets the brightness of the LED backpack. + @param b + The brightness value, from 0 (off) to 15 (full brightness). + */ + virtual void SetLedBackpackBrightness(uint8_t b) { + // noop + } + + /*! + @brief High-level fn, executes a call to the appropriate driver + function(s) based on the message data type to write. @param msg_backpack_write Pointer to a wippersnapper_i2c_output_LedBackpackWrite message. + @returns True if the message was written successfully, False otherwise. */ - void LedBackpackWrite(wippersnapper_i2c_output_LedBackpackWrite *msg_backpack_write) { + bool LedBackpackWrite( + wippersnapper_i2c_output_LedBackpackWrite *msg_backpack_write) { + // Check if we should adjust brightness + if (msg_backpack_write->adjust_brightness) + SetLedBackpackBrightness((uint8_t)msg_backpack_write->brightness); + // Write the message to a LED backpack + switch (msg_backpack_write->which_message) { + case wippersnapper_i2c_output_LedBackpackWrite_text_tag: + WriteMessage(msg_backpack_write->message.text); + break; + case wippersnapper_i2c_output_LedBackpackWrite_number_int_tag: + WriteValue(msg_backpack_write->message.number_int); + break; + case wippersnapper_i2c_output_LedBackpackWrite_number_float_tag: + WriteValue(msg_backpack_write->message.number_float); + break; + default: + return false; + break; + } + return true; } protected: - // TODO }; #endif // DRV_OUTPUT_BASE_H \ No newline at end of file diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index 014dc9ac4..88d581a45 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -335,7 +335,7 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cDeviceAddOrReplace_size 141 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 -#define wippersnapper_i2c_I2cDeviceOutputWrite_size 145 +#define wippersnapper_i2c_I2cDeviceOutputWrite_size 147 #define wippersnapper_i2c_I2cDeviceRemove_size 52 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 #if defined(wippersnapper_sensor_SensorEvent_size) diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h index e42a9b5ed..ebce9fffe 100644 --- a/src/protos/i2c_output.pb.h +++ b/src/protos/i2c_output.pb.h @@ -64,6 +64,7 @@ typedef struct _wippersnapper_i2c_output_LedBackpackWrite { int32_t number_int; /* * Number to write to the LED backpack. * */ float number_float; /* * Float to write to the LED backpack. * */ } message; + bool adjust_brightness; /* * Optionally used to enable the brightness tag. * */ int32_t brightness; /* * Optionally adjusts the brightness from 0 (off) to 15 (full brightness). * */ wippersnapper_i2c_output_LedBackpackBlinkRate blink_rate; /* * Optionally sets the blink rate for the LED backpack. * */ bool enable_scroll_marquee; /* * Optionally enables automatic text scrolling * */ @@ -111,12 +112,12 @@ extern "C" { #define wippersnapper_i2c_output_LedBackpackConfig_init_default {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} #define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_default {0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {""}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} #define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {""}, 0, "", 0} #define wippersnapper_i2c_output_LedBackpackConfig_init_zero {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} #define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_zero {0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {""}, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} #define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {""}, 0, "", 0} /* Field tags (for use in manual encoding/decoding) */ @@ -131,11 +132,12 @@ extern "C" { #define wippersnapper_i2c_output_LedBackpackWrite_text_tag 1 #define wippersnapper_i2c_output_LedBackpackWrite_number_int_tag 2 #define wippersnapper_i2c_output_LedBackpackWrite_number_float_tag 3 -#define wippersnapper_i2c_output_LedBackpackWrite_brightness_tag 4 -#define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_tag 5 -#define wippersnapper_i2c_output_LedBackpackWrite_enable_scroll_marquee_tag 6 -#define wippersnapper_i2c_output_LedBackpackWrite_scroll_marquee_speed_tag 7 -#define wippersnapper_i2c_output_LedBackpackWrite_enable_ampm_dot_tag 8 +#define wippersnapper_i2c_output_LedBackpackWrite_adjust_brightness_tag 4 +#define wippersnapper_i2c_output_LedBackpackWrite_brightness_tag 5 +#define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_tag 6 +#define wippersnapper_i2c_output_LedBackpackWrite_enable_scroll_marquee_tag 7 +#define wippersnapper_i2c_output_LedBackpackWrite_scroll_marquee_speed_tag 8 +#define wippersnapper_i2c_output_LedBackpackWrite_enable_ampm_dot_tag 9 #define wippersnapper_i2c_output_CharLCDWrite_text_tag 1 #define wippersnapper_i2c_output_CharLCDWrite_number_int_tag 2 #define wippersnapper_i2c_output_CharLCDWrite_number_float_tag 3 @@ -170,11 +172,12 @@ X(a, STATIC, ONEOF, MESSAGE, (config,char_lcd_config,config.char_lcd_confi X(a, STATIC, ONEOF, STRING, (message,text,message.text), 1) \ X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ -X(a, STATIC, SINGULAR, INT32, brightness, 4) \ -X(a, STATIC, SINGULAR, UENUM, blink_rate, 5) \ -X(a, STATIC, SINGULAR, BOOL, enable_scroll_marquee, 6) \ -X(a, STATIC, SINGULAR, FLOAT, scroll_marquee_speed, 7) \ -X(a, STATIC, SINGULAR, BOOL, enable_ampm_dot, 8) +X(a, STATIC, SINGULAR, BOOL, adjust_brightness, 4) \ +X(a, STATIC, SINGULAR, INT32, brightness, 5) \ +X(a, STATIC, SINGULAR, UENUM, blink_rate, 6) \ +X(a, STATIC, SINGULAR, BOOL, enable_scroll_marquee, 7) \ +X(a, STATIC, SINGULAR, FLOAT, scroll_marquee_speed, 8) \ +X(a, STATIC, SINGULAR, BOOL, enable_ampm_dot, 9) #define wippersnapper_i2c_output_LedBackpackWrite_CALLBACK NULL #define wippersnapper_i2c_output_LedBackpackWrite_DEFAULT NULL @@ -207,7 +210,7 @@ extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDWrite_msg; #define wippersnapper_i2c_output_CharLCDWrite_size 46 #define wippersnapper_i2c_output_I2cOutputAdd_size 32 #define wippersnapper_i2c_output_LedBackpackConfig_size 13 -#define wippersnapper_i2c_output_LedBackpackWrite_size 43 +#define wippersnapper_i2c_output_LedBackpackWrite_size 45 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index 79e519ce3..e31e82df3 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -257,7 +257,7 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; /* Maximum encoded size of messages (where known) */ #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[149];}; +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[151];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; From c9a20b3f50e6abaef85a2aa449ca8e801e550676 Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 8 May 2025 14:13:40 -0400 Subject: [PATCH 09/26] add 0a74dc96f50785d7f29d2f44b409033fd880d600 --- src/components/i2c/controller.cpp | 23 +++++++++---------- .../i2c/drivers/drvOutQuadAlphaNum.h | 7 +++--- src/protos/i2c.pb.h | 11 +++++---- 3 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index fd2438202..55119f54d 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -459,7 +459,7 @@ I2cController::~I2cController() { */ /***********************************************************************/ bool I2cController::RemoveDriver(uint32_t address) { - // Safely remove the i2c sensor drivers from the vector and free memory + // Safely remove the i2c sensor driver from the vector and free memory for (drvBase *driver : _i2c_drivers) { if (driver == nullptr) continue; @@ -475,7 +475,7 @@ bool I2cController::RemoveDriver(uint32_t address) { return true; } - // Safely remove the i2c output drivers from the vector and free memory + // This was an output driver type, safely remove the i2c output driver from the vector and free memory for (drvOutputBase *driver : _i2c_drivers_output) { if (driver == nullptr) continue; @@ -612,13 +612,7 @@ bool I2cController::Handle_I2cDeviceRemove(pb_istream_t *stream) { // TODO: Scan the mux to see what drivers are attached? wippersnapper_i2c_I2cBusScanned scan_results; _i2c_bus_default->ScanMux(&scan_results); - // DEBUG - TODO REMOVE - Print out the scan results for (int i = 0; i < scan_results.i2c_bus_found_devices_count; i++) { - WS_DEBUG_PRINT("[i2c] Found device at address: "); - WS_DEBUG_PRINT( - scan_results.i2c_bus_found_devices[i].i2c_device_address, HEX); - WS_DEBUG_PRINT(" on mux channel #: "); - WS_DEBUG_PRINTLN( scan_results.i2c_bus_found_devices[i].i2c_mux_channel); // Select the channel and remove the device _i2c_bus_default->SelectMuxChannel( @@ -794,7 +788,7 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { } wippersnapper_i2c_I2cDeviceDescriptor descriptor = _i2c_model->GetI2cDeviceOutputWriteMsg()->i2c_device_description; - // Get the driver + // Attempt to find the driver drvOutputBase *driver = nullptr; for (auto *drv : _i2c_drivers_output) { if (drv == nullptr) @@ -807,6 +801,12 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { break; } + if (driver == nullptr) { + WS_DEBUG_PRINT("[i2c] ERROR: Unable to find driver for device at addr 0x"); + WS_DEBUG_PRINTLN(descriptor.i2c_device_address, HEX); + return false; + } + // Optionally configure the I2C MUX uint32_t mux_channel = driver->GetMuxChannel(); WS_DEBUG_PRINTLN(mux_channel); @@ -816,8 +816,7 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { // Determine which driver cb function to use if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_led_backpack_write) { - // TODO - WS_DEBUG_PRINTLN("[i2c] LED backpack write!"); + WS_DEBUG_PRINT("[i2c] Writing message to LED backpack..."); if (!driver->LedBackpackWrite(&_i2c_model->GetI2cDeviceOutputWriteMsg()->led_backpack_write)) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to LED backpack!"); return false; @@ -828,7 +827,6 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine I2C Output Write type!"); return false; } - return true; } @@ -1045,6 +1043,7 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { // Create and publish the I2cDeviceAddedorReplaced message to the broker WS_DEBUG_PRINTLN("[i2c] MQTT Publish I2cDeviceAddedorReplaced not yet " "implemented!"); + // TODO! /* if (!PublishI2cDeviceAddedorReplaced(device_descriptor, device_status)) return false; */ } diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index 1ccb5309f..e6fd60b93 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -23,6 +23,7 @@ #define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 #define LED_BACKPACK_ALIGNMENT_LEFT 1 #define LED_BACKPACK_ALIGNMENT_RIGHT 2 +#define LED_BACKPACK_ALIGNMENT_DEFAULT LED_BACKPACK_ALIGNMENT_LEFT #define LED_MAX_CHARS 4 /*! @@ -80,8 +81,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { if (alignment == LED_BACKPACK_ALIGNMENT_RIGHT) { _alignment = LED_BACKPACK_ALIGNMENT_RIGHT; } else { - // default: left alignment - _alignment = LED_BACKPACK_ALIGNMENT_LEFT; + _alignment = LED_BACKPACK_ALIGNMENT_DEFAULT; } _brightness = brightness; } @@ -177,8 +177,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { nullptr; ///< ptr to a 4-digit alphanumeric display object int32_t _brightness; ///< Brightness of the LED backpack, from 0 (off) to 15 ///< (full brightness) - uint32_t _alignment = - LED_BACKPACK_ALIGNMENT_RIGHT; ///< Determines L/R alignment of the message + uint32_t _alignment = LED_BACKPACK_ALIGNMENT_DEFAULT; ///< Determines L/R alignment of the message ///< displayed }; diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index 88d581a45..c3c81442c 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -102,6 +102,7 @@ typedef struct _wippersnapper_i2c_I2cDeviceAddedOrReplaced { typedef struct _wippersnapper_i2c_I2cDeviceRemove { bool has_i2c_device_description; wippersnapper_i2c_I2cDeviceDescriptor i2c_device_description; /* * The I2c device's address and metadata. */ + bool is_output_device; /* * Determines if the device is an output device.* */ } wippersnapper_i2c_I2cDeviceRemove; /* * @@ -170,7 +171,7 @@ extern "C" { #define wippersnapper_i2c_I2cBusScanned_init_default {0, {wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default, wippersnapper_i2c_I2cDeviceDescriptor_init_default}, _wippersnapper_i2c_I2cBusStatus_MIN} #define wippersnapper_i2c_I2cDeviceAddOrReplace_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, "", 0, 0, {_wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN}, 0, 0, false, wippersnapper_i2c_output_I2cOutputAdd_init_default} #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, _wippersnapper_i2c_I2cBusStatus_MIN, _wippersnapper_i2c_I2cDeviceStatus_MIN} -#define wippersnapper_i2c_I2cDeviceRemove_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default} +#define wippersnapper_i2c_I2cDeviceRemove_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0} #define wippersnapper_i2c_I2cDeviceRemoved_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0} #define wippersnapper_i2c_I2cDeviceEvent_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0, {wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default}} #define wippersnapper_i2c_I2cDeviceOutputWrite_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, false, wippersnapper_i2c_output_LedBackpackWrite_init_default, false, wippersnapper_i2c_output_CharLCDWrite_init_default} @@ -180,7 +181,7 @@ extern "C" { #define wippersnapper_i2c_I2cBusScanned_init_zero {0, {wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, wippersnapper_i2c_I2cDeviceDescriptor_init_zero}, _wippersnapper_i2c_I2cBusStatus_MIN} #define wippersnapper_i2c_I2cDeviceAddOrReplace_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, "", 0, 0, {_wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN, _wippersnapper_sensor_SensorType_MIN}, 0, 0, false, wippersnapper_i2c_output_I2cOutputAdd_init_zero} #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, _wippersnapper_i2c_I2cBusStatus_MIN, _wippersnapper_i2c_I2cDeviceStatus_MIN} -#define wippersnapper_i2c_I2cDeviceRemove_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero} +#define wippersnapper_i2c_I2cDeviceRemove_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0} #define wippersnapper_i2c_I2cDeviceRemoved_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0} #define wippersnapper_i2c_I2cDeviceEvent_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0, {wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero}} #define wippersnapper_i2c_I2cDeviceOutputWrite_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, false, wippersnapper_i2c_output_LedBackpackWrite_init_zero, false, wippersnapper_i2c_output_CharLCDWrite_init_zero} @@ -211,6 +212,7 @@ extern "C" { #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_i2c_bus_status_tag 2 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_i2c_device_status_tag 3 #define wippersnapper_i2c_I2cDeviceRemove_i2c_device_description_tag 1 +#define wippersnapper_i2c_I2cDeviceRemove_is_output_device_tag 2 #define wippersnapper_i2c_I2cDeviceRemoved_i2c_device_description_tag 1 #define wippersnapper_i2c_I2cDeviceRemoved_did_remove_tag 2 #define wippersnapper_i2c_I2cDeviceEvent_i2c_device_description_tag 1 @@ -274,7 +276,8 @@ X(a, STATIC, SINGULAR, UENUM, i2c_device_status, 3) #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor #define wippersnapper_i2c_I2cDeviceRemove_FIELDLIST(X, a) \ -X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) +X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) \ +X(a, STATIC, SINGULAR, BOOL, is_output_device, 2) #define wippersnapper_i2c_I2cDeviceRemove_CALLBACK NULL #define wippersnapper_i2c_I2cDeviceRemove_DEFAULT NULL #define wippersnapper_i2c_I2cDeviceRemove_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor @@ -336,7 +339,7 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 #define wippersnapper_i2c_I2cDeviceOutputWrite_size 147 -#define wippersnapper_i2c_I2cDeviceRemove_size 52 +#define wippersnapper_i2c_I2cDeviceRemove_size 54 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 #if defined(wippersnapper_sensor_SensorEvent_size) #define wippersnapper_i2c_I2cDeviceEvent_size (142 + 15*wippersnapper_sensor_SensorEvent_size) From eb2cfa1fbdfc6a4b514bde1cd2e60c2c40bd0155 Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 8 May 2025 16:53:31 -0400 Subject: [PATCH 10/26] Writing working for everything but floats --- src/components/i2c/controller.cpp | 124 +++++++++++------- src/components/i2c/controller.h | 16 ++- .../i2c/drivers/drvOutQuadAlphaNum.h | 26 +++- 3 files changed, 109 insertions(+), 57 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 55119f54d..7e7558b03 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -455,42 +455,50 @@ I2cController::~I2cController() { @brief Removes an I2C driver from the controller and frees memory @param address The desired I2C device's address. + @param is_output_device + True if the driver is an output device, False otherwise. @returns True if the driver was removed, False otherwise. */ /***********************************************************************/ -bool I2cController::RemoveDriver(uint32_t address) { - // Safely remove the i2c sensor driver from the vector and free memory - for (drvBase *driver : _i2c_drivers) { - if (driver == nullptr) - continue; +bool I2cController::RemoveDriver(uint32_t address, bool is_output_device) { + if (!is_output_device) { + // Safely remove the i2c sensor driver from the vector and free memory + for (drvBase *driver : _i2c_drivers) { + if (driver == nullptr) + continue; - if (driver->GetAddress() != address) - continue; + if (driver->GetAddress() != address) + continue; - auto it = std::find(_i2c_drivers.begin(), _i2c_drivers.end(), driver); - if (it != _i2c_drivers.end()) { - _i2c_drivers.erase(it); + auto it = std::find(_i2c_drivers.begin(), _i2c_drivers.end(), driver); + if (it != _i2c_drivers.end()) { + _i2c_drivers.erase(it); + } + delete driver; + return true; } - delete driver; - return true; - } - - // This was an output driver type, safely remove the i2c output driver from the vector and free memory - for (drvOutputBase *driver : _i2c_drivers_output) { - if (driver == nullptr) - continue; + } else { + // This was an output driver type, safely remove the i2c output driver from + // the vector and free memory + for (drvOutputBase *driver : _i2c_drivers_output) { + if (driver == nullptr) + continue; - if (driver->GetAddress() != address) - continue; + if (driver->GetAddress() != address) + continue; - auto it = std::find(_i2c_drivers_output.begin(), _i2c_drivers_output.end(), - driver); - if (it != _i2c_drivers_output.end()) { - _i2c_drivers_output.erase(it); + auto it = std::find(_i2c_drivers_output.begin(), + _i2c_drivers_output.end(), driver); + if (it != _i2c_drivers_output.end()) { + _i2c_drivers_output.erase(it); + } + delete driver; + return true; } - delete driver; - return true; } + + // We didn't find the driver to remove + WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to find driver to remove!"); return false; } @@ -585,8 +593,8 @@ bool I2cController::Handle_I2cDeviceRemove(pb_istream_t *stream) { strlen(msgRemove->i2c_device_description.i2c_bus_sda) == 0) { WS_DEBUG_PRINTLN("[i2c] Removing device from default bus..."); if (!_i2c_bus_default->HasMux()) { - // TODO: Implement remove, straightforward - if (!RemoveDriver(msgRemove->i2c_device_description.i2c_device_address)) { + if (!RemoveDriver(msgRemove->i2c_device_description.i2c_device_address, + msgRemove->is_output_device)) { WS_DEBUG_PRINTLN( "[i2c] ERROR: Failed to remove i2c device from default bus!"); did_remove = false; @@ -596,11 +604,10 @@ bool I2cController::Handle_I2cDeviceRemove(pb_istream_t *stream) { // Case 1: Is the I2C device connected to a MUX? if (msgRemove->i2c_device_description.i2c_mux_address != 0xFFFF && msgRemove->i2c_device_description.i2c_mux_channel >= 0) { - // TODO: Remove the device from the mux's channel and delete the driver _i2c_bus_default->SelectMuxChannel( msgRemove->i2c_device_description.i2c_mux_channel); - if (!RemoveDriver( - msgRemove->i2c_device_description.i2c_device_address)) { + if (!RemoveDriver(msgRemove->i2c_device_description.i2c_device_address, + msgRemove->is_output_device)) { WS_DEBUG_PRINTLN( "[i2c] ERROR: Failed to remove i2c device from default bus!"); did_remove = false; @@ -609,16 +616,14 @@ bool I2cController::Handle_I2cDeviceRemove(pb_istream_t *stream) { // Case 2: Is the I2C device a MUX? if (msgRemove->i2c_device_description.i2c_device_address == msgRemove->i2c_device_description.i2c_mux_address) { - // TODO: Scan the mux to see what drivers are attached? wippersnapper_i2c_I2cBusScanned scan_results; _i2c_bus_default->ScanMux(&scan_results); for (int i = 0; i < scan_results.i2c_bus_found_devices_count; i++) { - scan_results.i2c_bus_found_devices[i].i2c_mux_channel); // Select the channel and remove the device _i2c_bus_default->SelectMuxChannel( scan_results.i2c_bus_found_devices[i].i2c_mux_channel); - RemoveDriver( - scan_results.i2c_bus_found_devices[i].i2c_device_address); + RemoveDriver(scan_results.i2c_bus_found_devices[i].i2c_device_address, + msgRemove->is_output_device); } _i2c_bus_default->RemoveMux(); } @@ -786,7 +791,8 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { "message!"); return false; } - wippersnapper_i2c_I2cDeviceDescriptor descriptor = _i2c_model->GetI2cDeviceOutputWriteMsg()->i2c_device_description; + wippersnapper_i2c_I2cDeviceDescriptor descriptor = + _i2c_model->GetI2cDeviceOutputWriteMsg()->i2c_device_description; // Attempt to find the driver drvOutputBase *driver = nullptr; @@ -816,8 +822,9 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { // Determine which driver cb function to use if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_led_backpack_write) { - WS_DEBUG_PRINT("[i2c] Writing message to LED backpack..."); - if (!driver->LedBackpackWrite(&_i2c_model->GetI2cDeviceOutputWriteMsg()->led_backpack_write)) { + WS_DEBUG_PRINTLN("[i2c] Writing message to LED backpack..."); + if (!driver->LedBackpackWrite( + &_i2c_model->GetI2cDeviceOutputWriteMsg()->led_backpack_write)) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to LED backpack!"); return false; } @@ -942,12 +949,14 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { did_init = true; } } else { + WS_DEBUG_PRINT("[i2c] Creating an I2C output driver..."); drv_out = CreateI2cOutputDrv( device_name, bus, device_descriptor.i2c_device_address, device_descriptor.i2c_mux_channel, device_status); if (drv_out != nullptr) { did_init = true; } + WS_DEBUG_PRINTLN("OK!"); } if (!did_init) { @@ -966,6 +975,7 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { if (!is_output) { drv->SetMuxAddress(device_descriptor.i2c_mux_address); } else { + WS_DEBUG_PRINTLN("[i2c] Setting MUX address for output driver..."); drv_out->SetMuxAddress(device_descriptor.i2c_mux_address); } WS_DEBUG_PRINTLN("[i2c] Set driver to use MUX"); @@ -977,6 +987,7 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { _i2c_model->GetI2cDeviceAddOrReplaceMsg() ->i2c_device_description.i2c_bus_sda); } else { + WS_DEBUG_PRINTLN("[i2c] Setting alt. I2C bus for output driver..."); drv_out->EnableAltI2CBus(_i2c_model->GetI2cDeviceAddOrReplaceMsg() ->i2c_device_description.i2c_bus_scl, _i2c_model->GetI2cDeviceAddOrReplaceMsg() @@ -995,19 +1006,22 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { drv->SetSensorPeriod( _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_device_period); } else { + WS_DEBUG_PRINTLN("[i2c] Configuring output driver..."); // Configure Output-driver settings pb_size_t config = _i2c_model->GetI2cDeviceAddOrReplaceMsg()->i2c_output_add.which_config; if (config == wippersnapper_i2c_output_I2cOutputAdd_led_backpack_config_tag) { - // TODO: Configure LED Backpack + WS_DEBUG_PRINTLN("[i2c] Configuring LED backpack..."); wippersnapper_i2c_output_LedBackpackConfig cfg = _i2c_model->GetI2cDeviceAddOrReplaceMsg() ->i2c_output_add.config.led_backpack_config; + WS_DEBUG_PRINT("[i2c] Got cfg, calling ConfigureLEDBackpack..."); drv_out->ConfigureLEDBackpack(cfg.brightness, cfg.alignment); + WS_DEBUG_PRINTLN("OK!"); } else if (config == wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag) { - // TODO: Configure Char LCD + WS_DEBUG_PRINTLN("[i2c] Configuring char LCD..."); } else { WS_DEBUG_PRINTLN( "[i2c] ERROR: Unknown config specified for output driver!"); @@ -1015,17 +1029,31 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { } } - if (!drv->begin()) { - if (WsV2._sdCardV2->isModeOffline()) { - WsV2.haltErrorV2("[i2c] Driver failed to initialize!\n\tDid you set " - "the correct value for i2cDeviceName?\n\tDid you set " - "the correct value for" - "i2cDeviceAddress?", - WS_LED_STATUS_ERROR_RUNTIME, false); + if (!is_output) { + if (!drv->begin()) { + if (WsV2._sdCardV2->isModeOffline()) { + WsV2.haltErrorV2("[i2c] Driver failed to initialize!\n\tDid you set " + "the correct value for i2cDeviceName?\n\tDid you set " + "the correct value for" + "i2cDeviceAddress?", + WS_LED_STATUS_ERROR_RUNTIME, false); + } + } + _i2c_drivers.push_back(drv); + } else { + if (!drv_out->begin()) { + if (WsV2._sdCardV2->isModeOffline()) { + WsV2.haltErrorV2("[i2c] Driver failed to initialize!\n\tDid you set " + "the correct value for i2cDeviceName?\n\tDid you set " + "the correct value for" + "i2cDeviceAddress?", + WS_LED_STATUS_ERROR_RUNTIME, false); + } } + _i2c_drivers_output.push_back(drv_out); } - _i2c_drivers.push_back(drv); + WS_DEBUG_PRINTLN("[i2c] Driver initialized and added to controller: "); WS_DEBUG_PRINTLN(device_name); diff --git a/src/components/i2c/controller.h b/src/components/i2c/controller.h index 5b0b7196d..1b33087e0 100644 --- a/src/components/i2c/controller.h +++ b/src/components/i2c/controller.h @@ -20,7 +20,6 @@ // I2C Drivers #include "drivers/drvAdt7410.h" #include "drivers/drvAhtx0.h" -#include "drivers/drvOutQuadAlphaNum.h" #include "drivers/drvBase.h" ///< Base i2c input driver class #include "drivers/drvBh1750.h" #include "drivers/drvBme280.h" @@ -46,6 +45,7 @@ #include "drivers/drvMprls.h" #include "drivers/drvMs8607.h" #include "drivers/drvNau7802.h" +#include "drivers/drvOutQuadAlphaNum.h" #include "drivers/drvOutputBase.h" ///< Base i2c output driver class #include "drivers/drvPct2075.h" #include "drivers/drvPm25.h" @@ -98,15 +98,17 @@ class I2cController { bool IsBusStatusOK(bool is_alt_bus = false); bool InitMux(const char *name, uint32_t address, bool is_alt_bus); void ConfigureMuxChannel(uint32_t mux_channel, bool is_alt_bus); - bool RemoveDriver(uint32_t address); + bool RemoveDriver(uint32_t address, bool is_output_device); private: - I2cModel *_i2c_model = nullptr; ///< Pointer to an I2C model object - I2cOutputModel *_i2c_output_model = nullptr; ///< Pointer to an I2C output model object - I2cHardware *_i2c_bus_default = nullptr; ///< Pointer to the default I2C bus - I2cHardware *_i2c_bus_alt = nullptr; ///< Pointer to an alternative I2C bus + I2cModel *_i2c_model = nullptr; ///< Pointer to an I2C model object + I2cOutputModel *_i2c_output_model = + nullptr; ///< Pointer to an I2C output model object + I2cHardware *_i2c_bus_default = nullptr; ///< Pointer to the default I2C bus + I2cHardware *_i2c_bus_alt = nullptr; ///< Pointer to an alternative I2C bus std::vector _i2c_drivers; ///< Vector of ptrs to I2C input drivers - std::vector _i2c_drivers_output; ///< Vector of ptrs to I2C output drivers + std::vector + _i2c_drivers_output; ///< Vector of ptrs to I2C output drivers }; extern Wippersnapper_V2 WsV2; ///< Wippersnapper V2 instance #endif // WS_I2C_CONTROLLER_H \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index e6fd60b93..714658e7a 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -78,12 +78,14 @@ class drvOutQuadAlphaNum : public drvOutputBase { The alignment of the LED backpack. */ void ConfigureLEDBackpack(int32_t brightness, uint32_t alignment) { + WS_DEBUG_PRINTLN("[i2c] drvOutQuadAlphaNum::ConfigureLEDBackpack() called"); if (alignment == LED_BACKPACK_ALIGNMENT_RIGHT) { _alignment = LED_BACKPACK_ALIGNMENT_RIGHT; } else { _alignment = LED_BACKPACK_ALIGNMENT_DEFAULT; } _brightness = brightness; + WS_DEBUG_PRINTLN("[i2c] drvOutQuadAlphaNum::configured"); } /*! @@ -131,17 +133,37 @@ class drvOutQuadAlphaNum : public drvOutputBase { pos_start = LED_MAX_CHARS - seg_chars; } + WS_DEBUG_PRINT("Message to display: "); + WS_DEBUG_PRINT(message); + WS_DEBUG_PRINT(" with len_display: "); + WS_DEBUG_PRINT(len_display); + WS_DEBUG_PRINT(" at pos_start: "); + WS_DEBUG_PRINT(pos_start); + + // TODO FRIDAY + // NOTE: If there's a ., increment len_display by 1 to account for the decimal + // Write to the display's buffer int cur_idx = pos_start; for (size_t i = 0; i < len_display; i++) { + // Save the character because if there's a decimal, we need to skip it in the buffer + char ch = message[i]; + // Look-ahead for a decimal point to attach to the current character bool display_dot = false; if (i + 1 < len_display && message[i + 1] == '.') { display_dot = true; i++; } + // Write the character to the display buffer - _alpha4->writeDigitAscii(cur_idx, message[i], display_dot); + WS_DEBUG_PRINT("Writing char: "); + WS_DEBUG_PRINT(message[i]); + WS_DEBUG_PRINT(" at index: "); + WS_DEBUG_PRINT(cur_idx); + WS_DEBUG_PRINT(" with dot: "); + WS_DEBUG_PRINTLN(display_dot); + _alpha4->writeDigitAscii(cur_idx, ch, display_dot); cur_idx++; } // Issue the buffered data in RAM to the display @@ -156,7 +178,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { */ void WriteValue(float value) { char message[LED_MAX_CHARS + 1]; - snprintf(message, sizeof(message), "%.4f", value); + snprintf(message, sizeof(message), "%.5f", value); WriteMessage(message); } From 878d186c8e2f27157e32a7182cf25df231355536 Mon Sep 17 00:00:00 2001 From: brentru Date: Fri, 9 May 2025 11:39:46 -0400 Subject: [PATCH 11/26] Fix float issues --- src/components/i2c/drivers/drvOutQuadAlphaNum.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index 714658e7a..cd858d001 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -133,12 +133,13 @@ class drvOutQuadAlphaNum : public drvOutputBase { pos_start = LED_MAX_CHARS - seg_chars; } + WS_DEBUG_PRINT("Message to display: "); - WS_DEBUG_PRINT(message); + WS_DEBUG_PRINTLN(message); WS_DEBUG_PRINT(" with len_display: "); - WS_DEBUG_PRINT(len_display); + WS_DEBUG_PRINTLN(len_display); WS_DEBUG_PRINT(" at pos_start: "); - WS_DEBUG_PRINT(pos_start); + WS_DEBUG_PRINTLN(pos_start); // TODO FRIDAY // NOTE: If there's a ., increment len_display by 1 to account for the decimal @@ -154,11 +155,12 @@ class drvOutQuadAlphaNum : public drvOutputBase { if (i + 1 < len_display && message[i + 1] == '.') { display_dot = true; i++; + len_display++; } // Write the character to the display buffer WS_DEBUG_PRINT("Writing char: "); - WS_DEBUG_PRINT(message[i]); + WS_DEBUG_PRINT(ch); WS_DEBUG_PRINT(" at index: "); WS_DEBUG_PRINT(cur_idx); WS_DEBUG_PRINT(" with dot: "); @@ -177,7 +179,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { displayed. */ void WriteValue(float value) { - char message[LED_MAX_CHARS + 1]; + char message[8+1]; snprintf(message, sizeof(message), "%.5f", value); WriteMessage(message); } From f06ac06b3057732b83d61d91341e25ef741f3c36 Mon Sep 17 00:00:00 2001 From: brentru Date: Fri, 9 May 2025 12:41:25 -0400 Subject: [PATCH 12/26] Implement begin and configure for a char lcd --- platformio.ini | 1 + src/components/i2c/controller.cpp | 8 +- src/components/i2c/controller.h | 1 + src/components/i2c/drivers/drvOutCharLcd.h | 89 +++++++++++++++++++ .../i2c/drivers/drvOutQuadAlphaNum.h | 17 ---- src/components/i2c/drivers/drvOutputBase.h | 14 +++ 6 files changed, 111 insertions(+), 19 deletions(-) create mode 100644 src/components/i2c/drivers/drvOutCharLcd.h diff --git a/platformio.ini b/platformio.ini index e68c95709..354b837c5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -90,6 +90,7 @@ lib_deps = https://github.com/bblanchon/ArduinoStreamUtils.git https://github.com/Sensirion/arduino-i2c-scd4x.git https://github.com/adafruit/Adafruit_LED_Backpack.git + https://github.com/adafruit/Adafruit_LiquidCrystal.git ; Common build environment for ESP32 platform [common:esp32] diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 7e7558b03..cda7a108d 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -365,6 +365,11 @@ static const std::map I2cFactoryOutput = { [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, const char *driver_name) -> drvOutputBase * { return new drvOutQuadAlphaNum(i2c, addr, mux_channel, driver_name); + }}, + {"charlcd", + [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, + const char *driver_name) -> drvOutputBase * { + return new drvOutCharLcd(i2c, addr, mux_channel, driver_name); }}}; ///< I2C output driver factory /*! @@ -822,7 +827,6 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { // Determine which driver cb function to use if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_led_backpack_write) { - WS_DEBUG_PRINTLN("[i2c] Writing message to LED backpack..."); if (!driver->LedBackpackWrite( &_i2c_model->GetI2cDeviceOutputWriteMsg()->led_backpack_write)) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to LED backpack!"); @@ -830,6 +834,7 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { } } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_char_lcd_write) { WS_DEBUG_PRINTLN("[i2c] Char LCD write not implemented yet!"); + // TODO! } else { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine I2C Output Write type!"); return false; @@ -1053,7 +1058,6 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { _i2c_drivers_output.push_back(drv_out); } - WS_DEBUG_PRINTLN("[i2c] Driver initialized and added to controller: "); WS_DEBUG_PRINTLN(device_name); diff --git a/src/components/i2c/controller.h b/src/components/i2c/controller.h index 1b33087e0..78de9b55b 100644 --- a/src/components/i2c/controller.h +++ b/src/components/i2c/controller.h @@ -45,6 +45,7 @@ #include "drivers/drvMprls.h" #include "drivers/drvMs8607.h" #include "drivers/drvNau7802.h" +#include "drivers/drvOutCharLcd.h" #include "drivers/drvOutQuadAlphaNum.h" #include "drivers/drvOutputBase.h" ///< Base i2c output driver class #include "drivers/drvPct2075.h" diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h new file mode 100644 index 000000000..5e62d4cbc --- /dev/null +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -0,0 +1,89 @@ +/*! + * @file drvOutCharLcd.h + * + * Device driver for I2C Character LCDs (HD44780) + * + * 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 for Adafruit Industries 2025 + * + * MIT license, all text here must be included in any redistribution. + * + */ + +#ifndef DRV_OUT_CHAR_LCD +#define DRV_OUT_CHAR_LCD + +#include "drvOutputBase.h" +#include +#include + +/*! + @brief Class that provides a driver interface for a lcd character display. + This class is a wrapper around the Adafruit_LiquidCrystal library. +*/ +class drvOutCharLcd : public drvOutputBase { +public: + /*! + @brief Constructor for a lcd character display. + @param i2c + The I2C interface. + @param sensorAddress + 7-bit device address. + @param mux_channel + The I2C multiplexer channel. + @param driver_name + The name of the driver. + */ + drvOutCharLcd(TwoWire *i2c, uint16_t sensorAddress, uint32_t mux_channel, + const char *driver_name) + : drvOutputBase(i2c, sensorAddress, mux_channel, driver_name) { + // Initialization handled by drvOutPutBase constructor + } + + /*! + @brief Destructor for a quad alphanumeric display. + */ + ~drvOutCharLcd() { + if (_lcd) { + delete _lcd; + _lcd = nullptr; + } + } + + /*! + @brief Initializes an I2C character LCD and begins I2C communication. + @returns True if initialized successfully, False otherwise. + */ + bool begin() override { + _lcd = new Adafruit_LiquidCrystal(_address, _i2c); + bool did_begin = _lcd->begin(_cols, _rows); + if (did_begin && _enable_backlight) { + _lcd->setBacklight(LOW); + } + return did_begin; + } + + /*! + @brief Writes a message to the LCD. + @note MUST be called prior to begin() to configure the LCD's size + @param message + The message to be displayed. + */ + void ConfigureCharLcd(uint8_t rows, uint8_t cols, bool enable_backlight) { + _rows = rows; + _cols = cols; + _enable_backlight = enable_backlight; + } + +protected: + Adafruit_LiquidCrystal + *_lcd; ///< Pointer to the Adafruit_LiquidCrystal object + uint8_t _rows = 2; ///< Number of rows in the display + uint8_t _cols = 16; ///< Number of columns in the display + bool _enable_backlight; ///< Flag to enable/disable backlight +}; + +#endif // DRV_OUT_CHAR_LCD \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index cd858d001..bff6bc944 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -133,17 +133,6 @@ class drvOutQuadAlphaNum : public drvOutputBase { pos_start = LED_MAX_CHARS - seg_chars; } - - WS_DEBUG_PRINT("Message to display: "); - WS_DEBUG_PRINTLN(message); - WS_DEBUG_PRINT(" with len_display: "); - WS_DEBUG_PRINTLN(len_display); - WS_DEBUG_PRINT(" at pos_start: "); - WS_DEBUG_PRINTLN(pos_start); - - // TODO FRIDAY - // NOTE: If there's a ., increment len_display by 1 to account for the decimal - // Write to the display's buffer int cur_idx = pos_start; for (size_t i = 0; i < len_display; i++) { @@ -159,12 +148,6 @@ class drvOutQuadAlphaNum : public drvOutputBase { } // Write the character to the display buffer - WS_DEBUG_PRINT("Writing char: "); - WS_DEBUG_PRINT(ch); - WS_DEBUG_PRINT(" at index: "); - WS_DEBUG_PRINT(cur_idx); - WS_DEBUG_PRINT(" with dot: "); - WS_DEBUG_PRINTLN(display_dot); _alpha4->writeDigitAscii(cur_idx, ch, display_dot); cur_idx++; } diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 1ccf6a508..3aad1834f 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -87,6 +87,20 @@ class drvOutputBase : public drvBase { // noop } + /*! + @brief Configures a character LCD. + @param rows + The number of rows in the LCD. + @param cols + The number of columns in the LCD. + @param enable_backlight + True if the backlight is enabled, False otherwise. + */ + virtual void ConfigureCharLcd(uint32_t rows, uint32_t cols, + bool enable_backlight) { + // noop + } + /*! @brief Sets the brightness of the LED backpack. @param b From a9b1e06656665b9c764e66aa6294c1cdcabfa687 Mon Sep 17 00:00:00 2001 From: brentru Date: Fri, 9 May 2025 15:37:28 -0400 Subject: [PATCH 13/26] Implement WriteMessage for CharLCD --- src/components/i2c/drivers/drvOutCharLcd.h | 38 ++++++++++++++++++++-- src/components/i2c/drivers/drvOutputBase.h | 9 +++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h index 5e62d4cbc..635992b55 100644 --- a/src/components/i2c/drivers/drvOutCharLcd.h +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -78,9 +78,43 @@ class drvOutCharLcd : public drvOutputBase { _enable_backlight = enable_backlight; } + /*! + @brief Writes a message to the LCD. + @param message + The message to be displayed. + */ + void WriteMessageCharLCD(const char *message) override { + if (_lcd == nullptr) + return; + + // Before writing, let's clear the display + _lcd->clear(); + + size_t message_length = strlen(message); + size_t cur_idx = 0; // Current index in the message + + // Write each row until it hits: \n, or the end of the message, or the last + // column/row position + for (int cur_row = 0; cur_row < _rows && cur_idx < message_length; + cur_row++) { + // Write each row out at the beginning of the row + _lcd->setCursor(0, cur_row); + for (int cur_col = 0; cur_col < _cols && cur_idx < message_length; + cur_col++) { + char c = message[cur_idx]; + if (c == '\n') { + cur_idx++; + break; + } + _lcd->write(c); + cur_idx++; + } + } + } + protected: - Adafruit_LiquidCrystal - *_lcd; ///< Pointer to the Adafruit_LiquidCrystal object + Adafruit_LiquidCrystal *_lcd = + nullptr; ///< Pointer to the Adafruit_LiquidCrystal object uint8_t _rows = 2; ///< Number of rows in the display uint8_t _cols = 16; ///< Number of columns in the display bool _enable_backlight; ///< Flag to enable/disable backlight diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 3aad1834f..00049bd3e 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -101,6 +101,15 @@ class drvOutputBase : public drvBase { // noop } + /*! + @brief Writes a message to the LCD. + @param message + The message to be displayed. + */ + virtual void WriteMessageCharLCD(const char *message) override { + // noop + } + /*! @brief Sets the brightness of the LED backpack. @param b From a388b6d822cc51883e5075e522f446e85d67a15b Mon Sep 17 00:00:00 2001 From: brentru Date: Mon, 12 May 2025 10:51:41 -0400 Subject: [PATCH 14/26] remove hardcode for row/col --- src/components/i2c/drivers/drvOutCharLcd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h index 635992b55..ae1196853 100644 --- a/src/components/i2c/drivers/drvOutCharLcd.h +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -61,7 +61,7 @@ class drvOutCharLcd : public drvOutputBase { _lcd = new Adafruit_LiquidCrystal(_address, _i2c); bool did_begin = _lcd->begin(_cols, _rows); if (did_begin && _enable_backlight) { - _lcd->setBacklight(LOW); + _lcd->setBacklight(HIGH); } return did_begin; } @@ -115,8 +115,8 @@ class drvOutCharLcd : public drvOutputBase { protected: Adafruit_LiquidCrystal *_lcd = nullptr; ///< Pointer to the Adafruit_LiquidCrystal object - uint8_t _rows = 2; ///< Number of rows in the display - uint8_t _cols = 16; ///< Number of columns in the display + uint8_t _rows; ///< Number of rows in the display + uint8_t _cols; ///< Number of columns in the display bool _enable_backlight; ///< Flag to enable/disable backlight }; From e5192612e2474da4f3ada272d13640e4a5e4f138 Mon Sep 17 00:00:00 2001 From: brentru Date: Mon, 12 May 2025 16:23:40 -0400 Subject: [PATCH 15/26] printing! --- src/components/i2c/controller.cpp | 17 +++++---- src/components/i2c/drivers/drvOutCharLcd.h | 41 +++++++++++++++++++--- src/components/i2c/drivers/drvOutputBase.h | 22 +++++++++--- src/protos/i2c.pb.h | 27 +++++++------- src/protos/i2c_output.pb.h | 2 +- src/protos/signal.pb.h | 2 +- 6 files changed, 82 insertions(+), 29 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index cda7a108d..1a8f811bd 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -826,15 +826,20 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { } // Determine which driver cb function to use - if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_led_backpack_write) { - if (!driver->LedBackpackWrite( - &_i2c_model->GetI2cDeviceOutputWriteMsg()->led_backpack_write)) { + if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg == + wippersnapper_i2c_I2cDeviceOutputWrite_write_led_backpack_tag) { + if (!driver->LedBackpackWrite(&_i2c_model->GetI2cDeviceOutputWriteMsg() + ->output_msg.write_led_backpack)) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to LED backpack!"); return false; } - } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->has_char_lcd_write) { - WS_DEBUG_PRINTLN("[i2c] Char LCD write not implemented yet!"); - // TODO! + } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg == + wippersnapper_i2c_I2cDeviceOutputWrite_write_char_lcd_tag) { + if (!driver->WriteMessageCharLCD(&_i2c_model->GetI2cDeviceOutputWriteMsg() + ->output_msg.write_char_lcd)) { + WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to char LCD!"); + return false; + } } else { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine I2C Output Write type!"); return false; diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h index ae1196853..b98ca807f 100644 --- a/src/components/i2c/drivers/drvOutCharLcd.h +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -83,13 +83,27 @@ class drvOutCharLcd : public drvOutputBase { @param message The message to be displayed. */ - void WriteMessageCharLCD(const char *message) override { + void WriteMessage(const char *message) { if (_lcd == nullptr) return; // Before writing, let's clear the display _lcd->clear(); + // TODO: Remove all the prints! + + // Print the message to the serial + Serial.print("Writing message to LCD: "); + Serial.println(message); + + // Debug: Print each character's ASCII value + Serial.print("Character values: "); + for (size_t i = 0; i < strlen(message); i++) { + Serial.print((int)message[i]); + Serial.print(" "); + } + Serial.println(); + size_t message_length = strlen(message); size_t cur_idx = 0; // Current index in the message @@ -102,12 +116,31 @@ class drvOutCharLcd : public drvOutputBase { for (int cur_col = 0; cur_col < _cols && cur_idx < message_length; cur_col++) { char c = message[cur_idx]; + + // Debug: Print the character we're processing + Serial.print("Processing char at position "); + Serial.print(cur_idx); + Serial.print(": '"); if (c == '\n') { + Serial.print("\\n"); + } else { + Serial.print(c); + } + Serial.print("' ("); + Serial.print((int)c); + Serial.println(")"); + + if (c == '\\' && message[cur_idx + 1] == 'n') { + Serial.println("Found newline, moving to next row"); + cur_idx += 2; // Skip the '\n' character in the buffer + break; // and move to the next row + } else if (c == 194 && message[cur_idx + 1] == 176) { + cur_idx += 2; // Skip the degree symbol sequence in the buffer + _lcd->write(0xDF); // and write the degree symbol + } else { + _lcd->write(c); cur_idx++; - break; } - _lcd->write(c); - cur_idx++; } } } diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 00049bd3e..d3f11f833 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -103,11 +103,25 @@ class drvOutputBase : public drvBase { /*! @brief Writes a message to the LCD. - @param message - The message to be displayed. + @param write_char_lcd + Pointer to a wippersnapper_i2c_output_CharLCDWrite message. */ - virtual void WriteMessageCharLCD(const char *message) override { - // noop + bool + WriteMessageCharLCD(wippersnapper_i2c_output_CharLCDWrite *write_char_lcd) { + switch (write_char_lcd->which_message) { + case wippersnapper_i2c_output_CharLCDWrite_text_tag: + WriteMessage(write_char_lcd->message.text); + break; + case wippersnapper_i2c_output_CharLCDWrite_number_int_tag: + // WriteValue(write_char_lcd->message.number_int); + break; + case wippersnapper_i2c_output_CharLCDWrite_number_float_tag: + // WriteValue(write_char_lcd->message.number_float); + break; + default: + return false; + } + return true; } /*! diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index c3c81442c..9c3808e4a 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -129,10 +129,11 @@ typedef struct _wippersnapper_i2c_I2cDeviceEvent { typedef struct _wippersnapper_i2c_I2cDeviceOutputWrite { bool has_i2c_device_description; wippersnapper_i2c_I2cDeviceDescriptor i2c_device_description; /* * Required - The I2c device's address and metadata. */ - bool has_led_backpack_write; - wippersnapper_i2c_output_LedBackpackWrite led_backpack_write; /* * Optional - If the I2C device is a LED backpack, fill this field. * */ - bool has_char_lcd_write; - wippersnapper_i2c_output_CharLCDWrite char_lcd_write; /* * Optional - If the I2C device is a character LCD, fill this field. * */ + pb_size_t which_output_msg; + union { + wippersnapper_i2c_output_LedBackpackWrite write_led_backpack; /* * Optional - If the I2C device is a LED backpack, fill this field. * */ + wippersnapper_i2c_output_CharLCDWrite write_char_lcd; /* * Optional - If the I2C device is a character LCD, fill this field. * */ + } output_msg; } wippersnapper_i2c_I2cDeviceOutputWrite; @@ -174,7 +175,7 @@ extern "C" { #define wippersnapper_i2c_I2cDeviceRemove_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0} #define wippersnapper_i2c_I2cDeviceRemoved_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0} #define wippersnapper_i2c_I2cDeviceEvent_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0, {wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default, wippersnapper_sensor_SensorEvent_init_default}} -#define wippersnapper_i2c_I2cDeviceOutputWrite_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, false, wippersnapper_i2c_output_LedBackpackWrite_init_default, false, wippersnapper_i2c_output_CharLCDWrite_init_default} +#define wippersnapper_i2c_I2cDeviceOutputWrite_init_default {false, wippersnapper_i2c_I2cDeviceDescriptor_init_default, 0, {wippersnapper_i2c_output_LedBackpackWrite_init_default}} #define wippersnapper_i2c_I2cDeviceDescriptor_init_zero {"", "", 0, 0, 0} #define wippersnapper_i2c_I2cBusDescriptor_init_zero {"", ""} #define wippersnapper_i2c_I2cBusScan_init_zero {0, 0, false, wippersnapper_i2c_I2cBusDescriptor_init_zero, 0, 0} @@ -184,7 +185,7 @@ extern "C" { #define wippersnapper_i2c_I2cDeviceRemove_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0} #define wippersnapper_i2c_I2cDeviceRemoved_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0} #define wippersnapper_i2c_I2cDeviceEvent_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0, {wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero, wippersnapper_sensor_SensorEvent_init_zero}} -#define wippersnapper_i2c_I2cDeviceOutputWrite_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, false, wippersnapper_i2c_output_LedBackpackWrite_init_zero, false, wippersnapper_i2c_output_CharLCDWrite_init_zero} +#define wippersnapper_i2c_I2cDeviceOutputWrite_init_zero {false, wippersnapper_i2c_I2cDeviceDescriptor_init_zero, 0, {wippersnapper_i2c_output_LedBackpackWrite_init_zero}} /* Field tags (for use in manual encoding/decoding) */ #define wippersnapper_i2c_I2cDeviceDescriptor_i2c_bus_sda_tag 1 @@ -218,8 +219,8 @@ extern "C" { #define wippersnapper_i2c_I2cDeviceEvent_i2c_device_description_tag 1 #define wippersnapper_i2c_I2cDeviceEvent_i2c_device_events_tag 2 #define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_tag 1 -#define wippersnapper_i2c_I2cDeviceOutputWrite_led_backpack_write_tag 2 -#define wippersnapper_i2c_I2cDeviceOutputWrite_char_lcd_write_tag 3 +#define wippersnapper_i2c_I2cDeviceOutputWrite_write_led_backpack_tag 2 +#define wippersnapper_i2c_I2cDeviceOutputWrite_write_char_lcd_tag 3 /* Struct field encoding specification for nanopb */ #define wippersnapper_i2c_I2cDeviceDescriptor_FIELDLIST(X, a) \ @@ -299,13 +300,13 @@ X(a, STATIC, REPEATED, MESSAGE, i2c_device_events, 2) #define wippersnapper_i2c_I2cDeviceOutputWrite_FIELDLIST(X, a) \ X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) \ -X(a, STATIC, OPTIONAL, MESSAGE, led_backpack_write, 2) \ -X(a, STATIC, OPTIONAL, MESSAGE, char_lcd_write, 3) +X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_led_backpack,output_msg.write_led_backpack), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_char_lcd,output_msg.write_char_lcd), 3) #define wippersnapper_i2c_I2cDeviceOutputWrite_CALLBACK NULL #define wippersnapper_i2c_I2cDeviceOutputWrite_DEFAULT NULL #define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor -#define wippersnapper_i2c_I2cDeviceOutputWrite_led_backpack_write_MSGTYPE wippersnapper_i2c_output_LedBackpackWrite -#define wippersnapper_i2c_I2cDeviceOutputWrite_char_lcd_write_MSGTYPE wippersnapper_i2c_output_CharLCDWrite +#define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_led_backpack_MSGTYPE wippersnapper_i2c_output_LedBackpackWrite +#define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_char_lcd_MSGTYPE wippersnapper_i2c_output_CharLCDWrite extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceDescriptor_msg; extern const pb_msgdesc_t wippersnapper_i2c_I2cBusDescriptor_msg; @@ -338,7 +339,7 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cDeviceAddOrReplace_size 141 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 -#define wippersnapper_i2c_I2cDeviceOutputWrite_size 147 +#define wippersnapper_i2c_I2cDeviceOutputWrite_size 100 #define wippersnapper_i2c_I2cDeviceRemove_size 54 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 #if defined(wippersnapper_sensor_SensorEvent_size) diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h index ebce9fffe..58bb53644 100644 --- a/src/protos/i2c_output.pb.h +++ b/src/protos/i2c_output.pb.h @@ -77,7 +77,7 @@ typedef struct _wippersnapper_i2c_output_LedBackpackWrite { typedef struct _wippersnapper_i2c_output_CharLCDWrite { pb_size_t which_message; union { - char text[20]; /* * Text to write to the character LCD. * */ + char text[100]; /* * Text to write to the character LCD. * */ int32_t number_int; /* * Number to write to the character LCD. * */ float number_float; /* * Float to write to the character LCD. * */ } message; diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index e31e82df3..4b13a8cf2 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -257,7 +257,7 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; /* Maximum encoded size of messages (where known) */ #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[151];}; +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[145];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; From 2cc9f32537ca1dabc511bb7a95714c80ff60bb0c Mon Sep 17 00:00:00 2001 From: brentru Date: Mon, 12 May 2025 16:35:02 -0400 Subject: [PATCH 16/26] charlcd prints, handlers for degrees symbol --- src/components/i2c/drivers/drvOutCharLcd.h | 26 +--------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h index b98ca807f..9279e9f6f 100644 --- a/src/components/i2c/drivers/drvOutCharLcd.h +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -91,19 +91,10 @@ class drvOutCharLcd : public drvOutputBase { _lcd->clear(); // TODO: Remove all the prints! - // Print the message to the serial - Serial.print("Writing message to LCD: "); + Serial.print("Writing message to Char. LCD: "); Serial.println(message); - // Debug: Print each character's ASCII value - Serial.print("Character values: "); - for (size_t i = 0; i < strlen(message); i++) { - Serial.print((int)message[i]); - Serial.print(" "); - } - Serial.println(); - size_t message_length = strlen(message); size_t cur_idx = 0; // Current index in the message @@ -116,22 +107,7 @@ class drvOutCharLcd : public drvOutputBase { for (int cur_col = 0; cur_col < _cols && cur_idx < message_length; cur_col++) { char c = message[cur_idx]; - - // Debug: Print the character we're processing - Serial.print("Processing char at position "); - Serial.print(cur_idx); - Serial.print(": '"); - if (c == '\n') { - Serial.print("\\n"); - } else { - Serial.print(c); - } - Serial.print("' ("); - Serial.print((int)c); - Serial.println(")"); - if (c == '\\' && message[cur_idx + 1] == 'n') { - Serial.println("Found newline, moving to next row"); cur_idx += 2; // Skip the '\n' character in the buffer break; // and move to the next row } else if (c == 194 && message[cur_idx + 1] == 176) { From 93dd43d6a22179e5bbadb9253e8207b8a4766fe3 Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 13 May 2025 11:37:57 -0400 Subject: [PATCH 17/26] Match charlcd commit --- src/components/i2c/drivers/drvOutputBase.h | 14 +---- src/protos/i2c.pb.h | 4 +- src/protos/i2c_output.pb.h | 64 ++++++++-------------- src/protos/signal.pb.h | 2 +- 4 files changed, 27 insertions(+), 57 deletions(-) diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index d3f11f833..76e0249eb 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -108,19 +108,7 @@ class drvOutputBase : public drvBase { */ bool WriteMessageCharLCD(wippersnapper_i2c_output_CharLCDWrite *write_char_lcd) { - switch (write_char_lcd->which_message) { - case wippersnapper_i2c_output_CharLCDWrite_text_tag: - WriteMessage(write_char_lcd->message.text); - break; - case wippersnapper_i2c_output_CharLCDWrite_number_int_tag: - // WriteValue(write_char_lcd->message.number_int); - break; - case wippersnapper_i2c_output_CharLCDWrite_number_float_tag: - // WriteValue(write_char_lcd->message.number_float); - break; - default: - return false; - } + WriteMessage(write_char_lcd->message); return true; } diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index 9c3808e4a..b4a28c8e0 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -336,10 +336,10 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cBusDescriptor_size 32 #define wippersnapper_i2c_I2cBusScan_size 42 #define wippersnapper_i2c_I2cBusScanned_size 6242 -#define wippersnapper_i2c_I2cDeviceAddOrReplace_size 141 +#define wippersnapper_i2c_I2cDeviceAddOrReplace_size 139 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 -#define wippersnapper_i2c_I2cDeviceOutputWrite_size 100 +#define wippersnapper_i2c_I2cDeviceOutputWrite_size 208 #define wippersnapper_i2c_I2cDeviceRemove_size 54 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 #if defined(wippersnapper_sensor_SensorEvent_size) diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h index 58bb53644..e0282705b 100644 --- a/src/protos/i2c_output.pb.h +++ b/src/protos/i2c_output.pb.h @@ -41,8 +41,7 @@ typedef struct _wippersnapper_i2c_output_LedBackpackConfig { typedef struct _wippersnapper_i2c_output_CharLCDConfig { uint32_t rows; /* * Number of rows for the character LCD. * */ uint32_t columns; /* * Number of columns for the character LCD. * */ - bool backlight_enable; /* * Backlight state for the character LCD. * */ - char backlight_color[15]; /* * Backlight color for the character LCD, in Hex. * */ + char backlight_color[15]; /* * Optional Backlight color for the character LCD, in Hex. * */ } wippersnapper_i2c_output_CharLCDConfig; /* * @@ -69,21 +68,14 @@ typedef struct _wippersnapper_i2c_output_LedBackpackWrite { wippersnapper_i2c_output_LedBackpackBlinkRate blink_rate; /* * Optionally sets the blink rate for the LED backpack. * */ bool enable_scroll_marquee; /* * Optionally enables automatic text scrolling * */ float scroll_marquee_speed; /* * Speed for the scrolling marquee. * */ - bool enable_ampm_dot; /* * Enable AM/PM dot. * */ } wippersnapper_i2c_output_LedBackpackWrite; /* * CharLCDWrite represents a request from the broker to write to a character LCD. */ typedef struct _wippersnapper_i2c_output_CharLCDWrite { - pb_size_t which_message; - union { - char text[100]; /* * Text to write to the character LCD. * */ - int32_t number_int; /* * Number to write to the character LCD. * */ - float number_float; /* * Float to write to the character LCD. * */ - } message; - bool enable_backlight; /* * Enable backlight for the character LCD. * */ - char backlight_color[20]; /* * Backlight color for the character LCD, in Hex. * */ - bool enable_scroll; /* * Enable automatic scrolling for the character LCD. * */ + char message[128]; /* * Message to write to the character LCD. * */ + char backlight_color[20]; /* * Optional Backlight color for the character LCD, in Hex. * */ + bool enable_scroll; /* * Optional Enable automatic scrolling for the character LCD. * */ } wippersnapper_i2c_output_CharLCDWrite; @@ -110,23 +102,22 @@ extern "C" { /* Initializer values for message structs */ #define wippersnapper_i2c_output_LedBackpackConfig_init_default {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} -#define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, 0, ""} +#define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_default {0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_default {0, {""}, 0, "", 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_default {"", "", 0} #define wippersnapper_i2c_output_LedBackpackConfig_init_zero {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} -#define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, 0, ""} +#define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, ""} #define wippersnapper_i2c_output_I2cOutputAdd_init_zero {0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_zero {0, {""}, 0, "", 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0} +#define wippersnapper_i2c_output_CharLCDWrite_init_zero {"", "", 0} /* Field tags (for use in manual encoding/decoding) */ #define wippersnapper_i2c_output_LedBackpackConfig_brightness_tag 1 #define wippersnapper_i2c_output_LedBackpackConfig_alignment_tag 2 #define wippersnapper_i2c_output_CharLCDConfig_rows_tag 1 #define wippersnapper_i2c_output_CharLCDConfig_columns_tag 2 -#define wippersnapper_i2c_output_CharLCDConfig_backlight_enable_tag 3 -#define wippersnapper_i2c_output_CharLCDConfig_backlight_color_tag 4 +#define wippersnapper_i2c_output_CharLCDConfig_backlight_color_tag 3 #define wippersnapper_i2c_output_I2cOutputAdd_led_backpack_config_tag 1 #define wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag 2 #define wippersnapper_i2c_output_LedBackpackWrite_text_tag 1 @@ -137,13 +128,9 @@ extern "C" { #define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_tag 6 #define wippersnapper_i2c_output_LedBackpackWrite_enable_scroll_marquee_tag 7 #define wippersnapper_i2c_output_LedBackpackWrite_scroll_marquee_speed_tag 8 -#define wippersnapper_i2c_output_LedBackpackWrite_enable_ampm_dot_tag 9 -#define wippersnapper_i2c_output_CharLCDWrite_text_tag 1 -#define wippersnapper_i2c_output_CharLCDWrite_number_int_tag 2 -#define wippersnapper_i2c_output_CharLCDWrite_number_float_tag 3 -#define wippersnapper_i2c_output_CharLCDWrite_enable_backlight_tag 4 -#define wippersnapper_i2c_output_CharLCDWrite_backlight_color_tag 5 -#define wippersnapper_i2c_output_CharLCDWrite_enable_scroll_tag 6 +#define wippersnapper_i2c_output_CharLCDWrite_message_tag 1 +#define wippersnapper_i2c_output_CharLCDWrite_backlight_color_tag 2 +#define wippersnapper_i2c_output_CharLCDWrite_enable_scroll_tag 3 /* Struct field encoding specification for nanopb */ #define wippersnapper_i2c_output_LedBackpackConfig_FIELDLIST(X, a) \ @@ -155,8 +142,7 @@ X(a, STATIC, SINGULAR, UENUM, alignment, 2) #define wippersnapper_i2c_output_CharLCDConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, rows, 1) \ X(a, STATIC, SINGULAR, UINT32, columns, 2) \ -X(a, STATIC, SINGULAR, BOOL, backlight_enable, 3) \ -X(a, STATIC, SINGULAR, STRING, backlight_color, 4) +X(a, STATIC, SINGULAR, STRING, backlight_color, 3) #define wippersnapper_i2c_output_CharLCDConfig_CALLBACK NULL #define wippersnapper_i2c_output_CharLCDConfig_DEFAULT NULL @@ -176,18 +162,14 @@ X(a, STATIC, SINGULAR, BOOL, adjust_brightness, 4) \ X(a, STATIC, SINGULAR, INT32, brightness, 5) \ X(a, STATIC, SINGULAR, UENUM, blink_rate, 6) \ X(a, STATIC, SINGULAR, BOOL, enable_scroll_marquee, 7) \ -X(a, STATIC, SINGULAR, FLOAT, scroll_marquee_speed, 8) \ -X(a, STATIC, SINGULAR, BOOL, enable_ampm_dot, 9) +X(a, STATIC, SINGULAR, FLOAT, scroll_marquee_speed, 8) #define wippersnapper_i2c_output_LedBackpackWrite_CALLBACK NULL #define wippersnapper_i2c_output_LedBackpackWrite_DEFAULT NULL #define wippersnapper_i2c_output_CharLCDWrite_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, STRING, (message,text,message.text), 1) \ -X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ -X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ -X(a, STATIC, SINGULAR, BOOL, enable_backlight, 4) \ -X(a, STATIC, SINGULAR, STRING, backlight_color, 5) \ -X(a, STATIC, SINGULAR, BOOL, enable_scroll, 6) +X(a, STATIC, SINGULAR, STRING, message, 1) \ +X(a, STATIC, SINGULAR, STRING, backlight_color, 2) \ +X(a, STATIC, SINGULAR, BOOL, enable_scroll, 3) #define wippersnapper_i2c_output_CharLCDWrite_CALLBACK NULL #define wippersnapper_i2c_output_CharLCDWrite_DEFAULT NULL @@ -206,11 +188,11 @@ extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDWrite_msg; /* Maximum encoded size of messages (where known) */ #define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_CharLCDWrite_size -#define wippersnapper_i2c_output_CharLCDConfig_size 30 -#define wippersnapper_i2c_output_CharLCDWrite_size 46 -#define wippersnapper_i2c_output_I2cOutputAdd_size 32 +#define wippersnapper_i2c_output_CharLCDConfig_size 28 +#define wippersnapper_i2c_output_CharLCDWrite_size 153 +#define wippersnapper_i2c_output_I2cOutputAdd_size 30 #define wippersnapper_i2c_output_LedBackpackConfig_size 13 -#define wippersnapper_i2c_output_LedBackpackWrite_size 45 +#define wippersnapper_i2c_output_LedBackpackWrite_size 43 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index 4b13a8cf2..c7b737dae 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -257,7 +257,7 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; /* Maximum encoded size of messages (where known) */ #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[145];}; +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[212];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; From 538ce3b7df456d21be54ad33a5c4fc01876f9617 Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 13 May 2025 15:03:08 -0400 Subject: [PATCH 18/26] Add libraries --- library.properties | 2 +- src/components/i2c/controller.cpp | 11 +- src/components/i2c/controller.h | 1 + src/components/i2c/drivers/drvOut7Seg.h | 207 ++++++++++++++++++ .../i2c/drivers/drvOutQuadAlphaNum.h | 4 +- src/components/i2c/drivers/drvOutputBase.h | 10 +- 6 files changed, 229 insertions(+), 6 deletions(-) create mode 100644 src/components/i2c/drivers/drvOut7Seg.h diff --git a/library.properties b/library.properties index d6840cbca..928523754 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,4 @@ paragraph=Arduino application for Adafruit.io WipperSnapper category=Communication url=https://github.com/adafruit/Adafruit_Wippersnapper_Arduino architectures=* -depends=SdFat - Adafruit Fork, Adafruit SPIFlash, Adafruit NeoPixel, ArduinoJson, Adafruit DotStar, Adafruit HDC302x, Adafruit INA219, 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, RTClib, StreamUtils, Adafruit SHT4x Library +depends=SdFat - Adafruit Fork, Adafruit SPIFlash, Adafruit NeoPixel, ArduinoJson, Adafruit DotStar, Adafruit HDC302x, Adafruit INA219, 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, RTClib, StreamUtils, Adafruit SHT4x Library, Adafruit LED Backpack Library, Adafruit LiquidCrystal diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 1a8f811bd..60ec9cf15 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -366,6 +366,11 @@ static const std::map I2cFactoryOutput = { const char *driver_name) -> drvOutputBase * { return new drvOutQuadAlphaNum(i2c, addr, mux_channel, driver_name); }}, + {"7seg", + [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, + const char *driver_name) -> drvOutputBase * { + return new drvOut7Seg(i2c, addr, mux_channel, driver_name); + }}, {"charlcd", [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, const char *driver_name) -> drvOutputBase * { @@ -828,6 +833,7 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { // Determine which driver cb function to use if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg == wippersnapper_i2c_I2cDeviceOutputWrite_write_led_backpack_tag) { + WS_DEBUG_PRINTLN("[i2c] Writing to LED backpack..."); if (!driver->LedBackpackWrite(&_i2c_model->GetI2cDeviceOutputWriteMsg() ->output_msg.write_led_backpack)) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to LED backpack!"); @@ -835,6 +841,7 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { } } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg == wippersnapper_i2c_I2cDeviceOutputWrite_write_char_lcd_tag) { + WS_DEBUG_PRINTLN("[i2c] Writing to char LCD..."); if (!driver->WriteMessageCharLCD(&_i2c_model->GetI2cDeviceOutputWriteMsg() ->output_msg.write_char_lcd)) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to char LCD!"); @@ -1026,8 +1033,8 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { wippersnapper_i2c_output_LedBackpackConfig cfg = _i2c_model->GetI2cDeviceAddOrReplaceMsg() ->i2c_output_add.config.led_backpack_config; - WS_DEBUG_PRINT("[i2c] Got cfg, calling ConfigureLEDBackpack..."); - drv_out->ConfigureLEDBackpack(cfg.brightness, cfg.alignment); + WS_DEBUG_PRINT("[i2c] Got cfg, calling ConfigureI2CBackpack..."); + drv_out->ConfigureI2CBackpack(cfg.brightness, cfg.alignment); WS_DEBUG_PRINTLN("OK!"); } else if (config == wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag) { diff --git a/src/components/i2c/controller.h b/src/components/i2c/controller.h index 78de9b55b..2492e4b3f 100644 --- a/src/components/i2c/controller.h +++ b/src/components/i2c/controller.h @@ -45,6 +45,7 @@ #include "drivers/drvMprls.h" #include "drivers/drvMs8607.h" #include "drivers/drvNau7802.h" +#include "drivers/drvOut7Seg.h" #include "drivers/drvOutCharLcd.h" #include "drivers/drvOutQuadAlphaNum.h" #include "drivers/drvOutputBase.h" ///< Base i2c output driver class diff --git a/src/components/i2c/drivers/drvOut7Seg.h b/src/components/i2c/drivers/drvOut7Seg.h new file mode 100644 index 000000000..d182b0725 --- /dev/null +++ b/src/components/i2c/drivers/drvOut7Seg.h @@ -0,0 +1,207 @@ +/*! + * @file drvOut7Seg.h + * + * Device driver designed specifically to work with the Adafruit LED 7-Segment + * I2C backpacks: + * ----> http://www.adafruit.com/products/881 + * ----> http://www.adafruit.com/products/880 + * ----> http://www.adafruit.com/products/879 + * ----> http://www.adafruit.com/products/878 + * + * 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 for Adafruit Industries 2025 + * + * MIT license, all text here must be included in any redistribution. + * + */ + +#ifndef DRV_OUT_7SEG_H +#define DRV_OUT_7SEG_H + +#include "drvOutputBase.h" +#include +#include + +#define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 +#define LED_BACKPACK_ALIGNMENT_LEFT 1 +#define LED_BACKPACK_ALIGNMENT_RIGHT 2 +#define LED_BACKPACK_ALIGNMENT_DEFAULT LED_BACKPACK_ALIGNMENT_LEFT +#define LED_MAX_CHARS 4 + +/*! + @brief Class that provides a driver for an Adafruit 7-Segment LED matrix + w/I2C backpack. +*/ +class drvOut7Seg : public drvOutputBase { +public: + /*! + @brief Constructor for an Adafruit 7-Segment LED matrix w/I2C backpack. + @param i2c + The I2C interface. + @param sensorAddress + 7-bit device address. + @param mux_channel + The I2C multiplexer channel. + @param driver_name + The name of the driver. + */ + drvOut7Seg(TwoWire *i2c, uint16_t sensorAddress, uint32_t mux_channel, + const char *driver_name) + : drvOutputBase(i2c, sensorAddress, mux_channel, driver_name) { + // Initialization handled by drvBase constructor + } + + /*! + @brief Destructor for an Adafruit 7-Segment LED matrix w/I2C backpack. + */ + ~drvOut7Seg() { + if (_matrix) { + delete _matrix; + _matrix = nullptr; + } + } + + /*! + @brief Initializes the 7-segment LED matrix and begins I2C + communication. + @returns True if initialized successfully, False otherwise. + */ + bool begin() override { + _matrix = new Adafruit_7segment(); + bool did_begin = _matrix->begin(0x70, _i2c); + return did_begin; + } + + /*! + @brief Configures the LED matrix's I2C backpack. + @param brightness + The brightness of the i2c backpack (0-15). + @param alignment + The alignment of the i2c backpack's LED matrix (left/right). +*/ + void ConfigureI2CBackpack(int32_t brightness, uint32_t alignment) { + if (alignment == LED_BACKPACK_ALIGNMENT_RIGHT) { + _alignment = LED_BACKPACK_ALIGNMENT_RIGHT; + } else { + _alignment = LED_BACKPACK_ALIGNMENT_DEFAULT; + } + + // Note: Adafruit_LEDBackpack normalizes only > 15, but not < 0, + // so, here we're normalizing < 0 to 8 (median brightness) + if (brightness < 0) { + brightness = 8; // Set to median brightness if out of range + } + } + + /*! + @brief Sets the brightness of the LED backpack. + @param b + The brightness value, from 0 (off) to 15 (full brightness). + */ + void SetLedBackpackBrightness(uint8_t b) { + if (_matrix == nullptr) { + return; + } + _matrix->setBrightness(b); + } + + /*! + @brief Writes the first four characters of a message to the Adafruit + 7-segment LED matrix. + @param message + The message to be displayed. + */ + void WriteMessage(const char *message) { + if (_matrix == nullptr || message == nullptr) { + return; + } + + // Clear before writing + _matrix->clear(); + + // Calculate the number of characters to display + size_t len_display = min(strlen(message), (size_t)LED_MAX_CHARS); + + // Set the starting position based on alignment + int pos_start; + if (_alignment == LED_BACKPACK_ALIGNMENT_LEFT) { + pos_start = 0; // start at the leftmost position of the display + } else { + // Exclude decimal points from the character count because those get + // displayed on a "special" segment of the LED display + int seg_chars = 0; + for (size_t i = 0; i < len_display; i++) { + if (message[i] != '.') { + seg_chars++; + } + } + // start at the rightmost position of the display + pos_start = LED_MAX_CHARS - seg_chars; + } + + // Write to the display's buffer + int cur_idx = pos_start; + for (size_t i = 0; i < len_display; i++) { + // skip position 2 + if (cur_idx == 2) { + cur_idx++; + } + // Save the character because if there's a decimal, we need to skip it in + // the buffer + char ch = message[i]; + + // Look-ahead for a decimal point to attach to the current character + bool display_dot = false; + if (i + 1 < len_display && message[i + 1] == '.') { + display_dot = true; + i++; + len_display++; + } + + // Write the character to the display buffer + _matrix->writeDigitAscii(cur_idx, ch, display_dot); + cur_idx++; + } + // Issue the buffered data in RAM to the display + _matrix->writeDisplay(); + } + + /*! + @brief Writes a floating point value to the Adafruit 7-segment LED + matrix. + @param value + The value to be displayed. Only the first four digits are + displayed. + */ + void WriteValue(float value) { + char message[8 + 1]; + snprintf(message, sizeof(message), "%.5f", value); + WriteMessage(message); + } + + /*! + @brief Writes an integer value to the Adafruit 7-segment LED matrix. + @param value + The value to be displayed. Only the first four digits are + displayed. + */ + void WriteValue(int32_t value) { + char message[LED_MAX_CHARS + 1]; + snprintf(message, sizeof(message), "%ld", value); + WriteMessage(message); + } + +protected: + Adafruit_7segment *_matrix = + nullptr; ///< ptr to a 7-segment LED matrix object + int32_t _brightness; ///< Brightness of the LED backpack, from 0 (off) to 15 + ///< (full brightness) + uint32_t _alignment = + LED_BACKPACK_ALIGNMENT_DEFAULT; ///< Determines L/R alignment of the + ///< message displayed +}; + +#endif // DRV_OUT_7SEG_H \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index bff6bc944..ae7761611 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -77,8 +77,8 @@ class drvOutQuadAlphaNum : public drvOutputBase { @param alignment The alignment of the LED backpack. */ - void ConfigureLEDBackpack(int32_t brightness, uint32_t alignment) { - WS_DEBUG_PRINTLN("[i2c] drvOutQuadAlphaNum::ConfigureLEDBackpack() called"); + void ConfigureI2CBackpack(int32_t brightness, uint32_t alignment) { + WS_DEBUG_PRINTLN("[i2c] drvOutQuadAlphaNum::ConfigureI2CBackpack() called"); if (alignment == LED_BACKPACK_ALIGNMENT_RIGHT) { _alignment = LED_BACKPACK_ALIGNMENT_RIGHT; } else { diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 76e0249eb..4c096c8ce 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -83,7 +83,7 @@ class drvOutputBase : public drvBase { @param alignment The alignment of the LED backpack. */ - virtual void ConfigureLEDBackpack(int32_t brightness, uint32_t alignment) { + virtual void ConfigureI2CBackpack(int32_t brightness, uint32_t alignment) { // noop } @@ -109,6 +109,9 @@ class drvOutputBase : public drvBase { bool WriteMessageCharLCD(wippersnapper_i2c_output_CharLCDWrite *write_char_lcd) { WriteMessage(write_char_lcd->message); + // NOTE: While this isn't calling any other funcs in here and ret'ing true, + // I want to keep this function high-level for when we implement backlight + // color and scrolling. return true; } @@ -137,15 +140,20 @@ class drvOutputBase : public drvBase { // Write the message to a LED backpack switch (msg_backpack_write->which_message) { case wippersnapper_i2c_output_LedBackpackWrite_text_tag: + WS_DEBUG_PRINTLN("[i2c] Writing text to LED backpack..."); WriteMessage(msg_backpack_write->message.text); break; case wippersnapper_i2c_output_LedBackpackWrite_number_int_tag: + WS_DEBUG_PRINTLN("[i2c] Writing int to LED backpack..."); WriteValue(msg_backpack_write->message.number_int); break; case wippersnapper_i2c_output_LedBackpackWrite_number_float_tag: + WS_DEBUG_PRINTLN("[i2c] Writing float to LED backpack..."); WriteValue(msg_backpack_write->message.number_float); break; default: + WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine LED backpack " + "message type!"); return false; break; } From 1a121454fa04b89912aa9cc182f5425ec752e7dc Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 13 May 2025 15:42:09 -0400 Subject: [PATCH 19/26] clang --- src/components/i2c/drivers/drvOutQuadAlphaNum.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index ae7761611..24f4b862a 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -136,7 +136,8 @@ class drvOutQuadAlphaNum : public drvOutputBase { // Write to the display's buffer int cur_idx = pos_start; for (size_t i = 0; i < len_display; i++) { - // Save the character because if there's a decimal, we need to skip it in the buffer + // Save the character because if there's a decimal, we need to skip it in + // the buffer char ch = message[i]; // Look-ahead for a decimal point to attach to the current character @@ -162,7 +163,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { displayed. */ void WriteValue(float value) { - char message[8+1]; + char message[8 + 1]; snprintf(message, sizeof(message), "%.5f", value); WriteMessage(message); } @@ -184,8 +185,9 @@ class drvOutQuadAlphaNum : public drvOutputBase { nullptr; ///< ptr to a 4-digit alphanumeric display object int32_t _brightness; ///< Brightness of the LED backpack, from 0 (off) to 15 ///< (full brightness) - uint32_t _alignment = LED_BACKPACK_ALIGNMENT_DEFAULT; ///< Determines L/R alignment of the message - ///< displayed + uint32_t _alignment = + LED_BACKPACK_ALIGNMENT_DEFAULT; ///< Determines L/R alignment of the + ///< message displayed }; #endif // DRV_OUT_QUAD_ALPHANUM_H \ No newline at end of file From f8aa81936c1eb60206c65bd7bfdefc807dae379a Mon Sep 17 00:00:00 2001 From: brentru Date: Tue, 13 May 2025 16:11:52 -0400 Subject: [PATCH 20/26] doxy --- src/components/i2c/drivers/drvOut7Seg.h | 12 +++++++----- src/components/i2c/drivers/drvOutCharLcd.h | 8 ++++++-- src/components/i2c/drivers/drvOutQuadAlphaNum.h | 14 ++++++++------ src/components/i2c/drivers/drvOutputBase.h | 4 +++- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/components/i2c/drivers/drvOut7Seg.h b/src/components/i2c/drivers/drvOut7Seg.h index d182b0725..d70621dab 100644 --- a/src/components/i2c/drivers/drvOut7Seg.h +++ b/src/components/i2c/drivers/drvOut7Seg.h @@ -25,11 +25,13 @@ #include #include -#define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 -#define LED_BACKPACK_ALIGNMENT_LEFT 1 -#define LED_BACKPACK_ALIGNMENT_RIGHT 2 -#define LED_BACKPACK_ALIGNMENT_DEFAULT LED_BACKPACK_ALIGNMENT_LEFT -#define LED_MAX_CHARS 4 +#define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 ///< Unspecified alignment +#define LED_BACKPACK_ALIGNMENT_LEFT 1 ///< Left alignment +#define LED_BACKPACK_ALIGNMENT_RIGHT 2 ///< Right alignment +#define LED_BACKPACK_ALIGNMENT_DEFAULT \ + LED_BACKPACK_ALIGNMENT_LEFT ///< Default alignment +#define LED_MAX_CHARS \ + 4 ///< Maximum number of characters to display on the 7-segment display /*! @brief Class that provides a driver for an Adafruit 7-Segment LED matrix diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h index 9279e9f6f..59163c4cf 100644 --- a/src/components/i2c/drivers/drvOutCharLcd.h +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -69,8 +69,12 @@ class drvOutCharLcd : public drvOutputBase { /*! @brief Writes a message to the LCD. @note MUST be called prior to begin() to configure the LCD's size - @param message - The message to be displayed. + @param rows + The number of rows in the LCD. + @param cols + The number of columns in the LCD. + @param enable_backlight + True if the backlight is enabled, False otherwise. */ void ConfigureCharLcd(uint8_t rows, uint8_t cols, bool enable_backlight) { _rows = rows; diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index 24f4b862a..8f62162ae 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -1,5 +1,5 @@ /*! - * @file drvQuadAlphaNum.h + * @file drvOutQuadAlphaNum.h * * Device driver for Quad Alphanumeric Displays w/I2C Backpack * @@ -20,11 +20,13 @@ #include #include -#define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 -#define LED_BACKPACK_ALIGNMENT_LEFT 1 -#define LED_BACKPACK_ALIGNMENT_RIGHT 2 -#define LED_BACKPACK_ALIGNMENT_DEFAULT LED_BACKPACK_ALIGNMENT_LEFT -#define LED_MAX_CHARS 4 +#define LED_BACKPACK_ALIGNMENT_UNSPECIFIED 0 ///< Unspecified alignment +#define LED_BACKPACK_ALIGNMENT_LEFT 1 ///< Left alignment +#define LED_BACKPACK_ALIGNMENT_RIGHT 2 ///< Right alignment +#define LED_BACKPACK_ALIGNMENT_DEFAULT \ + LED_BACKPACK_ALIGNMENT_LEFT ///< Default alignment +#define LED_MAX_CHARS \ + 4 ///< Maximum number of characters to display on the alphanumeric display /*! @brief Class that provides a driver interface for Quad Alphanumeric diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 4c096c8ce..f267865d9 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -50,7 +50,8 @@ class drvOutputBase : public drvBase { /*! @brief Initializes the I2C output device and begins I2C. - @returns True if initialized successfully, False otherwise. + @param message + The message to be displayed. */ virtual void WriteMessage(const char *message) { // noop @@ -105,6 +106,7 @@ class drvOutputBase : public drvBase { @brief Writes a message to the LCD. @param write_char_lcd Pointer to a wippersnapper_i2c_output_CharLCDWrite message. + @returns True if the message was written successfully, False otherwise. */ bool WriteMessageCharLCD(wippersnapper_i2c_output_CharLCDWrite *write_char_lcd) { From 4df009ef8599877a8b428cae22364084cd4adf69 Mon Sep 17 00:00:00 2001 From: brentru Date: Thu, 15 May 2025 09:47:36 -0400 Subject: [PATCH 21/26] Fix charLCD formatting, decimal on quadalphanum --- src/components/i2c/drivers/drvOutCharLcd.h | 6 +- .../i2c/drivers/drvOutQuadAlphaNum.h | 56 ++++++++++--------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h index 59163c4cf..c29b7040c 100644 --- a/src/components/i2c/drivers/drvOutCharLcd.h +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -111,10 +111,12 @@ class drvOutCharLcd : public drvOutputBase { for (int cur_col = 0; cur_col < _cols && cur_idx < message_length; cur_col++) { char c = message[cur_idx]; - if (c == '\\' && message[cur_idx + 1] == 'n') { + if (c == '\\' && cur_idx + 1 < message_length && + message[cur_idx + 1] == 'n') { cur_idx += 2; // Skip the '\n' character in the buffer break; // and move to the next row - } else if (c == 194 && message[cur_idx + 1] == 176) { + } else if (c == 194 && cur_idx + 1 < message_length && + message[cur_idx + 1] == 176) { cur_idx += 2; // Skip the degree symbol sequence in the buffer _lcd->write(0xDF); // and write the degree symbol } else { diff --git a/src/components/i2c/drivers/drvOutQuadAlphaNum.h b/src/components/i2c/drivers/drvOutQuadAlphaNum.h index 8f62162ae..18cced030 100644 --- a/src/components/i2c/drivers/drvOutQuadAlphaNum.h +++ b/src/components/i2c/drivers/drvOutQuadAlphaNum.h @@ -103,8 +103,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { } /*! - @brief Writes the first four characters of a message to the quad - alphanumeric display. + @brief Writes a message to the quad alphanumeric display. @param message The message to be displayed. */ @@ -115,45 +114,52 @@ class drvOutQuadAlphaNum : public drvOutputBase { // Clear before writing _alpha4->clear(); - // Calculate the number of characters to display - size_t len_display = min(strlen(message), (size_t)LED_MAX_CHARS); + // Calculate the total message length + size_t msg_len = strlen(message); + + // Count all characters but excluding decimal points as they are part of the + // "segment" + int char_count = 0; + for (size_t i = 0; i < msg_len && char_count < LED_MAX_CHARS; i++) { + if (message[i] != '.') { + char_count++; + } + } // Set the starting position based on alignment int pos_start; if (_alignment == LED_BACKPACK_ALIGNMENT_LEFT) { - pos_start = 0; // start at the leftmost position of the display + pos_start = 0; // start at the leftmost position } else { - // Exclude decimal points from the character count because those get - // displayed on a "special" segment of the LED display - int seg_chars = 0; - for (size_t i = 0; i < len_display; i++) { - if (message[i] != '.') { - seg_chars++; - } - } - // start at the rightmost position of the display - pos_start = LED_MAX_CHARS - seg_chars; + pos_start = LED_MAX_CHARS - char_count; // start at the rightmost position } // Write to the display's buffer int cur_idx = pos_start; - for (size_t i = 0; i < len_display; i++) { - // Save the character because if there's a decimal, we need to skip it in - // the buffer + for (size_t i = 0; i < msg_len && cur_idx < LED_MAX_CHARS; i++) { char ch = message[i]; - // Look-ahead for a decimal point to attach to the current character - bool display_dot = false; - if (i + 1 < len_display && message[i + 1] == '.') { - display_dot = true; - i++; - len_display++; + if (ch == '.') { + // If the previous character has already been processed (or we're at the + // start of the message), we need to show the decimal as a character + if (i == 0 || message[i - 1] == '.') { + _alpha4->writeDigitAscii(cur_idx, ch, false); + cur_idx++; + } else { + // Set decimal on an already written character + _alpha4->writeDigitAscii(cur_idx - 1, message[i - 1], true); + } + continue; } + // Perform a look-ahead for the decimal + bool display_dot = (i + 1 < msg_len && message[i + 1] == '.'); + // Write the character to the display buffer _alpha4->writeDigitAscii(cur_idx, ch, display_dot); cur_idx++; } + // Issue the buffered data in RAM to the display _alpha4->writeDisplay(); } @@ -166,7 +172,7 @@ class drvOutQuadAlphaNum : public drvOutputBase { */ void WriteValue(float value) { char message[8 + 1]; - snprintf(message, sizeof(message), "%.5f", value); + snprintf(message, sizeof(message), "%.3f", value); WriteMessage(message); } From dd6599a2381f8ab0d4ad5935288244c47842756b Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 21 May 2025 12:30:51 -0400 Subject: [PATCH 22/26] match pb commit 13325a9 --- src/protos/i2c.pb.h | 4 +- src/protos/i2c_output.pb.c | 6 ++ src/protos/i2c_output.pb.h | 148 ++++++++++++++++++++----------------- src/protos/signal.pb.h | 2 +- 4 files changed, 90 insertions(+), 70 deletions(-) diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index b4a28c8e0..a2f28b052 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -336,10 +336,10 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cBusDescriptor_size 32 #define wippersnapper_i2c_I2cBusScan_size 42 #define wippersnapper_i2c_I2cBusScanned_size 6242 -#define wippersnapper_i2c_I2cDeviceAddOrReplace_size 139 +#define wippersnapper_i2c_I2cDeviceAddOrReplace_size 125 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 -#define wippersnapper_i2c_I2cDeviceOutputWrite_size 208 +#define wippersnapper_i2c_I2cDeviceOutputWrite_size 157 #define wippersnapper_i2c_I2cDeviceRemove_size 54 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 #if defined(wippersnapper_sensor_SensorEvent_size) diff --git a/src/protos/i2c_output.pb.c b/src/protos/i2c_output.pb.c index dfd0fc075..d8474b88b 100644 --- a/src/protos/i2c_output.pb.c +++ b/src/protos/i2c_output.pb.c @@ -12,6 +12,9 @@ PB_BIND(wippersnapper_i2c_output_LedBackpackConfig, wippersnapper_i2c_output_Led PB_BIND(wippersnapper_i2c_output_CharLCDConfig, wippersnapper_i2c_output_CharLCDConfig, AUTO) +PB_BIND(wippersnapper_i2c_output_OledConfig, wippersnapper_i2c_output_OledConfig, AUTO) + + PB_BIND(wippersnapper_i2c_output_I2cOutputAdd, wippersnapper_i2c_output_I2cOutputAdd, AUTO) @@ -21,6 +24,9 @@ PB_BIND(wippersnapper_i2c_output_LedBackpackWrite, wippersnapper_i2c_output_LedB PB_BIND(wippersnapper_i2c_output_CharLCDWrite, wippersnapper_i2c_output_CharLCDWrite, AUTO) +PB_BIND(wippersnapper_i2c_output_OLEDWrite, wippersnapper_i2c_output_OLEDWrite, 2) + + diff --git a/src/protos/i2c_output.pb.h b/src/protos/i2c_output.pb.h index e0282705b..e14e12dfd 100644 --- a/src/protos/i2c_output.pb.h +++ b/src/protos/i2c_output.pb.h @@ -10,16 +10,6 @@ #endif /* Enum definitions */ -/* * - LedBackpackBlinkRate represents supported, OPTIONAL, blink rates for LED backpack displays */ -typedef enum _wippersnapper_i2c_output_LedBackpackBlinkRate { - wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_UNSPECIFIED = 0, /* * No blinking. * */ - wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_OFF = 1, /* * No blinking. * */ - wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_2HZ = 2, /* * 2 Hz blink rate. * */ - wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_1HZ = 3, /* * 1 Hz blink rate. * */ - wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ = 4 /* * 0.5 Hz blink rate. * */ -} wippersnapper_i2c_output_LedBackpackBlinkRate; - /* * LedBackpackAlignment represents all text alignment option for LED backpack displays */ typedef enum _wippersnapper_i2c_output_LedBackpackAlignment { @@ -28,6 +18,14 @@ typedef enum _wippersnapper_i2c_output_LedBackpackAlignment { wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_RIGHT = 2 /* * Right-aligned. * */ } wippersnapper_i2c_output_LedBackpackAlignment; +/* * + Desired OLED display text 'magnification' size. */ +typedef enum _wippersnapper_i2c_output_OledTextSize { + wippersnapper_i2c_output_OledTextSize_OLED_TEXT_SIZE_UNSPECIFIED = 0, /* * Unspecified text size. * */ + wippersnapper_i2c_output_OledTextSize_OLED_TEXT_SIZE_DEFAULT = 1, /* * Default text size, 6x8px. * */ + wippersnapper_i2c_output_OledTextSize_OLED_TEXT_SIZE_LARGE = 2 /* * Larger text size option, 12x16px. * */ +} wippersnapper_i2c_output_OledTextSize; + /* Struct definitions */ /* * LedBackpackConfig represents the configuration for a LED backpack display. */ @@ -41,96 +39,101 @@ typedef struct _wippersnapper_i2c_output_LedBackpackConfig { typedef struct _wippersnapper_i2c_output_CharLCDConfig { uint32_t rows; /* * Number of rows for the character LCD. * */ uint32_t columns; /* * Number of columns for the character LCD. * */ - char backlight_color[15]; /* * Optional Backlight color for the character LCD, in Hex. * */ } wippersnapper_i2c_output_CharLCDConfig; +/* * + OledConfig represents the configuration for a OLED display. */ +typedef struct _wippersnapper_i2c_output_OledConfig { + uint32_t width; /* * Width of the OLED display in pixels. * */ + uint32_t height; /* * Height of the OLED display in pixels. * */ + wippersnapper_i2c_output_OledTextSize font_size; /* * Desired font magnification for the OLED display. Defaults to OLED_TEXT_SIZE_DEFAULT. * */ +} wippersnapper_i2c_output_OledConfig; + /* * I2cOutputAdd represents a request from the broker to add an I2C output device to a device. */ typedef struct _wippersnapper_i2c_output_I2cOutputAdd { pb_size_t which_config; union { - wippersnapper_i2c_output_LedBackpackConfig led_backpack_config; /* * Configuration for LED backpack. * */ - wippersnapper_i2c_output_CharLCDConfig char_lcd_config; /* * Configuration for character LCD. * */ + wippersnapper_i2c_output_LedBackpackConfig led_backpack_config; /* * Configuration for a LED backpack. * */ + wippersnapper_i2c_output_CharLCDConfig char_lcd_config; /* * Configuration for a character LCD. * */ + wippersnapper_i2c_output_OledConfig oled_config; /* * Configuration for an OLED display. * */ } config; } wippersnapper_i2c_output_I2cOutputAdd; /* * LedBackpackWrite represents a request from the broker to write a message to a LED backpack. */ typedef struct _wippersnapper_i2c_output_LedBackpackWrite { - pb_size_t which_message; - union { - char text[20]; /* * Text to write to the LED backpack. * */ - int32_t number_int; /* * Number to write to the LED backpack. * */ - float number_float; /* * Float to write to the LED backpack. * */ - } message; - bool adjust_brightness; /* * Optionally used to enable the brightness tag. * */ - int32_t brightness; /* * Optionally adjusts the brightness from 0 (off) to 15 (full brightness). * */ - wippersnapper_i2c_output_LedBackpackBlinkRate blink_rate; /* * Optionally sets the blink rate for the LED backpack. * */ - bool enable_scroll_marquee; /* * Optionally enables automatic text scrolling * */ - float scroll_marquee_speed; /* * Speed for the scrolling marquee. * */ + char message[8]; /* * Message to write to the LED backpack. * */ } wippersnapper_i2c_output_LedBackpackWrite; /* * CharLCDWrite represents a request from the broker to write to a character LCD. */ typedef struct _wippersnapper_i2c_output_CharLCDWrite { - char message[128]; /* * Message to write to the character LCD. * */ - char backlight_color[20]; /* * Optional Backlight color for the character LCD, in Hex. * */ - bool enable_scroll; /* * Optional Enable automatic scrolling for the character LCD. * */ + char message[100]; /* * Message to write to the character LCD. * */ + bool enable_backlight; /* * Whether to enable the backlight. Defaults to True. * */ } wippersnapper_i2c_output_CharLCDWrite; +/* * + OLEDWrite represents a request from the broker to write to a OLED display. */ +typedef struct _wippersnapper_i2c_output_OLEDWrite { + char message[512]; /* * Message to write to an OLED display. * */ +} wippersnapper_i2c_output_OLEDWrite; + #ifdef __cplusplus extern "C" { #endif /* Helper constants for enums */ -#define _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_UNSPECIFIED -#define _wippersnapper_i2c_output_LedBackpackBlinkRate_MAX wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ -#define _wippersnapper_i2c_output_LedBackpackBlinkRate_ARRAYSIZE ((wippersnapper_i2c_output_LedBackpackBlinkRate)(wippersnapper_i2c_output_LedBackpackBlinkRate_LED_BACKPACK_BLINK_RATE_HALFHZ+1)) - #define _wippersnapper_i2c_output_LedBackpackAlignment_MIN wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_UNSPECIFIED #define _wippersnapper_i2c_output_LedBackpackAlignment_MAX wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_RIGHT #define _wippersnapper_i2c_output_LedBackpackAlignment_ARRAYSIZE ((wippersnapper_i2c_output_LedBackpackAlignment)(wippersnapper_i2c_output_LedBackpackAlignment_LED_BACKPACK_ALIGNMENT_RIGHT+1)) +#define _wippersnapper_i2c_output_OledTextSize_MIN wippersnapper_i2c_output_OledTextSize_OLED_TEXT_SIZE_UNSPECIFIED +#define _wippersnapper_i2c_output_OledTextSize_MAX wippersnapper_i2c_output_OledTextSize_OLED_TEXT_SIZE_LARGE +#define _wippersnapper_i2c_output_OledTextSize_ARRAYSIZE ((wippersnapper_i2c_output_OledTextSize)(wippersnapper_i2c_output_OledTextSize_OLED_TEXT_SIZE_LARGE+1)) + #define wippersnapper_i2c_output_LedBackpackConfig_alignment_ENUMTYPE wippersnapper_i2c_output_LedBackpackAlignment +#define wippersnapper_i2c_output_OledConfig_font_size_ENUMTYPE wippersnapper_i2c_output_OledTextSize + + -#define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_ENUMTYPE wippersnapper_i2c_output_LedBackpackBlinkRate /* Initializer values for message structs */ #define wippersnapper_i2c_output_LedBackpackConfig_init_default {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} -#define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0, ""} +#define wippersnapper_i2c_output_CharLCDConfig_init_default {0, 0} +#define wippersnapper_i2c_output_OledConfig_init_default {0, 0, _wippersnapper_i2c_output_OledTextSize_MIN} #define wippersnapper_i2c_output_I2cOutputAdd_init_default {0, {wippersnapper_i2c_output_LedBackpackConfig_init_default}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_default {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_default {"", "", 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_default {""} +#define wippersnapper_i2c_output_CharLCDWrite_init_default {"", 0} +#define wippersnapper_i2c_output_OLEDWrite_init_default {""} #define wippersnapper_i2c_output_LedBackpackConfig_init_zero {0, _wippersnapper_i2c_output_LedBackpackAlignment_MIN} -#define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0, ""} +#define wippersnapper_i2c_output_CharLCDConfig_init_zero {0, 0} +#define wippersnapper_i2c_output_OledConfig_init_zero {0, 0, _wippersnapper_i2c_output_OledTextSize_MIN} #define wippersnapper_i2c_output_I2cOutputAdd_init_zero {0, {wippersnapper_i2c_output_LedBackpackConfig_init_zero}} -#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {0, {""}, 0, 0, _wippersnapper_i2c_output_LedBackpackBlinkRate_MIN, 0, 0} -#define wippersnapper_i2c_output_CharLCDWrite_init_zero {"", "", 0} +#define wippersnapper_i2c_output_LedBackpackWrite_init_zero {""} +#define wippersnapper_i2c_output_CharLCDWrite_init_zero {"", 0} +#define wippersnapper_i2c_output_OLEDWrite_init_zero {""} /* Field tags (for use in manual encoding/decoding) */ #define wippersnapper_i2c_output_LedBackpackConfig_brightness_tag 1 #define wippersnapper_i2c_output_LedBackpackConfig_alignment_tag 2 #define wippersnapper_i2c_output_CharLCDConfig_rows_tag 1 #define wippersnapper_i2c_output_CharLCDConfig_columns_tag 2 -#define wippersnapper_i2c_output_CharLCDConfig_backlight_color_tag 3 +#define wippersnapper_i2c_output_OledConfig_width_tag 1 +#define wippersnapper_i2c_output_OledConfig_height_tag 2 +#define wippersnapper_i2c_output_OledConfig_font_size_tag 3 #define wippersnapper_i2c_output_I2cOutputAdd_led_backpack_config_tag 1 #define wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag 2 -#define wippersnapper_i2c_output_LedBackpackWrite_text_tag 1 -#define wippersnapper_i2c_output_LedBackpackWrite_number_int_tag 2 -#define wippersnapper_i2c_output_LedBackpackWrite_number_float_tag 3 -#define wippersnapper_i2c_output_LedBackpackWrite_adjust_brightness_tag 4 -#define wippersnapper_i2c_output_LedBackpackWrite_brightness_tag 5 -#define wippersnapper_i2c_output_LedBackpackWrite_blink_rate_tag 6 -#define wippersnapper_i2c_output_LedBackpackWrite_enable_scroll_marquee_tag 7 -#define wippersnapper_i2c_output_LedBackpackWrite_scroll_marquee_speed_tag 8 +#define wippersnapper_i2c_output_I2cOutputAdd_oled_config_tag 3 +#define wippersnapper_i2c_output_LedBackpackWrite_message_tag 1 #define wippersnapper_i2c_output_CharLCDWrite_message_tag 1 -#define wippersnapper_i2c_output_CharLCDWrite_backlight_color_tag 2 -#define wippersnapper_i2c_output_CharLCDWrite_enable_scroll_tag 3 +#define wippersnapper_i2c_output_CharLCDWrite_enable_backlight_tag 2 +#define wippersnapper_i2c_output_OLEDWrite_message_tag 1 /* Struct field encoding specification for nanopb */ #define wippersnapper_i2c_output_LedBackpackConfig_FIELDLIST(X, a) \ @@ -141,58 +144,69 @@ X(a, STATIC, SINGULAR, UENUM, alignment, 2) #define wippersnapper_i2c_output_CharLCDConfig_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, UINT32, rows, 1) \ -X(a, STATIC, SINGULAR, UINT32, columns, 2) \ -X(a, STATIC, SINGULAR, STRING, backlight_color, 3) +X(a, STATIC, SINGULAR, UINT32, columns, 2) #define wippersnapper_i2c_output_CharLCDConfig_CALLBACK NULL #define wippersnapper_i2c_output_CharLCDConfig_DEFAULT NULL +#define wippersnapper_i2c_output_OledConfig_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, UINT32, width, 1) \ +X(a, STATIC, SINGULAR, UINT32, height, 2) \ +X(a, STATIC, SINGULAR, UENUM, font_size, 3) +#define wippersnapper_i2c_output_OledConfig_CALLBACK NULL +#define wippersnapper_i2c_output_OledConfig_DEFAULT NULL + #define wippersnapper_i2c_output_I2cOutputAdd_FIELDLIST(X, a) \ X(a, STATIC, ONEOF, MESSAGE, (config,led_backpack_config,config.led_backpack_config), 1) \ -X(a, STATIC, ONEOF, MESSAGE, (config,char_lcd_config,config.char_lcd_config), 2) +X(a, STATIC, ONEOF, MESSAGE, (config,char_lcd_config,config.char_lcd_config), 2) \ +X(a, STATIC, ONEOF, MESSAGE, (config,oled_config,config.oled_config), 3) #define wippersnapper_i2c_output_I2cOutputAdd_CALLBACK NULL #define wippersnapper_i2c_output_I2cOutputAdd_DEFAULT NULL #define wippersnapper_i2c_output_I2cOutputAdd_config_led_backpack_config_MSGTYPE wippersnapper_i2c_output_LedBackpackConfig #define wippersnapper_i2c_output_I2cOutputAdd_config_char_lcd_config_MSGTYPE wippersnapper_i2c_output_CharLCDConfig +#define wippersnapper_i2c_output_I2cOutputAdd_config_oled_config_MSGTYPE wippersnapper_i2c_output_OledConfig #define wippersnapper_i2c_output_LedBackpackWrite_FIELDLIST(X, a) \ -X(a, STATIC, ONEOF, STRING, (message,text,message.text), 1) \ -X(a, STATIC, ONEOF, INT32, (message,number_int,message.number_int), 2) \ -X(a, STATIC, ONEOF, FLOAT, (message,number_float,message.number_float), 3) \ -X(a, STATIC, SINGULAR, BOOL, adjust_brightness, 4) \ -X(a, STATIC, SINGULAR, INT32, brightness, 5) \ -X(a, STATIC, SINGULAR, UENUM, blink_rate, 6) \ -X(a, STATIC, SINGULAR, BOOL, enable_scroll_marquee, 7) \ -X(a, STATIC, SINGULAR, FLOAT, scroll_marquee_speed, 8) +X(a, STATIC, SINGULAR, STRING, message, 1) #define wippersnapper_i2c_output_LedBackpackWrite_CALLBACK NULL #define wippersnapper_i2c_output_LedBackpackWrite_DEFAULT NULL #define wippersnapper_i2c_output_CharLCDWrite_FIELDLIST(X, a) \ X(a, STATIC, SINGULAR, STRING, message, 1) \ -X(a, STATIC, SINGULAR, STRING, backlight_color, 2) \ -X(a, STATIC, SINGULAR, BOOL, enable_scroll, 3) +X(a, STATIC, SINGULAR, BOOL, enable_backlight, 2) #define wippersnapper_i2c_output_CharLCDWrite_CALLBACK NULL #define wippersnapper_i2c_output_CharLCDWrite_DEFAULT NULL +#define wippersnapper_i2c_output_OLEDWrite_FIELDLIST(X, a) \ +X(a, STATIC, SINGULAR, STRING, message, 1) +#define wippersnapper_i2c_output_OLEDWrite_CALLBACK NULL +#define wippersnapper_i2c_output_OLEDWrite_DEFAULT NULL + extern const pb_msgdesc_t wippersnapper_i2c_output_LedBackpackConfig_msg; extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDConfig_msg; +extern const pb_msgdesc_t wippersnapper_i2c_output_OledConfig_msg; extern const pb_msgdesc_t wippersnapper_i2c_output_I2cOutputAdd_msg; extern const pb_msgdesc_t wippersnapper_i2c_output_LedBackpackWrite_msg; extern const pb_msgdesc_t wippersnapper_i2c_output_CharLCDWrite_msg; +extern const pb_msgdesc_t wippersnapper_i2c_output_OLEDWrite_msg; /* Defines for backwards compatibility with code written before nanopb-0.4.0 */ #define wippersnapper_i2c_output_LedBackpackConfig_fields &wippersnapper_i2c_output_LedBackpackConfig_msg #define wippersnapper_i2c_output_CharLCDConfig_fields &wippersnapper_i2c_output_CharLCDConfig_msg +#define wippersnapper_i2c_output_OledConfig_fields &wippersnapper_i2c_output_OledConfig_msg #define wippersnapper_i2c_output_I2cOutputAdd_fields &wippersnapper_i2c_output_I2cOutputAdd_msg #define wippersnapper_i2c_output_LedBackpackWrite_fields &wippersnapper_i2c_output_LedBackpackWrite_msg #define wippersnapper_i2c_output_CharLCDWrite_fields &wippersnapper_i2c_output_CharLCDWrite_msg +#define wippersnapper_i2c_output_OLEDWrite_fields &wippersnapper_i2c_output_OLEDWrite_msg /* Maximum encoded size of messages (where known) */ -#define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_CharLCDWrite_size -#define wippersnapper_i2c_output_CharLCDConfig_size 28 -#define wippersnapper_i2c_output_CharLCDWrite_size 153 -#define wippersnapper_i2c_output_I2cOutputAdd_size 30 +#define WIPPERSNAPPER_I2C_OUTPUT_I2C_OUTPUT_PB_H_MAX_SIZE wippersnapper_i2c_output_OLEDWrite_size +#define wippersnapper_i2c_output_CharLCDConfig_size 12 +#define wippersnapper_i2c_output_CharLCDWrite_size 103 +#define wippersnapper_i2c_output_I2cOutputAdd_size 16 #define wippersnapper_i2c_output_LedBackpackConfig_size 13 -#define wippersnapper_i2c_output_LedBackpackWrite_size 43 +#define wippersnapper_i2c_output_LedBackpackWrite_size 9 +#define wippersnapper_i2c_output_OLEDWrite_size 514 +#define wippersnapper_i2c_output_OledConfig_size 14 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index c7b737dae..ff21c8698 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -257,7 +257,7 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; /* Maximum encoded size of messages (where known) */ #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[212];}; +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[161];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; From 59c8a7332c84700bdbbb77fbb48562501c139cfe Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 21 May 2025 12:44:33 -0400 Subject: [PATCH 23/26] Update firmware to match previous PB commit's updated PBs --- src/components/i2c/controller.cpp | 7 +--- src/components/i2c/drivers/drvOutCharLcd.h | 21 +++++++--- src/components/i2c/drivers/drvOutputBase.h | 49 +++++----------------- 3 files changed, 28 insertions(+), 49 deletions(-) diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index 60ec9cf15..ed13c547b 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -834,11 +834,8 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg == wippersnapper_i2c_I2cDeviceOutputWrite_write_led_backpack_tag) { WS_DEBUG_PRINTLN("[i2c] Writing to LED backpack..."); - if (!driver->LedBackpackWrite(&_i2c_model->GetI2cDeviceOutputWriteMsg() - ->output_msg.write_led_backpack)) { - WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to LED backpack!"); - return false; - } + driver->WriteMessage(_i2c_model->GetI2cDeviceOutputWriteMsg() + ->output_msg.write_led_backpack.message); } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg == wippersnapper_i2c_I2cDeviceOutputWrite_write_char_lcd_tag) { WS_DEBUG_PRINTLN("[i2c] Writing to char LCD..."); diff --git a/src/components/i2c/drivers/drvOutCharLcd.h b/src/components/i2c/drivers/drvOutCharLcd.h index c29b7040c..3da962409 100644 --- a/src/components/i2c/drivers/drvOutCharLcd.h +++ b/src/components/i2c/drivers/drvOutCharLcd.h @@ -82,6 +82,22 @@ class drvOutCharLcd : public drvOutputBase { _enable_backlight = enable_backlight; } + /*! + @brief Enables or disables the backlight on a character LCD. + @param enable_backlight + True to enable the backlight, False to disable it. + */ + void EnableBackLightCharLCD(bool enable_backlight) { + if (_lcd == nullptr) + return; + if (_enable_backlight) { + _lcd->setBacklight(HIGH); + } else { + _lcd->setBacklight(LOW); + } + _enable_backlight = enable_backlight; + } + /*! @brief Writes a message to the LCD. @param message @@ -94,11 +110,6 @@ class drvOutCharLcd : public drvOutputBase { // Before writing, let's clear the display _lcd->clear(); - // TODO: Remove all the prints! - // Print the message to the serial - Serial.print("Writing message to Char. LCD: "); - Serial.println(message); - size_t message_length = strlen(message); size_t cur_idx = 0; // Current index in the message diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index f267865d9..6a80e13dc 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -102,6 +102,15 @@ class drvOutputBase : public drvBase { // noop } + /*! + @brief Enables or disables the backlight on a character LCD. + @param enable_backlight + True to enable the backlight, False to disable it. + */ + void EnableBackLightCharLCD(bool enable_backlight) { + // noop + } + /*! @brief Writes a message to the LCD. @param write_char_lcd @@ -110,10 +119,8 @@ class drvOutputBase : public drvBase { */ bool WriteMessageCharLCD(wippersnapper_i2c_output_CharLCDWrite *write_char_lcd) { + EnableBackLightCharLCD(write_char_lcd->enable_backlight); WriteMessage(write_char_lcd->message); - // NOTE: While this isn't calling any other funcs in here and ret'ing true, - // I want to keep this function high-level for when we implement backlight - // color and scrolling. return true; } @@ -126,42 +133,6 @@ class drvOutputBase : public drvBase { // noop } - /*! - @brief High-level fn, executes a call to the appropriate driver - function(s) based on the message data type to write. - @param msg_backpack_write - Pointer to a wippersnapper_i2c_output_LedBackpackWrite message. - @returns True if the message was written successfully, False otherwise. - */ - bool LedBackpackWrite( - wippersnapper_i2c_output_LedBackpackWrite *msg_backpack_write) { - // Check if we should adjust brightness - if (msg_backpack_write->adjust_brightness) - SetLedBackpackBrightness((uint8_t)msg_backpack_write->brightness); - - // Write the message to a LED backpack - switch (msg_backpack_write->which_message) { - case wippersnapper_i2c_output_LedBackpackWrite_text_tag: - WS_DEBUG_PRINTLN("[i2c] Writing text to LED backpack..."); - WriteMessage(msg_backpack_write->message.text); - break; - case wippersnapper_i2c_output_LedBackpackWrite_number_int_tag: - WS_DEBUG_PRINTLN("[i2c] Writing int to LED backpack..."); - WriteValue(msg_backpack_write->message.number_int); - break; - case wippersnapper_i2c_output_LedBackpackWrite_number_float_tag: - WS_DEBUG_PRINTLN("[i2c] Writing float to LED backpack..."); - WriteValue(msg_backpack_write->message.number_float); - break; - default: - WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine LED backpack " - "message type!"); - return false; - break; - } - return true; - } - protected: }; #endif // DRV_OUTPUT_BASE_H \ No newline at end of file From 4598bbe502ec5cbb4322c10a251c1b9e8be94627 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 21 May 2025 13:37:44 -0400 Subject: [PATCH 24/26] Add SSD1306 compatability --- platformio.ini | 1 + src/components/i2c/controller.cpp | 22 ++++ src/components/i2c/controller.h | 1 + src/components/i2c/drivers/drvOutSsd1306.h | 138 +++++++++++++++++++++ src/components/i2c/drivers/drvOutputBase.h | 24 +++- src/protos/i2c.pb.c | 2 +- src/protos/i2c.pb.h | 8 +- src/protos/signal.pb.h | 2 +- 8 files changed, 193 insertions(+), 5 deletions(-) create mode 100644 src/components/i2c/drivers/drvOutSsd1306.h diff --git a/platformio.ini b/platformio.ini index 354b837c5..fd85d5fa7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -91,6 +91,7 @@ lib_deps = https://github.com/Sensirion/arduino-i2c-scd4x.git https://github.com/adafruit/Adafruit_LED_Backpack.git https://github.com/adafruit/Adafruit_LiquidCrystal.git + https://github.com/adafruit/Adafruit_SSD1306.git ; Common build environment for ESP32 platform [common:esp32] diff --git a/src/components/i2c/controller.cpp b/src/components/i2c/controller.cpp index ed13c547b..e47a22a42 100644 --- a/src/components/i2c/controller.cpp +++ b/src/components/i2c/controller.cpp @@ -375,6 +375,11 @@ static const std::map I2cFactoryOutput = { [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, const char *driver_name) -> drvOutputBase * { return new drvOutCharLcd(i2c, addr, mux_channel, driver_name); + }}, + {"ssd1306", + [](TwoWire *i2c, uint16_t addr, uint32_t mux_channel, + const char *driver_name) -> drvOutputBase * { + return new drvOutSsd1306(i2c, addr, mux_channel, driver_name); }}}; ///< I2C output driver factory /*! @@ -844,6 +849,14 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to char LCD!"); return false; } + } else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg == + wippersnapper_i2c_I2cDeviceOutputWrite_write_oled_tag) { + WS_DEBUG_PRINTLN("[i2c] Writing to SSD1306 OLED..."); + // Note: In the future, we can expand this to support other OLEDs by + // creating and checking a tag within the write oled msg (e.g. SSD1327, + // etc.) + driver->WriteMessageSSD1306(_i2c_model->GetI2cDeviceOutputWriteMsg() + ->output_msg.write_oled.message); } else { WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine I2C Output Write type!"); return false; @@ -1036,6 +1049,15 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) { } else if (config == wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag) { WS_DEBUG_PRINTLN("[i2c] Configuring char LCD..."); + } else if (config == + wippersnapper_i2c_output_I2cOutputAdd_oled_config_tag) { + WS_DEBUG_PRINTLN("[i2c] Configuring OLED..."); + wippersnapper_i2c_output_OledConfig cfg = + _i2c_model->GetI2cDeviceAddOrReplaceMsg() + ->i2c_output_add.config.oled_config; + WS_DEBUG_PRINT("[i2c] Got cfg, calling ConfigureOLED..."); + drv_out->ConfigureSSD1306(cfg.width, cfg.height, cfg.font_size); + WS_DEBUG_PRINTLN("OK!"); } else { WS_DEBUG_PRINTLN( "[i2c] ERROR: Unknown config specified for output driver!"); diff --git a/src/components/i2c/controller.h b/src/components/i2c/controller.h index 2492e4b3f..201be0a86 100644 --- a/src/components/i2c/controller.h +++ b/src/components/i2c/controller.h @@ -48,6 +48,7 @@ #include "drivers/drvOut7Seg.h" #include "drivers/drvOutCharLcd.h" #include "drivers/drvOutQuadAlphaNum.h" +#include "drivers/drvOutSsd1306.h" #include "drivers/drvOutputBase.h" ///< Base i2c output driver class #include "drivers/drvPct2075.h" #include "drivers/drvPm25.h" diff --git a/src/components/i2c/drivers/drvOutSsd1306.h b/src/components/i2c/drivers/drvOutSsd1306.h new file mode 100644 index 000000000..f02a5c867 --- /dev/null +++ b/src/components/i2c/drivers/drvOutSsd1306.h @@ -0,0 +1,138 @@ +/*! + * @file drvOutSsd1306.h + * + * Device driver for OLED displays with a SSD1306 driver + * + * 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 for Adafruit Industries 2025 + * + * MIT license, all text here must be included in any redistribution. + * + */ + +#ifndef DRV_OUT_SSD1306_H +#define DRV_OUT_SSD1306_H + +#include "drvOutputBase.h" +#include +#include + +/*! + @brief Class that provides a driver interface for a SSD1306 OLED display. + This class is a wrapper around the Adafruit_SSD1306 library. +*/ +class drvOutSsd1306 : public drvOutputBase { +public: + /*! + @brief Constructor for a lcd character display. + @param i2c + The I2C interface. + @param sensorAddress + 7-bit device address. + @param mux_channel + The I2C multiplexer channel. + @param driver_name + The name of the driver. + */ + drvOutSsd1306(TwoWire *i2c, uint16_t sensorAddress, uint32_t mux_channel, + const char *driver_name) + : drvOutputBase(i2c, sensorAddress, mux_channel, driver_name) { + // Initialization handled by drvOutPutBase constructor + } + + /*! + @brief Destructor for a quad alphanumeric display. + */ + ~drvOutSsd1306() { + if (_display != nullptr) { + _display->ssd1306_command(SSD1306_DISPLAYOFF); + delete _display; + _display = nullptr; + } + } + + /*! + @brief Initializes the SSD1306 display and begins I2C. + @returns True if initialized successfully, False otherwise. + */ + bool begin() { + // Attempt to create and allocate a SSD1306 obj. + _display = new Adafruit_SSD1306(_width, _height, _i2c); + if (!_display->begin(SSD1306_SWITCHCAPVCC, _address)) + return false; + // Clear the buffer + _display->clearDisplay(); + // Configure the text size and color + _display->setTextSize(_text_sz); + _display->setTextColor(SSD1306_WHITE); + // Reset the cursor position + _display->setCursor(0, 0); + _display->display(); + return true; + } + + /*! + @brief Configures a SSD1306 OLED display. Must be called before driver + begin() + @param width + The width of the display in pixels. + @param height + The height of the display in pixels. + @param text_size + The magnification factor for the text size. + */ + void ConfigureSSD1306(uint8_t width, uint8_t height, uint8_t text_size) { + _width = width; + _height = height; + _text_sz = text_size; + } + + /*! + @brief Writes a message to the SSD1306 display. + @param message + The message to be displayed. + */ + void WriteMessageSSD1306(const char *message) { + if (_display == nullptr) + return; + + // Start with a fresh display buffer + // and settings + int16_t y_idx = 0; + _display->clearDisplay(); + _display->setTextSize(_text_sz); + _display->setTextColor(SSD1306_WHITE); + _display->setCursor(0, y_idx); + _display->display(); + + // 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 (message[i] == '\\' && i + 1 < msg_size && message[i + 1] == 'n') { + // detected a newline char sequence (\n) + i++; + // Skip to the next possible line + y_idx += line_height; + _display->setCursor(0, y_idx); + } else { + _display->print(message[i]); + _display->display(); + } + } + } + +protected: + Adafruit_SSD1306 *_display = + nullptr; ///< Pointer to the Adafruit_SSD1306 object + uint8_t _width; ///< Width of the display in pixels + uint8_t _height; ///< Height of the display in pixels + uint8_t _text_sz; ///< Text size of the display +}; + +#endif // DRV_OUT_SSD1306_H \ No newline at end of file diff --git a/src/components/i2c/drivers/drvOutputBase.h b/src/components/i2c/drivers/drvOutputBase.h index 6a80e13dc..ad75e12e3 100644 --- a/src/components/i2c/drivers/drvOutputBase.h +++ b/src/components/i2c/drivers/drvOutputBase.h @@ -133,6 +133,28 @@ class drvOutputBase : public drvBase { // noop } -protected: + /*! + @brief Configures a SSD1306 OLED display. Must be called before driver + begin() + @param width + The width of the display in pixels. + @param height + The height of the display in pixels. + @param text_size + The magnification factor for the text size. + */ + virtual void ConfigureSSD1306(uint8_t width, uint8_t height, + uint8_t text_size) { + // noop + } + + /*! + @brief Writes a message to the SSD1306 display. + @param message + The message to be displayed. + */ + virtual void WriteMessageSSD1306(const char *message) { + // noop + } }; #endif // DRV_OUTPUT_BASE_H \ No newline at end of file diff --git a/src/protos/i2c.pb.c b/src/protos/i2c.pb.c index 14ee91854..6fddefe17 100644 --- a/src/protos/i2c.pb.c +++ b/src/protos/i2c.pb.c @@ -33,7 +33,7 @@ PB_BIND(wippersnapper_i2c_I2cDeviceRemoved, wippersnapper_i2c_I2cDeviceRemoved, PB_BIND(wippersnapper_i2c_I2cDeviceEvent, wippersnapper_i2c_I2cDeviceEvent, 2) -PB_BIND(wippersnapper_i2c_I2cDeviceOutputWrite, wippersnapper_i2c_I2cDeviceOutputWrite, AUTO) +PB_BIND(wippersnapper_i2c_I2cDeviceOutputWrite, wippersnapper_i2c_I2cDeviceOutputWrite, 2) diff --git a/src/protos/i2c.pb.h b/src/protos/i2c.pb.h index a2f28b052..c6e41a862 100644 --- a/src/protos/i2c.pb.h +++ b/src/protos/i2c.pb.h @@ -133,6 +133,7 @@ typedef struct _wippersnapper_i2c_I2cDeviceOutputWrite { union { wippersnapper_i2c_output_LedBackpackWrite write_led_backpack; /* * Optional - If the I2C device is a LED backpack, fill this field. * */ wippersnapper_i2c_output_CharLCDWrite write_char_lcd; /* * Optional - If the I2C device is a character LCD, fill this field. * */ + wippersnapper_i2c_output_OLEDWrite write_oled; /* * Optional - If the I2C device is an OLED display, fill this field. * */ } output_msg; } wippersnapper_i2c_I2cDeviceOutputWrite; @@ -221,6 +222,7 @@ extern "C" { #define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_tag 1 #define wippersnapper_i2c_I2cDeviceOutputWrite_write_led_backpack_tag 2 #define wippersnapper_i2c_I2cDeviceOutputWrite_write_char_lcd_tag 3 +#define wippersnapper_i2c_I2cDeviceOutputWrite_write_oled_tag 4 /* Struct field encoding specification for nanopb */ #define wippersnapper_i2c_I2cDeviceDescriptor_FIELDLIST(X, a) \ @@ -301,12 +303,14 @@ X(a, STATIC, REPEATED, MESSAGE, i2c_device_events, 2) #define wippersnapper_i2c_I2cDeviceOutputWrite_FIELDLIST(X, a) \ X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) \ X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_led_backpack,output_msg.write_led_backpack), 2) \ -X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_char_lcd,output_msg.write_char_lcd), 3) +X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_char_lcd,output_msg.write_char_lcd), 3) \ +X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_oled,output_msg.write_oled), 4) #define wippersnapper_i2c_I2cDeviceOutputWrite_CALLBACK NULL #define wippersnapper_i2c_I2cDeviceOutputWrite_DEFAULT NULL #define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor #define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_led_backpack_MSGTYPE wippersnapper_i2c_output_LedBackpackWrite #define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_char_lcd_MSGTYPE wippersnapper_i2c_output_CharLCDWrite +#define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_oled_MSGTYPE wippersnapper_i2c_output_OLEDWrite extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceDescriptor_msg; extern const pb_msgdesc_t wippersnapper_i2c_I2cBusDescriptor_msg; @@ -339,7 +343,7 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg; #define wippersnapper_i2c_I2cDeviceAddOrReplace_size 125 #define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56 #define wippersnapper_i2c_I2cDeviceDescriptor_size 50 -#define wippersnapper_i2c_I2cDeviceOutputWrite_size 157 +#define wippersnapper_i2c_I2cDeviceOutputWrite_size 569 #define wippersnapper_i2c_I2cDeviceRemove_size 54 #define wippersnapper_i2c_I2cDeviceRemoved_size 54 #if defined(wippersnapper_sensor_SensorEvent_size) diff --git a/src/protos/signal.pb.h b/src/protos/signal.pb.h index ff21c8698..596c42840 100644 --- a/src/protos/signal.pb.h +++ b/src/protos/signal.pb.h @@ -257,7 +257,7 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg; /* Maximum encoded size of messages (where known) */ #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size) -union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[161];}; +union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[573];}; #endif #if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size) union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];}; From c1ace0bcd8886e7e884fcddb86571dc317ba66a1 Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 21 May 2025 16:01:12 -0400 Subject: [PATCH 25/26] Optimizations within pb.h --- src/pb.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pb.h b/src/pb.h index f5c9c6f34..fa7e0d893 100644 --- a/src/pb.h +++ b/src/pb.h @@ -16,7 +16,7 @@ /* Define this if your CPU / compiler combination does not support * unaligned memory access to packed structures. Note that packed * structures are only used when requested in .proto options. */ -/* #define PB_NO_PACKED_STRUCTS 1 */ +#define PB_NO_PACKED_STRUCTS 1 /* Increase the number of required fields that are tracked. * A compiler warning will tell if you need this. */ @@ -26,14 +26,14 @@ /* #define PB_FIELD_32BIT 1 */ /* Disable support for error messages in order to save some code space. */ -/* #define PB_NO_ERRMSG 1 */ +#define PB_NO_ERRMSG 1 /* Disable support for custom streams (support only memory buffers). */ -/* #define PB_BUFFER_ONLY 1 */ +#define PB_BUFFER_ONLY 1 /* Disable support for 64-bit datatypes, for compilers without int64_t or to save some code space. */ -/* #define PB_WITHOUT_64BIT 1 */ +#define PB_WITHOUT_64BIT 1 /* Don't encode scalar arrays as packed. This is only to be used when * the decoder on the receiving side cannot process packed scalar arrays. From 84a40177b6445abcaf99e557b3526d022a76b00d Mon Sep 17 00:00:00 2001 From: brentru Date: Wed, 21 May 2025 16:02:46 -0400 Subject: [PATCH 26/26] Modifications for @tyeth review --- platformio.ini | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index fd85d5fa7..fc6394b8c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -78,6 +78,9 @@ lib_deps = adafruit/Adafruit STMPE610 adafruit/Adafruit TouchScreen adafruit/Adafruit MQTT Library + adafruit/Adafruit LED Backpack Library + adafruit/Adafruit LiquidCrystal + adafruit/Adafruit SSD1306 https://github.com/adafruit/Adafruit_SHT4X.git bblanchon/ArduinoJson https://github.com/adafruit/SdFat.git @@ -89,9 +92,6 @@ lib_deps = https://github.com/adafruit/RTClib.git https://github.com/bblanchon/ArduinoStreamUtils.git https://github.com/Sensirion/arduino-i2c-scd4x.git - https://github.com/adafruit/Adafruit_LED_Backpack.git - https://github.com/adafruit/Adafruit_LiquidCrystal.git - https://github.com/adafruit/Adafruit_SSD1306.git ; Common build environment for ESP32 platform [common:esp32]