feature modbus tcp master slave v2

This commit is contained in:
Alex Lisitsyn committed 2024-09-02 03:12:36 +08:00
1 parent d4345f8cd7
commit 2e2be467f6
109 files changed
+4454 -2319

No files matched your search

+4 -2
View File
@@ -1,5 +1,6 @@
set(srcs "test_app_main.c"
"test_modbus_adapter_comm.c"
"test_modbus_adapter_serial.c"
"test_modbus_adapter_tcp.c"
)
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
@@ -7,4 +8,5 @@ idf_component_register(SRCS ${srcs}
PRIV_REQUIRES cmock test_common unity test_utils
) #
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u mb_test_include_impl")
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u mb_test_include_adapter_impl_serial")
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u mb_test_include_adapter_impl_tcp")
@@ -1,6 +1,6 @@
dependencies:
idf: ">=4.3"
espressif/esp-modbus:
version: "^2.0"
version: "^2.0.0-beta"
override_path: "../../../"
+8 -1
View File
@@ -8,9 +8,16 @@
#include "unity_test_runner.h"
#include "unity_fixture.h"
#include "sdkconfig.h"
static void run_all_tests(void)
{
RUN_TEST_GROUP(modbus_adapter_comm_basic);
#if (CONFIG_FMB_COMM_MODE_RTU_EN || CONFIG_FMB_COMM_MODE_ASCII_EN)
RUN_TEST_GROUP(modbus_adapter_serial);
#endif
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
RUN_TEST_GROUP(modbus_adapter_tcp);
#endif
}
void app_main(void)
@@ -1,249 +0,0 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity_fixture.h"
#include "test_utils.h"
#if __has_include("unity_test_utils.h")
#define UNITY_TEST_UTILS_INCLUDED
// unity test utils are used
#include "unity_test_utils.h"
#include "unity_test_utils_memory.h"
#else
// Unit_test_app utils from test_utils ("test_utils.h"), v4.4
#define unity_utils_task_delete test_utils_task_delete
#endif
#include "sdkconfig.h"
#include "test_common.h"
#define TEST_SER_PORT_NUM 1
#define TEST_TCP_PORT_NUM 1502
#define TEST_TASKS_NUM 3
#define TEST_TASK_TIMEOUT_MS 30000
#define TEST_LEAK_WARN 32
#define TEST_LEAK_CRITICAL 64
#define TEST_SLAVE_SEND_TOUT_US 30000
#define TEST_MASTER_SEND_TOUT_US 30000
#define TEST_MASTER_RESPOND_TOUT_MS CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND
#define TAG "MODBUS_SERIAL_TEST"
// The workaround to statically link whole test library
__attribute__((unused)) bool mb_test_include_impl = 1;
// Example Data (Object) Dictionary for Modbus parameters
static const mb_parameter_descriptor_t descriptors[] = {
{CID_DEV_REG0, STR("MB_hold_reg-0"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG1, STR("MB_hold_reg-1"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 1, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG2, STR("MB_hold_reg-2"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG3, STR("MB_hold_reg-3"), STR("Data"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 3, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG_COUNT, STR("CYCLE_COUNTER"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER}
};
// Calculate number of parameters in the table
const uint16_t num_descriptors = (sizeof(descriptors) / sizeof(descriptors[0]));
TaskHandle_t task_handles[TEST_TASKS_NUM] = {};
TEST_GROUP(modbus_adapter_comm_basic);
TEST_SETUP(modbus_adapter_comm_basic)
{
test_common_start();
}
TEST_TEAR_DOWN(modbus_adapter_comm_basic)
{
uint32_t test_task = 0;
uint32_t test_task_count = 0;
int i = 0;
// Trigger start of test task intentionally
for (i = 0; i < TEST_TASKS_NUM; i++) {
test_common_task_notify_start(task_handles[i], 1);
}
for (i = 0; (i < TEST_TASKS_NUM); i++) {
test_task = test_common_wait_done(pdMS_TO_TICKS(TEST_TASK_TIMEOUT_MS));
if (test_task) {
unity_utils_task_delete((TaskHandle_t)test_task);
ESP_LOGI(TAG, "Task %" PRIx32 " is complited.", test_task);
test_task_count++;
}
}
vTaskDelay(5); // Let the test tasks with lower priority to suspend or delete itself from test_common
TEST_ASSERT_EQUAL(TEST_TASKS_NUM, test_task_count);
ESP_LOGI(TAG, "Test done successfully.");
test_common_stop();
}
#if (CONFIG_FMB_COMM_MODE_RTU_EN || CONFIG_FMB_COMM_MODE_ASCII_EN)
TEST(modbus_adapter_comm_basic, test_modbus_adapter_rtu)
{
mb_communication_info_t slave_config1 = {
.ser_opts.port = TEST_SER_PORT_NUM,
.ser_opts.mode = MB_RTU,
.ser_opts.uid = MB_DEVICE_ADDR1,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
task_handles[0] = test_slave_serial_create(&slave_config1);
mb_communication_info_t slave_config2 = {
.ser_opts.port = TEST_SER_PORT_NUM,
.ser_opts.mode = MB_RTU,
.ser_opts.uid = MB_DEVICE_ADDR2,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
task_handles[1] = test_slave_serial_create(&slave_config2);
// Initialize and start Modbus controller
mb_communication_info_t master_config = {
.ser_opts.port = TEST_SER_PORT_NUM,
.ser_opts.mode = MB_RTU,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.ser_opts.test_tout_us = TEST_MASTER_SEND_TOUT_US
};
task_handles[2] = test_master_serial_create(&master_config, &descriptors[0], num_descriptors);
}
TEST(modbus_adapter_comm_basic, test_modbus_adapter_ascii)
{
mb_communication_info_t slave_config1 = {
.ser_opts.port = TEST_SER_PORT_NUM,
.ser_opts.mode = MB_ASCII,
.ser_opts.uid = MB_DEVICE_ADDR1,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
task_handles[0] = test_slave_serial_create(&slave_config1);
mb_communication_info_t slave_config2 = {
.ser_opts.port = TEST_SER_PORT_NUM,
.ser_opts.mode = MB_ASCII,
.ser_opts.uid = MB_DEVICE_ADDR2,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
task_handles[1] = test_slave_serial_create(&slave_config2);
mb_communication_info_t master_config = {
.ser_opts.port = TEST_SER_PORT_NUM,
.ser_opts.mode = MB_ASCII,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.ser_opts.test_tout_us = TEST_MASTER_SEND_TOUT_US
};
task_handles[2] = test_master_serial_create(&master_config, &descriptors[0], num_descriptors);
}
#endif
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
const char *slave_tcp_addr_table[] = {
"01;mb_slave_tcp_01;1502", // Corresponds to characteristic MB_DEVICE_ADDR1 "mb_slave_tcp_01"
"200;mb_slave_tcp_c8;1502", // Corresponds to characteristic MB_DEVICE_ADDR2 "mb_slave_tcp_C8"
NULL // End of table condition (must be included)
};
TEST(modbus_adapter_comm_basic, test_modbus_adapter_tcp)
{
mb_communication_info_t tcp_slave_cfg_1 = {
.tcp_opts.port = TEST_TCP_PORT_NUM,
.tcp_opts.mode = MB_TCP,
.tcp_opts.addr_type = MB_IPV4,
.tcp_opts.ip_addr_table = NULL,
.tcp_opts.uid = MB_DEVICE_ADDR1,
.tcp_opts.start_disconnected = true,
.tcp_opts.response_tout_ms = 1,
.tcp_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
task_handles[0] = test_slave_tcp_create(&tcp_slave_cfg_1);
mb_communication_info_t tcp_slave_cfg_2 = {
.tcp_opts.port = TEST_TCP_PORT_NUM,
.tcp_opts.mode = MB_TCP,
.tcp_opts.addr_type = MB_IPV4,
.tcp_opts.ip_addr_table = NULL,
.tcp_opts.uid = MB_DEVICE_ADDR2,
.tcp_opts.start_disconnected = true,
.tcp_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.tcp_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
task_handles[1] = test_slave_tcp_create(&tcp_slave_cfg_2);
// Initialize and start Modbus controller
mb_communication_info_t tcp_master_cfg_1 = {
.tcp_opts.port = TEST_TCP_PORT_NUM,
.tcp_opts.mode = MB_TCP,
.tcp_opts.addr_type = MB_IPV4,
.tcp_opts.ip_addr_table = (void *)slave_tcp_addr_table,
.tcp_opts.uid = 0,
.tcp_opts.start_disconnected = false,
.tcp_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.tcp_opts.test_tout_us = TEST_MASTER_SEND_TOUT_US
};
task_handles[2] = test_master_tcp_create(&tcp_master_cfg_1, &descriptors[0], num_descriptors);
}
#endif
TEST_GROUP_RUNNER(modbus_adapter_comm_basic)
{
#if (CONFIG_FMB_COMM_MODE_RTU_EN && CONFIG_FMB_COMM_MODE_ASCII_EN)
RUN_TEST_CASE(modbus_adapter_comm_basic, test_modbus_adapter_rtu);
RUN_TEST_CASE(modbus_adapter_comm_basic, test_modbus_adapter_ascii);
#endif
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
RUN_TEST_CASE(modbus_adapter_comm_basic, test_modbus_adapter_tcp);
#endif
}
@@ -0,0 +1,256 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity_fixture.h"
#include "test_utils.h"
#if __has_include("unity_test_utils.h")
#define UNITY_TEST_UTILS_INCLUDED
// unity test utils are used
#include "unity_test_utils.h"
#include "unity_test_utils_memory.h"
#else
// Unit_test_app utils from test_utils ("test_utils.h"), v4.4
#define unity_utils_task_delete test_utils_task_delete
#endif
#include "sdkconfig.h"
#include "test_common.h"
#define TEST_SER_PORT_NUM1 (1)
#define TEST_SER_PORT_NUM2 (2)
#define TEST_TASK_TIMEOUT_MS (120000)
#define TEST_LEAK_WARN (32)
#define TEST_LEAK_CRITICAL (64)
#define TEST_SLAVE_SEND_TOUT_US (5000)
#define TEST_MASTER_SEND_TOUT_US (5000)
#define TEST_MASTER_RESPOND_TOUT_MS (CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
#define TAG "MODBUS_SERIAL_TEST"
// The workaround to statically link whole test library
__attribute__((unused)) bool mb_test_include_adapter_impl_serial = true;
#if (CONFIG_FMB_COMM_MODE_RTU_EN || CONFIG_FMB_COMM_MODE_ASCII_EN)
// Example Data (Object) Dictionary for Modbus parameters
static const mb_parameter_descriptor_t descriptors[] = {
{CID_DEV_REG0, STR("MB_hold_reg-0"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG1, STR("MB_hold_reg-1"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 1, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG2, STR("MB_hold_reg-2"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG3, STR("MB_hold_reg-3"), STR("Data"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 3, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG_COUNT, STR("CYCLE_COUNTER"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER}
};
// Calculate number of parameters in the table
const uint16_t num_descriptors = (sizeof(descriptors) / sizeof(descriptors[0]));
TEST_GROUP(modbus_adapter_serial);
TEST_SETUP(modbus_adapter_serial)
{
test_common_start();
}
TEST_TEAR_DOWN(modbus_adapter_serial)
{
int task_count = test_common_task_start_all(1);
TEST_ASSERT_TRUE(task_count > 0);
TEST_ASSERT_EQUAL(task_count, test_common_task_wait_done_delete_all(TEST_TASK_TIMEOUT_MS));
test_common_stop();
ESP_LOGI(TAG, "%s, done successfully.", __func__);
}
TEST(modbus_adapter_serial, test_modbus_adapter_rtu)
{
mb_communication_info_t slave_config1 = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_RTU,
.ser_opts.uid = MB_DEVICE_ADDR1,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config1, 0));
mb_communication_info_t slave_config2 = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_RTU,
.ser_opts.uid = MB_DEVICE_ADDR2,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config2, 0));
// Initialize and start Modbus controller
mb_communication_info_t master_config = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_RTU,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.ser_opts.test_tout_us = TEST_MASTER_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_master_serial_create(&master_config, 0, &descriptors[0], num_descriptors));
}
TEST(modbus_adapter_serial, test_modbus_adapter_ascii)
{
mb_communication_info_t slave_config1 = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_ASCII,
.ser_opts.uid = MB_DEVICE_ADDR1,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config1, 0));
mb_communication_info_t slave_config2 = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_ASCII,
.ser_opts.uid = MB_DEVICE_ADDR2,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config2, 0));
mb_communication_info_t master_config = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_ASCII,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.ser_opts.test_tout_us = TEST_MASTER_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_master_serial_create(&master_config, 0, &descriptors[0], num_descriptors));
}
TEST(modbus_adapter_serial, test_modbus_adapter_rtu_two_ports)
{
mb_communication_info_t slave_config1 = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_ASCII,
.ser_opts.uid = MB_DEVICE_ADDR1,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config1, 0));
mb_communication_info_t slave_config2 = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_ASCII,
.ser_opts.uid = MB_DEVICE_ADDR2,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config2, 0));
mb_communication_info_t slave_config3 = {
.ser_opts.port = TEST_SER_PORT_NUM2,
.ser_opts.mode = MB_RTU,
.ser_opts.uid = MB_DEVICE_ADDR1,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config3, 0));
mb_communication_info_t slave_config4 = {
.ser_opts.port = TEST_SER_PORT_NUM2,
.ser_opts.mode = MB_RTU,
.ser_opts.uid = MB_DEVICE_ADDR2,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = 1,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_serial_create(&slave_config4, 0));
mb_communication_info_t master_config1 = {
.ser_opts.port = TEST_SER_PORT_NUM1,
.ser_opts.mode = MB_ASCII,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_master_serial_create(&master_config1, 0, &descriptors[0], num_descriptors));
mb_communication_info_t master_config2 = {
.ser_opts.port = TEST_SER_PORT_NUM2,
.ser_opts.mode = MB_RTU,
.ser_opts.data_bits = UART_DATA_8_BITS,
.ser_opts.stop_bits = UART_STOP_BITS_2,
.ser_opts.baudrate = 115200,
.ser_opts.parity = UART_PARITY_DISABLE,
.ser_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.ser_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_master_serial_create(&master_config2, 0, &descriptors[0], num_descriptors));
}
TEST_GROUP_RUNNER(modbus_adapter_serial)
{
RUN_TEST_CASE(modbus_adapter_serial, test_modbus_adapter_rtu);
RUN_TEST_CASE(modbus_adapter_serial, test_modbus_adapter_ascii);
RUN_TEST_CASE(modbus_adapter_serial, test_modbus_adapter_rtu_two_ports);
}
#endif
@@ -0,0 +1,128 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity_fixture.h"
#include "test_utils.h"
#if __has_include("unity_test_utils.h")
#define UNITY_TEST_UTILS_INCLUDED
// unity test utils are used
#include "unity_test_utils.h"
#include "unity_test_utils_memory.h"
#else
// Unit_test_app utils from test_utils ("test_utils.h"), v4.4
#define unity_utils_task_delete test_utils_task_delete
#endif
#include "sdkconfig.h"
#include "test_common.h"
#define TEST_TCP_PORT_NUM (1502)
#define TEST_TASK_TIMEOUT_MS (120000)
#define TEST_LEAK_WARN (32)
#define TEST_LEAK_CRITICAL (64)
#define TEST_SLAVE_SEND_TOUT_US (50)
#define TEST_MASTER_SEND_TOUT_US (50)
#define TEST_MASTER_RESPOND_TOUT_MS (CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
#define TAG "MODBUS_TCP_TEST"
// The workaround to statically link whole test library
__attribute__((unused)) bool mb_test_include_adapter_impl_tcp = true;
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
// Example Data (Object) Dictionary for Modbus parameters
static const mb_parameter_descriptor_t descriptors[] = {
{CID_DEV_REG0, STR("MB_hold_reg-0"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG1, STR("MB_hold_reg-1"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 1, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG2, STR("MB_hold_reg-2"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG3, STR("MB_hold_reg-3"), STR("Data"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 3, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER},
{CID_DEV_REG_COUNT, STR("CYCLE_COUNTER"), STR("Data"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 1,
0, PARAM_TYPE_U16, 2, OPTS(0, 0, 0), PAR_PERMS_READ_WRITE_TRIGGER}
};
// Calculate number of parameters in the table
const uint16_t num_descriptors = (sizeof(descriptors) / sizeof(descriptors[0]));
TEST_GROUP(modbus_adapter_tcp);
TEST_SETUP(modbus_adapter_tcp)
{
test_common_start();
}
TEST_TEAR_DOWN(modbus_adapter_tcp)
{
int task_count = test_common_task_start_all(1);
TEST_ASSERT_TRUE(task_count > 0);
TEST_ASSERT_EQUAL(task_count, test_common_task_wait_done_delete_all(TEST_TASK_TIMEOUT_MS));
test_common_stop();
ESP_LOGI(TAG, "%s, done successfully.", __func__);
}
const char *slave_tcp_addr_table[] = {
"01;mb_slave_tcp_01;1502", // Corresponds to characteristic MB_DEVICE_ADDR1 "mb_slave_tcp_01"
"200;mb_slave_tcp_c8;1502", // Corresponds to characteristic MB_DEVICE_ADDR2 "mb_slave_tcp_C8"
NULL // End of table condition (must be included)
};
TEST(modbus_adapter_tcp, test_modbus_adapter_tcp)
{
mb_communication_info_t tcp_slave_cfg_1 = {
.tcp_opts.port = TEST_TCP_PORT_NUM,
.tcp_opts.mode = MB_TCP,
.tcp_opts.addr_type = MB_IPV4,
.tcp_opts.ip_addr_table = NULL,
.tcp_opts.uid = MB_DEVICE_ADDR1,
.tcp_opts.start_disconnected = true,
.tcp_opts.response_tout_ms = 1,
.tcp_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_tcp_create(&tcp_slave_cfg_1, 0));
mb_communication_info_t tcp_slave_cfg_2 = {
.tcp_opts.port = TEST_TCP_PORT_NUM,
.tcp_opts.mode = MB_TCP,
.tcp_opts.addr_type = MB_IPV4,
.tcp_opts.ip_addr_table = NULL,
.tcp_opts.uid = MB_DEVICE_ADDR2,
.tcp_opts.start_disconnected = true,
.tcp_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.tcp_opts.test_tout_us = TEST_SLAVE_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_slave_tcp_create(&tcp_slave_cfg_2, 0));
// Initialize and start Modbus controller
mb_communication_info_t tcp_master_cfg_1 = {
.tcp_opts.port = TEST_TCP_PORT_NUM,
.tcp_opts.mode = MB_TCP,
.tcp_opts.addr_type = MB_IPV4,
.tcp_opts.ip_addr_table = (void *)slave_tcp_addr_table,
.tcp_opts.uid = 0,
.tcp_opts.start_disconnected = false,
.tcp_opts.response_tout_ms = TEST_MASTER_RESPOND_TOUT_MS,
.tcp_opts.test_tout_us = TEST_MASTER_SEND_TOUT_US
};
TEST_ASSERT_NOT_NULL(test_common_master_tcp_create(&tcp_master_cfg_1, 0, &descriptors[0], num_descriptors));
}
TEST_GROUP_RUNNER(modbus_adapter_tcp)
{
RUN_TEST_CASE(modbus_adapter_tcp, test_modbus_adapter_tcp);
}
#endif
@@ -6,12 +6,12 @@ from pytest_embedded import Dut
CONFIGS = [
pytest.param('serial', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.esp32s3, pytest.mark.esp32c3]),
pytest.param('tcp', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.esp32s3, pytest.mark.esp32c3]),
pytest.param('serial', marks=[pytest.mark.esp32, pytest.mark.esp32p4]),
pytest.param('tcp', marks=[pytest.mark.esp32, pytest.mark.esp32p4]),
]
@pytest.mark.generic_multi_device
@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='no multi-dev runner')
@pytest.mark.multi_dut_modbus_generic
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
def test_modbus_comm_adapter(dut: Dut) -> None:
dut.expect_unity_test_output()
+1 -1
View File
@@ -10,7 +10,7 @@ CONFIG_FMB_PORT_TASK_PRIO=10
CONFIG_FMB_COMM_MODE_RTU_EN=y
CONFIG_FMB_COMM_MODE_ASCII_EN=y
CONFIG_FMB_COMM_MODE_TCP_EN=n
CONFIG_FMB_TCP_UID_ENABLED=y
CONFIG_FMB_TCP_UID_ENABLED=n
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=2000
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y