Feature/mstp zero config option (#564)

* Added a MS/TP zero-config (automatically choose an unused MAC address) using an algorithm that starts with MAC=64 and waits for a random number of PFM (minimum of 8 plus modulo 64) before attempting to choose a MAC sequentially from 64..127. The confirmation uses a 128-bit UUID with the MSTP Test Request frame. The modifications are in src/bacnet/datalink/mstp.c and src/bacnet/datalink/dlmstp.c modules enabling any device to use zero-config if enabled. A working demonstration is in the ports/stm32f4xx for the NUCLEO board. Complete unit testing is included.  Options include lurking forever (wait for a router or another master node before joining) or lurking for a minimum time (enables self forming automatic MAC addressing device nodes).
This commit is contained in:
Steve Karg
2024-02-02 11:18:20 -06:00
committed by GitHub
parent 8f576461a8
commit 1f591db6e7
26 changed files with 2138 additions and 599 deletions
+6 -8
View File
@@ -75,7 +75,7 @@ static bool run_thread;
/*RT_TASK Receive_Task, Fsm_Task;*/
/* local MS/TP port data - shared with RS-485 */
static volatile struct mstp_port_struct_t MSTP_Port;
static struct mstp_port_struct_t MSTP_Port;
/* buffers needed by mstp port struct */
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
@@ -287,7 +287,7 @@ static void *dlmstp_master_fsm_task(void *pArg)
if (MSTP_Port.ReceivedValidFrame || MSTP_Port.ReceivedInvalidFrame) {
run_master = true;
} else {
silence = MSTP_Port.SilenceTimer(NULL);
silence = MSTP_Port.SilenceTimer(&MSTP_Port);
switch (MSTP_Port.master_state) {
case MSTP_MASTER_STATE_IDLE:
if (silence >= Tno_token)
@@ -353,7 +353,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
}
/* for the MS/TP state machine to use for putting received data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{
uint16_t pdu_len = 0;
@@ -384,8 +384,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */
uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
uint16_t MSTP_Get_Send(struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */
uint16_t pdu_len = 0;
uint8_t frame_type = 0;
@@ -421,7 +420,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send
*/
void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port,
struct mstp_port_struct_t *mstp_port,
uint8_t * buffer,
uint16_t nbytes)
{
@@ -584,8 +583,7 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
}
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
uint16_t MSTP_Get_Reply(struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; /* return value */
bool matched = false;
+7 -7
View File
@@ -228,7 +228,7 @@ void *dlmstp_receive_fsm_task(void *pArg)
do {
RS485_Check_UART_Data(mstp_port);
MSTP_Receive_Frame_FSM(
(volatile struct mstp_port_struct_t *)pArg);
(struct mstp_port_struct_t *)pArg);
received_frame = mstp_port->ReceivedValidFrame ||
mstp_port->ReceivedInvalidFrame;
if (received_frame) {
@@ -274,11 +274,11 @@ void *dlmstp_master_fsm_task(void *pArg)
run_master = true;
break;
case MSTP_MASTER_STATE_WAIT_FOR_REPLY:
if (silence >= poSharedData->Treply_timeout)
if (silence >= mstp_port->Treply_timeout)
run_master = true;
break;
case MSTP_MASTER_STATE_POLL_FOR_MASTER:
if (silence >= poSharedData->Tusage_timeout)
if (silence >= mstp_port->Tusage_timeout)
run_master = true;
break;
default:
@@ -324,7 +324,7 @@ void dlmstp_fill_bacnet_address(BACNET_ADDRESS *src, uint8_t mstp_address)
}
/* for the MS/TP state machine to use for putting received data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{
uint16_t pdu_len = 0;
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
@@ -353,7 +353,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */
uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */
uint16_t pdu_len = 0;
uint8_t frame_type = 0;
@@ -391,7 +391,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send
*/
void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port,
struct mstp_port_struct_t *mstp_port,
uint8_t * buffer,
uint16_t nbytes)
{
@@ -555,7 +555,7 @@ bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
/* Get the reply to a DATA_EXPECTING_REPLY frame, or nothing */
uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */
uint16_t pdu_len = 0; /* return value */
bool matched = false;
-10
View File
@@ -87,16 +87,6 @@ typedef struct shared_mstp_data {
/* buffers needed by mstp port struct */
uint8_t TxBuffer[DLMSTP_MPDU_MAX];
uint8_t RxBuffer[DLMSTP_MPDU_MAX];
/* The minimum time without a DataAvailable or ReceiveError event */
/* that a node must wait for a station to begin replying to a */
/* confirmed request: 255 milliseconds. (Implementations may use */
/* larger values for this timeout, not to exceed 300 milliseconds.) */
uint16_t Treply_timeout;
/* The minimum time without a DataAvailable or ReceiveError event that a */
/* node must wait for a remote node to begin using a token or replying to */
/* a Poll For Master frame: 20 milliseconds. (Implementations may use */
/* larger values for this timeout, not to exceed 100 milliseconds.) */
uint8_t Tusage_timeout;
/* Timer that indicates line silence - and functions */
uint16_t SilenceTime;
+7 -7
View File
@@ -59,7 +59,7 @@
#endif
/* local port data - shared with RS-485 */
static volatile struct mstp_port_struct_t MSTP_Port;
static struct mstp_port_struct_t MSTP_Port;
/* buffers needed by mstp port struct */
static uint8_t RxBuffer[DLMSTP_MPDU_MAX];
static uint8_t TxBuffer[DLMSTP_MPDU_MAX];
@@ -83,7 +83,7 @@ static void Timer_Silence_Reset(void *pArg)
}
/* functions used by the MS/TP state machine to put or get data */
uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
uint16_t MSTP_Put_Receive(struct mstp_port_struct_t *mstp_port)
{
(void)mstp_port;
@@ -93,7 +93,7 @@ uint16_t MSTP_Put_Receive(volatile struct mstp_port_struct_t *mstp_port)
/* for the MS/TP state machine to use for getting data to send */
/* Return: amount of PDU data */
uint16_t MSTP_Get_Send(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */
(void)mstp_port;
(void)timeout;
@@ -107,7 +107,7 @@ uint16_t MSTP_Get_Send(
* @param nbytes - number of bytes of data to send
*/
void MSTP_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port,
struct mstp_port_struct_t *mstp_port,
uint8_t * buffer,
uint16_t nbytes)
{
@@ -117,7 +117,7 @@ void MSTP_Send_Frame(
}
uint16_t MSTP_Get_Reply(
volatile struct mstp_port_struct_t *mstp_port, unsigned timeout)
struct mstp_port_struct_t *mstp_port, unsigned timeout)
{ /* milliseconds to wait for a packet */
(void)mstp_port;
(void)timeout;
@@ -165,7 +165,7 @@ static int network_init(const char *name, int protocol)
}
static void snap_received_packet(
volatile struct mstp_port_struct_t *mstp_port, int sockfd)
struct mstp_port_struct_t *mstp_port, int sockfd)
{
uint16_t mtu_len = 0; /* number of octets of packet saved in file */
unsigned i = 0; /* counter */
@@ -241,7 +241,7 @@ void signal_init(void)
/* simple test to packetize the data and print it */
int main(int argc, char *argv[])
{
volatile struct mstp_port_struct_t *mstp_port;
struct mstp_port_struct_t *mstp_port;
long my_baud = 38400;
uint32_t packet_count = 0;
int sockfd = -1;
+4 -4
View File
@@ -217,7 +217,7 @@ uint32_t RS485_Get_Baud_Rate(void)
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
uint32_t RS485_Get_Port_Baud_Rate(volatile struct mstp_port_struct_t *mstp_port)
uint32_t RS485_Get_Port_Baud_Rate(struct mstp_port_struct_t *mstp_port)
{
uint32_t baud = 0;
SHARED_MSTP_DATA *poSharedData = (SHARED_MSTP_DATA *)mstp_port->UserData;
@@ -382,7 +382,7 @@ bool RS485_Set_Baud_Rate(uint32_t baud)
* NOTES: none
*****************************************************************************/
void RS485_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t *buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes)
{ /* number of bytes of data (up to 501) */
@@ -458,7 +458,7 @@ void RS485_Send_Frame(
* ALGORITHM: none
* NOTES: none
*****************************************************************************/
void RS485_Check_UART_Data(volatile struct mstp_port_struct_t *mstp_port)
void RS485_Check_UART_Data(struct mstp_port_struct_t *mstp_port)
{
fd_set input;
struct timeval waiter;
@@ -694,7 +694,7 @@ void RS485_Print_Ports(void)
#include <string.h>
int main(int argc, char *argv[])
{
volatile struct mstp_port_struct_t mstp_port = { 0 };
struct mstp_port_struct_t mstp_port = { 0 };
uint8_t token_buf[8] = { 0x55, 0xFF, 0x00, 0x7E, 0x07, 0x00, 0x00, 0xFD };
uint8_t pfm_buf[8] = { 0x55, 0xFF, 0x01, 0x67, 0x07, 0x00, 0x00, 0x3E };
long baud = 38400;
+3 -3
View File
@@ -57,16 +57,16 @@ extern "C" {
BACNET_STACK_EXPORT
void RS485_Send_Frame(
volatile struct mstp_port_struct_t *mstp_port, /* port specific data */
struct mstp_port_struct_t *mstp_port, /* port specific data */
uint8_t * buffer, /* frame to send (up to 501 bytes of data) */
uint16_t nbytes); /* number of bytes of data (up to 501) */
BACNET_STACK_EXPORT
void RS485_Check_UART_Data(
volatile struct mstp_port_struct_t *mstp_port); /* port specific data */
struct mstp_port_struct_t *mstp_port); /* port specific data */
BACNET_STACK_EXPORT
uint32_t RS485_Get_Port_Baud_Rate(
volatile struct mstp_port_struct_t *mstp_port);
struct mstp_port_struct_t *mstp_port);
BACNET_STACK_EXPORT
uint32_t RS485_Get_Baud_Rate(
void);