Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -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
59 changes: 56 additions & 3 deletions NetX/inc/u_nx_ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
#define ETH_MESSAGE_SIZE 128 /* Maximum ethernet message size in bytes. */
#define ETH_MAX_PACKETS 10 /* Maximum number of packets we wanna handle simultaneously */
#define ETH_NUMBER_OF_NODES 8 /* Number of nodes in the network. */
#define ETH_ENABLE_MANUAL_UDP_MULTICAST 0 // whether to enable UDP multicast
#define ETH_ENABLE_IGMP 1 // whether to enable IGMP
#define ETH_ENABLE_MQTT 1 // whether to use a MQTT connection
#define ETH_MQTT_SERVER_IP IP_ADDRESS(10,0,0,1) // the server address of the broker (TPU usually)
#define ETH_MQTT_SERVER_PORT 1883

typedef enum {
TPU = (1 << 0), // 0b00000001
Expand Down Expand Up @@ -61,7 +66,12 @@ typedef struct __attribute__((__packed__)) {

/* Function Pointers (for initialization). */
typedef void (*DriverFunction)(NX_IP_DRIVER *); /* User-supplied network driver used to send and receive IP packets. */

#if ETH_ENABLE_MANUAL_UDP_MULTICAST
typedef void (*OnRecieve)(ethernet_message_t message); /* User-supplied function that will be called whenever an ethernet message is recieved. */
#else
typedef void (*OnRecieve)(ethernet_message_t message); /* User-supplied function that will be called whenever an ethernet message is recieved. */
#endif

/**
* @brief Initializes the NetX ethernet system in a repo.
Expand All @@ -70,8 +80,9 @@ typedef void (*OnRecieve)(ethernet_message_t message); /* User-supplied function
* @param on_recieve User-supplied function to be called whenever an ethernet message is recieved. The function's only parameter is an ethernet_message_t instance containing the recieved message.
* @return Status.
*/
uint8_t ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve on_recieve);
UINT ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve on_recieve);

#if ETH_ENABLE_MANUAL_UDP_MULTICAST
/**
* @brief Creates an ethernet message. Can be send with ethernet_send_message(), or added to a queue.
* @param recipient_id The ID of the recipient node.
Expand All @@ -88,12 +99,54 @@ ethernet_message_t ethernet_create_message(uint8_t message_id, ethernet_node_t r
* @return Status.
*/
uint8_t ethernet_send_message(ethernet_message_t *message);
#endif

#if ETH_ENABLE_MQTT
/**
* @brief Sends a MQTT message to outgoing queue
* @param topic_name The topic name
* @param topic_size The topic size in bytes
* @param message The data to send
* @param message_size The message size in bytes
* @return The error code.
*/
UINT ethernet_mqtt_publish(char* topic_name, UINT topic_size, char* message, UINT message_size);

/**
* Connect to a disconnected MQTT server (NX_MQTT_NOT_CONNECTED)
* Will yield while trying to connect
*/
UINT ethernet_mqtt_reconnect(void);

/**
*
*/
//ethernet_mqtt_subscribe();

/**
*
*/

#endif

/**
* @brief Retrieves the time from PTP stack.
* @return The UTC time
* @param datetime Buffer for the retrieved datetime info.
* @return U_SUCCESS if successful, U_ERROR is not successful.
*/
int ethernet_get_time(NX_PTP_DATE_TIME* datetime);

/**
* @brief Gets the number of microseconds since the Unix epoch (1970-01-01 00:00:00 UTC), using the PTP stack.
* @param buffer The buffer for the retrieved time.
* @return U_SUCCESS if successful, U_ERROR is not successful.
*/
int ethernet_ptp_get_unix_microseconds(uint64_t* buffer);

/**
* Debugging, print the status of ARP statistics
*/
NX_PTP_DATE_TIME ethernet_get_time(void);
UINT ethernent_print_arp_status(void);

// clang-format on
#endif /* u_nx_ethernet.h */
83 changes: 83 additions & 0 deletions NetX/inc/u_nx_protobuf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#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 <stddef.h>
#include <stdbool.h>
#include "serverdata.pb.h"

/* 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 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( \
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( \
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( \
(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)

/**
* @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 protobuf;
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);

// clang-format on
51 changes: 51 additions & 0 deletions NetX/src/u_nx_debug.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
#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

Expand Down Expand Up @@ -72,6 +84,45 @@ const char* nx_status_toString(UINT status) {
case NX_OPTION_HEADER_ERROR: return "NX_OPTION_HEADER_ERROR";
case NX_CONTINUE: return "NX_CONTINUE";
case NX_TCPIP_OFFLOAD_ERROR: return "NX_TCPIP_OFFLOAD_ERROR";

/* 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";
case NXD_MQTT_INTERNAL_ERROR: return "NXD_MQTT_INTERNAL_ERROR";
case NXD_MQTT_CONNECT_FAILURE: return "NXD_MQTT_CONNECT_FAILURE";
case NXD_MQTT_PACKET_POOL_FAILURE: return "NXD_MQTT_PACKET_POOL_FAILURE";
case NXD_MQTT_COMMUNICATION_FAILURE: return "NXD_MQTT_COMMUNICATION_FAILURE";
case NXD_MQTT_SERVER_MESSAGE_FAILURE: return "NXD_MQTT_SERVER_MESSAGE_FAILURE";
case NXD_MQTT_INVALID_PARAMETER: return "NXD_MQTT_INVALID_PARAMETER";
case NXD_MQTT_NO_MESSAGE: return "NXD_MQTT_NO_MESSAGE";
case NXD_MQTT_PACKET_POOL_EMPTY: return "NXD_MQTT_PACKET_POOL_EMPTY";
case NXD_MQTT_QOS2_NOT_SUPPORTED: return "NXD_MQTT_QOS2_NOT_SUPPORTED";
case NXD_MQTT_INSUFFICIENT_BUFFER_SPACE: return "NXD_MQTT_INSUFFICIENT_BUFFER_SPACE";
case NXD_MQTT_CLIENT_NOT_RUNNING: return "NXD_MQTT_CLIENT_NOT_RUNNING";
case NXD_MQTT_INVALID_PACKET: return "NXD_MQTT_INVALID_PACKET";
case NXD_MQTT_PARTIAL_PACKET: return "NXD_MQTT_PARTIAL_PACKET";
case NXD_MQTT_CONNECTING: return "NXD_MQTT_CONNECTING";
case NXD_MQTT_INVALID_STATE: return "NXD_MQTT_INVALID_STATE";
case NXD_MQTT_ERROR_CONNECT_RETURN_CODE: return "NXD_MQTT_ERROR_CONNECT_RETURN_CODE";
case NXD_MQTT_ERROR_UNACCEPTABLE_PROTOCOL: return "NXD_MQTT_ERROR_UNACCEPTABLE_PROTOCOL";
case NXD_MQTT_ERROR_IDENTIFYIER_REJECTED: return "NXD_MQTT_ERROR_IDENTIFYIER_REJECTED";
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";
case NX_PTP_CLIENT_ALREADY_STARTED: return "NX_PTP_CLIENT_ALREADY_STARTED";
case NX_PTP_PARAM_ERROR: return "NX_PTP_PARAM_ERROR";
case NX_PTP_CLIENT_INSUFFICIENT_PACKET_PAYLOAD: return "NX_PTP_CLIENT_INSUFFICIENT_PACKET_PAYLOAD";
case NX_PTP_CLIENT_CLOCK_CALLBACK_FAILURE: return "NX_PTP_CLIENT_CLOCK_CALLBACK_FAILURE";

default: return "UNKNOWN_STATUS";
}
}
Expand Down
Loading
Loading