Skip to content
2 changes: 2 additions & 0 deletions NetX/README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

nxd_ptp_client -- SOURCE: https://github.com/STMicroelectronics/stm32-mw-netxduo/tree/79232767cef83e20573f2fbc173810f9d29c8fdb/addons/ptp
779 changes: 779 additions & 0 deletions NetX/inc/nxd_ptp_client.h

Large diffs are not rendered by default.

29 changes: 18 additions & 11 deletions NetX/inc/u_nx_ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <stdint.h>
#include <stdbool.h>
#include "nx_api.h"
#include "nxd_ptp_client.h"

/* CONFIG */
#define ETH_UDP_PORT 2006 /* UDP port for communication */
Expand All @@ -18,29 +19,29 @@
#define ETH_NUMBER_OF_NODES 8 /* Number of nodes in the network. */

typedef enum {
VCU = (1 << 0), // 0b00000001
COMPUTE = (1 << 1), // 0b00000010
TPU = (1 << 2), // 0b00000100
TPU = (1 << 0), // 0b00000001
VCU = (1 << 1), // 0b00000010
COMPUTE = (1 << 2), // 0b00000100
MSB1 = (1 << 3), // 0b00001000
MSB2 = (1 << 4), // 0b00010000
MSB3 = (1 << 5), // 0b00100000
MSB4 = (1 << 6), // 0b01000000
NODE8 = (1 << 7), // 0b10000000
} ethernet_node_t;
#define ETH_IP(node) IP_ADDRESS(239, 0, 0, node)
#define ETH_IP(node) IP_ADDRESS(224, 0, 0, node)

/* These node ids are ONLY relavent to PLCA configuration.
They are meant to be used when configuring a PHY. The IDs must be sequential, and the "0" id always indicates the network's coordinator node.
They have no impact on application-level IP addresses or message processing.
They have no impact on application-level IP addresses or message processing.

For example, if you're using the LAN8670 PHY driver, you'd probably use these enum values like this:
LAN8670_PLCA_Set_Node_Count(&lan8670, PLCA_NUM_NODES);
LAN8670_PLCA_Set_Node_Id(&lan8670, PLCA_VCU) // replace 'PLCA_VCU' with whatever board it is
LAN8670_PLCA_Set_Node_Id(&lan8670, PLCA_VCU) // replace 'PLCA_VCU' with whatever board it is
*/
typedef enum {
PLCA_VCU, // 0. This is the PLCA coordinator node.
PLCA_TPU, // 0. This is the PLCA coordinator node.
PLCA_VCU,
PLCA_COMPUTE,
PLCA_TPU,
PLCA_MSB1,
PLCA_MSB2,
PLCA_MSB3,
Expand All @@ -55,7 +56,7 @@ typedef struct {
uint8_t recipient_id;
uint8_t message_id;
uint8_t data_length;
uint8_t data[ETH_MESSAGE_SIZE];
uint8_t data[10]; // change back
} ethernet_message_t;

/* Function Pointers (for initialization). */
Expand Down Expand Up @@ -88,5 +89,11 @@ ethernet_message_t ethernet_create_message(uint8_t message_id, ethernet_node_t r
*/
uint8_t ethernet_send_message(ethernet_message_t *message);

/**
* @brief Retrieves the time from PTP stack.
* @return The UTC time
*/
NX_PTP_DATE_TIME ethernet_get_time(void);

// clang-format on
#endif /* u_nx_ethernet.h */
#endif /* u_nx_ethernet.h */
6,154 changes: 6,154 additions & 0 deletions NetX/src/nxd_ptp_client.c

Large diffs are not rendered by default.

125 changes: 114 additions & 11 deletions NetX/src/u_nx_ethernet.c
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
// clang-format off
#include "u_nx_ethernet.h"
#include "nx_stm32_eth_driver.h"
#include "nxd_ptp_client.h"
#include "u_nx_debug.h"
#include "u_tx_debug.h"
#include "nx_api.h"
#include <string.h>
#include <stdio.h>

/* PRIVATE MACROS */
#define _PACKET_POOL_SIZE \
((sizeof(ethernet_message_t) + sizeof(NX_PACKET)) * ETH_MAX_PACKETS)
#define _IP_THREAD_STACK_SIZE 2048
#define _ARP_CACHE_SIZE 1024
#define _IP_THREAD_PRIORITY 1
#define _IP_NETWORK_MASK IP_ADDRESS(255, 255, 255, 0)
#define _UDP_QUEUE_MAXIMUM 12
#define _PTP_THREAD_PRIORITY 2

/* The DEFAULT_PAYLOAD_SIZE should match with RxBuffLen configured via MX_ETH_Init */
#define DEFAULT_PAYLOAD_SIZE 1524
#define NX_APP_PACKET_POOL_SIZE ((DEFAULT_PAYLOAD_SIZE + sizeof(NX_PACKET)) * 10)

/* DEVICE INFO */
typedef struct {
/* NetX Objects */
NX_UDP_SOCKET socket;
NX_PACKET_POOL packet_pool;
NX_IP ip;
NX_PTP_CLIENT ptp_client;
SHORT ptp_utc_offset;

/* Static memory for NetX stuff */
UCHAR packet_pool_memory[_PACKET_POOL_SIZE];
UCHAR packet_pool_memory[NX_APP_PACKET_POOL_SIZE];
UCHAR ip_memory[_IP_THREAD_STACK_SIZE];
UCHAR arp_cache_memory[_ARP_CACHE_SIZE];
ULONG ptp_stack[2048 / sizeof(ULONG)];

/* Device config variables */
bool is_initialized;
Expand All @@ -36,6 +44,45 @@ typedef struct {
} _ethernet_device_t;
static _ethernet_device_t device = { 0 };

/* Callback function. Called when a PTP event is processed. */
// extern UINT ptp_clock_callback(NX_PTP_CLIENT *client_ptr, UINT operation,
// NX_PTP_TIME *time_ptr, NX_PACKET *packet_ptr,
// VOID *callback_data);

/* Callback function. Called when a PTP event is processed. */
static UINT _ptp_event_callback(NX_PTP_CLIENT *ptp_client_ptr, UINT event, VOID *event_data, VOID *callback_data)
{
NX_PARAMETER_NOT_USED(callback_data);

switch (event)
{
case NX_PTP_CLIENT_EVENT_MASTER:
{
PRINTLN_WARNING("new MASTER clock!");
break;
}

case NX_PTP_CLIENT_EVENT_SYNC:
{
nx_ptp_client_sync_info_get((NX_PTP_CLIENT_SYNC *)event_data, NX_NULL, &device.ptp_utc_offset);
PRINTLN_INFO("SYNC event: utc offset=%d", device.ptp_utc_offset);
break;
}

case NX_PTP_CLIENT_EVENT_TIMEOUT:
{
PRINTLN_WARNING("Master clock TIMEOUT!");
break;
}
default:
{
break;
}
}

return 0;
}

/* Callback function. Called when an ethernet message is received. */
static void _receive_message(NX_UDP_SOCKET *socket) {
NX_PACKET *packet;
Expand Down Expand Up @@ -91,8 +138,9 @@ static void _receive_message(NX_UDP_SOCKET *socket) {
/* API FUNCTIONS */

uint8_t ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve on_recieve) {

uint8_t status;
device.ptp_utc_offset = 0; // no offset to start

/* Make sure device isn't already initialized */
if(device.is_initialized) {
Expand All @@ -109,9 +157,9 @@ uint8_t ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve
status = nx_packet_pool_create(
&device.packet_pool, // Pointer to the packet pool instance
"Ethernet Packet Pool", // Name
sizeof(ethernet_message_t), // Payload size (i.e. the size of each packet)
DEFAULT_PAYLOAD_SIZE, // Payload size (i.e. the size of each packet)
device.packet_pool_memory, // Pointer to the pool's memory area
_PACKET_POOL_SIZE // Size of the pool's memory area
NX_APP_PACKET_POOL_SIZE // Size of the pool's memory area
);
if(status != NX_SUCCESS) {
PRINTLN_ERROR("Failed to create packet pool (Status: %d/%s).", status, nx_status_toString(status));
Expand Down Expand Up @@ -161,11 +209,11 @@ uint8_t ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve
return status;
}

/* Set up multicast groups.
/* Set up multicast groups.
* (This iterates through every possible node combination between 0b00000001 and 0b11111111.
* If any of the combinations include device.node_id, that combination gets added as a multicast group.
* This ensures that ethernet messages can be sent to all possible combinations of recipients.)
*
*
* Note: This is probably pretty inefficient. I did it so you don't have to manually set up
* multicast groups any time you want to send a message to a new combination of nodes,
* but if this setup ends up being too slow or something, feel free to get rid of it.
Expand All @@ -180,6 +228,22 @@ uint8_t ethernet_init(ethernet_node_t node_id, DriverFunction driver, OnRecieve
}
}

/* Create the PTP client instance */
status = nx_ptp_client_create(&device.ptp_client, &device.ip, 0, &device.packet_pool,
_PTP_THREAD_PRIORITY, (UCHAR *)&device.ptp_stack, sizeof(device.ptp_stack),
_nx_ptp_client_soft_clock_callback, NX_NULL);
if(status != NX_SUCCESS) {
PRINTLN_ERROR("Failed to create PTP client (Status: %d/%s).", status, nx_status_toString(status));
return status;
}

/* start the PTP client */
status = nx_ptp_client_start(&device.ptp_client, NX_NULL, 0, 0, 0, _ptp_event_callback, NX_NULL);
if(status != NX_SUCCESS) {
PRINTLN_ERROR("Failed to start PTP client (Status: %d/%s).", status, nx_status_toString(status));
return status;
}

/* Create UDP socket for broadcasting */
status = nx_udp_socket_create(
&device.ip, // IP instance
Expand Down Expand Up @@ -263,6 +327,18 @@ uint8_t ethernet_send_message(ethernet_message_t *message) {
return U_ERROR;
}

PRINTLN_INFO("got to this part of ethernet_send_message()");

/* Make sure interface is up. */
ULONG actual_status = 0;
status = nx_ip_interface_status_check(&device.ip, 0, NX_IP_LINK_ENABLED, &actual_status, 1000);
if(status != NX_SUCCESS) {
PRINTLN_ERROR("Failed to call nx_ip_interface_status_check() (Status: %d/%s).", status, nx_status_toString(status));
return U_ERROR;
} else {
PRINTLN_INFO("Succeeded calling nx_ip_interface_status_check() (Status: %d/%s).", status, nx_status_toString(status));
}

/* Allocate a packet */
status = nx_packet_allocate(
&device.packet_pool, // Packet pool
Expand All @@ -275,6 +351,8 @@ uint8_t ethernet_send_message(ethernet_message_t *message) {
return U_ERROR;
}

PRINTLN_INFO("got to nx_packet_allocate() part of send message");

/* Append message data to packet */
status = nx_packet_data_append(
packet, // Packet
Expand All @@ -289,6 +367,16 @@ uint8_t ethernet_send_message(ethernet_message_t *message) {
return U_ERROR;
}

PRINTLN_INFO("got to nx_packet_data_append() part of send message");

ULONG length = 0;
status = nx_packet_length_get(packet, &length);
if(status != NX_SUCCESS) {
PRINTLN_ERROR("Failed to call nx_packet_length_get() (Status: %d/%n).", status, nx_status_toString(status));
} else {
PRINTLN_INFO("Packet has length of %d!", length);
}

/* Send message */
status = nx_udp_socket_send(
&device.socket,
Expand All @@ -297,12 +385,27 @@ uint8_t ethernet_send_message(ethernet_message_t *message) {
ETH_UDP_PORT
);
if(status != NX_SUCCESS) {
PRINTLN_ERROR("Failed to send packet (Status: %d/%s, Message ID: %d).", status, nx_status_toString(status), message->message_id);
PRINTLN_ERROR("Failed to send packet (Status: %d/%s, Message ID: %d, Recipient ID: %d, IP Address: %d, IP components: 224.0.0.%d).", status, nx_status_toString(status), message->message_id, message->recipient_id, ETH_IP(message->recipient_id), ETH_IP(message->recipient_id));
nx_packet_release(packet);
return U_ERROR;
}

PRINTLN_INFO("Sent ethernet message (Recipient ID: %d, Message ID: %d).", message->recipient_id, message->message_id);
PRINTLN_INFO("got to nx_udp_socket_send() part of send message");

PRINTLN_INFO("Sent ethernet message (Recipient ID: %d, Message ID: %d, Message Contents: %d).", message->recipient_id, message->message_id, message->data);
return U_SUCCESS;
}
// clang-format on

NX_PTP_DATE_TIME ethernet_get_time(void) {
NX_PTP_TIME tm;
NX_PTP_DATE_TIME date;
/* read the PTP clock */
nx_ptp_client_time_get(&device.ptp_client, &tm);

/* convert PTP time to UTC date and time */
nx_ptp_client_utility_convert_time_to_date(&tm, 0, &date);

return date;
}

// clang-format on
28 changes: 28 additions & 0 deletions general/include/lan8670.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,4 +182,32 @@ int32_t LAN8670_Get_Link_State(lan8670_t *lan, uint8_t *state);
* @return Status.
*/
int32_t LAN8670_RegisterBusIO(lan8670_t *lan, lan8670_IOCtx_t *ioctx);

/**
* @brief Reads the PLCA status.
*
* @param lan Pointer to the lan8670_t instance.
* @param status Buffer for the returned status value. false=The PLCA reconciliation sublayer is not regularly receiving or transmitting the BEACON, true=The PLCA reconciliation sublayer is regularly receiving or transmitting the BEACON
* @return Status (an error code, not related to the *status bool).
*/
int32_t LAN8670_PLCA_Get_Status(lan8670_t *lan, bool *status);

/**
* @brief Reads the PLCA TOTMR (Transmit Opportunity Timer) setting. Should be 32 bit-times by default.
*
* @param lan Pointer to the lan8670_t instance.
* @param buffer Buffer for the register value. The value has a unit of bit-times.
* @return Status.
*/
int32_t LAN8670_PLCA_ReadTOTMR(lan8670_t *lan, bool *buffer);

/**
* @brief Writes the PLCA TOTMR (Transmit Opportunity Timer) setting.
*
* @param lan Pointer to the lan8670_t instance.
* @param data Setting to write to the register. Should be an integer with a unit of bit-times.
* @return Status.
*/
int32_t LAN8670_PLCA_WriteTOTMR(lan8670_t *lan, uint8_t data);

// clang-format on
Loading
Loading