/** * @file * @brief Unit test for a basic BACnet MS/TP Datalink * @author Steve Karg * @date November 2024 * @copyright SPDX-License-Identifier: MIT */ #include #include #include #include #include /** * @addtogroup bacnet_tests * @{ */ static uint8_t RS485_Rx_Buffer[512]; static uint8_t RS485_Tx_Buffer[512]; static struct mstp_port_struct_t MSTP_Port; static struct dlmstp_user_data_t MSTP_User; static struct dlmstp_rs485_driver MSTP_RS485_Driver = { .init = MSTP_RS485_Init, .send = MSTP_RS485_Send, .read = MSTP_RS485_Read, .transmitting = MSTP_RS485_Transmitting, .baud_rate = MSTP_RS485_Baud_Rate, .baud_rate_set = MSTP_RS485_Baud_Rate_Set, .silence_milliseconds = MSTP_RS485_Silence_Milliseconds, .silence_reset = MSTP_RS485_Silence_Reset }; /** * @brief Test the basic operation of the MS/TP Datalink */ #if defined(CONFIG_ZTEST_NEW_API) ZTEST(dlsmtp_tests, test_MSTP_Datalink) #else static void test_MSTP_Datalink(void) #endif { bool status = false; struct dlmstp_statistics test_stats; uint32_t test_baudrate; uint8_t test_mac_address; BACNET_ADDRESS test_address; uint8_t test_frames; uint16_t test_length; uint8_t test_data[10] = { PDU_TYPE_ABORT, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; BACNET_NPDU_DATA test_npdu_data = { 0 }; /* error handling before port is initialized */ test_length = dlmstp_send_pdu(NULL, NULL, 0, 0); test_length = MSTP_Get_Send(NULL, 0); zassert_equal(test_length, 0, NULL); test_length = MSTP_Get_Reply(NULL, 0); zassert_equal(test_length, 0, NULL); MSTP_Send_Frame(NULL, NULL, 0); test_length = dlmstp_receive(&test_address, NULL, 0, 0); zassert_equal(test_length, 0, NULL); test_mac_address = dlmstp_mac_address(); zassert_equal(test_mac_address, 0, NULL); test_frames = dlmstp_max_info_frames(); zassert_equal(test_frames, 0, NULL); test_mac_address = dlmstp_max_master(); zassert_equal(test_mac_address, 0, NULL); status = dlmstp_sole_master(); zassert_equal(status, false, NULL); status = dlmstp_slave_mode_enabled_set(true); zassert_equal(status, false, NULL); status = dlmstp_slave_mode_enabled(); zassert_equal(status, false, NULL); status = dlmstp_zero_config_enabled(); zassert_equal(status, false, NULL); test_mac_address = dlmstp_zero_config_preferred_station(); zassert_equal(test_mac_address, 0, NULL); dlmstp_zero_config_preferred_station_set(0); dlmstp_set_baud_rate(38400); test_baudrate = dlmstp_baud_rate(); zassert_equal(test_baudrate, 0, NULL); dlmstp_set_frame_rx_complete_callback(NULL); dlmstp_set_invalid_frame_rx_complete_callback(NULL); dlmstp_set_frame_rx_start_callback(NULL); dlmstp_fill_statistics(NULL); dlmstp_reset_statistics(); /* initialize */ MSTP_User.RS485_Driver = &MSTP_RS485_Driver; MSTP_Port.UserData = &MSTP_User; MSTP_Port.InputBuffer = RS485_Rx_Buffer; MSTP_Port.InputBufferSize = sizeof(RS485_Rx_Buffer); MSTP_Port.OutputBuffer = RS485_Tx_Buffer; MSTP_Port.OutputBufferSize = sizeof(RS485_Tx_Buffer); ztest_expect_value(MSTP_Init, mstp_port, &MSTP_Port); status = dlmstp_init((char *)&MSTP_Port); zassert_true(status, NULL); zassert_true(MSTP_User.Initialized, NULL); zassert_equal( Ringbuf_Size(&MSTP_User.PDU_Queue), DLMSTP_MAX_INFO_FRAMES, NULL); zassert_equal( Ringbuf_Data_Size(&MSTP_User.PDU_Queue), sizeof(struct dlmstp_packet), NULL); zassert_equal(dlmstp_send_pdu_queue_empty(), true, NULL); zassert_equal(dlmstp_send_pdu_queue_full(), false, NULL); ztest_returns_value(MSTP_RS485_Silence_Milliseconds, 0); zassert_equal(dlmstp_silence_milliseconds(&MSTP_Port), 0, NULL); dlmstp_silence_reset(&MSTP_Port); ztest_returns_value(MSTP_RS485_Silence_Milliseconds, 0); zassert_equal(dlmstp_silence_milliseconds(&MSTP_Port), 0, NULL); zassert_equal(dlmstp_max_master_limit(), DLMSTP_MAX_MASTER, NULL); zassert_equal(dlmstp_max_info_frames_limit(), DLMSTP_MAX_INFO_FRAMES, NULL); dlmstp_fill_statistics(NULL); dlmstp_fill_statistics(&test_stats); zassert_equal( test_stats.transmit_frame_counter, MSTP_User.Statistics.transmit_frame_counter, NULL); zassert_equal( test_stats.receive_valid_frame_counter, MSTP_User.Statistics.receive_valid_frame_counter, NULL); zassert_equal( test_stats.receive_valid_frame_not_for_us_counter, MSTP_User.Statistics.receive_valid_frame_not_for_us_counter, NULL); zassert_equal( test_stats.receive_invalid_frame_counter, MSTP_User.Statistics.receive_invalid_frame_counter, NULL); zassert_equal( test_stats.transmit_pdu_counter, MSTP_User.Statistics.transmit_pdu_counter, NULL); zassert_equal( test_stats.receive_pdu_counter, MSTP_User.Statistics.receive_pdu_counter, NULL); zassert_equal( test_stats.bad_crc_counter, MSTP_User.Statistics.bad_crc_counter, NULL); zassert_equal( test_stats.poll_for_master_counter, MSTP_User.Statistics.poll_for_master_counter, NULL); dlmstp_reset_statistics(); dlmstp_set_frame_rx_complete_callback(NULL); dlmstp_set_invalid_frame_rx_complete_callback(NULL); dlmstp_set_frame_rx_start_callback(NULL); dlmstp_get_broadcast_address(&test_address); zassert_equal(test_address.mac_len, 1, NULL); zassert_equal(test_address.mac[0], MSTP_BROADCAST_ADDRESS, NULL); zassert_equal(test_address.net, BACNET_BROADCAST_NETWORK, NULL); zassert_equal(test_address.len, 0, NULL); dlmstp_get_my_address(&test_address); zassert_equal(test_address.mac_len, 1, NULL); zassert_equal(test_address.mac[0], MSTP_Port.This_Station, NULL); zassert_equal(test_address.net, 0, NULL); zassert_equal(test_address.len, 0, NULL); test_mac_address = dlmstp_max_master(); zassert_equal(test_mac_address, MSTP_Port.Nmax_master, NULL); dlmstp_set_max_master(10); test_mac_address = dlmstp_max_master(); zassert_equal(test_mac_address, 10, NULL); test_frames = dlmstp_max_info_frames(); zassert_equal(test_frames, MSTP_Port.Nmax_info_frames, NULL); dlmstp_set_max_info_frames(10); test_frames = dlmstp_max_info_frames(); zassert_equal(test_frames, 10, NULL); test_mac_address = dlmstp_mac_address(); zassert_equal(test_mac_address, MSTP_Port.This_Station, NULL); dlmstp_set_mac_address(10); test_mac_address = dlmstp_mac_address(); zassert_equal(test_mac_address, 10, NULL); dlmstp_fill_bacnet_address(&test_address, 10); zassert_equal(test_address.mac_len, 1, NULL); zassert_equal(test_address.mac[0], 10, NULL); zassert_equal(test_address.net, 0, NULL); zassert_equal(test_address.len, 0, NULL); dlmstp_fill_bacnet_address(&test_address, MSTP_BROADCAST_ADDRESS); zassert_equal(test_address.mac_len, 0, NULL); zassert_equal(test_address.mac[0], 0, NULL); zassert_equal(test_address.net, 0, NULL); zassert_equal(test_address.len, 0, NULL); ztest_returns_value(MSTP_RS485_Baud_Rate, 38400); test_baudrate = dlmstp_baud_rate(); zassert_equal(test_baudrate, 38400, NULL); ztest_expect_value(MSTP_RS485_Baud_Rate_Set, baud, 19200); ztest_returns_value(MSTP_RS485_Baud_Rate_Set, true); dlmstp_set_baud_rate(19200); dlmstp_zero_config_preferred_station_set(65); test_mac_address = dlmstp_zero_config_preferred_station(); zassert_equal(test_mac_address, 65, NULL); dlmstp_zero_config_enabled_set(true); status = dlmstp_zero_config_enabled(); zassert_equal(status, true, NULL); status = dlmstp_slave_mode_enabled_set(true); zassert_equal(status, true, NULL); status = dlmstp_slave_mode_enabled(); zassert_equal(status, true, NULL); status = dlmstp_sole_master(); zassert_equal(status, MSTP_Port.SoleMaster, NULL); /* various test cases */ ztest_returns_value(MSTP_RS485_Transmitting, true); test_length = dlmstp_receive(&test_address, NULL, 0, 0); zassert_equal(test_length, 0, NULL); /* fixme: dlmstp_receive() calls driver with local var pointer and zmock does not seem to have a way to test that. */ test_length = MSTP_Put_Receive(&MSTP_Port); zassert_equal(test_length, MSTP_Port.DataLength, NULL); zassert_equal(MSTP_User.ReceivePacketPending, true, NULL); ztest_expect_data(MSTP_RS485_Send, payload, test_data); MSTP_Send_Frame(&MSTP_Port, test_data, sizeof(test_data)); zassert_equal(MSTP_User.Statistics.transmit_frame_counter, 1, NULL); test_length = MSTP_Get_Reply(&MSTP_Port, 0); zassert_equal(test_length, 0, NULL); test_npdu_data.data_expecting_reply = false; test_length = dlmstp_send_pdu( &test_address, &test_npdu_data, test_data, sizeof(test_data)); zassert_equal( test_length, sizeof(test_data), "dlmstp_send_pdu() length=%d", test_length); ztest_expect_value(MSTP_Create_Frame, buffer, &MSTP_Port.OutputBuffer[0]); ztest_expect_value( MSTP_Create_Frame, buffer_len, MSTP_Port.OutputBufferSize); ztest_expect_value( MSTP_Create_Frame, frame_type, FRAME_TYPE_BACNET_DATA_NOT_EXPECTING_REPLY); ztest_expect_value(MSTP_Create_Frame, destination, MSTP_BROADCAST_ADDRESS); ztest_expect_value(MSTP_Create_Frame, source, MSTP_Port.This_Station); ztest_expect_data(MSTP_Create_Frame, data, test_data); ztest_returns_value( MSTP_Create_Frame, sizeof(test_data) + DLMSTP_HEADER_MAX); test_length = MSTP_Get_Send(&MSTP_Port, 0); zassert_equal( test_length, sizeof(test_data) + DLMSTP_HEADER_MAX, "MSTP_Get_Send() length=%d", test_length); } /** * @} */ #if defined(CONFIG_ZTEST_NEW_API) ZTEST_SUITE(dlmstp_tests, NULL, NULL, NULL, NULL, NULL); #else void test_main(void) { ztest_test_suite(dlmstp_tests, ztest_unit_test(test_MSTP_Datalink)); ztest_run_test_suite(dlmstp_tests); } #endif