From 4dced853242ff3cd26a8e3bbfee663d387fb844b Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 12:09:28 -0400 Subject: [PATCH 01/11] experimenting with adding nanopb to embedded-base --- .gitmodules | 3 +++ dev/nanopb/CMakeLists.txt | 8 ++++++++ dev/nanopb/nanopb | 1 + dev/nanopb/serverdata.options | 2 ++ dev/nanopb/serverdata.proto | 14 ++++++++++++++ 5 files changed, 28 insertions(+) create mode 100644 dev/nanopb/CMakeLists.txt create mode 160000 dev/nanopb/nanopb create mode 100644 dev/nanopb/serverdata.options create mode 100644 dev/nanopb/serverdata.proto diff --git a/.gitmodules b/.gitmodules index 393784b6..762fbcbd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -2,3 +2,6 @@ [submodule "dev/OpenOCD"] path = dev/OpenOCD url = https://github.com/STMicroelectronics/OpenOCD.git +[submodule "dev/nanopb/nanopb"] + path = dev/nanopb/nanopb + url = https://github.com/nanopb/nanopb.git diff --git a/dev/nanopb/CMakeLists.txt b/dev/nanopb/CMakeLists.txt new file mode 100644 index 00000000..7a531d71 --- /dev/null +++ b/dev/nanopb/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.22) + +set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/nanopb/extra) +find_package(Nanopb REQUIRED) + +nanopb_generate_cpp(TARGET proto serverdata.proto) + +target_link_libraries(${CMAKE_PROJECT_NAME} proto) diff --git a/dev/nanopb/nanopb b/dev/nanopb/nanopb new file mode 160000 index 00000000..c716db13 --- /dev/null +++ b/dev/nanopb/nanopb @@ -0,0 +1 @@ +Subproject commit c716db13070bfb7de03b33f5a6558528cbf8a249 diff --git a/dev/nanopb/serverdata.options b/dev/nanopb/serverdata.options new file mode 100644 index 00000000..77860c7c --- /dev/null +++ b/dev/nanopb/serverdata.options @@ -0,0 +1,2 @@ +serverdata.v2.ServerData.unit max_size: 15 +serverdata.v2.ServerData.values max_count: 5 diff --git a/dev/nanopb/serverdata.proto b/dev/nanopb/serverdata.proto new file mode 100644 index 00000000..3d74e6b0 --- /dev/null +++ b/dev/nanopb/serverdata.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; + +package serverdata.v2; + +message ServerData { + // ensure old type is reserved + reserved 1; + reserved "value"; + + string unit = 2; + // time since unix epoch in MICROSECONDS + uint64 time_us = 3; + repeated float values = 4; +} From a47bd23d6dda1aee79c46b3f3420b293b59651cc Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 12:21:06 -0400 Subject: [PATCH 02/11] fixes for u_nx_debug.c --- NetX/src/u_nx_debug.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/NetX/src/u_nx_debug.c b/NetX/src/u_nx_debug.c index 9869979e..4add549d 100644 --- a/NetX/src/u_nx_debug.c +++ b/NetX/src/u_nx_debug.c @@ -1,6 +1,17 @@ #include "u_nx_debug.h" #include "nxd_ptp_client.h" +#if defined(__has_include) +#if __has_include("nxd_mqtt_client.h") +#include "nxd_mqtt_client.h" +#define U_NX_DEBUG_HAS_MQTT 1 +#endif +#endif + +#ifndef U_NX_DEBUG_HAS_MQTT +#define U_NX_DEBUG_HAS_MQTT 0 +#endif + // clang-format off /* Converts a NetX status macro to a printable string. */ @@ -74,8 +85,11 @@ const char* nx_status_toString(UINT status) { case NX_CONTINUE: return "NX_CONTINUE"; case NX_TCPIP_OFFLOAD_ERROR: return "NX_TCPIP_OFFLOAD_ERROR"; - /* MQTT-specific stuff. */ + /* MQTT-specific stuff. */ +#if U_NX_DEBUG_HAS_MQTT +#if (NXD_MQTT_SUCCESS != NX_SUCCESS) case NXD_MQTT_SUCCESS: return "NXD_MQTT_SUCCESS"; +#endif case NXD_MQTT_ALREADY_CONNECTED: return "NXD_MQTT_ALREADY_CONNECTED"; case NXD_MQTT_NOT_CONNECTED: return "NXD_MQTT_NOT_CONNECTED"; case NXD_MQTT_MUTEX_FAILURE: return "NXD_MQTT_MUTEX_FAILURE"; @@ -100,6 +114,7 @@ const char* nx_status_toString(UINT status) { case NXD_MQTT_ERROR_SERVER_UNAVAILABLE: return "NXD_MQTT_ERROR_SERVER_UNAVAILABLE"; case NXD_MQTT_ERROR_BAD_USERNAME_PASSWORD: return "NXD_MQTT_ERROR_BAD_USERNAME_PASSWORD"; case NXD_MQTT_ERROR_NOT_AUTHORIZED: return "NXD_MQTT_ERROR_NOT_AUTHORIZED"; +#endif /* PTP-specific stuff. */ case NX_PTP_CLIENT_NOT_STARTED: return "NX_PTP_CLIENT_NOT_STARTED"; From dc9076036a7c997595b41b2ee6bcec0af830ce83 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 16:26:37 -0400 Subject: [PATCH 03/11] somemore stuff --- NetX/inc/u_nx_protobuf.h | 71 ++++++++++++++++++++++++++++++++++++++++ NetX/src/u_nx_protobuf.c | 33 +++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 NetX/inc/u_nx_protobuf.h create mode 100644 NetX/src/u_nx_protobuf.c diff --git a/NetX/inc/u_nx_protobuf.h b/NetX/inc/u_nx_protobuf.h new file mode 100644 index 00000000..91736d14 --- /dev/null +++ b/NetX/inc/u_nx_protobuf.h @@ -0,0 +1,71 @@ +#pragma once + +// clang-format off + +/* +* Wrapper for structuring and sending protobuf Ethernet messages over MQTT. +* This API sits above the lower-level u_nx_ethernet.h driver layer. Messages with nonstandard formats can still be sent using the u_nx_ethernet.h API directly. +*/ + +#include +#include +#include "serverdata.pb.h" + +/* CONFIG: Compile-time validation of topic size, unit size, and number of values. */ +#define PB_VALIDATE_ARGS(topic, unit, num_values) \ + do { \ + _Static_assert( \ + sizeof(topic) <= 100, \ + "MQTT topic parameter exceeds maximum length of 100 allowed by `nx_protobuf_mqtt_message_create()`."\ + ); \ + _Static_assert( \ + sizeof(unit) <= 15, \ + "MQTT unit parameter exceeds maximum length of 15 allowed by `nx_protobuf_mqtt_message_create()`." \ + ); \ + _Static_assert( \ + (num_values) >= 1, \ + "Must pass at least 1 value into the variable argument of `nx_protobuf_mqtt_message_create()`." \ + ); \ + _Static_assert( \ + (num_values) <= 5, \ + "Cannot pass more than 5 values into the variable argument of `nx_protobuf_mqtt_message_create()`." \ + ); \ + } while (0) + + +/* Helper macros. */ +#define PB_COUNT_ARGS(...) (sizeof((float[]){ __VA_ARGS__ }) / sizeof(float)) // Returns the number of arguments passed into it. +#define PB_STR_LEN(s) (sizeof(s) - 1) // Returns the length of a string literal. + +/** + * @brief Creates and formats a `ethernet_mqtt_message_t` object, and returns it to the caller. + * @param topic (const char*) String literal representing the message's MQTT topic name. + * @param unit (const char*) String literal representing the unit of the message's data. + * @param ... (float) The data to be sent in the message. This is a variable argument, so it can be repeated depending on how many datapoints you want to send. If you pass in more datapoints than allowed, you will get a compile-time error. + * @return An `ethernet_mqtt_message_t` object. + * @note If message creation was not completed for any reason, .initialized will be false in the returned `ethernet_mqtt_message_t` object. You may still use the object as you please (including attempting to initialize it again), but attempting to send the message (via `nx_protobuf_mqtt_message_send()`) will return an error. + */ +#define nx_protobuf_mqtt_message_create(topic, unit, ...) \ + ({ \ + PB_VALIDATE_ARGS(topic, unit, PB_COUNT_ARGS(__VA_ARGS__)); \ + _nx_protobuf_mqtt_message_create( \ + (topic), PB_STR_LEN(topic), \ + (unit), PB_STR_LEN(unit), \ + (float[]){ __VA_ARGS__ }, \ + PB_COUNT_ARGS(__VA_ARGS__) \ + ); \ + }) + + +/* Ethernet MQTT Message. */ +typedef struct { + const char* topic; + int topic_size; + serverdata_v2_ServerData msg; + bool initialized; +} ethernet_mqtt_message_t; + +/* MACRO IMPLEMENTATIONS */ +ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size_t topic_len, const char* unit, size_t unit_len, const float values[], int values_size); + +// clang-format on \ No newline at end of file diff --git a/NetX/src/u_nx_protobuf.c b/NetX/src/u_nx_protobuf.c new file mode 100644 index 00000000..61026d63 --- /dev/null +++ b/NetX/src/u_nx_protobuf.c @@ -0,0 +1,33 @@ +#include +#include "u_tx_debug.h" +#include "u_nx_protobuf.h" +#include "u_nx_ethernet.h" + +ethernet_mqtt_message_t _nx_protobuf_create_mqtt_message(const char* topic, const char* unit, float[] values, int values_size) { + /* Zero-initialize the protobuf struct and the sendable ethernet_mqtt_message_t message. */ + serverdata_v2_ServerData protobuf = serverdata_v2_ServerData_init_zero; + ethernet_mqtt_message_t message = { 0 }; + message.initialized = false; + + /* Calculate topic size. */ + int topic_size = strlen(topic); + if(topic_size > ETH_MAX_TOPIC_SIZE) { + PRINTLN_ERROR("MQTT Message topic exceeds maximum length (Topic: %s).", topic); + return message; // Return empty, uninitialized message. + } + + /* Get the PTP time and convert to appropriate protobuf time. */ + NX_PTP_DATE_TIME datetime = ethernet_get_time(); + uint64_t time_us = datetime.nanosecond; // u_TODO - this is temporary + // u_TODO - actually figure out how to convert this like it should be. Probably ask jack how this should be set up? + + /* Pack the protobuf message. */ + // PROTOBUF SCHEMA LOOKS LIKE THIS: + // typedef struct _serverdata_v2_ServerData { + // char unit[15]; + // uint64_t time_us; + // pb_size_t values_count; + // float values[5]; + // } serverdata_v2_ServerData; + *(msg.unit) = +} \ No newline at end of file From 8888b4558aa7b8843f0b7be8972f3fad4655f235 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 16:42:35 -0400 Subject: [PATCH 04/11] better static asserts --- NetX/inc/u_nx_protobuf.h | 46 +++++++++++++++++++++++----------------- NetX/src/u_nx_protobuf.c | 5 ++--- 2 files changed, 29 insertions(+), 22 deletions(-) diff --git a/NetX/inc/u_nx_protobuf.h b/NetX/inc/u_nx_protobuf.h index 91736d14..7842358b 100644 --- a/NetX/inc/u_nx_protobuf.h +++ b/NetX/inc/u_nx_protobuf.h @@ -11,25 +11,33 @@ #include #include "serverdata.pb.h" +/* Stringification macros. */ +#define PB_STR_HELPER(x) #x // Helper for PB_TOSTR(). Probably should never use directly. +#define PB_TOSTR(x) PB_STR_HELPER(x) // Converts a macro's value into a string. + /* CONFIG: Compile-time validation of topic size, unit size, and number of values. */ -#define PB_VALIDATE_ARGS(topic, unit, num_values) \ - do { \ - _Static_assert( \ - sizeof(topic) <= 100, \ - "MQTT topic parameter exceeds maximum length of 100 allowed by `nx_protobuf_mqtt_message_create()`."\ - ); \ - _Static_assert( \ - sizeof(unit) <= 15, \ - "MQTT unit parameter exceeds maximum length of 15 allowed by `nx_protobuf_mqtt_message_create()`." \ - ); \ - _Static_assert( \ - (num_values) >= 1, \ - "Must pass at least 1 value into the variable argument of `nx_protobuf_mqtt_message_create()`." \ - ); \ - _Static_assert( \ - (num_values) <= 5, \ - "Cannot pass more than 5 values into the variable argument of `nx_protobuf_mqtt_message_create()`." \ - ); \ +#define PB_MAX_TOPIC_LENGTH 100 // Maximum +#define PB_MAX_UNIT_LENGTH 15 +#define PB_MIN_DATAPOINTS 1 +#define PB_MAX_DATAPOINTS 5 +#define PB_VALIDATE_ARGS(topic, unit, num_values) \ + do { \ + _Static_assert( \ + sizeof(topic) <= PB_MAX_TOPIC_LENGTH, \ + "MQTT topic parameter exceeds maximum length of " PB_TOSTR(PB_MAX_TOPIC_LENGTH) " allowed by `nx_protobuf_mqtt_message_create()`."\ + ); \ + _Static_assert( \ + sizeof(unit) <= PB_MAX_UNIT_LENGTH, \ + "MQTT unit parameter exceeds maximum length of " PB_TOSTR(PB_MAX_UNIT_LENGTH) " allowed by `nx_protobuf_mqtt_message_create()`." \ + ); \ + _Static_assert( \ + (num_values) >= PB_MIN_DATAPOINTS, \ + "Must pass at least " PB_TOSTR(PB_MIN_DATAPOINTS) " value into the variable argument of `nx_protobuf_mqtt_message_create()`." \ + ); \ + _Static_assert( \ + (num_values) <= PB_MAX_DATAPOINTS, \ + "Cannot pass more than " PB_TOSTR(PB_MAX_DATAPOINTS) " values into the variable argument of `nx_protobuf_mqtt_message_create()`." \ + ); \ } while (0) @@ -37,7 +45,7 @@ #define PB_COUNT_ARGS(...) (sizeof((float[]){ __VA_ARGS__ }) / sizeof(float)) // Returns the number of arguments passed into it. #define PB_STR_LEN(s) (sizeof(s) - 1) // Returns the length of a string literal. -/** + /** * @brief Creates and formats a `ethernet_mqtt_message_t` object, and returns it to the caller. * @param topic (const char*) String literal representing the message's MQTT topic name. * @param unit (const char*) String literal representing the unit of the message's data. diff --git a/NetX/src/u_nx_protobuf.c b/NetX/src/u_nx_protobuf.c index 61026d63..416b2249 100644 --- a/NetX/src/u_nx_protobuf.c +++ b/NetX/src/u_nx_protobuf.c @@ -3,14 +3,13 @@ #include "u_nx_protobuf.h" #include "u_nx_ethernet.h" -ethernet_mqtt_message_t _nx_protobuf_create_mqtt_message(const char* topic, const char* unit, float[] values, int values_size) { +ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size_t topic_len, const char* unit, size_t unit_len, const float values[], int values_size) { /* Zero-initialize the protobuf struct and the sendable ethernet_mqtt_message_t message. */ serverdata_v2_ServerData protobuf = serverdata_v2_ServerData_init_zero; ethernet_mqtt_message_t message = { 0 }; message.initialized = false; - /* Calculate topic size. */ - int topic_size = strlen(topic); + /* Enforce topic size. */ if(topic_size > ETH_MAX_TOPIC_SIZE) { PRINTLN_ERROR("MQTT Message topic exceeds maximum length (Topic: %s).", topic); return message; // Return empty, uninitialized message. From dc72e960f2b61845ce0040fcd4a3f8b7e3e18994 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 17:03:57 -0400 Subject: [PATCH 05/11] fixed static asserts --- NetX/inc/u_nx_protobuf.h | 17 +++++++--------- NetX/src/u_nx_protobuf.c | 42 +++++++++++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 15 deletions(-) diff --git a/NetX/inc/u_nx_protobuf.h b/NetX/inc/u_nx_protobuf.h index 7842358b..fbe1d4db 100644 --- a/NetX/inc/u_nx_protobuf.h +++ b/NetX/inc/u_nx_protobuf.h @@ -11,9 +11,11 @@ #include #include "serverdata.pb.h" -/* Stringification macros. */ +/* Helper macros. */ #define PB_STR_HELPER(x) #x // Helper for PB_TOSTR(). Probably should never use directly. #define PB_TOSTR(x) PB_STR_HELPER(x) // Converts a macro's value into a string. +#define PB_COUNT_ARGS(...) (sizeof((float[]){ __VA_ARGS__ }) / sizeof(float)) // Returns the number of arguments passed into it. +#define PB_STR_LEN(s) (sizeof(s) - 1) // Returns the length of a string literal. /* CONFIG: Compile-time validation of topic size, unit size, and number of values. */ #define PB_MAX_TOPIC_LENGTH 100 // Maximum @@ -23,11 +25,11 @@ #define PB_VALIDATE_ARGS(topic, unit, num_values) \ do { \ _Static_assert( \ - sizeof(topic) <= PB_MAX_TOPIC_LENGTH, \ + PB_STR_LEN(topic) <= PB_MAX_TOPIC_LENGTH, \ "MQTT topic parameter exceeds maximum length of " PB_TOSTR(PB_MAX_TOPIC_LENGTH) " allowed by `nx_protobuf_mqtt_message_create()`."\ ); \ _Static_assert( \ - sizeof(unit) <= PB_MAX_UNIT_LENGTH, \ + PB_STR_LEN(unit) <= PB_MAX_UNIT_LENGTH, \ "MQTT unit parameter exceeds maximum length of " PB_TOSTR(PB_MAX_UNIT_LENGTH) " allowed by `nx_protobuf_mqtt_message_create()`." \ ); \ _Static_assert( \ @@ -40,11 +42,6 @@ ); \ } while (0) - -/* Helper macros. */ -#define PB_COUNT_ARGS(...) (sizeof((float[]){ __VA_ARGS__ }) / sizeof(float)) // Returns the number of arguments passed into it. -#define PB_STR_LEN(s) (sizeof(s) - 1) // Returns the length of a string literal. - /** * @brief Creates and formats a `ethernet_mqtt_message_t` object, and returns it to the caller. * @param topic (const char*) String literal representing the message's MQTT topic name. @@ -69,11 +66,11 @@ typedef struct { const char* topic; int topic_size; - serverdata_v2_ServerData msg; + serverdata_v2_ServerData protobuf; bool initialized; } ethernet_mqtt_message_t; /* MACRO IMPLEMENTATIONS */ -ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size_t topic_len, const char* unit, size_t unit_len, const float values[], int values_size); +ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size_t topic_size, const char* unit, size_t unit_len, const float values[], int values_count); // clang-format on \ No newline at end of file diff --git a/NetX/src/u_nx_protobuf.c b/NetX/src/u_nx_protobuf.c index 416b2249..c1804274 100644 --- a/NetX/src/u_nx_protobuf.c +++ b/NetX/src/u_nx_protobuf.c @@ -9,11 +9,33 @@ ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size ethernet_mqtt_message_t message = { 0 }; message.initialized = false; - /* Enforce topic size. */ - if(topic_size > ETH_MAX_TOPIC_SIZE) { - PRINTLN_ERROR("MQTT Message topic exceeds maximum length (Topic: %s).", topic); + /* Enforce topic length. */ + if(topic_len > PB_MAX_TOPIC_LENGTH) { + PRINTLN_ERROR("MQTT Message topic exceeds maximum length of %d (Topic: %s, Current Topic Length: %d).", PB_MAX_TOPIC_LENGTH, topic, topic_len); return message; // Return empty, uninitialized message. } + // NOTE: If using the `nx_protobuf_mqtt_message_create()` macro (as intended), the static asserts should catch this. This is just an extra check in case a caller uses this function directly for whatever reason. + + /* Enforce unit length. */ + if(unit_len > PB_MAX_UNIT_LENGTH) { + PRINTLN_ERROR("MQTT Unit string length exceeds maximum length of %d (Topic: %s, Current Unit String Length: %d).", PB_MAX_UNIT_LENGTH, topic, unit_len); + return message; // Return empty, uninitialized message. + } + // NOTE: If using the `nx_protobuf_mqtt_message_create()` macro (as intended), the static asserts should catch this. This is just an extra check in case a caller uses this function directly for whatever reason. + + /* Enforce minimum number of datapoints. */ + if(values_size < PB_MIN_DATAPOINTS) { + PRINTLN_ERROR("Message must have at least %d datapoints (Topic: %s, Current values_size: %d).", PB_MIN_DATAPOINTS, topic, values_size); + return message; // Return empty, uninitialized message. + } + // NOTE: If using the `nx_protobuf_mqtt_message_create()` macro (as intended), the static asserts should catch this. This is just an extra check in case a caller uses this function directly for whatever reason. + + /* Enforce maximum number of datapoints. */ + if(values_size > PB_MIN_DATAPOINTS) { + PRINTLN_ERROR("Message cannot have more than %d datapoints (Topic: %s, Current values_size: %d).", PB_MAX_DATAPOINTS, topic, values_size); + return message; // Return empty, uninitialized message. + } + // NOTE: If using the `nx_protobuf_mqtt_message_create()` macro (as intended), the static asserts should catch this. This is just an extra check in case a caller uses this function directly for whatever reason. /* Get the PTP time and convert to appropriate protobuf time. */ NX_PTP_DATE_TIME datetime = ethernet_get_time(); @@ -21,12 +43,22 @@ ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size // u_TODO - actually figure out how to convert this like it should be. Probably ask jack how this should be set up? /* Pack the protobuf message. */ - // PROTOBUF SCHEMA LOOKS LIKE THIS: + // CURRENT PROTOBUF SCHEMA LOOKS LIKE THIS: // typedef struct _serverdata_v2_ServerData { // char unit[15]; // uint64_t time_us; // pb_size_t values_count; // float values[5]; // } serverdata_v2_ServerData; - *(msg.unit) = + memcpy(protobuf.unit, unit, unit_len); + protobuf.time_us = time_us; + protobuf.values_count = values_size; + memcpy(protobuf.values, values, values_size * sizeof(float)); + + /* Pack the `ethernet_mqtt_message_t` object and return it as successfully initialized. */ + message.topic = topic; + message.topic_size = topic_len; + message.protobuf = protobuf; + message.initialized = true; + return message; } \ No newline at end of file From 73dec537caff9b3b0e253bcd5579cc813b5b87e5 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 17:32:18 -0400 Subject: [PATCH 06/11] nx_protobuf_mqtt_message_send() --- NetX/inc/u_nx_protobuf.h | 9 ++++++- NetX/src/u_nx_protobuf.c | 53 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/NetX/inc/u_nx_protobuf.h b/NetX/inc/u_nx_protobuf.h index fbe1d4db..360b9bf6 100644 --- a/NetX/inc/u_nx_protobuf.h +++ b/NetX/inc/u_nx_protobuf.h @@ -42,7 +42,7 @@ ); \ } while (0) - /** +/** * @brief Creates and formats a `ethernet_mqtt_message_t` object, and returns it to the caller. * @param topic (const char*) String literal representing the message's MQTT topic name. * @param unit (const char*) String literal representing the unit of the message's data. @@ -70,6 +70,13 @@ typedef struct { bool initialized; } ethernet_mqtt_message_t; +/** + * @brief Dispatches a `ethernet_mqtt_message_t` message over MQTT. + * @param message The message to send. + * @return U_SUCCESS if successful, U_ERROR is not successful. + */ +int nx_protobuf_mqtt_message_send(ethernet_mqtt_message_t* message); + /* MACRO IMPLEMENTATIONS */ ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size_t topic_size, const char* unit, size_t unit_len, const float values[], int values_count); diff --git a/NetX/src/u_nx_protobuf.c b/NetX/src/u_nx_protobuf.c index c1804274..8e877b53 100644 --- a/NetX/src/u_nx_protobuf.c +++ b/NetX/src/u_nx_protobuf.c @@ -2,6 +2,9 @@ #include "u_tx_debug.h" #include "u_nx_protobuf.h" #include "u_nx_ethernet.h" +#include "pb.h" +#include "pb_encode.h" +#include "tx_api.h" ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size_t topic_len, const char* unit, size_t unit_len, const float values[], int values_size) { /* Zero-initialize the protobuf struct and the sendable ethernet_mqtt_message_t message. */ @@ -31,7 +34,7 @@ ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size // NOTE: If using the `nx_protobuf_mqtt_message_create()` macro (as intended), the static asserts should catch this. This is just an extra check in case a caller uses this function directly for whatever reason. /* Enforce maximum number of datapoints. */ - if(values_size > PB_MIN_DATAPOINTS) { + if(values_size > PB_MAX_DATAPOINTS) { PRINTLN_ERROR("Message cannot have more than %d datapoints (Topic: %s, Current values_size: %d).", PB_MAX_DATAPOINTS, topic, values_size); return message; // Return empty, uninitialized message. } @@ -61,4 +64,52 @@ ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size message.protobuf = protobuf; message.initialized = true; return message; +} + +int nx_protobuf_mqtt_message_send(ethernet_mqtt_message_t* message) { + /* Make sure message isn't nullptr. */ + if(!message) { + PRINTLN_ERROR("Null pointer to `ethernet_mqtt_message_t` message."); + return U_ERROR; + } + + /* Make sure message is initialized. */ + if(!message->initialized) { + PRINTLN_ERROR("Attempting to send an uninitialized `ethernet_mqtt_message_t` message."); + return U_ERROR; + } + + /* Set up the buffer. */ + unsigned char buffer[serverdata_v2_ServerData_size]; + pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + + /* Encode the protobuf. */ + int status = pb_encode(&stream, serverdata_v2_ServerData_fields, &message->protobuf); + if(status != true) { + PRINTLN_ERROR("Failed to serialize protobuf message (Topic: %s): %s", message->topic, PB_GET_ERROR(&stream)); + return U_ERROR; + } + + /* Publish over MQTT. */ + status = ethernet_mqtt_publish(message->topic, message->topic_size, (char*)buffer, stream.bytes_written); // u_TODO - ethernet_mqtt_publish should return U_SUCCESS/U_ERROR instead of the internal netx error macro + if(status != NXD_MQTT_SUCCESS) { + PRINTLN_WARNING("Failed to publish MQTT message (Topic: %s, Status: %d).", message->topic, status); + + /* If disconnected, attempt reconnection. */ + if(status == NXD_MQTT_NOT_CONNECTED) { + PRINTLN_WARNING("Detected disconnect from MQTT. Attempting reconnection..."); + do { + tx_thread_sleep(1000); + status = ethernet_mqtt_reconnect(); + PRINTLN_WARNING("Attempting MQTT reconnection (Status: %d).", status); + } while ((status != NXD_MQTT_SUCCESS) && (status != NXD_MQTT_ALREADY_CONNECTED)); + PRINTLN_WARNING("MQTT reconnection successful."); + } + + return U_ERROR; + } + + /* Return successful! */ + PRINTLN_INFO("Sent MQTT message (Topic: %s).", message->topic); + return U_SUCCESS; } \ No newline at end of file From cc61547c5f2fe516ed91d13dd47027ae5df957f8 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 17:43:36 -0400 Subject: [PATCH 07/11] include the client file --- NetX/src/u_nx_protobuf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/NetX/src/u_nx_protobuf.c b/NetX/src/u_nx_protobuf.c index 8e877b53..0f901ac3 100644 --- a/NetX/src/u_nx_protobuf.c +++ b/NetX/src/u_nx_protobuf.c @@ -5,6 +5,7 @@ #include "pb.h" #include "pb_encode.h" #include "tx_api.h" +#include "nxd_mqtt_client.h" ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size_t topic_len, const char* unit, size_t unit_len, const float values[], int values_size) { /* Zero-initialize the protobuf struct and the sendable ethernet_mqtt_message_t message. */ From 6356440d02e966b50aceb339210cde86af31e835 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 19:54:45 -0400 Subject: [PATCH 08/11] print when ran init --- NetX/src/u_nx_ethernet.c | 1 + 1 file changed, 1 insertion(+) diff --git a/NetX/src/u_nx_ethernet.c b/NetX/src/u_nx_ethernet.c index 308a53da..f5474029 100644 --- a/NetX/src/u_nx_ethernet.c +++ b/NetX/src/u_nx_ethernet.c @@ -382,6 +382,7 @@ UINT ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve on_ /* Mark device as initialized. */ device.is_initialized = true; + PRINTLN_INFO("Ran ethernet_init()"); return NX_SUCCESS; } From 3688ab6ddb2a651be9025677bfa07e06353ba318 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 20:17:38 -0400 Subject: [PATCH 09/11] fix --- NetX/src/u_nx_protobuf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NetX/src/u_nx_protobuf.c b/NetX/src/u_nx_protobuf.c index 0f901ac3..fe633745 100644 --- a/NetX/src/u_nx_protobuf.c +++ b/NetX/src/u_nx_protobuf.c @@ -1,5 +1,6 @@ #include #include "u_tx_debug.h" +#include "u_nx_debug.h" #include "u_nx_protobuf.h" #include "u_nx_ethernet.h" #include "pb.h" @@ -61,7 +62,7 @@ ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size /* Pack the `ethernet_mqtt_message_t` object and return it as successfully initialized. */ message.topic = topic; - message.topic_size = topic_len; + message.topic_size = topic_len + 1; // u_TODO - for some reason you need to do + 1 here or else it will cut the last letter off of the topic in MQTT ui. The macro probably just calculates the topic length with one less than it should or something message.protobuf = protobuf; message.initialized = true; return message; @@ -102,7 +103,7 @@ int nx_protobuf_mqtt_message_send(ethernet_mqtt_message_t* message) { do { tx_thread_sleep(1000); status = ethernet_mqtt_reconnect(); - PRINTLN_WARNING("Attempting MQTT reconnection (Status: %d).", status); + PRINTLN_WARNING("Attempting MQTT reconnection (Status: %d/%s).", status, nx_status_toString(status)); } while ((status != NXD_MQTT_SUCCESS) && (status != NXD_MQTT_ALREADY_CONNECTED)); PRINTLN_WARNING("MQTT reconnection successful."); } From 9f74482d290c849d63df63a13b9ea3f83d12013e Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 20:53:30 -0400 Subject: [PATCH 10/11] stuff core --- NetX/src/u_nx_protobuf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/NetX/src/u_nx_protobuf.c b/NetX/src/u_nx_protobuf.c index fe633745..0cb1a9c2 100644 --- a/NetX/src/u_nx_protobuf.c +++ b/NetX/src/u_nx_protobuf.c @@ -43,9 +43,8 @@ ethernet_mqtt_message_t _nx_protobuf_mqtt_message_create(const char* topic, size // NOTE: If using the `nx_protobuf_mqtt_message_create()` macro (as intended), the static asserts should catch this. This is just an extra check in case a caller uses this function directly for whatever reason. /* Get the PTP time and convert to appropriate protobuf time. */ - NX_PTP_DATE_TIME datetime = ethernet_get_time(); - uint64_t time_us = datetime.nanosecond; // u_TODO - this is temporary - // u_TODO - actually figure out how to convert this like it should be. Probably ask jack how this should be set up? + //NX_PTP_DATE_TIME datetime = ethernet_get_time(); u_TODO - for some reason ethernet_get_time() is blocking! kind of weird. it doesn't always block either, just when called from certain areas. + uint64_t time_us = 10; // u_TODO - obviously this is temporary, but can't use ethernet_get_time() since it's blocking /* Pack the protobuf message. */ // CURRENT PROTOBUF SCHEMA LOOKS LIKE THIS: From 34a8cba1afff0734425dba5deb28475964629f84 Mon Sep 17 00:00:00 2001 From: bjackson312006 Date: Wed, 1 Apr 2026 21:39:26 -0400 Subject: [PATCH 11/11] comments for the config limit macros --- NetX/inc/u_nx_protobuf.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/NetX/inc/u_nx_protobuf.h b/NetX/inc/u_nx_protobuf.h index 360b9bf6..3c88e650 100644 --- a/NetX/inc/u_nx_protobuf.h +++ b/NetX/inc/u_nx_protobuf.h @@ -18,10 +18,10 @@ #define PB_STR_LEN(s) (sizeof(s) - 1) // Returns the length of a string literal. /* CONFIG: Compile-time validation of topic size, unit size, and number of values. */ -#define PB_MAX_TOPIC_LENGTH 100 // Maximum -#define PB_MAX_UNIT_LENGTH 15 -#define PB_MIN_DATAPOINTS 1 -#define PB_MAX_DATAPOINTS 5 +#define PB_MAX_TOPIC_LENGTH 100 // Maximum length of topic string literal (in characters). +#define PB_MAX_UNIT_LENGTH 15 // Maximum length of unit string literal (in characters). +#define PB_MIN_DATAPOINTS 1 // Minimum number of datapoints (i.e., variable `...` arguments passed into `nx_protobuf_mqtt_message_create()`). +#define PB_MAX_DATAPOINTS 5 // Maximum number of datapoints (i.e., variable `...` arguments passed into `nx_protobuf_mqtt_message_create()`). #define PB_VALIDATE_ARGS(topic, unit, num_values) \ do { \ _Static_assert( \