Added MS/TP automatic baudrate detection option into the core MS/TP state machine. (#900)
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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 (;;) {
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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
@@ -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) */
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user