Added MS/TP automatic baudrate detection option into the core MS/TP state machine. (#900)

This commit is contained in:
Steve Karg
2025-02-03 15:10:31 -06:00
committed by GitHub
parent c5b129e9ab
commit 19ef7f74cd
12 changed files with 471 additions and 11 deletions
+1
View File
@@ -129,6 +129,7 @@ static void mstp_configure(void)
/* user data */ /* user data */
MSTP_Port.ZeroConfigEnabled = true; MSTP_Port.ZeroConfigEnabled = true;
MSTP_Port.SlaveNodeEnabled = false; MSTP_Port.SlaveNodeEnabled = false;
MSTP_Port.CheckAutoBaud = false;
MSTP_Zero_Config_UUID_Init(&MSTP_Port); MSTP_Zero_Config_UUID_Init(&MSTP_Port);
MSTP_User_Data.RS485_Driver = &RS485_Driver; MSTP_User_Data.RS485_Driver = &RS485_Driver;
MSTP_Port.UserData = &MSTP_User_Data; MSTP_Port.UserData = &MSTP_User_Data;
+5 -2
View File
@@ -102,6 +102,7 @@ int main(void)
MSTP_Port.ZeroConfigEnabled = true; MSTP_Port.ZeroConfigEnabled = true;
MSTP_Port.Zero_Config_Preferred_Station = 0; MSTP_Port.Zero_Config_Preferred_Station = 0;
MSTP_Port.SlaveNodeEnabled = false; MSTP_Port.SlaveNodeEnabled = false;
MSTP_Port.CheckAutoBaud = false;
/* user data */ /* user data */
MSTP_User_Data.RS485_Driver = &RS485_Driver; MSTP_User_Data.RS485_Driver = &RS485_Driver;
MSTP_Port.UserData = &MSTP_User_Data; MSTP_Port.UserData = &MSTP_User_Data;
@@ -113,8 +114,10 @@ int main(void)
/* FIXME: get the address from hardware DIP or from EEPROM */ /* FIXME: get the address from hardware DIP or from EEPROM */
dlmstp_set_mac_address(1); dlmstp_set_mac_address(1);
} }
/* FIXME: get the baud rate from hardware DIP or from EEPROM */ if (!MSTP_Port.CheckAutoBaud) {
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT); /* FIXME: get the baud rate from hardware DIP or from EEPROM */
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT);
}
/* initialize application layer*/ /* initialize application layer*/
bacnet_init(); bacnet_init();
for (;;) { for (;;) {
+5
View File
@@ -91,6 +91,11 @@ static void dlmstp_configure(void)
} else { } else {
MSTP_Port.SlaveNodeEnabled = true; MSTP_Port.SlaveNodeEnabled = true;
} }
MSTP_Port.CheckAutoBaud = false;
if (!MSTP_Port.CheckAutoBaud) {
/* FIXME: get the baud rate from hardware DIP or from EEPROM */
dlmstp_set_baud_rate(DLMSTP_BAUD_RATE_DEFAULT);
}
MSTP_Zero_Config_UUID_Init(&MSTP_Port); MSTP_Zero_Config_UUID_Init(&MSTP_Port);
MSTP_User_Data.RS485_Driver = &RS485_Driver; MSTP_User_Data.RS485_Driver = &RS485_Driver;
MSTP_Port.UserData = &MSTP_User_Data; MSTP_Port.UserData = &MSTP_User_Data;
+78 -1
View File
@@ -417,7 +417,7 @@ uint16_t dlmstp_receive(
MSTP_Slave_Node_FSM(MSTP_Port); MSTP_Slave_Node_FSM(MSTP_Port);
} else if ( } else if (
(MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) || (MSTP_Port->This_Station <= DEFAULT_MAX_MASTER) ||
MSTP_Port->ZeroConfigEnabled) { MSTP_Port->ZeroConfigEnabled || MSTP_Port->CheckAutoBaud) {
while (MSTP_Master_Node_FSM(MSTP_Port)) { while (MSTP_Master_Node_FSM(MSTP_Port)) {
/* do nothing while some states fast transition */ /* do nothing while some states fast transition */
}; };
@@ -700,6 +700,39 @@ bool dlmstp_zero_config_enabled_set(bool flag)
return true; return true;
} }
/**
* @brief Get the MSTP port AutoBaudEnabled status
* @return true if the MSTP port has AutoBaudEnabled
*/
bool dlmstp_check_auto_baud(void)
{
if (!MSTP_Port) {
return false;
}
return MSTP_Port->CheckAutoBaud;
}
/**
* @brief Set the MSTP port AutoBaudEnabled flag
* @param flag - true if the MSTP port has AutoBaudEnabled
* @return true if the MSTP port AutoBaudEnabled was set
* @note This flag is used to enable the Zero Configuration state machine
* for the MSTP port. The Zero Configuration state machine is used to
* automatically assign a MAC address to the MSTP port.
*/
bool dlmstp_check_auto_baud_set(bool flag)
{
if (!MSTP_Port) {
return false;
}
MSTP_Port->CheckAutoBaud = flag;
if (flag) {
MSTP_Port->Auto_Baud_State = MSTP_AUTO_BAUD_STATE_INIT;
}
return true;
}
/** /**
* @brief Get the MSTP port MAC address that this node prefers to use. * @brief Get the MSTP port MAC address that this node prefers to use.
* @return ZeroConfigStation value, or an out-of-range value if invalid * @return ZeroConfigStation value, or an out-of-range value if invalid
@@ -961,6 +994,46 @@ uint32_t dlmstp_silence_milliseconds(void *arg)
return milliseconds; return milliseconds;
} }
/**
* @brief Return the valid frame time in milliseconds
* @param arg - pointer to MSTP port structure
* @return valid frame time in milliseconds
*/
uint32_t dlmstp_valid_frame_milliseconds(void *arg)
{
uint32_t milliseconds = 0, now = 0;
struct mstp_port_struct_t *port = arg;
struct dlmstp_user_data_t *user = NULL;
if (port) {
user = port->UserData;
}
if (user) {
now = mstimer_now();
milliseconds = now - user->Valid_Frame_Milliseconds;
}
return milliseconds;
}
/**
* @brief Reset the valid frame timer
* @param arg - pointer to MSTP port structure
* @return valid frame time in milliseconds
*/
void dlmstp_valid_frame_milliseconds_reset(void *arg)
{
struct mstp_port_struct_t *port = arg;
struct dlmstp_user_data_t *user = NULL;
if (port) {
user = port->UserData;
}
if (user) {
user->Valid_Frame_Milliseconds = mstimer_now();
}
}
/** /**
* @brief Reset the RS-485 silence time to zero * @brief Reset the RS-485 silence time to zero
* @param arg - pointer to MSTP port structure * @param arg - pointer to MSTP port structure
@@ -994,6 +1067,10 @@ bool dlmstp_init(char *ifname)
if (MSTP_Port) { if (MSTP_Port) {
MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds; MSTP_Port->SilenceTimer = dlmstp_silence_milliseconds;
MSTP_Port->SilenceTimerReset = dlmstp_silence_reset; MSTP_Port->SilenceTimerReset = dlmstp_silence_reset;
MSTP_Port->ValidFrameTimer = dlmstp_valid_frame_milliseconds;
MSTP_Port->ValidFrameTimerReset = dlmstp_valid_frame_milliseconds_reset;
MSTP_Port->BaudRate = dlmstp_baud_rate;
MSTP_Port->BaudRateSet = dlmstp_set_baud_rate;
user = (struct dlmstp_user_data_t *)MSTP_Port->UserData; user = (struct dlmstp_user_data_t *)MSTP_Port->UserData;
if (user && !user->Initialized) { if (user && !user->Initialized) {
Ringbuf_Initialize( Ringbuf_Initialize(
+10
View File
@@ -102,6 +102,7 @@ struct dlmstp_user_data_t {
dlmstp_hook_frame_rx_start_cb Preamble_Callback; dlmstp_hook_frame_rx_start_cb Preamble_Callback;
dlmstp_hook_frame_rx_complete_cb Valid_Frame_Rx_Callback; dlmstp_hook_frame_rx_complete_cb Valid_Frame_Rx_Callback;
dlmstp_hook_frame_rx_complete_cb Invalid_Frame_Rx_Callback; dlmstp_hook_frame_rx_complete_cb Invalid_Frame_Rx_Callback;
uint32_t Valid_Frame_Milliseconds;
/* the PDU Queue is made of Nmax_info_frames x dlmstp_packet's */ /* the PDU Queue is made of Nmax_info_frames x dlmstp_packet's */
RING_BUFFER PDU_Queue; RING_BUFFER PDU_Queue;
struct dlmstp_packet PDU_Buffer[DLMSTP_MAX_INFO_FRAMES]; struct dlmstp_packet PDU_Buffer[DLMSTP_MAX_INFO_FRAMES];
@@ -192,6 +193,10 @@ bool dlmstp_zero_config_enabled(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool dlmstp_zero_config_enabled_set(bool flag); bool dlmstp_zero_config_enabled_set(bool flag);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool dlmstp_check_auto_baud(void);
BACNET_STACK_EXPORT
bool dlmstp_check_auto_baud_set(bool flag);
BACNET_STACK_EXPORT
uint8_t dlmstp_zero_config_preferred_station(void); uint8_t dlmstp_zero_config_preferred_station(void);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
bool dlmstp_zero_config_preferred_station_set(uint8_t station); bool dlmstp_zero_config_preferred_station_set(uint8_t station);
@@ -211,6 +216,11 @@ uint32_t dlmstp_silence_milliseconds(void *arg);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void dlmstp_silence_reset(void *arg); void dlmstp_silence_reset(void *arg);
BACNET_STACK_EXPORT
uint32_t dlmstp_valid_frame_milliseconds(void *arg);
BACNET_STACK_EXPORT
void dlmstp_valid_frame_milliseconds_reset(void *arg);
/* Set the callback function to be called on every valid received frame */ /* Set the callback function to be called on every valid received frame */
/* This is not necessary for normal usage, but is helpful if the caller */ /* This is not necessary for normal usage, but is helpful if the caller */
/* needs to monitor traffic on the MS/TP bus */ /* needs to monitor traffic on the MS/TP bus */
+109 -7
View File
@@ -648,7 +648,9 @@ bool MSTP_Master_Node_FSM(struct mstp_port_struct_t *mstp_port)
} }
switch (mstp_port->master_state) { switch (mstp_port->master_state) {
case MSTP_MASTER_STATE_INITIALIZE: case MSTP_MASTER_STATE_INITIALIZE:
if (mstp_port->ZeroConfigEnabled) { if (mstp_port->CheckAutoBaud) {
MSTP_Auto_Baud_FSM(mstp_port);
} else if (mstp_port->ZeroConfigEnabled) {
MSTP_Zero_Config_FSM(mstp_port); MSTP_Zero_Config_FSM(mstp_port);
if (mstp_port->This_Station != 255) { if (mstp_port->This_Station != 255) {
/* indicate that the next station is unknown */ /* indicate that the next station is unknown */
@@ -1430,8 +1432,8 @@ static void MSTP_Zero_Config_State_Idle(struct mstp_port_struct_t *mstp_port)
return; return;
} }
if (mstp_port->ReceivedValidFrame) { if (mstp_port->ReceivedValidFrame) {
/* IdleValidFrame */
/* next state will clear the frame flags */ /* next state will clear the frame flags */
/* MonitorPFM */
mstp_port->Poll_Count = 0; mstp_port->Poll_Count = 0;
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_LURK; mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_LURK;
} else if (mstp_port->ReceivedInvalidFrame) { } else if (mstp_port->ReceivedInvalidFrame) {
@@ -1482,7 +1484,7 @@ static void MSTP_Zero_Config_State_Lurk(struct mstp_port_struct_t *mstp_port)
} }
} }
if (src == mstp_port->Zero_Config_Station) { if (src == mstp_port->Zero_Config_Station) {
/* AddressInUse */ /* LurkAddressInUse */
/* monitor PFM from the next address */ /* monitor PFM from the next address */
mstp_port->Zero_Config_Station = MSTP_Zero_Config_Station_Increment( mstp_port->Zero_Config_Station = MSTP_Zero_Config_Station_Increment(
mstp_port->Zero_Config_Station); mstp_port->Zero_Config_Station);
@@ -1493,23 +1495,23 @@ static void MSTP_Zero_Config_State_Lurk(struct mstp_port_struct_t *mstp_port)
/* calculate this node poll count priority number */ /* calculate this node poll count priority number */
count = Nmin_poll + mstp_port->Npoll_slot; count = Nmin_poll + mstp_port->Npoll_slot;
if (mstp_port->Poll_Count == count) { if (mstp_port->Poll_Count == count) {
/* PollResponse */ /* LurkPollResponse */
MSTP_Create_And_Send_Frame( MSTP_Create_And_Send_Frame(
mstp_port, FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, src, mstp_port, FRAME_TYPE_REPLY_TO_POLL_FOR_MASTER, src,
mstp_port->Zero_Config_Station, NULL, 0); mstp_port->Zero_Config_Station, NULL, 0);
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_CLAIM; mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_CLAIM;
} else { } else {
/* CountFrame */ /* LurkCountFrame */
mstp_port->Poll_Count++; mstp_port->Poll_Count++;
} }
} }
} else if (mstp_port->ReceivedInvalidFrame) { } else if (mstp_port->ReceivedInvalidFrame) {
/* InvalidFrame */ /* LurkInvalidFrame */
mstp_port->ReceivedInvalidFrame = false; mstp_port->ReceivedInvalidFrame = false;
} else if (mstp_port->Zero_Config_Silence > 0) { } else if (mstp_port->Zero_Config_Silence > 0) {
if (mstp_port->SilenceTimer((void *)mstp_port) > if (mstp_port->SilenceTimer((void *)mstp_port) >
mstp_port->Zero_Config_Silence) { mstp_port->Zero_Config_Silence) {
/* LurkingTimeout */ /* LurkTimeout */
mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE; mstp_port->Zero_Config_State = MSTP_ZERO_CONFIG_STATE_IDLE;
} }
} }
@@ -1660,6 +1662,106 @@ void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port)
} }
} }
/**
* @brief Get the baud rate for auto-baud at a given index
* @param baud_rate_index the index of the baud rate
* @return the baud rate at the index
* @note A modulo operation keeps the index within the bounds of the array of
* baud rates.
*/
uint32_t MSTP_Auto_Baud_Rate(unsigned baud_rate_index)
{
const uint32_t TestBaudrates[6] = {
115200, 76800, 57600, 38400, 19200, 9600
};
unsigned index;
index = baud_rate_index % ARRAY_SIZE(TestBaudrates);
return TestBaudrates[index];
}
/**
* @brief The MSTP_AUTO_BAUD_STATE_INIT state is entered when
* CheckAutoBaud is TRUE
* @param mstp_port the context of the MSTP port
*/
static void MSTP_Auto_Baud_State_Init(struct mstp_port_struct_t *mstp_port)
{
uint32_t baud;
if (!mstp_port) {
return;
}
mstp_port->ValidFrames = 0;
mstp_port->BaudRateIndex = 0;
mstp_port->ValidFrameTimerReset((void *)mstp_port);
baud = MSTP_Auto_Baud_Rate(mstp_port->BaudRateIndex);
mstp_port->BaudRateSet(baud);
mstp_port->Auto_Baud_State = MSTP_AUTO_BAUD_STATE_IDLE;
}
/**
* @brief The MSTP_AUTO_BAUD_STATE_IDLE state is entered when
* CheckAutoBaud is TRUE and waits for good frames or timeout
* @param mstp_port the context of the MSTP port
*/
static void MSTP_Auto_Baud_State_Idle(struct mstp_port_struct_t *mstp_port)
{
uint32_t baud;
if (!mstp_port) {
return;
}
if (mstp_port->ReceivedValidFrame) {
/* IdleValidFrame */
mstp_port->ValidFrames++;
if (mstp_port->ValidFrames >= 4) {
/* GoodBaudRate */
mstp_port->CheckAutoBaud = false;
mstp_port->Auto_Baud_State = MSTP_AUTO_BAUD_STATE_USE;
}
mstp_port->ReceivedValidFrame = false;
} else if (mstp_port->ReceivedInvalidFrame) {
/* IdleInvalidFrame */
mstp_port->ValidFrames = 0;
mstp_port->ReceivedInvalidFrame = false;
} else if (mstp_port->ValidFrameTimer((void *)mstp_port) >= 5000UL) {
/* IdleTimeout */
mstp_port->BaudRateIndex++;
baud = MSTP_Auto_Baud_Rate(mstp_port->BaudRateIndex);
mstp_port->BaudRateSet(baud);
mstp_port->ValidFrames = 0;
mstp_port->ValidFrameTimerReset((void *)mstp_port);
}
}
/**
* @brief Finite State Machine for the Auto Baud Rate process
* @param mstp_port the context of the MSTP port
*/
void MSTP_Auto_Baud_FSM(struct mstp_port_struct_t *mstp_port)
{
if (!mstp_port) {
return;
}
if (!mstp_port->CheckAutoBaud) {
return;
}
switch (mstp_port->Auto_Baud_State) {
case MSTP_AUTO_BAUD_STATE_INIT:
MSTP_Auto_Baud_State_Init(mstp_port);
break;
case MSTP_AUTO_BAUD_STATE_IDLE:
MSTP_Auto_Baud_State_Idle(mstp_port);
break;
case MSTP_AUTO_BAUD_STATE_USE:
break;
default:
break;
}
}
/* note: This_Station assumed to be set with the MAC address */ /* note: This_Station assumed to be set with the MAC address */
/* note: Nmax_info_frames assumed to be set (default=1) */ /* note: Nmax_info_frames assumed to be set (default=1) */
/* note: Nmax_master assumed to be set (default=127) */ /* note: Nmax_master assumed to be set (default=127) */
+24
View File
@@ -213,6 +213,24 @@ struct mstp_port_struct_t {
turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */ turnaround_time_milliseconds = (Tturnaround*1000UL)/RS485_Baud; */
uint8_t Tturnaround_timeout; uint8_t Tturnaround_timeout;
/* orderly transition tracking for auto-baud node startup */
MSTP_AUTO_BAUD_STATE Auto_Baud_State;
/* A Boolean flag set to TRUE if this node is checking frames for
automatic baud rate detection */
unsigned CheckAutoBaud : 1;
/* The number of elapsed milliseconds since the last received valid frame */
uint32_t (*ValidFrameTimer)(void *pArg);
void (*ValidFrameTimerReset)(void *pArg);
/* The number of header frames received with good CRC since
initialization at the current trial baudrate. */
uint8_t ValidFrames;
/** Get the current baud rate */
uint32_t (*BaudRate)(void);
/** Set the current baud rate */
void (*BaudRateSet)(uint32_t baud);
/* The zero-based index in TestBaudrates of the next baudrate to try. */
unsigned BaudRateIndex;
/*Platform-specific port data */ /*Platform-specific port data */
void *UserData; void *UserData;
}; };
@@ -265,6 +283,12 @@ unsigned MSTP_Zero_Config_Station_Increment(unsigned station);
BACNET_STACK_EXPORT BACNET_STACK_EXPORT
void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port); void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port);
BACNET_STACK_EXPORT
uint32_t MSTP_Auto_Baud_Rate(unsigned baud_rate_index);
BACNET_STACK_EXPORT
void MSTP_Auto_Baud_FSM(struct mstp_port_struct_t *mstp_port);
/* functions used by the MS/TP state machine to put or get data */ /* functions used by the MS/TP state machine to put or get data */
/* FIXME: developer must implement these in their DLMSTP module */ /* FIXME: developer must implement these in their DLMSTP module */
+7
View File
@@ -90,6 +90,13 @@ typedef enum MSTP_Zero_Config_State {
MSTP_ZERO_CONFIG_STATE_USE = 5 MSTP_ZERO_CONFIG_STATE_USE = 5
} MSTP_ZERO_CONFIG_STATE; } MSTP_ZERO_CONFIG_STATE;
/* MSTP auto-baud FSM states */
typedef enum MSTP_Auto_Baud_State {
MSTP_AUTO_BAUD_STATE_INIT = 0,
MSTP_AUTO_BAUD_STATE_IDLE = 1,
MSTP_AUTO_BAUD_STATE_USE = 2
} MSTP_AUTO_BAUD_STATE;
/* The time without a DataAvailable or ReceiveError event before declaration */ /* The time without a DataAvailable or ReceiveError event before declaration */
/* of loss of token: 500 milliseconds. */ /* of loss of token: 500 milliseconds. */
#define Tno_token 500 #define Tno_token 500
+20
View File
@@ -0,0 +1,20 @@
/**
* @file
* @brief Stub functions for unit test of a BACnet object
* @author Steve Karg <skarg@users.sourceforge.net>
* @date January 2025
* @copyright SPDX-License-Identifier: MIT
*/
#include <zephyr/ztest.h>
#include <stdbool.h>
#include <stdint.h>
#include "bacnet/basic/sys/mstimer.h"
/**
* @brief Get the current time in milliseconds
* @return milliseconds
*/
unsigned long mstimer_now(void)
{
return ztest_get_return_value();
}
@@ -47,6 +47,7 @@ add_executable(${PROJECT_NAME}
./src/main.c ./src/main.c
${TST_DIR}/bacnet/datalink/test/mstp-mock.c ${TST_DIR}/bacnet/datalink/test/mstp-mock.c
${TST_DIR}/bacnet/datalink/test/mstp-rs485.c ${TST_DIR}/bacnet/datalink/test/mstp-rs485.c
${TST_DIR}/bacnet/basic/sys/test/mstimer_mock.c
${ZTST_DIR}/ztest_mock.c ${ZTST_DIR}/ztest_mock.c
${ZTST_DIR}/ztest.c ${ZTST_DIR}/ztest.c
) )
+206 -1
View File
@@ -149,6 +149,52 @@ static void Timer_Silence_Reset(void *pArg)
SilenceTime = 0; SilenceTime = 0;
} }
/* track the last good header time in milliseconds */
uint32_t Good_Header_Time = 0;
/**
* @brief MS/TP state machine calls this to get the good header time
* @param pArg pointer to the port specific context data
* @return amount of time in milliseconds
*/
static uint32_t Good_Header_Timer(void *pArg)
{
(void)pArg;
return Good_Header_Time;
}
/**
* @brief MS/TP state machine calls this to reset the good header time
* @param pArg pointer to the port specific context data
*/
void Good_Header_Timer_Reset(void *pArg)
{
(void)pArg;
Good_Header_Time = 0;
}
/* track the internal baud rate */
static uint32_t Baud_Rate_Internal = 0;
/**
* @brief Get the current baud rate
* @param pArg pointer to the port specific context data
* @return The current baud rate
*/
uint32_t Baud_Rate(void)
{
return Baud_Rate_Internal;
}
/**
* @brief Set the current baud rate
* @param pArg pointer to the port specific context data
* @param baud the new baud rate
* @return true if the baud rate was set
*/
void Baud_Rate_Set(uint32_t baud)
{
Baud_Rate_Internal = baud;
}
/** /**
* @brief MS/TP state machine calls this to send a frame * @brief MS/TP state machine calls this to send a frame
* @param mstp_port port specific context data * @param mstp_port port specific context data
@@ -648,6 +694,9 @@ static void testZeroConfigNode_Init(struct mstp_port_struct_t *mstp_port)
mstp_port->SilenceTimer = Timer_Silence; mstp_port->SilenceTimer = Timer_Silence;
mstp_port->SilenceTimerReset = Timer_Silence_Reset; mstp_port->SilenceTimerReset = Timer_Silence_Reset;
mstp_port->CheckAutoBaud = false;
mstp_port->SlaveNodeEnabled = false;
/* configure for Zero Config */ /* configure for Zero Config */
mstp_port->ZeroConfigEnabled = true; mstp_port->ZeroConfigEnabled = true;
mstp_port->This_Station = 255; mstp_port->This_Station = 255;
@@ -1126,6 +1175,161 @@ static void testZeroConfigNodeFSM(void)
next_station); next_station);
} }
static void testAutoBaudNode_Init(struct mstp_port_struct_t *mstp_port)
{
bool transition_now;
mstp_port->InputBuffer = &RxBuffer[0];
mstp_port->InputBufferSize = sizeof(RxBuffer);
mstp_port->OutputBuffer = &TxBuffer[0];
mstp_port->OutputBufferSize = sizeof(TxBuffer);
mstp_port->Nmax_info_frames = 1;
mstp_port->Nmax_master = 127;
mstp_port->Tframe_abort = DEFAULT_Tframe_abort;
mstp_port->Treply_delay = DEFAULT_Treply_delay;
mstp_port->Treply_timeout = DEFAULT_Treply_timeout;
mstp_port->Tusage_timeout = DEFAULT_Tusage_timeout;
mstp_port->SilenceTimer = Timer_Silence;
mstp_port->SilenceTimerReset = Timer_Silence_Reset;
mstp_port->CheckAutoBaud = true;
mstp_port->SlaveNodeEnabled = false;
mstp_port->ZeroConfigEnabled = false;
mstp_port->This_Station = 255;
mstp_port->Auto_Baud_State = MSTP_AUTO_BAUD_STATE_INIT;
mstp_port->BaudRate = Baud_Rate;
mstp_port->BaudRateSet = Baud_Rate_Set;
mstp_port->ValidFrameTimer = Good_Header_Timer;
mstp_port->ValidFrameTimerReset = Good_Header_Timer_Reset;
MSTP_Init(mstp_port);
zassert_true(mstp_port->master_state == MSTP_MASTER_STATE_INITIALIZE, NULL);
zassert_true(mstp_port->Auto_Baud_State == MSTP_AUTO_BAUD_STATE_INIT, NULL);
zassert_true(mstp_port->Tframe_abort == DEFAULT_Tframe_abort, NULL);
zassert_true(mstp_port->Treply_delay == DEFAULT_Treply_delay, NULL);
zassert_true(mstp_port->Treply_timeout == DEFAULT_Treply_timeout, NULL);
zassert_true(mstp_port->Tusage_timeout == DEFAULT_Tusage_timeout, NULL);
transition_now = MSTP_Master_Node_FSM(mstp_port);
zassert_false(transition_now, NULL);
zassert_true(mstp_port->Auto_Baud_State == MSTP_AUTO_BAUD_STATE_IDLE, NULL);
zassert_true(mstp_port->ValidFrames == 0, NULL);
zassert_true(mstp_port->BaudRateIndex == 0, NULL);
zassert_true(mstp_port->BaudRate() != 0, NULL);
zassert_true(mstp_port->ValidFrameTimer(NULL) == 0, NULL);
}
static void
testAutoBaudNode_Idle_ValidFrame(struct mstp_port_struct_t *mstp_port)
{
bool transition_now;
if (!mstp_port->CheckAutoBaud) {
return;
}
Good_Header_Time = 0;
SilenceTime = 0;
mstp_port->SourceAddress = 0;
mstp_port->DestinationAddress = 1;
mstp_port->ReceivedValidFrame = true;
mstp_port->ReceivedInvalidFrame = false;
transition_now = MSTP_Master_Node_FSM(mstp_port);
zassert_false(transition_now, NULL);
zassert_true(mstp_port->ReceivedValidFrame == false, NULL);
zassert_true(mstp_port->ReceivedInvalidFrame == false, NULL);
zassert_true(mstp_port->BaudRateIndex == 0, NULL);
zassert_true(mstp_port->ValidFrames > 0, NULL);
if (mstp_port->ValidFrames >= 4) {
zassert_true(mstp_port->CheckAutoBaud == 0, NULL);
zassert_true(
mstp_port->Auto_Baud_State == MSTP_AUTO_BAUD_STATE_USE, NULL);
} else {
zassert_true(
mstp_port->Auto_Baud_State == MSTP_AUTO_BAUD_STATE_IDLE, NULL);
}
}
static void
testAutoBaudNode_Idle_InvalidFrame(struct mstp_port_struct_t *mstp_port)
{
bool transition_now;
if (!mstp_port->CheckAutoBaud) {
return;
}
Good_Header_Time = 0;
SilenceTime = 0;
mstp_port->SourceAddress = 0;
mstp_port->DestinationAddress = 1;
mstp_port->ReceivedValidFrame = false;
mstp_port->ReceivedInvalidFrame = true;
transition_now = MSTP_Master_Node_FSM(mstp_port);
zassert_false(transition_now, NULL);
zassert_true(mstp_port->ReceivedValidFrame == false, NULL);
zassert_true(mstp_port->ReceivedInvalidFrame == false, NULL);
zassert_true(mstp_port->BaudRateIndex == 0, NULL);
zassert_true(mstp_port->ValidFrames == 0, NULL);
zassert_true(mstp_port->CheckAutoBaud, NULL);
zassert_true(mstp_port->Auto_Baud_State == MSTP_AUTO_BAUD_STATE_IDLE, NULL);
}
static void testAutoBaudNode_Idle_Timeout(struct mstp_port_struct_t *mstp_port)
{
bool transition_now;
uint32_t baud;
if (!mstp_port->CheckAutoBaud) {
return;
}
Good_Header_Time = 5000UL;
zassert_true(mstp_port->ValidFrameTimer(NULL) == 5000UL, NULL);
SilenceTime = 0;
mstp_port->SourceAddress = 0;
mstp_port->DestinationAddress = 1;
mstp_port->ReceivedValidFrame = false;
mstp_port->ReceivedInvalidFrame = false;
transition_now = MSTP_Master_Node_FSM(mstp_port);
zassert_false(transition_now, NULL);
zassert_true(mstp_port->ReceivedValidFrame == false, NULL);
zassert_true(mstp_port->ReceivedInvalidFrame == false, NULL);
baud = MSTP_Auto_Baud_Rate(mstp_port->BaudRateIndex);
zassert_true(mstp_port->BaudRate() == baud, NULL);
zassert_true(mstp_port->ValidFrames == 0, NULL);
zassert_true(mstp_port->CheckAutoBaud, NULL);
zassert_true(mstp_port->Auto_Baud_State == MSTP_AUTO_BAUD_STATE_IDLE, NULL);
zassert_true(mstp_port->ValidFrameTimer(NULL) == 0, NULL);
}
static void testAutoBaudNodeFSM(void)
{
struct mstp_port_struct_t MSTP_Port = { 0 }; /* port data */
/* test case: got at least valid frames, use the baud rate */
testAutoBaudNode_Init(&MSTP_Port);
testAutoBaudNode_Idle_ValidFrame(&MSTP_Port);
testAutoBaudNode_Idle_ValidFrame(&MSTP_Port);
testAutoBaudNode_Idle_ValidFrame(&MSTP_Port);
testAutoBaudNode_Idle_ValidFrame(&MSTP_Port);
testAutoBaudNode_Idle_ValidFrame(&MSTP_Port);
testAutoBaudNode_Idle_ValidFrame(&MSTP_Port);
/* test case: got an invalid frame */
testAutoBaudNode_Init(&MSTP_Port);
testAutoBaudNode_Idle_InvalidFrame(&MSTP_Port);
testAutoBaudNode_Idle_InvalidFrame(&MSTP_Port);
/* test case: timeout */
testAutoBaudNode_Init(&MSTP_Port);
testAutoBaudNode_Idle_Timeout(&MSTP_Port);
testAutoBaudNode_Idle_Timeout(&MSTP_Port);
testAutoBaudNode_Idle_Timeout(&MSTP_Port);
testAutoBaudNode_Idle_Timeout(&MSTP_Port);
testAutoBaudNode_Idle_Timeout(&MSTP_Port);
}
/** /**
* @} * @}
*/ */
@@ -1135,7 +1339,8 @@ void test_main(void)
ztest_test_suite( ztest_test_suite(
crc_tests, ztest_unit_test(testReceiveNodeFSM), crc_tests, ztest_unit_test(testReceiveNodeFSM),
ztest_unit_test(testMasterNodeFSM), ztest_unit_test(testSlaveNodeFSM), ztest_unit_test(testMasterNodeFSM), ztest_unit_test(testSlaveNodeFSM),
ztest_unit_test(testZeroConfigNodeFSM)); ztest_unit_test(testZeroConfigNodeFSM),
ztest_unit_test(testAutoBaudNodeFSM));
ztest_run_test_suite(crc_tests); ztest_run_test_suite(crc_tests);
} }
+5
View File
@@ -91,3 +91,8 @@ void MSTP_Zero_Config_FSM(struct mstp_port_struct_t *mstp_port)
{ {
ztest_check_expected_value(mstp_port); ztest_check_expected_value(mstp_port);
} }
void MSTP_Auto_Baud_FSM(struct mstp_port_struct_t *mstp_port)
{
ztest_check_expected_value(mstp_port);
}