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
+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
${TST_DIR}/bacnet/datalink/test/mstp-mock.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.c
)
+206 -1
View File
@@ -149,6 +149,52 @@ static void Timer_Silence_Reset(void *pArg)
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
* @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->SilenceTimerReset = Timer_Silence_Reset;
mstp_port->CheckAutoBaud = false;
mstp_port->SlaveNodeEnabled = false;
/* configure for Zero Config */
mstp_port->ZeroConfigEnabled = true;
mstp_port->This_Station = 255;
@@ -1126,6 +1175,161 @@ static void testZeroConfigNodeFSM(void)
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(
crc_tests, ztest_unit_test(testReceiveNodeFSM),
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);
}
+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);
}
void MSTP_Auto_Baud_FSM(struct mstp_port_struct_t *mstp_port)
{
ztest_check_expected_value(mstp_port);
}