forked from espressif/esp-modbus
feature modbus tcp master slave v2
This commit is contained in:
@@ -1,14 +1,16 @@
|
||||
physical_tests:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: only manual test is performed for other targets
|
||||
disable:
|
||||
- if: CONFIG_NAME != "serial" or IDF_TARGET != "esp32"
|
||||
# disable_test:
|
||||
# - if: IDF_TARGET != "esp32"
|
||||
# reason: only manual test is performed for other targets
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- if: CONFIG_NAME == "wifi" and SOC_WIFI_SUPPORTED != 1 and IDF_TARGET != "esp32"
|
||||
|
||||
unit_tests:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: only manual test is performed for other targets
|
||||
|
||||
adapter_tests:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: only manual test is performed for other targets
|
||||
@@ -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,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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_modbus_rs485_comm_master_slave.c"
|
||||
"test_modbus_tcp_comm_master_slave.c"
|
||||
)
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
idf_component_register(SRCS ${srcs}
|
||||
PRIV_REQUIRES cmock test_utils test_common unity
|
||||
PRIV_REQUIRES cmock test_utils test_common unity nvs_flash esp_event esp_eth
|
||||
)
|
||||
|
||||
# The workaround for WHOLE_ARCHIVE is absent in v4.4
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u mb_test_include_impl")
|
||||
# The workaround for WHOLE_ARCHIVE which is absent in v4.4
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u mb_test_include_phys_impl_tcp")
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u mb_test_include_phys_impl_serial")
|
||||
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
dependencies:
|
||||
idf: ">=4.3"
|
||||
espressif/esp-modbus:
|
||||
version: "^2.0"
|
||||
version: "^2.0.0-beta"
|
||||
override_path: "../../../"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
||||
rules:
|
||||
- if: "idf_version >=5.0"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
|
||||
|
||||
@@ -7,16 +7,6 @@
|
||||
#include "unity.h"
|
||||
#include "test_common.h"
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
test_common_start();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
test_common_stop();
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
printf("Modbus RS485 multi-device test cases/n");
|
||||
|
||||
@@ -17,28 +17,27 @@
|
||||
#define unity_utils_task_delete test_utils_task_delete
|
||||
#endif
|
||||
|
||||
#define TEST_SER_PORT_NUM (1)
|
||||
#define TEST_TASK_TIMEOUT_MS (30000)
|
||||
#define TEST_SEND_TOUT_US (30000)
|
||||
#define TEST_RESP_TOUT_MS (1000)
|
||||
#define TEST_SER_PORT_NUM (1)
|
||||
#define TEST_TASK_TIMEOUT_MS (160000)
|
||||
#define TEST_SEND_TOUT_US (30000)
|
||||
#define TEST_RESP_TOUT_MS (1000)
|
||||
#define TEST_BAUD_RATE (115200)
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define TEST_SER_PIN_RX (22)
|
||||
#define TEST_SER_PIN_TX (23)
|
||||
#define TEST_SER_PIN_RX (22)
|
||||
#define TEST_SER_PIN_TX (23)
|
||||
// RTS for RS485 Half-Duplex Mode manages DE/~RE
|
||||
#define TEST_SER_PIN_RTS (18)
|
||||
#define TEST_BAUD_RATE (115200)
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#define TEST_SER_PIN_RX (4)
|
||||
#define TEST_SER_PIN_TX (5)
|
||||
#define TEST_SER_PIN_RTS (10)
|
||||
#define TEST_BAUD_RATE (115200)
|
||||
#define TEST_SER_PIN_RTS (18)
|
||||
#else
|
||||
#define TEST_SER_PIN_RX (4)
|
||||
#define TEST_SER_PIN_TX (5)
|
||||
#define TEST_SER_PIN_RTS (10)
|
||||
#endif
|
||||
|
||||
#define TEST_MASTER_RESPOND_TOUT_MS CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND
|
||||
#define TEST_MASTER_RESPOND_TOUT_MS (CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
|
||||
|
||||
// The workaround to statically link the whole test library
|
||||
__attribute__((unused)) bool mb_test_include_impl = 1;
|
||||
__attribute__((unused)) bool mb_test_include_phys_impl_serial = true;
|
||||
|
||||
#define TAG "MODBUS_SERIAL_COMM_TEST"
|
||||
|
||||
@@ -61,32 +60,6 @@ static const mb_parameter_descriptor_t descriptors[] = {
|
||||
// The number of parameters in the table
|
||||
const uint16_t num_descriptors = (sizeof(descriptors) / sizeof(descriptors[0]));
|
||||
|
||||
static void test_task_start_wait_done(TaskHandle_t task_handle)
|
||||
{
|
||||
uint32_t test_task = 0;
|
||||
|
||||
// Start test sequence intentionally in the task
|
||||
test_common_task_notify_start(task_handle, 1);
|
||||
|
||||
for (int i = 0; (i < 2); i++) {
|
||||
test_task = test_common_wait_done(pdMS_TO_TICKS(TEST_TASK_TIMEOUT_MS));
|
||||
if (test_task == (uint32_t)task_handle) {
|
||||
unity_utils_task_delete((TaskHandle_t)test_task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(5); // A small delay to let the test lower priority task delete itself
|
||||
if (test_task != (uint32_t)task_handle) {
|
||||
ESP_LOGI(TAG, "Could not complete task 0x%" PRIx32" after %d ms, force kill the task.",
|
||||
(uint32_t)task_handle, TEST_TASK_TIMEOUT_MS);
|
||||
unity_utils_task_delete((TaskHandle_t)task_handle);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL(test_task, (uint32_t)task_handle);
|
||||
ESP_LOGI(TAG, "Test task 0x%" PRIx32 ", done successfully.", (uint32_t)task_handle);
|
||||
}
|
||||
|
||||
static void test_modbus_rs485_rtu_slave(void)
|
||||
{
|
||||
mb_communication_info_t slave_config1 = {
|
||||
@@ -104,7 +77,7 @@ static void test_modbus_rs485_rtu_slave(void)
|
||||
TEST_ESP_OK(uart_set_pin(slave_config1.ser_opts.port, TEST_SER_PIN_TX,
|
||||
TEST_SER_PIN_RX, TEST_SER_PIN_RTS, UART_PIN_NO_CHANGE));
|
||||
|
||||
TaskHandle_t slave_task_handle = test_slave_serial_create(&slave_config1);
|
||||
TaskHandle_t slave_task_handle = test_common_slave_serial_create(&slave_config1, 0);
|
||||
|
||||
// Set driver mode to Half Duplex
|
||||
TEST_ESP_OK(uart_set_mode(slave_config1.ser_opts.port, UART_MODE_RS485_HALF_DUPLEX));
|
||||
@@ -114,8 +87,8 @@ static void test_modbus_rs485_rtu_slave(void)
|
||||
unity_send_signal("Slave_ready");
|
||||
unity_wait_for_signal("Master_started");
|
||||
|
||||
test_task_start_wait_done(slave_task_handle);
|
||||
|
||||
test_common_task_start(slave_task_handle, 1);
|
||||
TEST_ASSERT_TRUE(test_common_task_wait_done(slave_task_handle, pdMS_TO_TICKS(TEST_TASK_TIMEOUT_MS)));
|
||||
}
|
||||
|
||||
static void test_modbus_rs485_rtu_master(void)
|
||||
@@ -136,14 +109,15 @@ static void test_modbus_rs485_rtu_master(void)
|
||||
.ser_opts.test_tout_us = TEST_SEND_TOUT_US
|
||||
};
|
||||
|
||||
TaskHandle_t master_task_handle = test_master_serial_create(&master_config, &descriptors[0], num_descriptors);
|
||||
TaskHandle_t master_task_handle = test_common_master_serial_create(&master_config, 0, &descriptors[0], num_descriptors);
|
||||
|
||||
// Set driver mode to Half Duplex
|
||||
TEST_ESP_OK(uart_set_mode(master_config.ser_opts.port, UART_MODE_RS485_HALF_DUPLEX));
|
||||
TEST_ESP_OK(uart_set_pin(master_config.ser_opts.port, TEST_SER_PIN_TX,
|
||||
TEST_SER_PIN_RX, TEST_SER_PIN_RTS, UART_PIN_NO_CHANGE));
|
||||
|
||||
test_task_start_wait_done(master_task_handle);
|
||||
test_common_task_start(master_task_handle, 1);
|
||||
TEST_ASSERT_TRUE(test_common_task_wait_done(master_task_handle, pdMS_TO_TICKS(TEST_TASK_TIMEOUT_MS)));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -168,7 +142,7 @@ static void test_modbus_rs485_ascii_slave(void)
|
||||
TEST_ESP_OK(uart_set_pin(slave_config1.ser_opts.port, TEST_SER_PIN_TX,
|
||||
TEST_SER_PIN_RX, TEST_SER_PIN_RTS, UART_PIN_NO_CHANGE));
|
||||
|
||||
TaskHandle_t slave_task_handle = test_slave_serial_create(&slave_config1);
|
||||
TaskHandle_t slave_task_handle = test_common_slave_serial_create(&slave_config1, 0);
|
||||
|
||||
// Set driver mode to Half Duplex
|
||||
TEST_ESP_OK(uart_set_mode(slave_config1.ser_opts.port, UART_MODE_RS485_HALF_DUPLEX));
|
||||
@@ -178,9 +152,9 @@ static void test_modbus_rs485_ascii_slave(void)
|
||||
unity_send_signal("Slave_ready");
|
||||
unity_wait_for_signal("Master_started");
|
||||
|
||||
test_task_start_wait_done(slave_task_handle);
|
||||
|
||||
}
|
||||
test_common_task_start(slave_task_handle, 1);
|
||||
TEST_ASSERT_TRUE(test_common_task_wait_done(slave_task_handle, pdMS_TO_TICKS(TEST_TASK_TIMEOUT_MS)));
|
||||
};
|
||||
|
||||
static void test_modbus_rs485_ascii_master(void)
|
||||
{
|
||||
@@ -199,16 +173,16 @@ static void test_modbus_rs485_ascii_master(void)
|
||||
.ser_opts.test_tout_us = TEST_SEND_TOUT_US
|
||||
};
|
||||
|
||||
TaskHandle_t master_task_handle = test_master_serial_create(&master_config, &descriptors[0], num_descriptors);
|
||||
TaskHandle_t master_task_handle = test_common_master_serial_create(&master_config, 0, &descriptors[0], num_descriptors);
|
||||
|
||||
// Set driver mode to Half Duplex
|
||||
TEST_ESP_OK(uart_set_mode(master_config.ser_opts.port, UART_MODE_RS485_HALF_DUPLEX));
|
||||
TEST_ESP_OK(uart_set_pin(master_config.ser_opts.port, TEST_SER_PIN_TX,
|
||||
TEST_SER_PIN_RX, TEST_SER_PIN_RTS, UART_PIN_NO_CHANGE));
|
||||
|
||||
unity_send_signal("Master_started");
|
||||
|
||||
test_task_start_wait_done(master_task_handle);
|
||||
test_common_task_start(master_task_handle, 1);
|
||||
TEST_ASSERT_TRUE(test_common_task_wait_done(master_task_handle, pdMS_TO_TICKS(TEST_TASK_TIMEOUT_MS)));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "test_common.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#if MB_MDNS_IS_INCLUDED
|
||||
#include "mdns.h"
|
||||
#endif
|
||||
|
||||
#include "protocol_examples_common.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
#if __has_include("unity_test_utils.h")
|
||||
// unity test utils are used
|
||||
#include "unity_test_utils.h"
|
||||
#else
|
||||
// Unit_test_app utils from test_utils ("test_utils.h"), v4.4
|
||||
#define unity_utils_task_delete test_utils_task_delete
|
||||
#endif
|
||||
|
||||
#define TEST_TCP_PORT_NUM1 (1502)
|
||||
#define TEST_TCP_PORT_NUM2 (502)
|
||||
#define TEST_TCP_TASK_TIMEOUT_MS (160000)
|
||||
#define TEST_TCP_SLAVE_SEND_TOUT_US (500)
|
||||
#define TEST_TCP_MASTER_SEND_TOUT_US (500)
|
||||
|
||||
#define TEST_MASTER_RESPOND_TOUT_MS (CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)
|
||||
|
||||
// The workaround to statically link the whole test library
|
||||
__attribute__((unused)) bool mb_test_include_phys_impl_tcp = true;
|
||||
|
||||
#define TAG "MODBUS_TCP_COMM_TEST"
|
||||
|
||||
#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_ADDR2, 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_ADDR1, 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}
|
||||
};
|
||||
|
||||
// The number of parameters in the table
|
||||
const uint16_t num_descriptors = (sizeof(descriptors) / sizeof(descriptors[0]));
|
||||
|
||||
const char *slave_tcp_addr_table[] = {
|
||||
"01;mb_slave_tcp_01;1502", // Corresponds to characteristic MB_DEVICE_ADDR1
|
||||
"200;mb_slave_tcp_c8;502", // Corresponds to characteristic MB_DEVICE_ADDR2
|
||||
NULL // End of table condition (must be included)
|
||||
};
|
||||
|
||||
static esp_err_t test_tcp_services_init(void **pnetif)
|
||||
{
|
||||
esp_err_t result = nvs_flash_init();
|
||||
if ((result == ESP_ERR_NVS_NO_FREE_PAGES) || (result == ESP_ERR_NVS_NEW_VERSION_FOUND)) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
result = nvs_flash_init();
|
||||
}
|
||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"nvs_flash_init fail, returns(0x%x).",
|
||||
(int)result);
|
||||
result = esp_netif_init();
|
||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_netif_init fail, returns(0x%x).",
|
||||
(int)result);
|
||||
result = esp_event_loop_create_default();
|
||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_event_loop_create_default fail, returns(0x%x).",
|
||||
(int)result);
|
||||
#if MB_MDNS_IS_INCLUDED
|
||||
// Start mdns service and register device
|
||||
if (mdns_init() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "initialization of mdns fail.");
|
||||
};
|
||||
#endif
|
||||
// This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
|
||||
// Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||
// examples/protocols/README.md for more information about this function.
|
||||
result = example_connect();
|
||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"example_connect fail, returns(0x%x).",
|
||||
(int)result);
|
||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||
// result = esp_wifi_set_ps(WIFI_PS_NONE);
|
||||
// ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
// TAG,
|
||||
// "esp_wifi_set_ps fail, returns(0x%x).",
|
||||
// (int)result);
|
||||
#endif
|
||||
if (pnetif) {
|
||||
*pnetif = get_example_netif();
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t test_tcp_services_destroy(void)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
err = example_disconnect();
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"example_disconnect fail, returns(0x%x).",
|
||||
(int)err);
|
||||
err = esp_event_loop_delete_default();
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_event_loop_delete_default fail, returns(0x%x).",
|
||||
(int)err);
|
||||
err = esp_netif_deinit();
|
||||
ESP_RETURN_ON_FALSE(((err == ESP_OK) || (err == ESP_ERR_NOT_SUPPORTED)),
|
||||
ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"esp_netif_deinit fail, returns(0x%x).",
|
||||
(int)err);
|
||||
err = nvs_flash_deinit();
|
||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||
TAG,
|
||||
"nvs_flash_deinit fail, returns(0x%x).",
|
||||
(int)err);
|
||||
#if MB_MDNS_IS_INCLUDED
|
||||
// Stop mdns service and register device
|
||||
mdns_free();
|
||||
#endif
|
||||
return err;
|
||||
}
|
||||
|
||||
static void test_modbus_tcp_slave(void)
|
||||
{
|
||||
void *pnetif = NULL;
|
||||
TEST_ASSERT_TRUE(test_tcp_services_init(&pnetif) == ESP_OK);
|
||||
TEST_ASSERT_NOT_NULL(pnetif);
|
||||
test_common_start();
|
||||
|
||||
mb_communication_info_t tcp_slave_cfg_1 = {
|
||||
.tcp_opts.port = TEST_TCP_PORT_NUM1,
|
||||
.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_TCP_SLAVE_SEND_TOUT_US,
|
||||
.tcp_opts.ip_netif_ptr = pnetif
|
||||
};
|
||||
|
||||
TEST_ASSERT_NOT_NULL(test_common_slave_tcp_create(&tcp_slave_cfg_1, 0));
|
||||
|
||||
ESP_LOGI(TAG, "Slave TCP #1 is started. (%s).", __func__);
|
||||
|
||||
mb_communication_info_t tcp_slave_cfg_2 = {
|
||||
.tcp_opts.port = TEST_TCP_PORT_NUM2,
|
||||
.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 = 1,
|
||||
.tcp_opts.test_tout_us = TEST_TCP_SLAVE_SEND_TOUT_US,
|
||||
.tcp_opts.ip_netif_ptr = pnetif
|
||||
};
|
||||
|
||||
TEST_ASSERT_NOT_NULL(test_common_slave_tcp_create(&tcp_slave_cfg_2, 0));
|
||||
|
||||
ESP_LOGI(TAG, "Slave TCP #2 is started. (%s).", __func__);
|
||||
|
||||
unity_send_signal("Slave_ready");
|
||||
unity_wait_for_signal("Master_started");
|
||||
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(1),
|
||||
test_common_task_wait_done_delete_all(TEST_TCP_TASK_TIMEOUT_MS));
|
||||
|
||||
ESP_LOGI(TAG, "Slave TCP test is complited. (%s).", __func__);
|
||||
|
||||
test_common_stop();
|
||||
|
||||
test_tcp_services_destroy();
|
||||
}
|
||||
|
||||
static void test_modbus_tcp_master(void)
|
||||
{
|
||||
void *pnetif = NULL;
|
||||
TEST_ASSERT_TRUE(test_tcp_services_init(&pnetif) == ESP_OK);
|
||||
TEST_ASSERT_NOT_NULL(pnetif);
|
||||
test_common_start();
|
||||
|
||||
ESP_LOGI(TAG, "Master TCP is started (%s).", __func__);
|
||||
unity_wait_for_signal("Slave_ready");
|
||||
|
||||
// Initialize and start Modbus controller
|
||||
mb_communication_info_t tcp_master_cfg_1 = {
|
||||
.tcp_opts.port = TEST_TCP_PORT_NUM1,
|
||||
.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_TCP_MASTER_SEND_TOUT_US,
|
||||
.tcp_opts.ip_netif_ptr = pnetif
|
||||
};
|
||||
|
||||
TEST_ASSERT_NOT_NULL(test_common_master_tcp_create(&tcp_master_cfg_1, 0, &descriptors[0], num_descriptors));
|
||||
|
||||
unity_send_signal("Master_started");
|
||||
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(1),
|
||||
test_common_task_wait_done_delete_all(TEST_TCP_TASK_TIMEOUT_MS));
|
||||
|
||||
test_common_stop();
|
||||
|
||||
test_tcp_services_destroy();
|
||||
ESP_LOGI(TAG, "Master TCP is complited. (%s).", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* Modbus TCP multi device test case
|
||||
*/
|
||||
TEST_CASE_MULTIPLE_DEVICES("Modbus TCP multi device master - slave case.", "[modbus][test_env=multi_dut_modbus_tcp]",
|
||||
test_modbus_tcp_slave, test_modbus_tcp_master);
|
||||
|
||||
#endif
|
||||
@@ -8,17 +8,16 @@ from pytest_embedded_idf import CaseTester
|
||||
@pytest.mark.multi_dut_modbus_serial
|
||||
@pytest.mark.parametrize('count, config', [(2, 'serial')], indirect=True)
|
||||
def test_modbus_comm_multi_dev_serial(case_tester) -> None: # type: ignore
|
||||
#case_tester.run_all_multi_dev_cases(reset=True)
|
||||
for case in case_tester.test_menu:
|
||||
if case.attributes.get('test_env', 'multi_dut_modbus_serial') == 'multi_dut_modbus_serial':
|
||||
print(case.name)
|
||||
case_tester.run_multi_dev_case(case=case, reset=True)
|
||||
|
||||
|
||||
# @pytest.mark.esp32
|
||||
# @pytest.mark.multi_dut_modbus_tcp
|
||||
# #@pytest.mark.parametrize('count, config', [(2, 'tcp')], indirect=True)
|
||||
# def test_modbus_comm_multi_dev_tcp(case_tester) -> None: # type: ignore
|
||||
# for case in case_tester.test_menu:
|
||||
# if case.attributes.get('test_env', 'multi_dut_modbus_tcp') == 'multi_dut_modbus_tcp':
|
||||
# case_tester.run_multi_dev_case(case=case, reset=True)
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.multi_dut_modbus_tcp
|
||||
@pytest.mark.parametrize('count, config', [(2, 'wifi'), (2, 'ethernet')], indirect=True)
|
||||
def test_modbus_comm_multi_dev_tcp(case_tester) -> None: # type: ignore
|
||||
for case in case_tester.test_menu:
|
||||
if case.attributes.get('test_env', 'multi_dut_modbus_tcp') == 'multi_dut_modbus_tcp':
|
||||
print(case.name)
|
||||
case_tester.run_multi_dev_case(case=case, reset=True)
|
||||
@@ -0,0 +1,34 @@
|
||||
#
|
||||
# Modbus configuration
|
||||
#
|
||||
CONFIG_FMB_COMM_MODE_TCP_EN=y
|
||||
CONFIG_FMB_TCP_PORT_DEFAULT=1502
|
||||
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
|
||||
CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||
CONFIG_FMB_COMM_MODE_RTU_EN=n
|
||||
CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=3000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_FMB_EXT_TYPE_SUPPORT=y
|
||||
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=n
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=y
|
||||
CONFIG_EXAMPLE_USE_INTERNAL_ETHERNET=y
|
||||
CONFIG_EXAMPLE_ETH_PHY_IP101=y
|
||||
CONFIG_EXAMPLE_ETH_MDC_GPIO=23
|
||||
CONFIG_EXAMPLE_ETH_MDIO_GPIO=18
|
||||
CONFIG_EXAMPLE_ETH_PHY_RST_GPIO=5
|
||||
CONFIG_EXAMPLE_ETH_PHY_ADDR=1
|
||||
CONFIG_EXAMPLE_ETHERNET_EMAC_TASK_STACK_SIZE=4096
|
||||
|
||||
CONFIG_ETH_ENABLED=y
|
||||
CONFIG_ETH_USE_ESP32_EMAC=y
|
||||
CONFIG_ETH_PHY_INTERFACE_RMII=y
|
||||
CONFIG_ETH_USE_SPI_ETHERNET=n
|
||||
|
||||
# Enable debug logging
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
@@ -9,7 +9,7 @@ CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
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=y
|
||||
CONFIG_FMB_COMM_MODE_TCP_EN=n
|
||||
CONFIG_FMB_TCP_UID_ENABLED=y
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=2000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
@@ -21,3 +21,10 @@ CONFIG_MB_PORT_ADAPTER_EN=n
|
||||
CONFIG_MB_TEST_LEAK_CRITICAL_LEVEL=128
|
||||
CONFIG_MB_TEST_LEAK_WARN_LEVEL=128
|
||||
|
||||
# Avoid CI issues "Warning: The smallest app partition is nearly full (5% free space left)!"
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
# Enable debug logging
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
CONFIG_FMB_COMM_MODE_TCP_EN=y
|
||||
CONFIG_FMB_TCP_PORT_DEFAULT=502
|
||||
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
|
||||
CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
CONFIG_FMB_PORT_TASK_PRIO=10
|
||||
CONFIG_FMB_COMM_MODE_RTU_EN=n
|
||||
CONFIG_FMB_COMM_MODE_ASCII_EN=n
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=3000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_EXAMPLE_CONNECT_IPV6=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
|
||||
CONFIG_EXAMPLE_CONNECT_WIFI=y
|
||||
CONFIG_EXAMPLE_WIFI_SSID="${CI_WIFI_SSID}"
|
||||
CONFIG_EXAMPLE_WIFI_PASSWORD="${CI_WIFI_PASSW}"
|
||||
|
||||
|
||||
# Avoid CI issues "Warning: The smallest app partition is nearly full (5% free space left)!"
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
|
||||
# Enable debug logging
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
@@ -18,3 +18,10 @@ CONFIG_MB_PORT_ADAPTER_EN=n
|
||||
CONFIG_MB_TEST_MASTER_TASK_PRIO=5
|
||||
CONFIG_MB_TEST_MASTER_TASK_PRIO=5
|
||||
CONFIG_MB_TEST_COMM_CYCLE_COUNTER=10
|
||||
|
||||
# Avoid CI issues "Warning: The smallest app partition is nearly full (5% free space left)!"
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
|
||||
CONFIG_PARTITION_TABLE_SINGLE_APP_LARGE=y
|
||||
|
||||
# Enable debug logging
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=y
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
idf_component_register(SRCS "test_common.c"
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES unity)
|
||||
INCLUDE_DIRS "include"
|
||||
REQUIRES unity)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
|
||||
@@ -43,26 +45,57 @@ enum {
|
||||
TEST_REG_VAL4 = 0x4444
|
||||
};
|
||||
|
||||
typedef struct task_entry_s {
|
||||
TaskHandle_t task_handle;
|
||||
SemaphoreHandle_t task_sema_handle;
|
||||
void *inst_handle;
|
||||
LIST_ENTRY(task_entry_s) entries;
|
||||
} task_entry_t;
|
||||
|
||||
/**
|
||||
* @brief Start, stop helpers for common test module
|
||||
*
|
||||
*/
|
||||
void test_common_start();
|
||||
void test_common_stop();
|
||||
|
||||
/**
|
||||
* @brief Helper test functions for multi instance modbus master - slave test
|
||||
*
|
||||
*/
|
||||
TaskHandle_t test_slave_serial_create(mb_communication_info_t *pconfig);
|
||||
TaskHandle_t test_master_serial_create(mb_communication_info_t *pconfig, const mb_parameter_descriptor_t *pdescr, uint16_t descr_size);
|
||||
TaskHandle_t test_slave_tcp_create(mb_communication_info_t *pconfig);
|
||||
TaskHandle_t test_master_tcp_create(mb_communication_info_t *pconfig, const mb_parameter_descriptor_t *pdescr, uint16_t descr_size);
|
||||
TaskHandle_t test_slave_start_busy_task();
|
||||
// slave setup register area helper
|
||||
void test_slave_setup_start(void *mbs_handle);
|
||||
// Helper function to read characteristic from slave
|
||||
esp_err_t read_modbus_parameter(void *handle, uint16_t cid, uint16_t *par_data);
|
||||
// Helper function to write characteristic into slave
|
||||
esp_err_t write_modbus_parameter(void *handle, uint16_t cid, uint16_t *par_data);
|
||||
// TaskHandle_t test_common_slave_serial_create(mb_communication_info_t *pconfig);
|
||||
|
||||
// Common test check leak function
|
||||
TaskHandle_t test_common_slave_serial_create(mb_communication_info_t *pconfig, uint32_t priority);
|
||||
TaskHandle_t test_common_master_serial_create(mb_communication_info_t *pconfig,uint32_t priority, const mb_parameter_descriptor_t *pdescr, uint16_t descr_size);
|
||||
TaskHandle_t test_common_slave_tcp_create(mb_communication_info_t *pconfig, uint32_t priority);
|
||||
TaskHandle_t test_common_master_tcp_create(mb_communication_info_t *pconfig, uint32_t priority, const mb_parameter_descriptor_t *pdescr, uint16_t descr_size);
|
||||
TaskHandle_t test_common_start_busy_task(uint32_t priority);
|
||||
|
||||
/**
|
||||
* @brief The test helper function to check memory leak
|
||||
*
|
||||
*/
|
||||
void test_common_check_leak(size_t before_free, size_t after_free, const char *type, size_t warn_threshold, size_t critical_threshold);
|
||||
void test_slave_stop_busy_task(TaskHandle_t busy_task_handle);
|
||||
uint32_t test_common_wait_done(TickType_t timeout_ticks);
|
||||
void test_common_start();
|
||||
void test_common_stop();
|
||||
|
||||
// Slave setup register area helper
|
||||
void test_common_slave_setup_start(void *mbs_handle);
|
||||
// Helper function to read characteristic from slave
|
||||
esp_err_t test_common_read_modbus_parameter(void *handle, uint16_t cid, uint16_t *par_data);
|
||||
// Helper function to write characteristic into slave
|
||||
esp_err_t test_common_write_modbus_parameter(void *handle, uint16_t cid, uint16_t *par_data);
|
||||
|
||||
/**
|
||||
* @brief The test helper functions to work with test tasks
|
||||
*
|
||||
*/
|
||||
void test_common_task_notify_start(TaskHandle_t task_handle, uint32_t value);
|
||||
void test_common_task_start(TaskHandle_t task_handle, uint32_t value);
|
||||
int test_common_task_start_all(uint32_t value);
|
||||
bool test_common_task_wait_done(TaskHandle_t task_handle, TickType_t timeout_ticks);
|
||||
bool test_common_task_wait_done_delete(TaskHandle_t task_handle, TickType_t task_timeout_ticks);
|
||||
int test_common_task_wait_done_delete_all(TickType_t task_timeout_tick);
|
||||
void test_common_task_delete(TaskHandle_t task_handle);
|
||||
void test_common_task_delete_all();
|
||||
void *test_common_task_get_instance(TaskHandle_t task_handle);
|
||||
|
||||
|
||||
|
||||
@@ -43,15 +43,14 @@ if(CONFIG_MB_PORT_ADAPTER_EN)
|
||||
mbm_port_tcp_enable
|
||||
mbm_port_tcp_disable
|
||||
mbm_port_tcp_delete
|
||||
# mbm_port_timer_expired
|
||||
mbs_port_tcp_create
|
||||
mbs_port_tcp_enable
|
||||
mbs_port_tcp_disable
|
||||
mbs_port_tcp_send_data
|
||||
mbs_port_tcp_recv_data
|
||||
mbs_port_tcp_delete
|
||||
mb_port_evt_post
|
||||
mb_port_evt_get
|
||||
mb_port_event_post
|
||||
mb_port_event_get
|
||||
mb_port_ser_create
|
||||
mb_port_ser_recv_data
|
||||
mb_port_ser_send_data
|
||||
@@ -69,4 +68,8 @@ endforeach()
|
||||
endif()
|
||||
|
||||
# allow multiple symbol definitions
|
||||
target_link_libraries(mb_ut_lib PUBLIC "-Wl,--allow-multiple-definition")
|
||||
target_link_libraries(mb_ut_lib PUBLIC "-Wl,--allow-multiple-definition")
|
||||
|
||||
if(CONFIG_MB_PORT_ADAPTER_EN)
|
||||
set_property(TARGET ${COMPONENT_LIB} APPEND PROPERTY INTERFACE_LINK_LIBRARIES "-u mb_test_include_stub_impl")
|
||||
endif()
|
||||
@@ -46,7 +46,7 @@ typedef struct _mb_adapter_port_entry
|
||||
uint16_t recv_length;
|
||||
uint64_t send_time_stamp;
|
||||
uint64_t recv_time_stamp;
|
||||
uint64_t test_timeout_us;
|
||||
_Atomic uint64_t test_timeout_us;
|
||||
uint32_t flags;
|
||||
mb_uid_info_t addr_info;
|
||||
QueueHandle_t rx_queue;
|
||||
@@ -69,37 +69,37 @@ static QueueSetHandle_t queue_set = NULL;
|
||||
static TaskHandle_t adapter_task_handle; /*!< receive task handle */
|
||||
|
||||
IRAM_ATTR
|
||||
static bool mb_port_adapter_tmr_expired(void *inst)
|
||||
static bool mb_port_adapter_timer_expired(void *inst)
|
||||
{
|
||||
mb_port_adapter_t *port_obj = __containerof(inst, mb_port_adapter_t, base);
|
||||
|
||||
bool need_poll = false;
|
||||
mb_tmr_mode_enum_t timer_mode = mb_port_get_cur_tmr_mode(&port_obj->base);
|
||||
mb_timer_mode_enum_t timer_mode = mb_port_get_cur_timer_mode(&port_obj->base);
|
||||
|
||||
mb_port_tmr_disable(&port_obj->base);
|
||||
mb_port_timer_disable(&port_obj->base);
|
||||
|
||||
switch (timer_mode)
|
||||
{
|
||||
case MB_TMODE_T35:
|
||||
need_poll = mb_port_evt_post(&port_obj->base, EVENT(EV_READY));
|
||||
need_poll = mb_port_event_post(&port_obj->base, EVENT(EV_READY));
|
||||
ESP_EARLY_LOGD(TAG, "%p:EV_READY", port_obj->base.descr.parent);
|
||||
break;
|
||||
|
||||
case MB_TMODE_RESPOND_TIMEOUT:
|
||||
mb_port_evt_set_err_type(&port_obj->base, EV_ERROR_RESPOND_TIMEOUT);
|
||||
need_poll = mb_port_evt_post(&port_obj->base, EVENT(EV_ERROR_PROCESS));
|
||||
mb_port_event_set_err_type(&port_obj->base, EV_ERROR_RESPOND_TIMEOUT);
|
||||
need_poll = mb_port_event_post(&port_obj->base, EVENT(EV_ERROR_PROCESS));
|
||||
|
||||
ESP_EARLY_LOGW(TAG, "%p:EV_ERROR_RESPOND_TIMEOUT", port_obj->base.descr.parent);
|
||||
break;
|
||||
|
||||
case MB_TMODE_CONVERT_DELAY:
|
||||
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
|
||||
need_poll = mb_port_evt_post(&port_obj->base, EVENT(EV_EXECUTE));
|
||||
need_poll = mb_port_event_post(&port_obj->base, EVENT(EV_EXECUTE));
|
||||
ESP_EARLY_LOGD(TAG, "%p:MB_TMODE_CONVERT_DELAY", port_obj->base.descr.parent);
|
||||
break;
|
||||
|
||||
default:
|
||||
need_poll = mb_port_evt_post(&port_obj->base, EVENT(EV_READY));
|
||||
need_poll = mb_port_event_post(&port_obj->base, EVENT(EV_READY));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ static void mb_port_adapter_timer_cb(void *param)
|
||||
// Send the data to all ports with the same communication port setting except itself
|
||||
queue_push(it->rx_queue, (void *)&temp_buffer[0], sz, NULL);
|
||||
mb_port_adapter_set_flag(&port_obj->base, MB_QUEUE_FLAG_SENT);
|
||||
ESP_LOGW(TAG, "Send (%d bytes) from %s to %s. ", (int)sz, port_obj->base.descr.parent_name, it->base.descr.parent_name);
|
||||
ESP_LOGD(TAG, "Send (%d bytes) from %s to %s. ", (int)sz, port_obj->base.descr.parent_name, it->base.descr.parent_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,7 @@ static void mb_port_adapter_conn_logic(void *inst, mb_uid_info_t *paddr_info)
|
||||
&& !slave->base.descr.is_master
|
||||
&& (paddr_info->port == slave->addr_info.port)) {
|
||||
// Register each slave object
|
||||
ESP_LOGW(TAG, "Check connection state of object #%d(%s), uid: %d, port: %d, %s",
|
||||
ESP_LOGD(TAG, "Check connection state of object #%d(%s), uid: %d, port: %d, %s",
|
||||
paddr_info->index, paddr_info->node_name_str,
|
||||
paddr_info->uid, paddr_info->port,
|
||||
(paddr_info->state == MB_SOCK_STATE_CONNECTED) ? "CONNECTED" : "DISCONNECTED");
|
||||
@@ -249,7 +249,7 @@ static void mb_port_adapter_conn_logic(void *inst, mb_uid_info_t *paddr_info)
|
||||
vTaskDelay(MB_ADAPTER_CONN_TIMEOUT);
|
||||
}
|
||||
} else { // slave connection logic
|
||||
ESP_LOGW(TAG, "Register connection in adapter object #%d(%s), uid: %d, port: %d, to master %s",
|
||||
ESP_LOGD(TAG, "Register connection in adapter object #%d(%s), uid: %d, port: %d, to master %s",
|
||||
port_obj->addr_info.index, port_obj->addr_info.node_name_str,
|
||||
port_obj->addr_info.uid, port_obj->addr_info.port, paddr_info->node_name_str);
|
||||
// Mimic connection logic for each slave here
|
||||
@@ -279,8 +279,8 @@ static void mb_port_adapter_task(void *p_args)
|
||||
if (it && active_queue && (it->rx_queue == active_queue)) {
|
||||
if (xQueuePeek(it->rx_queue, &frame_entry, 0) == pdTRUE) {
|
||||
it->recv_length = frame_entry.len;
|
||||
mb_port_evt_post(&it->base, EVENT(EV_FRAME_RECEIVED, frame_entry.len, NULL, 0));
|
||||
ESP_LOGW(TAG, "%s, frame %d bytes is ready.", (it->base.descr.parent_name), (int)frame_entry.len);
|
||||
mb_port_event_post(&it->base, EVENT(EV_FRAME_RECEIVED, frame_entry.len, NULL, 0));
|
||||
ESP_LOGD(TAG, "%s, frame %d bytes is ready.", (it->base.descr.parent_name), (int)frame_entry.len);
|
||||
}
|
||||
} else if (it && (it->conn_queue == active_queue)) {
|
||||
if (xQueueReceive(it->conn_queue, &addr_info, MB_ADAPTER_QUEUE_TIMEOUT) == pdTRUE) {
|
||||
@@ -312,7 +312,7 @@ static mb_err_enum_t mb_port_adapter_connect(mb_tcp_opts_t *tcp_opts, void *pobj
|
||||
int res = port_scan_addr_string((char *)*paddr_table, &uid_info);
|
||||
if (res > 0)
|
||||
{
|
||||
ESP_LOGW(TAG, "Config: %s, IP: %s, port: %d, slave_addr: %d, ip_ver: %s",
|
||||
ESP_LOGD(TAG, "Config: %s, IP: %s, port: %d, slave_addr: %d, ip_ver: %s",
|
||||
(char *)*paddr_table, uid_info.ip_addr_str, uid_info.port,
|
||||
uid_info.uid, (uid_info.addr_type == MB_IPV4 ? "IPV4" : "IPV6"));
|
||||
uid_info.index = count++;
|
||||
@@ -337,7 +337,7 @@ static mb_err_enum_t mb_port_adapter_connect(mb_tcp_opts_t *tcp_opts, void *pobj
|
||||
}
|
||||
paddr_table++;
|
||||
}
|
||||
ESP_LOGW(TAG, "parsed and added %d slave configurations.", count);
|
||||
ESP_LOGD(TAG, "parsed and added %d slave configurations.", count);
|
||||
return count ? MB_ENOERR : MB_EINVAL;
|
||||
}
|
||||
|
||||
@@ -357,7 +357,8 @@ mb_err_enum_t mb_port_adapter_create(mb_uid_info_t *paddr_info, mb_port_base_t *
|
||||
.callback = mb_port_adapter_timer_cb,
|
||||
.arg = padapter,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = padapter->base.descr.parent_name};
|
||||
.name = padapter->base.descr.parent_name
|
||||
};
|
||||
// Create Modbus timer handlers for streams
|
||||
MB_GOTO_ON_ERROR(esp_timer_create(&timer_conf, &padapter->timer_handle),
|
||||
error, TAG, "create input stream timer failed.");
|
||||
@@ -404,7 +405,7 @@ mb_err_enum_t mb_port_adapter_create(mb_uid_info_t *paddr_info, mb_port_base_t *
|
||||
padapter->base.descr.parent_name, (unsigned)paddr_info->port);
|
||||
MB_GOTO_ON_FALSE((res), MB_EILLSTATE, error,
|
||||
TAG, "object adress info alloc fail, err: %d", (int)res);
|
||||
padapter->base.cb.tmr_expired = mb_port_adapter_tmr_expired;
|
||||
padapter->base.cb.tmr_expired = mb_port_adapter_timer_expired;
|
||||
padapter->base.cb.tx_empty = NULL;
|
||||
padapter->base.cb.byte_rcvd = NULL;
|
||||
padapter->base.arg = (void *)padapter;
|
||||
@@ -414,7 +415,7 @@ mb_err_enum_t mb_port_adapter_create(mb_uid_info_t *paddr_info, mb_port_base_t *
|
||||
padapter->addr_info.node_name_str = pstr;
|
||||
padapter->addr_info.ip_addr_str = pstr;
|
||||
*in_out_obj = &(padapter->base);
|
||||
ESP_LOGW(TAG, "created object @%p, from parent %p", padapter, padapter->base.descr.parent);
|
||||
ESP_LOGD(TAG, "created object @%p, from parent %p", padapter, padapter->base.descr.parent);
|
||||
return MB_ENOERR;
|
||||
|
||||
error:
|
||||
@@ -447,7 +448,7 @@ mb_err_enum_t mb_port_adapter_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t
|
||||
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EILLSTATE, error, TAG,
|
||||
"%s, could not parse config, err=%x.", pobj->descr.parent_name, (int)ret);
|
||||
}
|
||||
ESP_LOGW(TAG, "%s, set test time to %" PRIu64, pobj->descr.parent_name, tcp_opts->test_tout_us);
|
||||
ESP_LOGD(TAG, "%s, set test time to %" PRIu64, pobj->descr.parent_name, tcp_opts->test_tout_us);
|
||||
mb_port_adapter_set_response_time(pobj, (tcp_opts->test_tout_us));
|
||||
}
|
||||
*in_out_obj = pobj;
|
||||
@@ -478,7 +479,7 @@ mb_err_enum_t mb_port_adapter_ser_create(mb_serial_opts_t *ser_opts, mb_port_bas
|
||||
mb_port_base_t *pobj = *in_out_obj;
|
||||
mb_err_enum_t ret = mb_port_adapter_create(&addr_info, &pobj);
|
||||
if ((ret == MB_ENOERR) && pobj) {
|
||||
ESP_LOGW(TAG, "%s, set test time to %d", pobj->descr.parent_name, (int)(ser_opts->test_tout_us));
|
||||
ESP_LOGD(TAG, "%s, set test time to %d", pobj->descr.parent_name, (int)(ser_opts->test_tout_us));
|
||||
mb_port_adapter_set_response_time(pobj, (ser_opts->test_tout_us));
|
||||
*in_out_obj = pobj;
|
||||
}
|
||||
@@ -576,14 +577,14 @@ bool mb_port_adapter_recv_data(mb_port_base_t *inst, uint8_t **ppframe, uint16_t
|
||||
int length = queue_pop(port_obj->rx_queue, &port_obj->rx_buffer[0], CONFIG_FMB_BUFFER_SIZE, NULL);
|
||||
if (length)
|
||||
{
|
||||
mb_port_tmr_disable(inst);
|
||||
ESP_LOGW(TAG, "%s, received data: %d bytes.", inst->descr.parent_name, length);
|
||||
mb_port_timer_disable(inst);
|
||||
ESP_LOGD(TAG, "%s, received data: %d bytes.", inst->descr.parent_name, length);
|
||||
// Stop timer because the new data is received
|
||||
// Store the timestamp of received frame
|
||||
port_obj->recv_time_stamp = esp_timer_get_time();
|
||||
*ppframe = &port_obj->rx_buffer[0];
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":PORT_RECV"),
|
||||
(void *)&port_obj->rx_buffer[0], (uint16_t)length, ESP_LOG_WARN);
|
||||
(void *)&port_obj->rx_buffer[0], (uint16_t)length, ESP_LOG_DEBUG);
|
||||
}
|
||||
CRITICAL_SECTION_UNLOCK(inst->lock);
|
||||
}
|
||||
@@ -615,9 +616,9 @@ bool mb_port_adapter_send_data(mb_port_base_t *inst, uint8_t address, uint8_t *p
|
||||
port_obj->send_time_stamp = esp_timer_get_time();
|
||||
// Print sent packet, the tag used is more clear to see
|
||||
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":PORT_SEND"),
|
||||
(void *)pframe, length, ESP_LOG_WARN);
|
||||
(void)mb_port_evt_post(inst, EVENT(EV_FRAME_SENT));
|
||||
ESP_LOGW(TAG, "%s, tx completed, flags = 0x%04x.", inst->descr.parent_name, (int)flags);
|
||||
(void *)pframe, length, ESP_LOG_DEBUG);
|
||||
(void)mb_port_event_post(inst, EVENT(EV_FRAME_SENT));
|
||||
ESP_LOGD(TAG, "%s, tx completed, flags = 0x%04x.", inst->descr.parent_name, (int)flags);
|
||||
res = true;
|
||||
|
||||
}
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdatomic.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
|
||||
#include "esp_timer.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
@@ -24,11 +22,18 @@
|
||||
#include "port_adapter.h"
|
||||
#include "port_stubs.h"
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static const char *TAG = "port_stub";
|
||||
static __attribute__((unused)) const char *TAG = "port_stub";
|
||||
|
||||
#if (CONFIG_MB_PORT_ADAPTER_EN)
|
||||
|
||||
// The workaround to statically link whole test library
|
||||
__attribute__((unused)) bool mb_test_include_stub_impl = true;
|
||||
|
||||
// Below are function wrappers to substitute actual port object with the adapter object for test purpose
|
||||
|
||||
@@ -66,18 +71,18 @@ void __wrap_mb_port_ser_disable(mb_port_base_t *inst)
|
||||
|
||||
#endif
|
||||
|
||||
IRAM_ATTR
|
||||
bool __wrap_mb_port_evt_get(mb_port_base_t *inst, mb_event_t *pevent)
|
||||
IRAM_ATTR
|
||||
bool __wrap_mb_port_event_get(mb_port_base_t *inst, mb_event_t *pevent)
|
||||
{
|
||||
bool result = __real_mb_port_evt_get(inst, pevent);
|
||||
ESP_LOGW(TAG, "%s, get event:%x.", inst->descr.parent_name, pevent->event);
|
||||
bool result = __real_mb_port_event_get(inst, pevent);
|
||||
ESP_LOGD(TAG, "%s, get event:%x.", inst->descr.parent_name, pevent->event);
|
||||
return result;
|
||||
}
|
||||
|
||||
IRAM_ATTR
|
||||
bool __wrap_mb_port_evt_post(mb_port_base_t *inst, mb_event_t event)
|
||||
IRAM_ATTR
|
||||
bool __wrap_mb_port_event_post(mb_port_base_t *inst, mb_event_t event)
|
||||
{
|
||||
bool result = __real_mb_port_evt_post(inst, event);
|
||||
bool result = __real_mb_port_event_post(inst, event);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -86,7 +91,7 @@ bool __wrap_mb_port_evt_post(mb_port_base_t *inst, mb_event_t event)
|
||||
// Below are the TCP port function wrappers to exchange the port layer to TCP adapter
|
||||
mb_err_enum_t __wrap_mbm_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **in_out_obj)
|
||||
{
|
||||
ESP_LOGW(TAG, "master tcp adapter installed.");
|
||||
ESP_LOGD(TAG, "master tcp adapter installed.");
|
||||
return mb_port_adapter_tcp_create(tcp_opts, in_out_obj);
|
||||
}
|
||||
|
||||
@@ -107,37 +112,31 @@ void __wrap_mbm_port_tcp_delete(mb_port_base_t *inst)
|
||||
|
||||
void __wrap_mbm_port_tcp_enable(mb_port_base_t *inst)
|
||||
{
|
||||
ESP_LOGW(TAG, "adapter master tcp enable port.");
|
||||
ESP_LOGD(TAG, "adapter master tcp enable port.");
|
||||
}
|
||||
|
||||
void __wrap_mbm_port_tcp_disable(mb_port_base_t *inst)
|
||||
{
|
||||
ESP_LOGW(TAG, "adapter master tcp disable port.");
|
||||
ESP_LOGD(TAG, "adapter master tcp disable port.");
|
||||
}
|
||||
|
||||
void __wrap_mbm_port_tcp_set_conn_cb(mb_port_base_t *inst, void *conn_fp, void *arg)
|
||||
{
|
||||
ESP_LOGW(TAG, "adapter set connection callback.");
|
||||
ESP_LOGD(TAG, "adapter set connection callback.");
|
||||
mb_port_adapter_tcp_set_conn_cb(inst, conn_fp, arg);
|
||||
}
|
||||
|
||||
mb_uid_info_t *__wrap_mbm_port_tcp_get_slave_info(mb_port_base_t *inst, uint8_t slave_addr, mb_sock_state_t exp_state)
|
||||
{
|
||||
ESP_LOGW(TAG, "adapter get slave #%d info.", slave_addr);
|
||||
ESP_LOGD(TAG, "adapter get slave #%d info.", slave_addr);
|
||||
return mb_port_adapter_get_slave_info(inst, slave_addr, exp_state);
|
||||
}
|
||||
|
||||
// IRAM_ATTR
|
||||
// bool __wrap_mbm_port_timer_expired(void *inst)
|
||||
// {
|
||||
// return mb_port_adapter_tmr_expired(inst);
|
||||
// }
|
||||
|
||||
// Wrappers for modbus slave tcp
|
||||
|
||||
mb_err_enum_t __wrap_mbs_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **in_out_obj)
|
||||
{
|
||||
ESP_LOGW(TAG, "install slave tcp adapter.");
|
||||
ESP_LOGD(TAG, "install slave tcp adapter.");
|
||||
return mb_port_adapter_tcp_create(tcp_opts, in_out_obj);
|
||||
}
|
||||
|
||||
@@ -158,16 +157,18 @@ void __wrap_mbs_port_tcp_delete(mb_port_base_t *inst)
|
||||
|
||||
void __wrap_mbs_port_tcp_enable(mb_port_base_t *inst)
|
||||
{
|
||||
ESP_LOGW(TAG, "adapter slave tcp enable port.");
|
||||
ESP_LOGD(TAG, "adapter slave tcp enable port.");
|
||||
}
|
||||
|
||||
void __wrap_mbs_port_tcp_disable(mb_port_base_t *inst)
|
||||
{
|
||||
ESP_LOGW(TAG, "adapter slave tcp disable port.");
|
||||
ESP_LOGD(TAG, "adapter slave tcp disable port.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_MB_PORT_ADAPTER_EN
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -6,17 +6,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sdkconfig.h>
|
||||
#include "esp_log.h"
|
||||
#include "mb_common.h"
|
||||
#include "mb_port_types.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// Serial port function wrappers
|
||||
|
||||
bool __wrap_mb_port_evt_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
bool __wrap_mb_port_evt_post(mb_port_base_t *inst, mb_event_t event);
|
||||
extern bool __real_mb_port_evt_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
extern bool __real_mb_port_evt_post(mb_port_base_t *inst, mb_event_t event);
|
||||
bool __wrap_mb_port_event_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
bool __wrap_mb_port_event_post(mb_port_base_t *inst, mb_event_t event);
|
||||
extern bool __real_mb_port_event_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
extern bool __real_mb_port_event_post(mb_port_base_t *inst, mb_event_t event);
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN)
|
||||
|
||||
@@ -46,7 +46,7 @@ void __wrap_mbm_port_tcp_enable(mb_port_base_t *inst);
|
||||
void __wrap_mbm_port_tcp_disable(mb_port_base_t *inst);
|
||||
void __wrap_mbm_port_tcp_set_conn_cb(mb_port_base_t *inst, void *conn_fp, void *arg);
|
||||
mb_uid_info_t *__wrap_mbm_port_tcp_get_slave_info(mb_port_base_t *inst, uint8_t uid, mb_sock_state_t exp_state);
|
||||
//bool __wrap_mbm_port_timer_expired(void *inst);
|
||||
//bool __wrap_mbm_port__expired(void *inst);
|
||||
|
||||
extern void __real_mbm_port_tcp_enable(mb_port_base_t *inst);
|
||||
extern void __real_mbm_port_tcp_disable(mb_port_base_t *inst);
|
||||
|
||||
@@ -21,28 +21,27 @@
|
||||
#include "esp_heap_trace.h"
|
||||
#endif
|
||||
|
||||
#define TEST_TASK_PRIO_MASTER CONFIG_MB_TEST_MASTER_TASK_PRIO
|
||||
#define TEST_TASK_PRIO_SLAVE CONFIG_MB_TEST_SLAVE_TASK_PRIO
|
||||
#define TEST_TASK_STACK_SIZE 5120
|
||||
#define TEST_TASK_CYCLE_COUNTER CONFIG_MB_TEST_COMM_CYCLE_COUNTER
|
||||
#define TEST_BUSY_TASK_PRIO 20
|
||||
#define TEST_TASK_PRIO_MASTER (CONFIG_MB_TEST_MASTER_TASK_PRIO)
|
||||
#define TEST_TASK_PRIO_SLAVE (CONFIG_MB_TEST_SLAVE_TASK_PRIO)
|
||||
#define TEST_TASK_STACK_SIZE (5120)
|
||||
#define TEST_TASK_CYCLE_COUNTER (CONFIG_MB_TEST_COMM_CYCLE_COUNTER)
|
||||
#define TEST_BUSY_TASK_PRIO (20)
|
||||
|
||||
#define TEST_REG_START_AREA0 (0x0000)
|
||||
#define TEST_READ_MASK (MB_EVENT_HOLDING_REG_RD | MB_EVENT_INPUT_REG_RD | MB_EVENT_DISCRETE_RD | MB_EVENT_COILS_RD)
|
||||
#define TEST_WRITE_MASK (MB_EVENT_HOLDING_REG_WR | MB_EVENT_COILS_WR)
|
||||
#define TEST_READ_WRITE_MASK (TEST_WRITE_MASK | TEST_READ_MASK)
|
||||
|
||||
#define TEST_BUSY_COUNT 150000
|
||||
|
||||
#define TEST_PAR_INFO_GET_TOUT (10)
|
||||
#define TEST_SEND_TIMEOUT (200 / portTICK_PERIOD_MS)
|
||||
#define TEST_TASK_START_TIMEOUT (5000 / portTICK_PERIOD_MS)
|
||||
|
||||
#define TEST_NOTIF_SEND_TOUT 100
|
||||
#define TEST_NOTIF_SIZE 20
|
||||
#define TEST_ALLOW_PROC_FAIL 2 // percentage of allowed failures
|
||||
|
||||
#define TEST_TASK_TICK_TIME (20 / portTICK_PERIOD_MS)
|
||||
#define TEST_REG_START_AREA0 (0x0000)
|
||||
#define TEST_READ_MASK (MB_EVENT_HOLDING_REG_RD |\
|
||||
MB_EVENT_INPUT_REG_RD |\
|
||||
MB_EVENT_DISCRETE_RD |\
|
||||
MB_EVENT_COILS_RD)
|
||||
#define TEST_WRITE_MASK (MB_EVENT_HOLDING_REG_WR | MB_EVENT_COILS_WR)
|
||||
#define TEST_READ_WRITE_MASK (TEST_WRITE_MASK | TEST_READ_MASK)
|
||||
#define TEST_BUSY_COUNT (150000)
|
||||
#define TEST_PAR_INFO_GET_TOUT (10)
|
||||
#define TEST_SEND_TIMEOUT (200 / portTICK_PERIOD_MS)
|
||||
#define TEST_TASK_START_TIMEOUT (10000 / portTICK_PERIOD_MS)
|
||||
#define TEST_NOTIF_SEND_TOUT (400 / portTICK_PERIOD_MS)
|
||||
#define TEST_NOTIF_SIZE (20)
|
||||
#define TEST_ALLOW_PROC_FAIL (5) // percentage of allowed failures due to desynchronization
|
||||
#define TEST_TASK_TICK_TIME (50 / portTICK_PERIOD_MS)
|
||||
|
||||
#define TAG "TEST_COMMON"
|
||||
|
||||
@@ -59,15 +58,15 @@ const uint16_t holding_registers_counter = (sizeof(holding_registers) / sizeof(h
|
||||
const uint16_t input_registers_counter = (sizeof(input_registers) / sizeof(input_registers[0]));
|
||||
const uint16_t coil_registers_counter = (sizeof(coil_registers) / sizeof(coil_registers[0]));
|
||||
|
||||
static QueueHandle_t tasks_done_queue = NULL;
|
||||
static int test_error_counter = 0;
|
||||
static int test_good_counter = 0;
|
||||
|
||||
static size_t before_free_8bit = 0;
|
||||
static size_t before_free_32bit = 0;
|
||||
|
||||
// Heap memory leak traicing
|
||||
#ifdef CONFIG_HEAP_TRACING
|
||||
#define NUM_RECORDS 200
|
||||
#define NUM_RECORDS 500
|
||||
static heap_trace_record_t trace_record[NUM_RECORDS];
|
||||
#endif
|
||||
|
||||
@@ -87,6 +86,82 @@ static heap_trace_record_t trace_record[NUM_RECORDS];
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// The linked list of test tasks instances
|
||||
LIST_HEAD(task_entry, task_entry_s) s_task_list;
|
||||
|
||||
static portMUX_TYPE s_list_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
static void task_entry_remove(task_entry_t *task_entry)
|
||||
{
|
||||
portENTER_CRITICAL(&s_list_spinlock);
|
||||
LIST_REMOVE(task_entry, entries);
|
||||
portEXIT_CRITICAL(&s_list_spinlock);
|
||||
ESP_LOGD(TAG, "Delete task 0x%" PRIx32, (uint32_t)task_entry->task_handle);
|
||||
vTaskDelete(task_entry->task_handle);
|
||||
vSemaphoreDelete(task_entry->task_sema_handle);
|
||||
free(task_entry);
|
||||
}
|
||||
|
||||
static bool task_wait_done_and_remove(task_entry_t *task_entry, TickType_t tout_ticks)
|
||||
{
|
||||
bool is_done = false;
|
||||
if (task_entry && task_entry->task_handle && task_entry->task_sema_handle) {
|
||||
if ((xSemaphoreTake(task_entry->task_sema_handle, tout_ticks) == pdTRUE)) {
|
||||
ESP_LOGI(TAG, "Test task 0x%" PRIx32 ", done successfully.", (uint32_t)task_entry->task_handle);
|
||||
is_done = true;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Could not complete task 0x%" PRIx32 " after timeout, force kill the task.",
|
||||
(uint32_t)task_entry->task_handle);
|
||||
is_done = false;
|
||||
}
|
||||
vTaskDelay(1); // Let the lower priority task to suspend or delete itself
|
||||
task_entry_remove(task_entry);
|
||||
}
|
||||
return (is_done);
|
||||
}
|
||||
|
||||
static void test_task_add_entry(TaskHandle_t task_handle, void *pinst)
|
||||
{
|
||||
TEST_ASSERT_TRUE(task_handle);
|
||||
task_entry_t *new_entry = (task_entry_t*) calloc(1, sizeof(task_entry_t));
|
||||
TEST_ASSERT_TRUE(new_entry);
|
||||
portENTER_CRITICAL(&s_list_spinlock);
|
||||
new_entry->task_handle = task_handle;
|
||||
new_entry->task_sema_handle = xSemaphoreCreateBinary();
|
||||
new_entry->inst_handle = pinst;
|
||||
LIST_INSERT_HEAD(&s_task_list, new_entry, entries);
|
||||
portEXIT_CRITICAL(&s_list_spinlock);
|
||||
xSemaphoreTake(new_entry->task_sema_handle, 1);
|
||||
}
|
||||
|
||||
static task_entry_t *test_task_find_entry(TaskHandle_t task_handle)
|
||||
{
|
||||
TEST_ASSERT_NOT_NULL(task_handle);
|
||||
|
||||
task_entry_t *it, *pfound = NULL;
|
||||
if (LIST_EMPTY(&s_task_list)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
portENTER_CRITICAL(&s_list_spinlock);
|
||||
LIST_FOREACH(it, &s_task_list, entries) {
|
||||
if (it->task_handle == task_handle) {
|
||||
pfound = it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&s_list_spinlock);
|
||||
return pfound;
|
||||
}
|
||||
|
||||
static void test_common_task_notify_done(TaskHandle_t task_handle)
|
||||
{
|
||||
task_entry_t *it = test_task_find_entry(task_handle);
|
||||
if (it) {
|
||||
xSemaphoreGive(it->task_sema_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_busy_task(void *phandle)
|
||||
{
|
||||
spinlock_t spin_lock;
|
||||
@@ -102,21 +177,95 @@ static void test_busy_task(void *phandle)
|
||||
}
|
||||
}
|
||||
|
||||
// Start the high priority task to mimic the case when the modbus
|
||||
// tasks do not get time quota from RTOS.
|
||||
TaskHandle_t test_slave_start_busy_task()
|
||||
void test_common_task_start(TaskHandle_t task_handle, uint32_t value)
|
||||
{
|
||||
TaskHandle_t busy_task_handle = NULL;
|
||||
TEST_ASSERT_TRUE(xTaskCreatePinnedToCore(test_busy_task, "busy_task",
|
||||
TEST_TASK_STACK_SIZE,
|
||||
NULL, TEST_BUSY_TASK_PRIO,
|
||||
&busy_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
return busy_task_handle;
|
||||
// Directly notify the task waiting to start loop
|
||||
test_common_task_notify_start(task_handle, value);
|
||||
}
|
||||
|
||||
void test_slave_stop_busy_task(TaskHandle_t busy_task_handle)
|
||||
int test_common_task_start_all(uint32_t value)
|
||||
{
|
||||
vTaskDelete(busy_task_handle);
|
||||
task_entry_t *it = NULL;
|
||||
if (LIST_EMPTY(&s_task_list)) {
|
||||
return 0;
|
||||
}
|
||||
int task_count = 0;
|
||||
LIST_FOREACH(it, &s_task_list, entries) {
|
||||
test_common_task_notify_start(it->task_handle, value);
|
||||
task_count++;
|
||||
}
|
||||
return task_count;
|
||||
}
|
||||
|
||||
bool test_common_task_wait_done(TaskHandle_t task_handle, TickType_t timeout_ticks)
|
||||
{
|
||||
task_entry_t *it = test_task_find_entry(task_handle);
|
||||
if (it && (xSemaphoreTake(it->task_sema_handle, timeout_ticks) == pdTRUE)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool test_common_task_wait_done_delete(TaskHandle_t task_handle, TickType_t task_timeout_ticks)
|
||||
{
|
||||
task_entry_t *it = test_task_find_entry(task_handle);
|
||||
return task_wait_done_and_remove(it, task_timeout_ticks);
|
||||
}
|
||||
|
||||
int test_common_task_wait_done_delete_all(TickType_t task_timeout_tick)
|
||||
{
|
||||
task_entry_t *it, *ptmp = NULL;
|
||||
int task_count = 0;
|
||||
if (LIST_EMPTY(&s_task_list)) {
|
||||
return 0;
|
||||
}
|
||||
LIST_FOREACH_SAFE(it, &s_task_list, entries, ptmp) {
|
||||
task_wait_done_and_remove(it, task_timeout_tick);
|
||||
task_count++;
|
||||
}
|
||||
return task_count;
|
||||
}
|
||||
|
||||
void test_common_task_delete(TaskHandle_t task_handle)
|
||||
{
|
||||
task_entry_t *it = test_task_find_entry(task_handle);
|
||||
if (it) {
|
||||
task_entry_remove(it);
|
||||
}
|
||||
}
|
||||
|
||||
void test_common_task_delete_all()
|
||||
{
|
||||
task_entry_t *it = NULL;
|
||||
while ((it = LIST_FIRST(&s_task_list))) {
|
||||
task_entry_remove(it);
|
||||
}
|
||||
}
|
||||
|
||||
void *test_common_task_get_instance(TaskHandle_t task_handle)
|
||||
{
|
||||
task_entry_t *it = test_task_find_entry(task_handle);
|
||||
if (it) {
|
||||
return it->inst_handle;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Start the high priority task to mimic the case when the modbus
|
||||
// tasks do not get time quota from RTOS.
|
||||
TaskHandle_t test_common_start_busy_task(uint32_t priority)
|
||||
{
|
||||
TaskHandle_t busy_task_handle = NULL;
|
||||
if (!priority) {
|
||||
priority = TEST_BUSY_TASK_PRIO;
|
||||
}
|
||||
|
||||
TEST_ASSERT_TRUE(xTaskCreatePinnedToCore(test_busy_task, "busy_task",
|
||||
TEST_TASK_STACK_SIZE,
|
||||
NULL, priority,
|
||||
&busy_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
test_task_add_entry(busy_task_handle, NULL);
|
||||
return busy_task_handle;
|
||||
}
|
||||
|
||||
void test_common_start()
|
||||
@@ -131,47 +280,12 @@ void test_common_start()
|
||||
#ifdef CONFIG_HEAP_TRACING
|
||||
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
|
||||
#endif
|
||||
|
||||
tasks_done_queue = xQueueCreate(TEST_NOTIF_SIZE, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint32_t test_common_wait_done(TickType_t timeout_ticks)
|
||||
{
|
||||
uint32_t tmp_val = 0;
|
||||
|
||||
if (xQueueReceive(tasks_done_queue, &tmp_val, timeout_ticks) == pdTRUE) {
|
||||
return tmp_val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t test_comon_notify_done(uint32_t value)
|
||||
{
|
||||
uint32_t tmp_val = value;
|
||||
return (uint32_t)xQueueSend(tasks_done_queue, (const void*)&tmp_val, TEST_NOTIF_SEND_TOUT);
|
||||
}
|
||||
|
||||
static uint32_t test_common_task_wait_start(TickType_t timeout_ticks)
|
||||
{
|
||||
static uint32_t notify_value = 0;
|
||||
|
||||
if (xTaskNotifyWait(0, 0, ¬ify_value, timeout_ticks) == pdTRUE) {
|
||||
ESP_LOGW(TAG, "Task: 0x%" PRIx32 ", get notify value = %d",
|
||||
(uint32_t)xTaskGetCurrentTaskHandle(), (int)notify_value);
|
||||
return pdTRUE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_common_task_notify_start(TaskHandle_t task_handle, uint32_t value)
|
||||
{
|
||||
ESP_LOGW(TAG, "Notify task 0x%" PRIx32, (uint32_t)task_handle);
|
||||
TEST_ASSERT_EQUAL_INT(xTaskNotify(task_handle, value, eSetValueWithOverwrite), pdTRUE);
|
||||
LIST_INIT(&s_task_list);
|
||||
}
|
||||
|
||||
void test_common_stop()
|
||||
{
|
||||
vQueueDelete(tasks_done_queue);
|
||||
//vQueueDelete(tasks_done_queue);
|
||||
holding_registers[CID_DEV_REG_COUNT] = 0;
|
||||
test_error_counter = 0;
|
||||
test_good_counter = 0;
|
||||
@@ -183,7 +297,6 @@ void test_common_stop()
|
||||
ESP_ERROR_CHECK( heap_trace_stop() );
|
||||
heap_trace_dump();
|
||||
#endif
|
||||
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
test_common_check_leak(before_free_8bit, after_free_8bit, "8BIT",
|
||||
@@ -192,11 +305,29 @@ void test_common_stop()
|
||||
CONFIG_MB_TEST_LEAK_WARN_LEVEL, CONFIG_MB_TEST_LEAK_CRITICAL_LEVEL);
|
||||
}
|
||||
|
||||
static uint32_t test_common_task_wait_start(TickType_t timeout_ticks)
|
||||
{
|
||||
static uint32_t notify_value = 0;
|
||||
|
||||
if (xTaskNotifyWait(0, 0, ¬ify_value, timeout_ticks) == pdTRUE) {
|
||||
ESP_LOGD(TAG, "Task: 0x%" PRIx32 ", get notify value = %u",
|
||||
(uint32_t)xTaskGetCurrentTaskHandle(), (unsigned)notify_value);
|
||||
return pdTRUE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_common_task_notify_start(TaskHandle_t task_handle, uint32_t value)
|
||||
{
|
||||
ESP_LOGD(TAG, "Notify task start 0x%" PRIx32, (uint32_t)task_handle);
|
||||
TEST_ASSERT_EQUAL_INT(xTaskNotify(task_handle, value, eSetValueWithOverwrite), pdTRUE);
|
||||
}
|
||||
|
||||
void test_common_check_leak(size_t before_free,
|
||||
size_t after_free,
|
||||
const char *type,
|
||||
size_t warn_threshold,
|
||||
size_t critical_threshold)
|
||||
size_t after_free,
|
||||
const char *type,
|
||||
size_t warn_threshold,
|
||||
size_t critical_threshold)
|
||||
{
|
||||
int free_delta = (int)after_free - (int)before_free;
|
||||
printf("MALLOC_CAP_%s usage: Free memory delta: %d Leak threshold: -%u \n",
|
||||
@@ -222,7 +353,7 @@ void test_common_check_leak(size_t before_free,
|
||||
}
|
||||
|
||||
// Helper function to read one characteristic from slave
|
||||
esp_err_t read_modbus_parameter(void *handle, uint16_t cid, uint16_t *par_data)
|
||||
esp_err_t test_common_read_modbus_parameter(void *handle, uint16_t cid, uint16_t *par_data)
|
||||
{
|
||||
const mb_parameter_descriptor_t *param_descriptor = NULL;
|
||||
|
||||
@@ -312,16 +443,16 @@ static void test_master_task(void *arg)
|
||||
switch (req_type)
|
||||
{
|
||||
case RT_HOLDING_RD:
|
||||
err = read_modbus_parameter(mbm_handle, CID_DEV_REG0, &holding_registers[CID_DEV_REG0]);
|
||||
err = test_common_read_modbus_parameter(mbm_handle, CID_DEV_REG0, &holding_registers[CID_DEV_REG0]);
|
||||
CHECK_PAR_VALUE(CID_DEV_REG0, err, holding_registers[CID_DEV_REG0], TEST_REG_VAL1);
|
||||
|
||||
err = read_modbus_parameter(mbm_handle, CID_DEV_REG1, &holding_registers[CID_DEV_REG1]);
|
||||
err = test_common_read_modbus_parameter(mbm_handle, CID_DEV_REG1, &holding_registers[CID_DEV_REG1]);
|
||||
CHECK_PAR_VALUE(CID_DEV_REG1, err, holding_registers[CID_DEV_REG1], TEST_REG_VAL2);
|
||||
|
||||
err = read_modbus_parameter(mbm_handle, CID_DEV_REG2, &holding_registers[CID_DEV_REG2]);
|
||||
err = test_common_read_modbus_parameter(mbm_handle, CID_DEV_REG2, &holding_registers[CID_DEV_REG2]);
|
||||
CHECK_PAR_VALUE(CID_DEV_REG2, err, holding_registers[CID_DEV_REG2], TEST_REG_VAL3);
|
||||
|
||||
err = read_modbus_parameter(mbm_handle, CID_DEV_REG3, &holding_registers[CID_DEV_REG3]);
|
||||
err = test_common_read_modbus_parameter(mbm_handle, CID_DEV_REG3, &holding_registers[CID_DEV_REG3]);
|
||||
CHECK_PAR_VALUE(CID_DEV_REG3, err, holding_registers[CID_DEV_REG3], TEST_REG_VAL4);
|
||||
req_type = RT_HOLDING_WR;
|
||||
break;
|
||||
@@ -344,16 +475,17 @@ static void test_master_task(void *arg)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
write_modbus_parameter(mbm_handle, CID_DEV_REG_COUNT, &cycle_counter);
|
||||
vTaskDelay(TEST_TASK_TICK_TIME); // Let the IDLE task to trigger
|
||||
if (holding_registers[CID_DEV_REG_COUNT] >= TEST_TASK_CYCLE_COUNTER) {
|
||||
ESP_LOGI(TAG, "Stop master: %p.", mbm_handle);
|
||||
break;
|
||||
} else {
|
||||
write_modbus_parameter(mbm_handle, CID_DEV_REG_COUNT, &cycle_counter);
|
||||
vTaskDelay(TEST_TASK_TICK_TIME); // Let the IDLE task to trigger
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Destroy master, inst: %p.", mbm_handle);
|
||||
TEST_ESP_OK(mbc_master_delete(mbm_handle));
|
||||
test_comon_notify_done((uint32_t)xTaskGetCurrentTaskHandle());
|
||||
test_common_task_notify_done(xTaskGetCurrentTaskHandle());
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
@@ -387,18 +519,20 @@ static void test_slave_task(void *arg)
|
||||
}
|
||||
vTaskDelay(TEST_TASK_TICK_TIME); // Let IDLE task to trigger
|
||||
if (holding_registers[CID_DEV_REG_COUNT] >= TEST_TASK_CYCLE_COUNTER) {
|
||||
ESP_LOGI(TAG, "Stop slave: %p.", mbs_handle);
|
||||
ESP_LOGD(TAG, "Stop slave: %p.", mbs_handle);
|
||||
vTaskDelay(TEST_TASK_TICK_TIME); // Let master to get response from slave prior to close
|
||||
break;
|
||||
}
|
||||
}
|
||||
ESP_LOGI(TAG, "Destroy slave, inst: %p.", mbs_handle);
|
||||
TEST_ESP_OK(mbc_slave_delete(mbs_handle));
|
||||
test_comon_notify_done((uint32_t)xTaskGetCurrentTaskHandle());
|
||||
ESP_LOGD(TAG, "Notify task done, inst: %p.", xTaskGetCurrentTaskHandle());
|
||||
test_common_task_notify_done(xTaskGetCurrentTaskHandle());
|
||||
vTaskDelay(10);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
void test_slave_setup_start(void *mbs_handle)
|
||||
void test_common_slave_setup_start(void *mbs_handle)
|
||||
{
|
||||
TEST_ASSERT_TRUE(mbs_handle);
|
||||
mb_register_area_descriptor_t reg_area;
|
||||
@@ -425,7 +559,10 @@ void test_slave_setup_start(void *mbs_handle)
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_RTU_EN || CONFIG_FMB_COMM_MODE_ASCII_EN)
|
||||
|
||||
TaskHandle_t test_master_serial_create(mb_communication_info_t *pconfig, const mb_parameter_descriptor_t *pdescr, uint16_t descr_size)
|
||||
TaskHandle_t test_common_master_serial_create(mb_communication_info_t *pconfig,
|
||||
uint32_t priority,
|
||||
const mb_parameter_descriptor_t *pdescr,
|
||||
uint16_t descr_size)
|
||||
{
|
||||
if (!pconfig || !pdescr) {
|
||||
ESP_LOGI(TAG, "invalid master configuration.");
|
||||
@@ -442,16 +579,21 @@ TaskHandle_t test_master_serial_create(mb_communication_info_t *pconfig, const m
|
||||
|
||||
TEST_ESP_OK(mbc_master_start(mbm_handle));
|
||||
ESP_LOGI(TAG, "%p, modbus master start...", mbm_handle) ;
|
||||
|
||||
if (priority) {
|
||||
priority = TEST_TASK_PRIO_MASTER;
|
||||
}
|
||||
|
||||
char* port_name = pbase->mb_base->descr.parent_name;
|
||||
TEST_ASSERT_TRUE(xTaskCreatePinnedToCore(test_master_task, port_name,
|
||||
TEST_TASK_STACK_SIZE,
|
||||
mbm_handle, (TEST_TASK_PRIO_MASTER),
|
||||
mbm_handle, priority,
|
||||
&master_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
test_task_add_entry(master_task_handle, mbm_handle);
|
||||
return master_task_handle;
|
||||
}
|
||||
|
||||
TaskHandle_t test_slave_serial_create(mb_communication_info_t *pconfig)
|
||||
TaskHandle_t test_common_slave_serial_create(mb_communication_info_t *pconfig, uint32_t priority)
|
||||
{
|
||||
if (!pconfig) {
|
||||
ESP_LOGI(TAG, "invalid slave configuration.");
|
||||
@@ -464,12 +606,17 @@ TaskHandle_t test_slave_serial_create(mb_communication_info_t *pconfig)
|
||||
|
||||
mbs_controller_iface_t *pbase = mbs_handle;
|
||||
|
||||
test_slave_setup_start(mbs_handle);
|
||||
test_common_slave_setup_start(mbs_handle);
|
||||
|
||||
if (priority) {
|
||||
priority = TEST_TASK_PRIO_SLAVE;
|
||||
}
|
||||
|
||||
TEST_ASSERT_TRUE(xTaskCreatePinnedToCore(test_slave_task, pbase->mb_base->descr.parent_name,
|
||||
TEST_TASK_STACK_SIZE,
|
||||
mbs_handle, (TEST_TASK_PRIO_SLAVE),
|
||||
mbs_handle, priority,
|
||||
&slave_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
test_task_add_entry(slave_task_handle, mbs_handle);
|
||||
return slave_task_handle;
|
||||
}
|
||||
|
||||
@@ -477,7 +624,7 @@ TaskHandle_t test_slave_serial_create(mb_communication_info_t *pconfig)
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
|
||||
|
||||
TaskHandle_t test_master_tcp_create(mb_communication_info_t *pconfig, const mb_parameter_descriptor_t *pdescr, uint16_t descr_size)
|
||||
TaskHandle_t test_common_master_tcp_create(mb_communication_info_t *pconfig, uint32_t priority, const mb_parameter_descriptor_t *pdescr, uint16_t descr_size)
|
||||
{
|
||||
if (!pconfig || !pdescr) {
|
||||
ESP_LOGI(TAG, "invalid master configuration.");
|
||||
@@ -495,15 +642,21 @@ TaskHandle_t test_master_tcp_create(mb_communication_info_t *pconfig, const mb_p
|
||||
TEST_ESP_OK(mbc_master_start(mbm_handle));
|
||||
ESP_LOGI(TAG, "%p, modbus master start...", mbm_handle) ;
|
||||
|
||||
if (priority) {
|
||||
priority = TEST_TASK_PRIO_MASTER;
|
||||
}
|
||||
|
||||
char *port_name = pbase->mb_base->descr.parent_name;
|
||||
TEST_ASSERT_TRUE(xTaskCreatePinnedToCore(test_master_task, port_name,
|
||||
TEST_TASK_STACK_SIZE,
|
||||
mbm_handle, (TEST_TASK_PRIO_MASTER),
|
||||
mbm_handle, priority,
|
||||
&master_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
|
||||
test_task_add_entry(master_task_handle, mbm_handle);
|
||||
return master_task_handle;
|
||||
}
|
||||
|
||||
TaskHandle_t test_slave_tcp_create(mb_communication_info_t *pconfig)
|
||||
TaskHandle_t test_common_slave_tcp_create(mb_communication_info_t *pconfig, uint32_t priority)
|
||||
{
|
||||
if (!pconfig) {
|
||||
ESP_LOGI(TAG, "invalid slave configuration.");
|
||||
@@ -515,12 +668,17 @@ TaskHandle_t test_slave_tcp_create(mb_communication_info_t *pconfig)
|
||||
TEST_ESP_OK(mbc_slave_create_tcp(pconfig, &mbs_handle));
|
||||
|
||||
mbs_controller_iface_t *pbase = mbs_handle;
|
||||
test_slave_setup_start(mbs_handle);
|
||||
test_common_slave_setup_start(mbs_handle);
|
||||
|
||||
if (priority) {
|
||||
priority = TEST_TASK_PRIO_SLAVE;
|
||||
}
|
||||
|
||||
TEST_ASSERT_TRUE(xTaskCreatePinnedToCore(test_slave_task, pbase->mb_base->descr.parent_name,
|
||||
TEST_TASK_STACK_SIZE,
|
||||
mbs_handle, (TEST_TASK_PRIO_SLAVE),
|
||||
mbs_handle, priority,
|
||||
&slave_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
test_task_add_entry(slave_task_handle, mbs_handle);
|
||||
return slave_task_handle;
|
||||
}
|
||||
|
||||
|
||||
+10
-9
@@ -22,11 +22,11 @@ extern "C" {
|
||||
typedef struct mb_base_t mb_base_t; /*!< Type of modbus object */
|
||||
typedef struct mb_port_base_t mb_port_base_t;
|
||||
|
||||
bool mb_port_evt_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
bool mb_port_evt_post(mb_port_base_t *inst, mb_event_t event);
|
||||
bool mb_port_evt_res_take(mb_port_base_t *inst, uint32_t timeout);
|
||||
void mb_port_evt_res_release(mb_port_base_t *inst);
|
||||
mb_err_enum_t mb_port_evt_wait_req_finish(mb_port_base_t *inst);
|
||||
bool mb_port_event_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
bool mb_port_event_post(mb_port_base_t *inst, mb_event_t event);
|
||||
bool mb_port_event_res_take(mb_port_base_t *inst, uint32_t timeout);
|
||||
void mb_port_event_res_release(mb_port_base_t *inst);
|
||||
mb_err_enum_t mb_port_event_wait_req_finish(mb_port_base_t *inst);
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN)
|
||||
|
||||
@@ -91,6 +91,10 @@ mb_exception_t mbs_fn_rw_multi_holding_reg(mb_base_t *inst, uint8_t *frame_ptr,u
|
||||
|
||||
#endif
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
|
||||
|
||||
typedef struct _port_tcp_opts mb_tcp_opts_t;
|
||||
|
||||
mb_err_enum_t mbs_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj);
|
||||
|
||||
mb_err_enum_t mbs_delete(mb_base_t *inst);
|
||||
@@ -99,11 +103,8 @@ mb_err_enum_t mbs_disable(mb_base_t *inst);
|
||||
mb_err_enum_t mbs_poll(mb_base_t *inst);
|
||||
mb_err_enum_t mbs_set_slv_id(mb_base_t *inst, uint8_t slv_id, bool is_running, uint8_t const *slv_idstr, uint16_t slv_idstr_len);
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
|
||||
|
||||
typedef struct _port_tcp_opts mb_tcp_opts_t;
|
||||
|
||||
mb_err_enum_t mbm_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj);
|
||||
mb_uid_info_t *mbm_port_tcp_get_slave_info(mb_port_base_t *inst, uint8_t slave_addr, mb_sock_state_t exp_state);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
idf: ">=4.3"
|
||||
espressif/esp-modbus:
|
||||
version: "^2.0"
|
||||
version: "^2.0.0-beta"
|
||||
override_path: "../../../../"
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@
|
||||
|
||||
#define TEST_MASTER_RESPOND_TOUT_MS CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND
|
||||
|
||||
#define TAG "MODBUS_SERIAL_TEST"
|
||||
#define TAG "MODBUS_CONTROLLER_COMMON_TEST"
|
||||
|
||||
// The workaround to statically link whole test library
|
||||
__attribute__((unused)) bool mb_test_include_impl = 1;
|
||||
__attribute__((unused)) bool mb_test_include_impl = true;
|
||||
|
||||
enum {
|
||||
CID_DEV_REG0_INPUT,
|
||||
@@ -34,7 +34,8 @@ enum {
|
||||
CID_DEV_REG1_INPUT,
|
||||
CID_DEV_REG0_COIL,
|
||||
CID_DEV_REG0_DISCRITE,
|
||||
CID_DEV_REG_CNT
|
||||
CID_DEV_REG_CNT,
|
||||
CID_ITEMS_CNT
|
||||
};
|
||||
|
||||
// Example Data (Object) Dictionary for Modbus parameters
|
||||
@@ -68,7 +69,42 @@ TEST_TEAR_DOWN(unit_test_controller)
|
||||
test_common_stop();
|
||||
}
|
||||
|
||||
TEST(unit_test_controller, test_setup_destroy_master)
|
||||
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
|
||||
|
||||
TEST(unit_test_controller, test_setup_destroy_master_tcp)
|
||||
{
|
||||
mb_communication_info_t master_config = {
|
||||
.tcp_opts.port = TEST_TCP_PORT_NUM,
|
||||
.tcp_opts.mode = MB_TCP,
|
||||
.tcp_opts.addr_type = MB_IPV4,
|
||||
.tcp_opts.ip_addr_table = (void *)(0x44332211),
|
||||
.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,
|
||||
.tcp_opts.ip_netif_ptr = (void *)(0x11223344)
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "TEST: Verify master create-destroy sequence TCP.");
|
||||
|
||||
void *mbm_handle = NULL;
|
||||
mb_base_t *pmb_base = NULL;
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_tcp_create(&master_config.tcp_opts, (void *)&pmb_base));
|
||||
|
||||
mbm_tcp_create_ExpectAnyArgsAndReturn(MB_ENOERR);
|
||||
mbm_tcp_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
mbm_port_tcp_get_slave_info_IgnoreAndReturn((void *)(0x11223344));
|
||||
TEST_ESP_OK(mbc_master_create_tcp(&master_config, &mbm_handle));
|
||||
TEST_ESP_OK(mbc_master_set_descriptor(mbm_handle, &descriptors[0], num_descriptors));
|
||||
TEST_ESP_OK(mbc_master_delete(mbm_handle));
|
||||
ESP_LOGI(TAG, "Test passed successfully.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_RTU_EN || CONFIG_FMB_COMM_MODE_ASCII_EN)
|
||||
|
||||
TEST(unit_test_controller, test_setup_destroy_master_serial)
|
||||
{
|
||||
mb_communication_info_t master_config = {
|
||||
.ser_opts.port = TEST_SER_PORT_NUM,
|
||||
@@ -86,7 +122,7 @@ TEST(unit_test_controller, test_setup_destroy_master)
|
||||
|
||||
void *mbm_handle = NULL;
|
||||
mb_base_t *pmb_base = NULL;
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_serial_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
|
||||
mbm_rtu_create_ExpectAnyArgsAndReturn(MB_ENOERR);
|
||||
mbm_rtu_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
@@ -105,7 +141,7 @@ TEST(unit_test_controller, test_setup_destroy_master)
|
||||
ESP_LOGI(TAG, "Test passed successfully.");
|
||||
}
|
||||
|
||||
TEST(unit_test_controller, test_setup_destroy_slave)
|
||||
TEST(unit_test_controller, test_setup_destroy_slave_serial)
|
||||
{
|
||||
// Initialize and start Modbus controller
|
||||
mb_communication_info_t slave_config = {
|
||||
@@ -122,7 +158,7 @@ TEST(unit_test_controller, test_setup_destroy_slave)
|
||||
ESP_LOGI(TAG, "TEST: Verify slave create-destroy sequence.");
|
||||
void *mbs_handle = NULL;
|
||||
mb_base_t *pmb_base = mbs_handle;
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_create(&slave_config.ser_opts, (void *)&pmb_base));
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_serial_create(&slave_config.ser_opts, (void *)&pmb_base));
|
||||
mbs_rtu_create_ExpectAndReturn(&slave_config.ser_opts, (void *)pmb_base, MB_ENOERR);
|
||||
mbs_rtu_create_IgnoreArg_in_out_obj();
|
||||
mbs_rtu_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
@@ -153,14 +189,14 @@ esp_err_t test_master_registers(int par_index, mb_err_enum_t mb_err)
|
||||
mb_base_t *pmb_base = NULL; // fake mb_base handle
|
||||
void *mbm_handle = NULL;
|
||||
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_serial_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
pmb_base->port_obj = (mb_port_base_t *)0x44556677;
|
||||
mbm_rtu_create_ExpectAnyArgsAndReturn(MB_ENOERR);
|
||||
mbm_rtu_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
TEST_ESP_OK(mbc_master_create_serial(&master_config, &mbm_handle));
|
||||
TEST_ESP_OK(mbc_master_set_descriptor(mbm_handle, &descriptors[0], num_descriptors));
|
||||
mb_port_evt_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_evt_res_release_ExpectAnyArgs();
|
||||
mb_port_event_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_event_res_release_ExpectAnyArgs();
|
||||
TEST_ESP_OK(mbc_master_start(mbm_handle));
|
||||
|
||||
const mb_parameter_descriptor_t *param_descriptor = NULL;
|
||||
@@ -225,7 +261,7 @@ esp_err_t test_master_registers(int par_index, mb_err_enum_t mb_err)
|
||||
// Check if modbus controller object forms correct modbus request from data dictionary
|
||||
// and is able to transfer data using mb_object. Check possible errors returned back from
|
||||
// mb_object and make sure the modbus controller handles them correctly.
|
||||
TEST(unit_test_controller, test_master_send_request)
|
||||
TEST(unit_test_controller, test_master_send_request_serial)
|
||||
{
|
||||
TEST_ESP_ERR(ESP_OK, test_master_registers(CID_DEV_REG0_INPUT, MB_ENOERR));
|
||||
TEST_ESP_ERR(ESP_ERR_TIMEOUT, test_master_registers(CID_DEV_REG0_INPUT, MB_ETIMEDOUT));
|
||||
@@ -237,9 +273,19 @@ TEST(unit_test_controller, test_master_send_request)
|
||||
TEST_ESP_ERR(ESP_ERR_TIMEOUT, test_master_registers(CID_DEV_REG0_DISCRITE, MB_ETIMEDOUT));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_GROUP_RUNNER(unit_test_controller)
|
||||
{
|
||||
RUN_TEST_CASE(unit_test_controller, test_setup_destroy_master);
|
||||
RUN_TEST_CASE(unit_test_controller, test_setup_destroy_slave);
|
||||
RUN_TEST_CASE(unit_test_controller, test_master_send_request);
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_RTU_EN || CONFIG_FMB_COMM_MODE_ASCII_EN)
|
||||
RUN_TEST_CASE(unit_test_controller, test_setup_destroy_master_serial);
|
||||
RUN_TEST_CASE(unit_test_controller, test_setup_destroy_slave_serial);
|
||||
RUN_TEST_CASE(unit_test_controller, test_master_send_request_serial);
|
||||
#endif
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
|
||||
RUN_TEST_CASE(unit_test_controller, test_setup_destroy_master_tcp);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ from pytest_embedded import Dut
|
||||
|
||||
|
||||
CONFIGS = [
|
||||
pytest.param('serial', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.esp32s3, pytest.mark.esp32c3]),
|
||||
pytest.param('generic', marks=[pytest.mark.esp32, pytest.mark.esp32s2, pytest.mark.esp32s3, pytest.mark.esp32c3]),
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.generic_multi_device
|
||||
@pytest.mark.multi_dut_modbus_generic
|
||||
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
||||
def test_modbus_controller_common(dut: Dut) -> None:
|
||||
dut.expect_unity_test_output()
|
||||
|
||||
+2
-2
@@ -9,12 +9,12 @@ CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
|
||||
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_COMM_MODE_TCP_EN=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=y
|
||||
CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=2000
|
||||
CONFIG_FMB_MASTER_DELAY_MS_CONVERT=300
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_MB_PORT_ADAPTER_EN=y
|
||||
CONFIG_MB_PORT_ADAPTER_EN=n
|
||||
CONFIG_MB_TEST_SLAVE_TASK_PRIO=4
|
||||
CONFIG_MB_TEST_MASTER_TASK_PRIO=4
|
||||
CONFIG_MB_TEST_COMM_CYCLE_COUNTER=10
|
||||
+5
-5
@@ -73,11 +73,11 @@ extern "C" {
|
||||
typedef struct mb_base_t mb_base_t; /*!< Type of modbus object */
|
||||
typedef struct mb_port_base_t mb_port_base_t;
|
||||
|
||||
bool mb_port_evt_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
bool mb_port_evt_post(mb_port_base_t *inst, mb_event_t event);
|
||||
bool mb_port_evt_res_take(mb_port_base_t *inst, uint32_t timeout);
|
||||
void mb_port_evt_res_release(mb_port_base_t *inst);
|
||||
mb_err_enum_t mb_port_evt_wait_req_finish(mb_port_base_t *inst);
|
||||
bool mb_port_event_get(mb_port_base_t *inst, mb_event_t *pevent);
|
||||
bool mb_port_event_post(mb_port_base_t *inst, mb_event_t event);
|
||||
bool mb_port_event_res_take(mb_port_base_t *inst, uint32_t timeout);
|
||||
void mb_port_event_res_release(mb_port_base_t *inst);
|
||||
mb_err_enum_t mb_port_event_wait_req_finish(mb_port_base_t *inst);
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
idf: ">=4.3"
|
||||
espressif/esp-modbus:
|
||||
version: "^2.0"
|
||||
version: "^2.0.0-beta"
|
||||
override_path: "../../../../"
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define TAG "MB_CONTROLLER_TEST"
|
||||
|
||||
// The workaround to statically link whole test library
|
||||
__attribute__((unused)) bool mb_test_include_impl = 1;
|
||||
__attribute__((unused)) bool mb_test_include_impl = true;
|
||||
|
||||
enum
|
||||
{
|
||||
@@ -106,7 +106,7 @@ static void test_slave_check_descriptor(int par_index)
|
||||
void *mbs_handle = NULL;
|
||||
mb_base_t *pmb_base = NULL; // fake mb_base handle
|
||||
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_create(&slave_config.ser_opts, (void *)&pmb_base));
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_serial_create(&slave_config.ser_opts, (void *)&pmb_base));
|
||||
pmb_base->port_obj = (mb_port_base_t *)0x44556677;
|
||||
mbs_rtu_create_ExpectAnyArgsAndReturn(MB_ENOERR);
|
||||
mbs_rtu_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
@@ -173,15 +173,15 @@ static esp_err_t test_master_read_req(int par_index, mb_err_enum_t mb_err)
|
||||
mb_base_t *pmb_base = NULL; // fake mb_base handle
|
||||
void *mbm_handle = NULL;
|
||||
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_serial_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
pmb_base->port_obj = (mb_port_base_t *)0x44556677;
|
||||
mbm_rtu_create_ExpectAnyArgsAndReturn(MB_ENOERR);
|
||||
mbm_rtu_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
TEST_ESP_OK(mbc_master_create_serial(&master_config, &mbm_handle));
|
||||
TEST_ESP_OK(mbc_master_set_descriptor(mbm_handle, &descriptors[0], num_descriptors));
|
||||
mb_port_evt_post_ExpectAndReturn(pmb_base->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START), true);
|
||||
mb_port_event_post_ExpectAndReturn(pmb_base->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START), true);
|
||||
TEST_ESP_OK(mbc_master_start(mbm_handle));
|
||||
mb_port_evt_wait_req_finish_ExpectAndReturn(pmb_base->port_obj, mb_err);
|
||||
mb_port_event_wait_req_finish_ExpectAndReturn(pmb_base->port_obj, mb_err);
|
||||
|
||||
const mb_parameter_descriptor_t *param_descriptor = NULL;
|
||||
TEST_ESP_OK(mbc_master_get_cid_info(mbm_handle, par_index, ¶m_descriptor));
|
||||
@@ -189,10 +189,10 @@ static esp_err_t test_master_read_req(int par_index, mb_err_enum_t mb_err)
|
||||
uint8_t type = 0; // type of parameter from dictionary
|
||||
uint8_t pdata[100] = {0};
|
||||
ESP_LOGI(TAG, "Test CID #%d, %s, %s", param_descriptor->cid, param_descriptor->param_key, param_descriptor->param_units);
|
||||
mb_port_evt_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_evt_res_release_ExpectAnyArgs();
|
||||
mb_port_evt_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_evt_res_release_ExpectAnyArgs();
|
||||
mb_port_event_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_event_res_release_ExpectAnyArgs();
|
||||
mb_port_event_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_event_res_release_ExpectAnyArgs();
|
||||
|
||||
// Call the read method of modbus controller
|
||||
esp_err_t err = mbc_master_get_parameter(mbm_handle, par_index, pdata, &type);
|
||||
@@ -264,14 +264,14 @@ static esp_err_t test_master_write_req(int par_index, mb_err_enum_t mb_err)
|
||||
mb_base_t *pmb_base = NULL; // fake mb_base handle
|
||||
void *mbm_handle = NULL;
|
||||
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_serial_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
pmb_base->port_obj = (mb_port_base_t *)0x44556677;
|
||||
mbm_rtu_create_ExpectAnyArgsAndReturn(MB_ENOERR);
|
||||
mbm_rtu_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
TEST_ESP_OK(mbc_master_create_serial(&master_config, &mbm_handle));
|
||||
TEST_ESP_OK(mbc_master_set_descriptor(mbm_handle, &descriptors[0], num_descriptors));
|
||||
mb_port_evt_post_ExpectAndReturn(pmb_base->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START), true);
|
||||
mb_port_evt_wait_req_finish_ExpectAndReturn(pmb_base->port_obj, mb_err);
|
||||
mb_port_event_post_ExpectAndReturn(pmb_base->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START), true);
|
||||
mb_port_event_wait_req_finish_ExpectAndReturn(pmb_base->port_obj, mb_err);
|
||||
TEST_ESP_OK(mbc_master_start(mbm_handle));
|
||||
|
||||
const mb_parameter_descriptor_t *param_descriptor = NULL;
|
||||
@@ -280,10 +280,10 @@ static esp_err_t test_master_write_req(int par_index, mb_err_enum_t mb_err)
|
||||
uint8_t type = 0; // type of parameter from dictionary
|
||||
uint8_t reg_data[] = {0x11, 0x22, 0x33, 0x44};
|
||||
ESP_LOGI(TAG, "Test CID #%d, %s, %s", param_descriptor->cid, param_descriptor->param_key, param_descriptor->param_units);
|
||||
mb_port_evt_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_evt_res_release_ExpectAnyArgs();
|
||||
mb_port_evt_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_evt_res_release_ExpectAnyArgs();
|
||||
mb_port_event_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_event_res_release_ExpectAnyArgs();
|
||||
mb_port_event_res_take_ExpectAnyArgsAndReturn(true);
|
||||
mb_port_event_res_release_ExpectAnyArgs();
|
||||
|
||||
// Call the read method of modbus controller
|
||||
esp_err_t err = mbc_master_set_parameter(mbm_handle, par_index, reg_data, &type);
|
||||
@@ -350,7 +350,7 @@ static esp_err_t test_master_check_callback(int par_index, mb_err_enum_t mb_err)
|
||||
mb_base_t *pmb_base = NULL; // fake mb_base handle
|
||||
void *mbm_handle = NULL;
|
||||
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
TEST_ESP_ERR(MB_ENOERR, mb_stub_serial_create(&master_config.ser_opts, (void *)&pmb_base));
|
||||
pmb_base->port_obj = (mb_port_base_t *)0x44556677;
|
||||
mbm_rtu_create_ExpectAnyArgsAndReturn(MB_ENOERR);
|
||||
mbm_rtu_create_ReturnThruPtr_in_out_obj((void **)&pmb_base);
|
||||
|
||||
@@ -10,7 +10,7 @@ CONFIGS = [
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.generic_multi_device
|
||||
@pytest.mark.multi_dut_modbus_generic
|
||||
@pytest.mark.parametrize('config', CONFIGS, indirect=True)
|
||||
def test_modbus_controller_mapping(dut: Dut) -> None:
|
||||
dut.expect_unity_test_output()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dependencies:
|
||||
idf: ">=4.3"
|
||||
espressif/esp-modbus:
|
||||
version: "^2.0"
|
||||
version: "^2.0.0-beta"
|
||||
override_path: "../../../../"
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
#@pytest.mark.supported_targets
|
||||
@pytest.mark.esp32 # test on esp32 for now
|
||||
@pytest.mark.multi_dut_modbus_generic
|
||||
def test_mb_endianness_utils(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
@@ -11,4 +11,10 @@
|
||||
#include "mb_common.h"
|
||||
#include "mb_port_types.h"
|
||||
|
||||
mb_err_enum_t mb_stub_create(mb_serial_opts_t *ser_opts, void **in_out_obj);
|
||||
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
|
||||
mb_err_enum_t mb_stub_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj);
|
||||
#endif
|
||||
|
||||
#if (MB_MASTER_ASCII_ENABLED || MB_MASTER_RTU_ENABLED)
|
||||
mb_err_enum_t mb_stub_serial_create(mb_serial_opts_t *ser_opts, void **in_out_obj);
|
||||
#endif
|
||||
|
||||
@@ -24,10 +24,9 @@ typedef struct
|
||||
mb_base_t base;
|
||||
uint16_t pdu_snd_len;
|
||||
uint8_t dst_addr;
|
||||
uint8_t snd_buf[MB_RTU_SER_PDU_SIZE_MAX];
|
||||
uint8_t snd_buf[MB_BUFFER_SIZE];
|
||||
} mb_object_t;
|
||||
|
||||
mb_err_enum_t mb_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj);
|
||||
|
||||
mb_err_enum_t mb_delete(mb_base_t *inst);
|
||||
mb_err_enum_t mb_enable(mb_base_t *inst);
|
||||
@@ -40,11 +39,49 @@ static void mb_set_dest_addr(mb_base_t *inst, uint8_t dest_addr);
|
||||
static uint8_t mb_get_dest_addr(mb_base_t *inst);
|
||||
static void mb_get_pdu_send_buf(mb_base_t *inst, uint8_t **pbuf);
|
||||
|
||||
//mb_err_enum_t mb_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj);
|
||||
|
||||
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
|
||||
|
||||
mb_err_enum_t mb_stub_tcp_create(mb_tcp_opts_t *tcp_opts, void **in_out_obj)
|
||||
{
|
||||
MB_RETURN_ON_FALSE((tcp_opts && in_out_obj), MB_EINVAL, TAG, "invalid options for the instance.");
|
||||
mb_err_enum_t ret = MB_ENOERR;
|
||||
mb_object_t *mb_obj = NULL;
|
||||
mb_obj = (mb_object_t *)calloc(1, sizeof(mb_object_t));
|
||||
MB_GOTO_ON_FALSE((mb_obj), MB_EILLSTATE, error, TAG, "no mem for mb master instance.");
|
||||
CRITICAL_SECTION_INIT(mb_obj->base.lock);
|
||||
ESP_LOGW(TAG, "Create fake mb_base object.");
|
||||
mb_obj->base.delete = mb_delete;
|
||||
mb_obj->base.enable = mb_enable;
|
||||
mb_obj->base.disable = mb_disable;
|
||||
mb_obj->base.poll = mb_poll;
|
||||
mb_obj->base.set_dest_addr = mb_set_dest_addr;
|
||||
mb_obj->base.get_dest_addr = mb_get_dest_addr;
|
||||
mb_obj->base.set_send_len = mb_set_pdu_send_length;
|
||||
mb_obj->base.get_send_len = mb_get_pdu_send_length;
|
||||
mb_obj->base.get_send_buf = mb_get_pdu_send_buf;
|
||||
mb_obj->base.descr.parent = *in_out_obj;
|
||||
mb_obj->base.descr.is_master = true;
|
||||
mb_obj->base.descr.obj_name = (char *)TAG;
|
||||
mb_obj->base.descr.inst_index = mb_port_get_inst_counter_inc();
|
||||
*in_out_obj = (void *)mb_obj;
|
||||
return MB_ENOERR;
|
||||
|
||||
error:
|
||||
CRITICAL_SECTION_CLOSE(mb_obj->base.lock);
|
||||
free(mb_obj);
|
||||
mb_port_get_inst_counter_dec();
|
||||
ESP_LOGW(TAG, "Delete fake mb_base object.");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (MB_MASTER_ASCII_ENABLED || MB_MASTER_RTU_ENABLED)
|
||||
|
||||
typedef struct _port_serial_opts mb_serial_opts_t;
|
||||
|
||||
mb_err_enum_t mb_stub_create(mb_serial_opts_t *ser_opts, void **in_out_obj)
|
||||
mb_err_enum_t mb_stub_serial_create(mb_serial_opts_t *ser_opts, void **in_out_obj)
|
||||
{
|
||||
MB_RETURN_ON_FALSE((ser_opts && in_out_obj), MB_EINVAL, TAG, "invalid options for the instance.");
|
||||
mb_err_enum_t ret = MB_ENOERR;
|
||||
@@ -146,13 +183,7 @@ mb_err_enum_t mb_poll(mb_base_t *inst)
|
||||
{
|
||||
mb_err_enum_t status = MB_ENOERR;
|
||||
ESP_LOGW(TAG, "Poll function called of fake mb_base object.");
|
||||
//mb_object_t *mb_obj = __containerof(inst, mb_object_t, base);
|
||||
vTaskDelay(1);
|
||||
//mb_port_evt_get_ExpectAnyArgsAndReturn(true);
|
||||
// mb_event_t event = {0};
|
||||
// if (mb_port_evt_get(mb_obj->base.port_obj, &event)) {
|
||||
|
||||
// }
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ typedef struct
|
||||
uint16_t snd_buf_cnt;
|
||||
uint16_t rcv_buf_pos;
|
||||
bool frame_is_broadcast;
|
||||
volatile mb_tmr_mode_enum_t cur_tmr_mode;
|
||||
volatile mb_timer_mode_enum_t cur_timer_mode;
|
||||
mb_rtu_state_enum_t state;
|
||||
} mbm_rtu_transp_t;
|
||||
|
||||
@@ -36,7 +36,7 @@ static mb_err_enum_t mbm_rtu_transp_receive(mb_trans_base_t *inst, uint8_t *rcv_
|
||||
static mb_err_enum_t mbm_rtu_transp_send(mb_trans_base_t *inst, uint8_t slv_addr, const uint8_t *frame_ptr, uint16_t len);
|
||||
static bool mbm_rtu_transp_rcv_fsm(mb_trans_base_t *inst);
|
||||
static bool mbm_rtu_transp_snd_fsm(mb_trans_base_t *inst);
|
||||
static bool mbm_rtu_transp_tmr_35_expired(void *inst);
|
||||
static bool mbm_rtu_transp_timer_expired(void *inst);
|
||||
static void mbm_rtu_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
|
||||
static void mbm_rtu_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
|
||||
// static uint16_t mbm_rtu_transp_get_snd_len(mb_trans_base_t *inst);
|
||||
@@ -67,17 +67,17 @@ mb_err_enum_t mbm_rtu_transp_create(mb_serial_opts_t *ser_opts, void **in_out_in
|
||||
mb_port_base_t *port_obj = (mb_port_base_t *)*in_out_inst;
|
||||
ret = mb_port_ser_create(ser_opts, &port_obj);
|
||||
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EILLSTATE, error, TAG, "serial port creation, err: %d", ret);
|
||||
ret = mb_port_tmr_create(port_obj, MB_RTU_GET_T35_VAL(ser_opts->baudrate));
|
||||
ret = mb_port_timer_create(port_obj, MB_RTU_GET_T35_VAL(ser_opts->baudrate));
|
||||
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EILLSTATE, error, TAG, "timer port creation, err: %d", ret);
|
||||
// Override default response time if defined
|
||||
if (ser_opts->response_tout_ms) {
|
||||
mb_port_tmr_set_response_time(port_obj, ser_opts->response_tout_ms);
|
||||
mb_port_timer_set_response_time(port_obj, ser_opts->response_tout_ms);
|
||||
}
|
||||
ret = mb_port_evt_create(port_obj);
|
||||
ret = mb_port_event_create(port_obj);
|
||||
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EILLSTATE, error, TAG, "event port creation, err: %d", ret);
|
||||
transp->base.port_obj = port_obj;
|
||||
// Set callback function pointer for the timer
|
||||
port_obj->cb.tmr_expired = mbm_rtu_transp_tmr_35_expired;
|
||||
port_obj->cb.tmr_expired = mbm_rtu_transp_timer_expired;
|
||||
port_obj->cb.tx_empty = NULL;
|
||||
port_obj->cb.byte_rcvd = NULL;
|
||||
port_obj->arg = (void *)transp;
|
||||
@@ -89,10 +89,10 @@ mb_err_enum_t mbm_rtu_transp_create(mb_serial_opts_t *ser_opts, void **in_out_in
|
||||
|
||||
error:
|
||||
if (port_obj->timer_obj) {
|
||||
mb_port_tmr_delete(port_obj);
|
||||
mb_port_timer_delete(port_obj);
|
||||
}
|
||||
if (port_obj->event_obj) {
|
||||
mb_port_evt_delete(port_obj);
|
||||
mb_port_event_delete(port_obj);
|
||||
}
|
||||
if (port_obj) {
|
||||
mb_port_ser_delete(port_obj);
|
||||
@@ -106,8 +106,8 @@ bool mbm_rtu_transp_delete(mb_trans_base_t *inst)
|
||||
{
|
||||
mbm_rtu_transp_t *transp = __containerof(inst, mbm_rtu_transp_t, base);
|
||||
mb_port_ser_delete(transp->base.port_obj);
|
||||
mb_port_tmr_delete(transp->base.port_obj);
|
||||
mb_port_evt_delete(transp->base.port_obj);
|
||||
mb_port_timer_delete(transp->base.port_obj);
|
||||
mb_port_event_delete(transp->base.port_obj);
|
||||
CRITICAL_SECTION_CLOSE(inst->lock);
|
||||
free(transp);
|
||||
return true;
|
||||
@@ -119,17 +119,17 @@ static void mbm_rtu_transp_start(mb_trans_base_t *inst)
|
||||
transp->state = MB_RTU_STATE_INIT;
|
||||
CRITICAL_SECTION(inst->lock) {
|
||||
mb_port_ser_enable(inst->port_obj);
|
||||
mb_port_tmr_enable(inst->port_obj);
|
||||
mb_port_timer_enable(inst->port_obj);
|
||||
};
|
||||
/* No special startup required for RTU. */
|
||||
(void)mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
|
||||
(void)mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
|
||||
}
|
||||
|
||||
static void mbm_rtu_transp_stop(mb_trans_base_t *inst)
|
||||
{
|
||||
CRITICAL_SECTION(inst->lock) {
|
||||
mb_port_ser_disable(inst->port_obj);
|
||||
mb_port_tmr_disable(inst->port_obj);
|
||||
mb_port_timer_disable(inst->port_obj);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -207,9 +207,9 @@ static mb_err_enum_t mbm_rtu_transp_send(mb_trans_base_t *inst, uint8_t slv_addr
|
||||
// If the frame is broadcast, master will enable timer of convert delay,
|
||||
// else master will enable timer of respond timeout. */
|
||||
if (transp->frame_is_broadcast) {
|
||||
mb_port_tmr_convert_delay_enable(transp->base.port_obj);
|
||||
mb_port_timer_convert_delay_enable(transp->base.port_obj);
|
||||
} else {
|
||||
mb_port_tmr_respond_timeout_enable(transp->base.port_obj);
|
||||
mb_port_timer_respond_timeout_enable(transp->base.port_obj);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -231,35 +231,35 @@ static bool mbm_rtu_transp_snd_fsm(mb_trans_base_t *inst)
|
||||
}
|
||||
|
||||
|
||||
static bool mbm_rtu_transp_tmr_35_expired(void *inst)
|
||||
static bool mbm_rtu_transp_timer_expired(void *inst)
|
||||
{
|
||||
mbm_rtu_transp_t *transp = __containerof(inst, mbm_rtu_transp_t, base);
|
||||
|
||||
bool need_poll = false;
|
||||
mb_tmr_mode_enum_t timer_mode = mb_port_get_cur_tmr_mode(transp->base.port_obj);
|
||||
mb_timer_mode_enum_t timer_mode = mb_port_get_cur_timer_mode(transp->base.port_obj);
|
||||
|
||||
mb_port_tmr_disable(transp->base.port_obj);
|
||||
mb_port_timer_disable(transp->base.port_obj);
|
||||
|
||||
switch(timer_mode) {
|
||||
case MB_TMODE_T35:
|
||||
//need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
|
||||
//need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
|
||||
//ESP_EARLY_LOGD(TAG, "%p:EV_READY", transp->base.descr.parent);
|
||||
break;
|
||||
|
||||
case MB_TMODE_RESPOND_TIMEOUT:
|
||||
mb_port_evt_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
|
||||
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
|
||||
mb_port_event_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
|
||||
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
|
||||
ESP_EARLY_LOGW(TAG, "%p:EV_ERROR_RESPOND_TIMEOUT", transp->base.descr.parent);
|
||||
break;
|
||||
|
||||
case MB_TMODE_CONVERT_DELAY:
|
||||
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
|
||||
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_EXECUTE));
|
||||
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_EXECUTE));
|
||||
ESP_EARLY_LOGD(TAG, "%p:MB_TMODE_CONVERT_DELAY", transp->base.descr.parent);
|
||||
break;
|
||||
|
||||
default:
|
||||
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
|
||||
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user