mirror of
https://github.com/espressif/esp-modbus.git
synced 2026-08-03 20:24:09 +02:00
Multiple instances example
This commit is contained in:
@@ -5,6 +5,20 @@ physical_tests:
|
||||
disable:
|
||||
- if: CONFIG_NAME == "wifi" and SOC_WIFI_SUPPORTED != 1 and IDF_TARGET != "esp32"
|
||||
|
||||
tcp_instances_tests/mb_tcp_master_instances:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: only manual test is performed for other targets
|
||||
disable:
|
||||
- if: CONFIG_NAME == "wifi" and SOC_WIFI_SUPPORTED != 1 and IDF_TARGET != "esp32"
|
||||
|
||||
tcp_instances_tests/mb_tcp_slave_instances:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
reason: only manual test is performed for other targets
|
||||
disable:
|
||||
- if: CONFIG_NAME == "wifi" and SOC_WIFI_SUPPORTED != 1 and IDF_TARGET != "esp32"
|
||||
|
||||
unit_tests:
|
||||
disable_test:
|
||||
- if: IDF_TARGET != "esp32"
|
||||
|
||||
@@ -73,7 +73,7 @@ TEST_SETUP(modbus_adapter_serial)
|
||||
|
||||
TEST_TEAR_DOWN(modbus_adapter_serial)
|
||||
{
|
||||
int task_count = test_common_task_start_all(1);
|
||||
int task_count = test_common_task_start_all();
|
||||
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();
|
||||
|
||||
@@ -72,7 +72,7 @@ TEST_SETUP(modbus_adapter_tcp)
|
||||
|
||||
TEST_TEAR_DOWN(modbus_adapter_tcp)
|
||||
{
|
||||
int task_count = test_common_task_start_all(1);
|
||||
int task_count = test_common_task_start_all();
|
||||
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();
|
||||
|
||||
@@ -196,7 +196,7 @@ static void test_modbus_tcp_slave(void)
|
||||
unity_send_signal("Slave_ready");
|
||||
unity_wait_for_signal("Master_started");
|
||||
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(1),
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(),
|
||||
test_common_task_wait_done_delete_all(TEST_TCP_TASK_TIMEOUT_MS));
|
||||
|
||||
ESP_LOGI(TAG, "Slave TCP test is completed. (%s).", __func__);
|
||||
@@ -235,7 +235,7 @@ static void test_modbus_tcp_master(void)
|
||||
|
||||
unity_send_signal("Master_started");
|
||||
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(1),
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(),
|
||||
test_common_task_wait_done_delete_all(TEST_TCP_TASK_TIMEOUT_MS));
|
||||
|
||||
test_common_stop();
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Exclude old component feemodbus which exists in old versions
|
||||
set(EXCLUDE_COMPONENTS freemodbus)
|
||||
set(EXTRA_COMPONENT_DIRS "../../test_common")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# The workaround for the test_utils under ESP-IDF v6.0
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.5")
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/test_apps/components")
|
||||
else()
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
endif()
|
||||
|
||||
project(modbus_tcp_master_instances)
|
||||
@@ -0,0 +1,4 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
This test app is a application to test multi-instance modbus communication.
|
||||
@@ -0,0 +1,6 @@
|
||||
set(PROJECT_NAME "modbus_tcp_master_instances")
|
||||
|
||||
idf_component_register(SRCS "tcp_master_instances.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES test_utils test_common unity nvs_flash esp_event esp_eth
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
menu "Modbus Test Configuration"
|
||||
|
||||
config MB_PORT_ADAPTER_EN
|
||||
bool "Enable Modbus port adapter to substitute hardware layer for test."
|
||||
default y
|
||||
help
|
||||
When option is enabled the port communication layer is substituted by
|
||||
port adapter layer to allow testing of higher layers without access to physical layer.
|
||||
|
||||
config MB_TEST_SLAVE_TASK_PRIO
|
||||
int "Modbus master test task priority"
|
||||
range 4 23
|
||||
default 4
|
||||
help
|
||||
Modbus master task priority for the test.
|
||||
|
||||
config MB_TEST_MASTER_TASK_PRIO
|
||||
int "Modbus slave test task priority"
|
||||
range 4 23
|
||||
default 4
|
||||
help
|
||||
Modbus slave task priority for the test.
|
||||
|
||||
config MB_TEST_COMM_CYCLE_COUNTER
|
||||
int "Modbus test communication cycle counter"
|
||||
range 10 1000
|
||||
default 10
|
||||
help
|
||||
Modbus communication cycle counter for test.
|
||||
|
||||
config MB_TEST_LEAK_WARN_LEVEL
|
||||
int "Modbus test leak warning level"
|
||||
range 4 256
|
||||
default 32
|
||||
help
|
||||
Modbus test leak warning level.
|
||||
|
||||
config MB_TEST_LEAK_CRITICAL_LEVEL
|
||||
int "Modbus test leak critical level"
|
||||
range 4 1024
|
||||
default 64
|
||||
help
|
||||
Modbus test leak critical level.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,12 @@
|
||||
dependencies:
|
||||
idf:
|
||||
version: ">=5.0"
|
||||
espressif/esp-modbus:
|
||||
version: "^2.0.0"
|
||||
override_path: "../../../../"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
||||
mb_example_common:
|
||||
path: "../../../../tools/mb_example_common"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
@@ -0,0 +1,699 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "test_common.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_err.h"
|
||||
#include "mbc_master.h"
|
||||
#include "mbc_slave.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#if MB_MDNS_IS_INCLUDED
|
||||
#include "mdns.h"
|
||||
#endif
|
||||
|
||||
#include "mbcontroller.h" // for mbcontroller defines and api
|
||||
#include "modbus_params.h" // for modbus parameters structures
|
||||
|
||||
#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_TASK_TIMEOUT_MS (160000)
|
||||
#define TEST_TCP_MASTER_SEND_TOUT_US (500)
|
||||
#define TEST_TASK_START_TIMEOUT (10000 / portTICK_PERIOD_MS)
|
||||
#define TEST_TASK_TICK_TIME (50 / portTICK_PERIOD_MS)
|
||||
#define TEST_TASK_NOTIFY_STOP_TOUT (200 / portTICK_PERIOD_MS)
|
||||
|
||||
#define TEST_VALUE (12345) // default test value
|
||||
#define TEST_ASCII_BIN (0xAAAAAAAA)
|
||||
#define TEST_ARR_REG_SZ (58)
|
||||
#define TEST_HUMI_MIN (-40)
|
||||
#define TEST_HUMI_MAX (50)
|
||||
#define TEST_TEMP_MIN (0)
|
||||
#define TEST_TEMP_MAX (100)
|
||||
|
||||
|
||||
// Number of reading of parameters from slave
|
||||
#define MASTER_MAX_RETRY (10)
|
||||
|
||||
// The number of parameters that intended to be used in the particular control process
|
||||
#define MASTER_MAX_CIDS num_descriptors
|
||||
|
||||
// The macro to get offset for parameter in the appropriate structure
|
||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
||||
#define COIL_OFFSET(field) ((uint16_t)(offsetof(coil_reg_params_t, field) + 1))
|
||||
#define DISCR_OFFSET(field) ((uint16_t)(offsetof(discrete_reg_params_t, field) + 1))
|
||||
|
||||
#define TEST_HOLD_REG_START(field) (HOLD_OFFSET(field) >> 1)
|
||||
#define TEST_HOLD_REG_SIZE(field) (sizeof(((holding_reg_params_t *)0)->field) >> 1)
|
||||
|
||||
#define TEST_INPUT_REG_START(field) (INPUT_OFFSET(field) >> 1)
|
||||
#define TEST_INPUT_REG_SIZE(field) (sizeof(((input_reg_params_t *)0)->field) >> 1)
|
||||
|
||||
// Options can be used as bit masks or parameter limits
|
||||
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
|
||||
|
||||
#define EACH_ITEM(array, length) \
|
||||
(typeof(*(array)) *pitem = (array); (pitem < &((array)[length])); pitem++)
|
||||
|
||||
#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_MASTER_TEST"
|
||||
|
||||
|
||||
// Enumeration of all supported CIDs for device (used in parameter definition table)
|
||||
enum {
|
||||
CID_INP_DATA_0 = 0,
|
||||
CID_HOLD_DATA_0,
|
||||
CID_INP_DATA_1,
|
||||
CID_HOLD_DATA_1,
|
||||
CID_INP_DATA_2,
|
||||
CID_HOLD_DATA_2,
|
||||
CID_HOLD_TEST_REG,
|
||||
CID_RELAY_P1,
|
||||
CID_RELAY_P2,
|
||||
CID_DISCR_P1,
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
CID_HOLD_U8_A,
|
||||
CID_HOLD_U8_B,
|
||||
CID_HOLD_U16_AB,
|
||||
CID_HOLD_U16_BA,
|
||||
CID_HOLD_UINT32_ABCD,
|
||||
CID_HOLD_UINT32_CDAB,
|
||||
CID_HOLD_UINT32_BADC,
|
||||
CID_HOLD_UINT32_DCBA,
|
||||
CID_HOLD_FLOAT_ABCD,
|
||||
CID_HOLD_FLOAT_CDAB,
|
||||
CID_HOLD_FLOAT_BADC,
|
||||
CID_HOLD_FLOAT_DCBA,
|
||||
CID_HOLD_DOUBLE_ABCDEFGH,
|
||||
CID_HOLD_DOUBLE_HGFEDCBA,
|
||||
CID_HOLD_DOUBLE_GHEFCDAB,
|
||||
CID_HOLD_DOUBLE_BADCFEHG,
|
||||
#endif
|
||||
CID_COUNT
|
||||
};
|
||||
|
||||
|
||||
// Example Data (Object) Dictionary for Modbus parameters
|
||||
const mb_parameter_descriptor_t descriptors[] = {
|
||||
{
|
||||
CID_INP_DATA_0, STR("Data_channel_0"), STR("Volts"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data0), TEST_INPUT_REG_SIZE(input_data0),
|
||||
INPUT_OFFSET(input_data0), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( TEST_TEMP_MIN, TEST_TEMP_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_DATA_0, STR("Humidity_1"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data0), TEST_HOLD_REG_SIZE(holding_data0),
|
||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( TEST_HUMI_MIN, TEST_HUMI_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data1), TEST_INPUT_REG_SIZE(input_data1),
|
||||
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( TEST_TEMP_MIN, TEST_TEMP_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data1), TEST_HOLD_REG_SIZE(holding_data1),
|
||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( TEST_HUMI_MIN, TEST_HUMI_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT,
|
||||
TEST_INPUT_REG_START(input_data2), TEST_INPUT_REG_SIZE(input_data2),
|
||||
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( TEST_TEMP_MIN, TEST_TEMP_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_data2), TEST_HOLD_REG_SIZE(holding_data2),
|
||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4,
|
||||
OPTS( TEST_HUMI_MIN, TEST_HUMI_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(test_regs), TEST_ARR_REG_SZ,
|
||||
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, (TEST_ARR_REG_SZ * 2),
|
||||
OPTS( TEST_TEMP_MIN, TEST_TEMP_MAX, TEST_ASCII_BIN ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 2, 6,
|
||||
COIL_OFFSET(coils_port0), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_RELAY_P2, STR("RelayP2"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 10, 6,
|
||||
COIL_OFFSET(coils_port1), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0x55, 0x2A, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_DISCR_P1, STR("DiscreteInpP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_DISCRETE, 2, 7,
|
||||
DISCR_OFFSET(discrete_input_port1), PARAM_TYPE_U8, 1,
|
||||
OPTS( 0xAA, 0x15, 0 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
{
|
||||
CID_HOLD_U8_A, STR("U8_A"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u8_a), TEST_HOLD_REG_SIZE(holding_u8_a),
|
||||
HOLD_OFFSET(holding_u8_a), PARAM_TYPE_U8_A, (TEST_HOLD_REG_SIZE(holding_u8_a) << 1),
|
||||
OPTS( CHAR_MIN, 0x0055, 0x0055 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_U8_B, STR("U8_B"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u8_b), TEST_HOLD_REG_SIZE(holding_u8_b),
|
||||
HOLD_OFFSET(holding_u8_b), PARAM_TYPE_U8_B, (TEST_HOLD_REG_SIZE(holding_u8_b) << 1),
|
||||
OPTS( 0, 0x5500, 0x5500 ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_U16_AB, STR("U16_AB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u16_ab), TEST_HOLD_REG_SIZE(holding_u16_ab),
|
||||
HOLD_OFFSET(holding_u16_ab), PARAM_TYPE_U16_AB, (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_U16_BA, STR("U16_BA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_u16_ba), TEST_HOLD_REG_SIZE(holding_u16_ba),
|
||||
HOLD_OFFSET(holding_u16_ba), PARAM_TYPE_U16_BA, (TEST_HOLD_REG_SIZE(holding_u16_ab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_UINT32_ABCD, STR("UINT32_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_abcd), TEST_HOLD_REG_SIZE(holding_uint32_abcd),
|
||||
HOLD_OFFSET(holding_uint32_abcd), PARAM_TYPE_U32_ABCD, (TEST_HOLD_REG_SIZE(holding_uint32_abcd) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_UINT32_CDAB, STR("UINT32_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_cdab), TEST_HOLD_REG_SIZE(holding_uint32_cdab),
|
||||
HOLD_OFFSET(holding_uint32_cdab), PARAM_TYPE_U32_CDAB, (TEST_HOLD_REG_SIZE(holding_uint32_cdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_UINT32_BADC, STR("UINT32_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_badc), TEST_HOLD_REG_SIZE(holding_uint32_badc),
|
||||
HOLD_OFFSET(holding_uint32_badc), PARAM_TYPE_U32_BADC, (TEST_HOLD_REG_SIZE(holding_uint32_badc) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_UINT32_DCBA, STR("UINT32_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_uint32_dcba), TEST_HOLD_REG_SIZE(holding_uint32_dcba),
|
||||
HOLD_OFFSET(holding_uint32_dcba), PARAM_TYPE_U32_DCBA, (TEST_HOLD_REG_SIZE(holding_uint32_dcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_FLOAT_ABCD, STR("FLOAT_ABCD"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_abcd), TEST_HOLD_REG_SIZE(holding_float_abcd),
|
||||
HOLD_OFFSET(holding_float_abcd), PARAM_TYPE_FLOAT_ABCD, (TEST_HOLD_REG_SIZE(holding_float_abcd) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_FLOAT_CDAB, STR("FLOAT_CDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_cdab), TEST_HOLD_REG_SIZE(holding_float_cdab),
|
||||
HOLD_OFFSET(holding_float_cdab), PARAM_TYPE_FLOAT_CDAB, (TEST_HOLD_REG_SIZE(holding_float_cdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_FLOAT_BADC, STR("FLOAT_BADC"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_badc), TEST_HOLD_REG_SIZE(holding_float_badc),
|
||||
HOLD_OFFSET(holding_float_badc), PARAM_TYPE_FLOAT_BADC, (TEST_HOLD_REG_SIZE(holding_float_badc) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_FLOAT_DCBA, STR("FLOAT_DCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_float_dcba), TEST_HOLD_REG_SIZE(holding_float_dcba),
|
||||
HOLD_OFFSET(holding_float_dcba), PARAM_TYPE_FLOAT_DCBA, (TEST_HOLD_REG_SIZE(holding_float_dcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_DOUBLE_ABCDEFGH, STR("DOUBLE_ABCDEFGH"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_abcdefgh), TEST_HOLD_REG_SIZE(holding_double_abcdefgh),
|
||||
HOLD_OFFSET(holding_double_abcdefgh), PARAM_TYPE_DOUBLE_ABCDEFGH, (TEST_HOLD_REG_SIZE(holding_double_abcdefgh) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_DOUBLE_HGFEDCBA, STR("DOUBLE_HGFEDCBA"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_hgfedcba), TEST_HOLD_REG_SIZE(holding_double_hgfedcba),
|
||||
HOLD_OFFSET(holding_double_hgfedcba), PARAM_TYPE_DOUBLE_HGFEDCBA, (TEST_HOLD_REG_SIZE(holding_double_hgfedcba) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_DOUBLE_GHEFCDAB, STR("DOUBLE_GHEFCDAB"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_ghefcdab), TEST_HOLD_REG_SIZE(holding_double_ghefcdab),
|
||||
HOLD_OFFSET(holding_double_ghefcdab), PARAM_TYPE_DOUBLE_GHEFCDAB, (TEST_HOLD_REG_SIZE(holding_double_ghefcdab) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
},
|
||||
{
|
||||
CID_HOLD_DOUBLE_BADCFEHG, STR("DOUBLE_BADCFEHG"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
|
||||
TEST_HOLD_REG_START(holding_double_badcfehg), TEST_HOLD_REG_SIZE(holding_double_badcfehg),
|
||||
HOLD_OFFSET(holding_double_badcfehg), PARAM_TYPE_DOUBLE_BADCFEHG, (TEST_HOLD_REG_SIZE(holding_double_badcfehg) << 1),
|
||||
OPTS( 0, TEST_VALUE, TEST_VALUE ), PAR_PERMS_READ_WRITE_TRIGGER
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// The function to get pointer to parameter storage (instance) according to parameter description table
|
||||
void *master_get_param_data(const mb_parameter_descriptor_t *param_descriptor)
|
||||
{
|
||||
assert(param_descriptor != NULL);
|
||||
void *instance_ptr = NULL;
|
||||
if (param_descriptor->param_offset != 0) {
|
||||
switch (param_descriptor->mb_param_type) {
|
||||
case MB_PARAM_HOLDING:
|
||||
instance_ptr = ((void *)&holding_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_INPUT:
|
||||
instance_ptr = ((void *)&input_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_COIL:
|
||||
instance_ptr = ((void *)&coil_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
case MB_PARAM_DISCRETE:
|
||||
instance_ptr = ((void *)&discrete_reg_params + param_descriptor->param_offset - 1);
|
||||
break;
|
||||
default:
|
||||
instance_ptr = NULL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Wrong parameter offset for CID #%u", param_descriptor->cid);
|
||||
assert(instance_ptr != NULL);
|
||||
}
|
||||
return instance_ptr;
|
||||
}
|
||||
|
||||
|
||||
#define TEST_VERIFY_VALUES(handle, pdescr, pinst) (__extension__( \
|
||||
{ \
|
||||
assert(pinst); \
|
||||
assert(pdescr); \
|
||||
uint8_t type = 0; \
|
||||
esp_err_t err = ESP_FAIL; \
|
||||
err = mbc_master_get_parameter(handle, pdescr->cid, (uint8_t *)pinst, &type); \
|
||||
if (err == ESP_OK) { \
|
||||
bool is_correct = true; \
|
||||
if (pdescr->param_opts.opt3) { \
|
||||
for EACH_ITEM(pinst, pdescr->param_size / sizeof(*pitem)) { \
|
||||
if (*pitem != (typeof(*(pinst)))pdescr->param_opts.opt3) { \
|
||||
*pitem = (typeof(*(pinst)))pdescr->param_opts.opt3; \
|
||||
ESP_LOGD(TAG, "%p Characteristic #%d (%s), initialize to 0x%" PRIx16 ".", \
|
||||
handle, \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(uint16_t)pdescr->param_opts.opt3); \
|
||||
is_correct = false; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (!is_correct) { \
|
||||
ESP_LOGE(TAG, "%p Characteristic #%d (%s), initialize.", \
|
||||
handle, \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key); \
|
||||
err = mbc_master_set_parameter(handle, cid, (uint8_t *)pinst, &type); \
|
||||
if (err != ESP_OK) { \
|
||||
ESP_LOGE(TAG, "%p Characteristic #%d (%s) write fail, err = 0x%x (%s).", \
|
||||
handle, \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(int)err, \
|
||||
(char *)esp_err_to_name(err)); \
|
||||
} else { \
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = (..) write successful.", \
|
||||
handle, \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(char *)pdescr->param_units); \
|
||||
} \
|
||||
} \
|
||||
} else { \
|
||||
ESP_LOGE(TAG, "%p Characteristic #%d (%s) read fail, err = 0x%x (%s).", \
|
||||
handle, \
|
||||
(int)pdescr->cid, \
|
||||
(char *)pdescr->param_key, \
|
||||
(int)err, \
|
||||
(char *)esp_err_to_name(err)); \
|
||||
} \
|
||||
(err); \
|
||||
} \
|
||||
))
|
||||
|
||||
|
||||
void func_task_master(void *arg)
|
||||
{
|
||||
|
||||
void *mbm_handle = arg;
|
||||
esp_err_t err = ESP_OK, request_err = ESP_OK;
|
||||
bool message_destroy_found = false;
|
||||
bool alarm_state = false;
|
||||
const mb_parameter_descriptor_t *param_descriptor = NULL;
|
||||
|
||||
test_common_task_wait_start_and_stop(TEST_TASK_START_TIMEOUT);
|
||||
|
||||
ESP_LOGI(TAG, "Start modbus test...");
|
||||
|
||||
for (uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
||||
// Read all found characteristics from slave(s)
|
||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++) {
|
||||
|
||||
if (test_common_task_wait_start_and_stop(TEST_TASK_NOTIFY_STOP_TOUT)) {
|
||||
ESP_LOGD(TAG, "Received destroy message, destroying instance: %p.", mbm_handle);
|
||||
message_destroy_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Get data from parameters description table
|
||||
// and use this information to fill the characteristics description table
|
||||
// and having all required fields in just one table
|
||||
esp_err_t err = mbc_master_get_cid_info(mbm_handle, cid, ¶m_descriptor);
|
||||
if ((err != ESP_ERR_NOT_FOUND) && (param_descriptor != NULL)) {
|
||||
void *temp_data_ptr = master_get_param_data(param_descriptor);
|
||||
assert(temp_data_ptr);
|
||||
|
||||
if ((param_descriptor->param_type == PARAM_TYPE_ASCII) &&
|
||||
(param_descriptor->cid == CID_HOLD_TEST_REG)) {
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (uint32_t *)temp_data_ptr);
|
||||
if (request_err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = (0x%" PRIx32 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_U16_AB)
|
||||
&& (param_descriptor->cid <= CID_HOLD_U16_BA)) {
|
||||
// Check the uint16 parameters
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (uint16_t *)temp_data_ptr);
|
||||
if (err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = (0x%" PRIx16 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint16_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_U8_A)
|
||||
&& (param_descriptor->cid <= CID_HOLD_U8_B)) {
|
||||
// Check the uint8 parameters
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (uint16_t *)temp_data_ptr);
|
||||
if (request_err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = (0x%" PRIx16 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint16_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_UINT32_ABCD)
|
||||
&& (param_descriptor->cid <= CID_HOLD_UINT32_DCBA)) {
|
||||
// Check the uint32 parameters
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (uint32_t *)temp_data_ptr);
|
||||
if (request_err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = %" PRIu32 " (0x%" PRIx32 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(uint32_t *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else if ((param_descriptor->cid >= CID_HOLD_FLOAT_ABCD)
|
||||
&& (param_descriptor->cid <= CID_HOLD_FLOAT_DCBA)) {
|
||||
// Check the float parameters
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (float *)temp_data_ptr);
|
||||
if (request_err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(float *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
} else if (param_descriptor->cid >= CID_HOLD_DOUBLE_ABCDEFGH) {
|
||||
// Check the double parameters
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (double *)temp_data_ptr);
|
||||
if (request_err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = %lf (0x%" PRIx64 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(double *)temp_data_ptr,
|
||||
*(uint64_t *)temp_data_ptr);
|
||||
}
|
||||
#endif
|
||||
} else if (cid <= CID_HOLD_DATA_2) {
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (float *)temp_data_ptr);
|
||||
if (request_err == ESP_OK) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = %f (0x%" PRIx32 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
*(float *)temp_data_ptr,
|
||||
*(uint32_t *)temp_data_ptr);
|
||||
}
|
||||
float value = *(float *)temp_data_ptr;
|
||||
if (((value > param_descriptor->param_opts.max) ||
|
||||
(value < param_descriptor->param_opts.min))) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
} else if ((cid >= CID_RELAY_P1) && (cid <= CID_DISCR_P1)) {
|
||||
request_err = TEST_VERIFY_VALUES(mbm_handle, param_descriptor, (uint8_t *)temp_data_ptr);
|
||||
if (request_err == ESP_OK) {
|
||||
uint8_t state = *(uint8_t *)temp_data_ptr;
|
||||
const char *rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||
if ((state & param_descriptor->param_opts.opt2) == param_descriptor->param_opts.opt2) {
|
||||
ESP_LOGI(TAG, "%p Characteristic #%d %s (%s) value = %s (0x%" PRIx8 ") read successful.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
(const char *)rw_str,
|
||||
*(uint8_t *)temp_data_ptr);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%p Characteristic #%d %s (%s) value = %s (0x%" PRIx8 "), unexpected value.",
|
||||
mbm_handle,
|
||||
(int)param_descriptor->cid,
|
||||
(char *)param_descriptor->param_key,
|
||||
(char *)param_descriptor->param_units,
|
||||
(const char *)rw_str,
|
||||
*(uint8_t *)temp_data_ptr);
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
if (state & param_descriptor->param_opts.opt1) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (request_err != ESP_OK) {
|
||||
alarm_state = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (message_destroy_found) {
|
||||
break;
|
||||
}
|
||||
|
||||
vTaskDelay(TEST_TASK_TICK_TIME); // Let the IDLE task to trigger
|
||||
if ((retry == MASTER_MAX_RETRY - 1) || alarm_state) {
|
||||
ESP_LOGI(TAG, "Alarm triggered by cid #%u.", param_descriptor->cid);
|
||||
alarm_state = false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
ESP_LOGI(TAG, "Destroy master, inst: %p.", mbm_handle);
|
||||
TEST_ESP_OK(mbc_master_delete(mbm_handle));
|
||||
test_common_task_notify_done(xTaskGetCurrentTaskHandle());
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
|
||||
TaskHandle_t master_tcp_create_instance(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.");
|
||||
}
|
||||
|
||||
void *mbm_handle = NULL;
|
||||
TaskHandle_t master_task_handle = NULL;
|
||||
|
||||
TEST_ESP_OK(mbc_master_create_tcp(pconfig, &mbm_handle));
|
||||
mbm_controller_iface_t *pbase = mbm_handle;
|
||||
|
||||
TEST_ESP_OK(mbc_master_set_descriptor(mbm_handle, pdescr, descr_size));
|
||||
ESP_LOGI(TAG, "%p, Modbus master stack initialized", mbm_handle);
|
||||
|
||||
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(func_task_master, port_name,
|
||||
TEST_TASK_STACK_SIZE,
|
||||
mbm_handle, TEST_TASK_PRIO_MASTER,
|
||||
&master_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
|
||||
|
||||
test_task_add_entry(master_task_handle, mbm_handle);
|
||||
|
||||
return master_task_handle;
|
||||
}
|
||||
|
||||
void app_main(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.");
|
||||
|
||||
// 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(master_tcp_create_instance(&tcp_master_cfg_1, 0, &descriptors[0], num_descriptors));
|
||||
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(),
|
||||
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 completed. (%s).", __func__);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# 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_LOG_DEFAULT_LEVEL_DEBUG=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_USE_SPI_ETHERNET=n
|
||||
@@ -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
|
||||
@@ -0,0 +1,27 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
#
|
||||
# Modbus configuration
|
||||
#
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
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_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=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
|
||||
@@ -0,0 +1,17 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# Exclude old component feemodbus which exists in old versions
|
||||
set(EXCLUDE_COMPONENTS freemodbus)
|
||||
set(EXTRA_COMPONENT_DIRS "../../test_common")
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
|
||||
# The workaround for the test_utils under ESP-IDF v6.0
|
||||
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "5.5")
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/test_apps/components")
|
||||
else()
|
||||
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/unit-test-app/components")
|
||||
endif()
|
||||
|
||||
project(modbus_tcp_slave_instances)
|
||||
@@ -0,0 +1,4 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- | -------- |
|
||||
|
||||
This test app is a application to test multi-instance modbus communication.
|
||||
@@ -0,0 +1,6 @@
|
||||
set(PROJECT_NAME "modbus_tcp_slave_instances")
|
||||
|
||||
idf_component_register(SRCS "tcp_slave_instances.c"
|
||||
INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES test_utils test_common unity nvs_flash esp_event esp_eth
|
||||
)
|
||||
@@ -0,0 +1,45 @@
|
||||
menu "Modbus Test Configuration"
|
||||
|
||||
config MB_PORT_ADAPTER_EN
|
||||
bool "Enable Modbus port adapter to substitute hardware layer for test."
|
||||
default y
|
||||
help
|
||||
When option is enabled the port communication layer is substituted by
|
||||
port adapter layer to allow testing of higher layers without access to physical layer.
|
||||
|
||||
config MB_TEST_SLAVE_TASK_PRIO
|
||||
int "Modbus master test task priority"
|
||||
range 4 23
|
||||
default 4
|
||||
help
|
||||
Modbus master task priority for the test.
|
||||
|
||||
config MB_TEST_MASTER_TASK_PRIO
|
||||
int "Modbus slave test task priority"
|
||||
range 4 23
|
||||
default 4
|
||||
help
|
||||
Modbus slave task priority for the test.
|
||||
|
||||
config MB_TEST_COMM_CYCLE_COUNTER
|
||||
int "Modbus test communication cycle counter"
|
||||
range 10 1000
|
||||
default 10
|
||||
help
|
||||
Modbus communication cycle counter for test.
|
||||
|
||||
config MB_TEST_LEAK_WARN_LEVEL
|
||||
int "Modbus test leak warning level"
|
||||
range 4 256
|
||||
default 32
|
||||
help
|
||||
Modbus test leak warning level.
|
||||
|
||||
config MB_TEST_LEAK_CRITICAL_LEVEL
|
||||
int "Modbus test leak critical level"
|
||||
range 4 1024
|
||||
default 64
|
||||
help
|
||||
Modbus test leak critical level.
|
||||
|
||||
endmenu
|
||||
@@ -0,0 +1,11 @@
|
||||
dependencies:
|
||||
idf: ">=5.0"
|
||||
espressif/esp-modbus:
|
||||
version: "^2.0.0"
|
||||
override_path: "../../../../"
|
||||
espressif/mdns:
|
||||
version: "^1.0.0"
|
||||
mb_example_common:
|
||||
path: "../../../../tools/mb_example_common"
|
||||
protocol_examples_common:
|
||||
path: ${IDF_PATH}/examples/common_components/protocol_examples_common
|
||||
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "test_common.h"
|
||||
#include "test_utils.h"
|
||||
#include "esp_err.h"
|
||||
#include "mbc_slave.h"
|
||||
#include "mbc_master.h"
|
||||
|
||||
#include "esp_timer.h"
|
||||
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#if MB_MDNS_IS_INCLUDED
|
||||
#include "mdns.h"
|
||||
#endif
|
||||
|
||||
#include "mbcontroller.h" // for mbcontroller defines and api
|
||||
#include "modbus_params.h" // for modbus parameters structures
|
||||
|
||||
#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_PAR_INFO_GET_TOUT (10)
|
||||
#define TEST_TASK_START_TIMEOUT (10000 / portTICK_PERIOD_MS)
|
||||
#define TEST_TASK_NOTIFY_STOP_TOUT (100 / portTICK_PERIOD_MS)
|
||||
#define TEST_TASK_TICK_TIME (50 / portTICK_PERIOD_MS)
|
||||
|
||||
#define TEST_VALUE (12345) // default test value
|
||||
|
||||
// Options can be used as bit masks or parameter limits
|
||||
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
|
||||
|
||||
// Defines below are used to define register start address for each type of Modbus registers
|
||||
#define HOLD_OFFSET_SLAVE(field) ((uint16_t)(offsetof(holding_reg_params_t, field) >> 1))
|
||||
#define INPUT_OFFSET_SLAVE(field) ((uint16_t)(offsetof(input_reg_params_t, field) >> 1))
|
||||
#define MB_REG_DISCRETE_INPUT_START (0x0000)
|
||||
#define MB_REG_COILS_START (0x0000)
|
||||
#define MB_REG_INPUT_START_AREA0 (INPUT_OFFSET_SLAVE(input_data0)) // register offset input area 0
|
||||
#define MB_REG_INPUT_START_AREA1 (INPUT_OFFSET_SLAVE(input_data4)) // register offset input area 1
|
||||
#define MB_REG_HOLDING_START_AREA0 (HOLD_OFFSET_SLAVE(holding_data0))
|
||||
#define MB_REG_HOLDING_START_AREA1 (HOLD_OFFSET_SLAVE(holding_data4))
|
||||
#define MB_REG_HOLDING_START_AREA2 (HOLD_OFFSET_SLAVE(holding_u8_a))
|
||||
#define MB_REG_HOLDING_START_AREA2_SIZE ((size_t)((HOLD_OFFSET_SLAVE(holding_area2_end) - HOLD_OFFSET_SLAVE(holding_u8_a)) << 1))
|
||||
|
||||
#define MB_CHAN_DATA_MAX_VAL (10)
|
||||
#define MB_CHAN_DATA_OFFSET (1.1f)
|
||||
|
||||
#define MB_READ_MASK (MB_EVENT_INPUT_REG_RD \
|
||||
| MB_EVENT_HOLDING_REG_RD \
|
||||
| MB_EVENT_DISCRETE_RD \
|
||||
| MB_EVENT_COILS_RD)
|
||||
#define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR \
|
||||
| MB_EVENT_COILS_WR)
|
||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||
#define MB_TEST_VALUE (12345.0)
|
||||
|
||||
// The workaround to statically link the whole test library
|
||||
__attribute__((unused)) bool mb_test_include_phys_impl_tcp = true;
|
||||
|
||||
#define TAG "MODBUS_TCP_COMM_SLAVE_TEST"
|
||||
|
||||
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 func_slave_task(void *arg)
|
||||
{
|
||||
|
||||
void *mbs_handle = arg;
|
||||
mbs_controller_iface_t *pctrl_obj = ((mbs_controller_iface_t *)mbs_handle);
|
||||
mb_param_info_t reg_info; // keeps the Modbus registers access information
|
||||
|
||||
test_common_task_wait_start_and_stop(TEST_TASK_START_TIMEOUT);
|
||||
|
||||
while (1) {
|
||||
// Get parameter information from parameter queue
|
||||
esp_err_t err = mbc_slave_get_param_info(mbs_handle, ®_info, TEST_PAR_INFO_GET_TOUT);
|
||||
const char *rw_str = (reg_info.type & MB_READ_MASK) ? "READ" : "WRITE";
|
||||
|
||||
if (test_common_task_wait_start_and_stop(TEST_TASK_NOTIFY_STOP_TOUT)) {
|
||||
ESP_LOGD(TAG, "Received destroy message, destroying instance: %p.", mbs_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
// Filter events and process them accordingly
|
||||
if ((err != ESP_ERR_TIMEOUT) && (reg_info.type & MB_READ_WRITE_MASK)) {
|
||||
|
||||
if (reg_info.type & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||
// Get parameter information from parameter queue
|
||||
ESP_LOGI(TAG, "OBJ %p, HOLDING %s (%" PRIu32 " us), SL: %u, REG:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 "(0x%" PRIx16 "), SIZE:%u",
|
||||
(void *)pctrl_obj->mb_base->descr.parent,
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(unsigned)pctrl_obj->opts.comm_opts.common_opts.uid,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
*(uint16_t *)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
|
||||
if (reg_info.address == (uint8_t *)&holding_reg_params.holding_data0) {
|
||||
(void)mbc_slave_unlock(mbs_handle);
|
||||
holding_reg_params.holding_data0 += MB_CHAN_DATA_OFFSET;
|
||||
if (holding_reg_params.holding_data0 >= MB_CHAN_DATA_MAX_VAL) {
|
||||
coil_reg_params.coils_port1 = 0xFF;
|
||||
ESP_LOGI(TAG, "Reached maximum value");
|
||||
}
|
||||
(void)mbc_slave_unlock(mbs_handle);
|
||||
}
|
||||
} else if (reg_info.type & MB_EVENT_INPUT_REG_RD) {
|
||||
ESP_LOGI(TAG, "OBJ %p, INPUT %s (%" PRIu32 " us), SL: %u, REG:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 "(0x%" PRIx16 "), SIZE:%u",
|
||||
(void *)pctrl_obj->mb_base->descr.parent,
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(unsigned)pctrl_obj->opts.comm_opts.common_opts.uid,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
*(uint16_t *)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
|
||||
} else if (reg_info.type & MB_EVENT_DISCRETE_RD) {
|
||||
ESP_LOGI(TAG, "OBJ %p, DISCRETE %s (%" PRIu32 " us), SL: %u, REG:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 "(0x%" PRIx16 "), SIZE:%u",
|
||||
(void *)pctrl_obj->mb_base->descr.parent,
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(unsigned)pctrl_obj->opts.comm_opts.common_opts.uid,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
*(uint16_t *)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
|
||||
} else if (reg_info.type & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
||||
ESP_LOGI(TAG, "OBJ %p, COILS %s (%" PRIu32 " us), SL: %u, REG:%u, TYPE:%u, INST_ADDR:0x%" PRIx32 "(0x%" PRIx16 "), SIZE:%u",
|
||||
(void *)pctrl_obj->mb_base->descr.parent,
|
||||
rw_str,
|
||||
(uint32_t)reg_info.time_stamp,
|
||||
(unsigned)pctrl_obj->opts.comm_opts.common_opts.uid,
|
||||
(unsigned)reg_info.mb_offset,
|
||||
(unsigned)reg_info.type,
|
||||
(uint32_t)reg_info.address,
|
||||
*(uint16_t *)reg_info.address,
|
||||
(unsigned)reg_info.size);
|
||||
}
|
||||
}
|
||||
|
||||
vTaskDelay(TEST_TASK_TICK_TIME); // Let IDLE task to trigger
|
||||
if (coil_reg_params.coils_port1 == 0xFF) {
|
||||
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));
|
||||
ESP_LOGD(TAG, "Notify task done, inst: %p.", xTaskGetCurrentTaskHandle());
|
||||
test_common_task_notify_done(xTaskGetCurrentTaskHandle());
|
||||
vTaskDelay(10);
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
// Set register values into known state
|
||||
static void setup_reg_data(void)
|
||||
{
|
||||
// Define initial state of parameters
|
||||
discrete_reg_params.discrete_input0 = 1;
|
||||
discrete_reg_params.discrete_input1 = 0;
|
||||
discrete_reg_params.discrete_input2 = 1;
|
||||
discrete_reg_params.discrete_input3 = 0;
|
||||
discrete_reg_params.discrete_input4 = 1;
|
||||
discrete_reg_params.discrete_input5 = 0;
|
||||
discrete_reg_params.discrete_input6 = 1;
|
||||
discrete_reg_params.discrete_input7 = 0;
|
||||
|
||||
holding_reg_params.holding_data0 = 0.34;
|
||||
holding_reg_params.holding_data1 = 2.56;
|
||||
holding_reg_params.holding_data2 = 3.78;
|
||||
holding_reg_params.holding_data3 = 4.90;
|
||||
|
||||
holding_reg_params.holding_data4 = 5.67;
|
||||
holding_reg_params.holding_data5 = 6.78;
|
||||
holding_reg_params.holding_data6 = 7.79;
|
||||
holding_reg_params.holding_data7 = 8.80;
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
mb_set_uint8_a((val_16_arr *)&holding_reg_params.holding_u8_a[0], (uint8_t)0x55);
|
||||
mb_set_uint8_a((val_16_arr *)&holding_reg_params.holding_u8_a[1], (uint8_t)0x55);
|
||||
mb_set_uint8_b((val_16_arr *)&holding_reg_params.holding_u8_b[0], (uint8_t)0x55);
|
||||
mb_set_uint8_b((val_16_arr *)&holding_reg_params.holding_u8_b[1], (uint8_t)0x55);
|
||||
mb_set_uint16_ab((val_16_arr *)&holding_reg_params.holding_u16_ab[1], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ab((val_16_arr *)&holding_reg_params.holding_u16_ab[0], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ba((val_16_arr *)&holding_reg_params.holding_u16_ba[0], (uint16_t)MB_TEST_VALUE);
|
||||
mb_set_uint16_ba((val_16_arr *)&holding_reg_params.holding_u16_ba[1], (uint16_t)MB_TEST_VALUE);
|
||||
|
||||
mb_set_float_abcd((val_32_arr *)&holding_reg_params.holding_float_abcd[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_abcd((val_32_arr *)&holding_reg_params.holding_float_abcd[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_cdab((val_32_arr *)&holding_reg_params.holding_float_cdab[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_cdab((val_32_arr *)&holding_reg_params.holding_float_cdab[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_badc((val_32_arr *)&holding_reg_params.holding_float_badc[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_badc((val_32_arr *)&holding_reg_params.holding_float_badc[1], (float)MB_TEST_VALUE);
|
||||
mb_set_float_dcba((val_32_arr *)&holding_reg_params.holding_float_dcba[0], (float)MB_TEST_VALUE);
|
||||
mb_set_float_dcba((val_32_arr *)&holding_reg_params.holding_float_dcba[1], (float)MB_TEST_VALUE);
|
||||
|
||||
mb_set_uint32_abcd((val_32_arr *)&holding_reg_params.holding_uint32_abcd[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_abcd((val_32_arr *)&holding_reg_params.holding_uint32_abcd[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_cdab((val_32_arr *)&holding_reg_params.holding_uint32_cdab[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_cdab((val_32_arr *)&holding_reg_params.holding_uint32_cdab[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_badc((val_32_arr *)&holding_reg_params.holding_uint32_badc[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_badc((val_32_arr *)&holding_reg_params.holding_uint32_badc[1], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_dcba((val_32_arr *)&holding_reg_params.holding_uint32_dcba[0], (uint32_t)MB_TEST_VALUE);
|
||||
mb_set_uint32_dcba((val_32_arr *)&holding_reg_params.holding_uint32_dcba[1], (uint32_t)MB_TEST_VALUE);
|
||||
|
||||
mb_set_double_abcdefgh((val_64_arr *)&holding_reg_params.holding_double_abcdefgh[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_abcdefgh((val_64_arr *)&holding_reg_params.holding_double_abcdefgh[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_hgfedcba((val_64_arr *)&holding_reg_params.holding_double_hgfedcba[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_hgfedcba((val_64_arr *)&holding_reg_params.holding_double_hgfedcba[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_ghefcdab((val_64_arr *)&holding_reg_params.holding_double_ghefcdab[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_ghefcdab((val_64_arr *)&holding_reg_params.holding_double_ghefcdab[1], (double)MB_TEST_VALUE);
|
||||
mb_set_double_badcfehg((val_64_arr *)&holding_reg_params.holding_double_badcfehg[0], (double)MB_TEST_VALUE);
|
||||
mb_set_double_badcfehg((val_64_arr *)&holding_reg_params.holding_double_badcfehg[1], (double)MB_TEST_VALUE);
|
||||
#endif
|
||||
|
||||
coil_reg_params.coils_port0 = 0x55;
|
||||
coil_reg_params.coils_port1 = 0xAA;
|
||||
|
||||
input_reg_params.input_data0 = 1.12;
|
||||
input_reg_params.input_data1 = 2.34;
|
||||
input_reg_params.input_data2 = 3.56;
|
||||
input_reg_params.input_data3 = 4.78;
|
||||
input_reg_params.input_data4 = 1.12;
|
||||
input_reg_params.input_data5 = 2.34;
|
||||
input_reg_params.input_data6 = 3.56;
|
||||
input_reg_params.input_data7 = 4.78;
|
||||
}
|
||||
|
||||
void instance_slave_setup_start(void *mbs_handle)
|
||||
{
|
||||
TEST_ASSERT_TRUE(mbs_handle);
|
||||
mb_register_area_descriptor_t reg_area;
|
||||
|
||||
reg_area.type = MB_PARAM_HOLDING; // Set type of register area
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA0; // Offset of register area in Modbus protocol
|
||||
reg_area.address = (void *)&holding_reg_params.holding_data0; // Set pointer to storage instance
|
||||
reg_area.size = (MB_REG_HOLDING_START_AREA1 - MB_REG_HOLDING_START_AREA0) << 1; // Set the size of register storage instance
|
||||
TEST_ESP_OK(mbc_slave_set_descriptor(mbs_handle, reg_area));
|
||||
|
||||
|
||||
reg_area.type = MB_PARAM_HOLDING; // Set type of register area
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol
|
||||
reg_area.address = (void *)&holding_reg_params.holding_data4; // Set pointer to storage instance
|
||||
reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
|
||||
TEST_ESP_OK(mbc_slave_set_descriptor(mbs_handle, reg_area));
|
||||
|
||||
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
// The extended parameters register area
|
||||
reg_area.type = MB_PARAM_HOLDING;
|
||||
reg_area.start_offset = MB_REG_HOLDING_START_AREA2;
|
||||
reg_area.address = (void *)&holding_reg_params.holding_u8_a;
|
||||
reg_area.size = MB_REG_HOLDING_START_AREA2_SIZE;
|
||||
TEST_ESP_OK(mbc_slave_set_descriptor(mbs_handle, reg_area));
|
||||
|
||||
#endif
|
||||
|
||||
// Initialization of Input Registers area
|
||||
reg_area.type = MB_PARAM_INPUT;
|
||||
reg_area.start_offset = MB_REG_INPUT_START_AREA0;
|
||||
reg_area.address = (void *)&input_reg_params.input_data0;
|
||||
reg_area.size = sizeof(float) << 2;
|
||||
TEST_ESP_OK(mbc_slave_set_descriptor(mbs_handle, reg_area));
|
||||
|
||||
reg_area.type = MB_PARAM_INPUT;
|
||||
reg_area.start_offset = MB_REG_INPUT_START_AREA1;
|
||||
reg_area.address = (void *)&input_reg_params.input_data4;
|
||||
reg_area.size = sizeof(float) << 2;
|
||||
TEST_ESP_OK(mbc_slave_set_descriptor(mbs_handle, reg_area));
|
||||
|
||||
// Initialization of Coils register area
|
||||
reg_area.type = MB_PARAM_COIL;
|
||||
reg_area.start_offset = MB_REG_COILS_START;
|
||||
reg_area.address = (void *)&coil_reg_params;
|
||||
reg_area.size = sizeof(coil_reg_params);
|
||||
TEST_ESP_OK(mbc_slave_set_descriptor(mbs_handle, reg_area));
|
||||
|
||||
|
||||
// Initialization of Discrete Inputs register area
|
||||
reg_area.type = MB_PARAM_DISCRETE;
|
||||
reg_area.start_offset = MB_REG_DISCRETE_INPUT_START;
|
||||
reg_area.address = (void *)&discrete_reg_params;
|
||||
reg_area.size = sizeof(discrete_reg_params);
|
||||
TEST_ESP_OK(mbc_slave_set_descriptor(mbs_handle, reg_area));
|
||||
|
||||
|
||||
// Set values into known state
|
||||
setup_reg_data();
|
||||
|
||||
// Starts of modbus controller and stack
|
||||
TEST_ESP_OK(mbc_slave_start(mbs_handle));
|
||||
}
|
||||
|
||||
TaskHandle_t slave_tcp_create_instance(mb_communication_info_t *pconfig, uint32_t priority)
|
||||
{
|
||||
if (!pconfig) {
|
||||
ESP_LOGI(TAG, "invalid slave configuration.");
|
||||
}
|
||||
|
||||
void *mbs_handle = NULL;
|
||||
TaskHandle_t slave_task_handle = NULL;
|
||||
|
||||
TEST_ESP_OK(mbc_slave_create_tcp(pconfig, &mbs_handle));
|
||||
|
||||
mbs_controller_iface_t *pbase = mbs_handle;
|
||||
instance_slave_setup_start(mbs_handle);
|
||||
|
||||
if (priority) {
|
||||
priority = TEST_TASK_PRIO_SLAVE;
|
||||
}
|
||||
|
||||
TEST_ASSERT_TRUE(xTaskCreatePinnedToCore(func_slave_task, pbase->mb_base->descr.parent_name,
|
||||
TEST_TASK_STACK_SIZE,
|
||||
mbs_handle, priority,
|
||||
&slave_task_handle, MB_PORT_TASK_AFFINITY));
|
||||
|
||||
test_task_add_entry(slave_task_handle, mbs_handle);
|
||||
|
||||
return slave_task_handle;
|
||||
}
|
||||
|
||||
void app_main(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(slave_tcp_create_instance(&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(slave_tcp_create_instance(&tcp_slave_cfg_2, 0));
|
||||
|
||||
ESP_LOGI(TAG, "Slave TCP #2 is started. (%s).", __func__);
|
||||
|
||||
TEST_ASSERT_EQUAL(test_common_task_start_all(),
|
||||
test_common_task_wait_done_delete_all(TEST_TCP_TASK_TIMEOUT_MS));
|
||||
|
||||
ESP_LOGI(TAG, "Slave TCP test is completed. (%s).", __func__);
|
||||
|
||||
test_common_stop();
|
||||
|
||||
test_tcp_services_destroy();
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#
|
||||
# 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_EXT_TYPE_SUPPORT=y
|
||||
CONFIG_FMB_TCP_UID_ENABLED=n
|
||||
CONFIG_FMB_TIMER_USE_ISR_DISPATCH_METHOD=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL_DEBUG=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_USE_SPI_ETHERNET=n
|
||||
@@ -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
|
||||
@@ -0,0 +1,27 @@
|
||||
# This file was generated using idf.py save-defconfig. It can be edited manually.
|
||||
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
|
||||
#
|
||||
#
|
||||
# Modbus configuration
|
||||
#
|
||||
CONFIG_UNITY_ENABLE_FIXTURE=y
|
||||
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_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=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
|
||||
@@ -0,0 +1,5 @@
|
||||
# The following five lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
idf_component_register(SRCS "modbus_params.c"
|
||||
INCLUDE_DIRS "include")
|
||||
@@ -0,0 +1,10 @@
|
||||
# Modbus Example Common
|
||||
|
||||
This directory contains component that is common for Modbus master and slave examples. The component defines Modbus parameters that are shared between examples and provide code that you can copy and adapt into your own projects.
|
||||
For more information please refer to Modbus example README.md files located in the folders:
|
||||
|
||||
* `examples/protocols/modbus/serial/mb_master` Modbus serial master implementation (RTU and ASCII)
|
||||
* `examples/protocols/modbus/serial/mb_slave` Modbus serial slave implementation (RTU and ASCII)
|
||||
* `examples/protocols/modbus/serial/mb_master` Modbus serial master implementation (RTU and ASCII)
|
||||
* `examples/protocols/modbus/tcp/mb_tcp_slave` Modbus serial slave implementation (TCP)
|
||||
* `examples/protocols/modbus/tcp/mb_tcp_master` Modbus serial master implementation (TCP)
|
||||
@@ -0,0 +1,5 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_SRCDIRS := .
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*=====================================================================================
|
||||
* Description:
|
||||
* The Modbus parameter structures used to define Modbus instances that
|
||||
* can be addressed by Modbus protocol. Define these structures per your needs in
|
||||
* your application. Below is just an example of possible parameters.
|
||||
*====================================================================================*/
|
||||
#ifndef _DEVICE_PARAMS
|
||||
#define _DEVICE_PARAMS
|
||||
|
||||
#include <stdint.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// This file defines structure of modbus parameters which reflect correspond modbus address space
|
||||
// for each modbus register type (coils, discrete inputs, holding registers, input registers)
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t discrete_input0: 1;
|
||||
uint8_t discrete_input1: 1;
|
||||
uint8_t discrete_input2: 1;
|
||||
uint8_t discrete_input3: 1;
|
||||
uint8_t discrete_input4: 1;
|
||||
uint8_t discrete_input5: 1;
|
||||
uint8_t discrete_input6: 1;
|
||||
uint8_t discrete_input7: 1;
|
||||
uint8_t discrete_input_port1;
|
||||
uint8_t discrete_input_port2;
|
||||
} discrete_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
uint8_t coils_port0;
|
||||
uint8_t coils_port1;
|
||||
uint8_t coils_port2;
|
||||
} coil_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
float input_data0; // 0
|
||||
float input_data1; // 2
|
||||
float input_data2; // 4
|
||||
float input_data3; // 6
|
||||
uint16_t data[150]; // 8 + 150 = 158
|
||||
float input_data4; // 158
|
||||
float input_data5;
|
||||
float input_data6;
|
||||
float input_data7;
|
||||
uint16_t data_block1[150];
|
||||
} input_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push, 1)
|
||||
typedef struct {
|
||||
#if CONFIG_FMB_EXT_TYPE_SUPPORT
|
||||
uint16_t holding_u8_a[2];
|
||||
uint16_t holding_u8_b[2];
|
||||
uint16_t holding_u16_ab[2];
|
||||
uint16_t holding_u16_ba[2];
|
||||
uint32_t holding_uint32_abcd[2];
|
||||
uint32_t holding_uint32_cdab[2];
|
||||
uint32_t holding_uint32_badc[2];
|
||||
uint32_t holding_uint32_dcba[2];
|
||||
float holding_float_abcd[2];
|
||||
float holding_float_cdab[2];
|
||||
float holding_float_badc[2];
|
||||
float holding_float_dcba[2];
|
||||
double holding_double_abcdefgh[2];
|
||||
double holding_double_hgfedcba[2];
|
||||
double holding_double_ghefcdab[2];
|
||||
double holding_double_badcfehg[2];
|
||||
uint32_t holding_area2_end;
|
||||
#endif
|
||||
float holding_data0;
|
||||
float holding_data1;
|
||||
float holding_data2;
|
||||
float holding_data3;
|
||||
uint16_t test_regs[150];
|
||||
float holding_data4;
|
||||
float holding_data5;
|
||||
float holding_data6;
|
||||
float holding_data7;
|
||||
uint32_t holding_area1_end;
|
||||
} holding_reg_params_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
extern holding_reg_params_t holding_reg_params;
|
||||
extern input_reg_params_t input_reg_params;
|
||||
extern coil_reg_params_t coil_reg_params;
|
||||
extern discrete_reg_params_t discrete_reg_params;
|
||||
|
||||
#endif // !defined(_DEVICE_PARAMS)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
/*=====================================================================================
|
||||
* Description:
|
||||
* C file to define parameter storage instances
|
||||
*====================================================================================*/
|
||||
#include <stdint.h>
|
||||
#include "modbus_params.h"
|
||||
|
||||
// Here are the user defined instances for device parameters packed by 1 byte
|
||||
// These are keep the values that can be accessed from Modbus master
|
||||
holding_reg_params_t holding_reg_params = { 0 };
|
||||
|
||||
input_reg_params_t input_reg_params = { 0 };
|
||||
|
||||
coil_reg_params_t coil_reg_params = { 0 };
|
||||
|
||||
discrete_reg_params_t discrete_reg_params = { 0 };
|
||||
Reference in New Issue
Block a user