freemodbus: allow address gaps in master data dictionary (support of UID field in MBAP) (backport v4.3)

This commit is contained in:
Alex Lisitsyn
2022-02-18 05:40:49 +00:00
committed by Jiang Jiang Jian
parent 5bad27d0d5
commit 073da59d27
20 changed files with 669 additions and 429 deletions

View File

@@ -38,14 +38,6 @@
#define POLL_TIMEOUT_MS (1)
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
#define MASTER_TAG "MASTER_TEST"
#define MASTER_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
}
// 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))
@@ -57,6 +49,8 @@
// 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 }
static const char *TAG = "MASTER_TEST";
// Enumeration of modbus device addresses accessed by master device
enum {
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
@@ -135,7 +129,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
break;
}
} else {
ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
@@ -149,7 +143,7 @@ static void master_operation_func(void *arg)
bool alarm_state = false;
const mb_parameter_descriptor_t* param_descriptor = NULL;
ESP_LOGI(MASTER_TAG, "Start modbus test...");
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)
@@ -169,7 +163,7 @@ static void master_operation_func(void *arg)
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)temp_data_ptr, &type);
if (err == ESP_OK) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@@ -181,13 +175,13 @@ static void master_operation_func(void *arg)
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)temp_data_ptr, &type);
if (err == ESP_OK) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
*(uint32_t*)temp_data_ptr);
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@@ -195,7 +189,7 @@ static void master_operation_func(void *arg)
}
}
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@@ -208,7 +202,7 @@ static void master_operation_func(void *arg)
*(float*)temp_data_ptr = value;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@@ -222,7 +216,7 @@ static void master_operation_func(void *arg)
} else {
uint16_t state = *(uint16_t*)temp_data_ptr;
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@@ -234,7 +228,7 @@ static void master_operation_func(void *arg)
}
}
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@@ -248,13 +242,13 @@ static void master_operation_func(void *arg)
}
if (alarm_state) {
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
param_descriptor->cid);
} else {
ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
MASTER_MAX_RETRY);
}
ESP_LOGI(MASTER_TAG, "Destroy master...");
ESP_LOGI(TAG, "Destroy master...");
ESP_ERROR_CHECK(mbc_master_destroy());
}
@@ -275,13 +269,13 @@ static esp_err_t master_init(void)
void* master_handler = NULL;
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
MASTER_CHECK((master_handler != NULL), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail.");
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail, returns(0x%x).",
(uint32_t)err);
err = mbc_master_setup((void*)&comm);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller setup fail, returns(0x%x).",
(uint32_t)err);
@@ -290,23 +284,23 @@ static esp_err_t master_init(void)
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
err = mbc_master_start();
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller start fail, returns(0x%x).",
(uint32_t)err);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (uint32_t)err);
// Set driver mode to Half Duplex
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err);
vTaskDelay(5);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller set descriptor fail, returns(0x%x).",
(uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
ESP_LOGI(TAG, "Modbus master stack initialized...");
return err;
}

View File

@@ -40,7 +40,7 @@
| MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
static const char *SLAVE_TAG = "SLAVE_TEST";
static const char *TAG = "SLAVE_TEST";
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
@@ -92,7 +92,7 @@ void app_main(void)
mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
// Set UART log level
esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
esp_log_level_set(TAG, ESP_LOG_INFO);
void* mbc_slave_handler = NULL;
ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller
@@ -166,8 +166,8 @@ void app_main(void)
// Set UART driver mode to Half Duplex
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
ESP_LOGI(SLAVE_TAG, "Start modbus test...");
ESP_LOGI(TAG, "Modbus slave stack initialized.");
ESP_LOGI(TAG, "Start modbus test...");
// The cycle below will be terminated when parameter holdingRegParams.dataChan0
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
@@ -180,7 +180,7 @@ void app_main(void)
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
// Get parameter information from parameter queue
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@@ -198,7 +198,7 @@ void app_main(void)
}
} else if (event & MB_EVENT_INPUT_REG_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@@ -206,7 +206,7 @@ void app_main(void)
(uint32_t)reg_info.size);
} else if (event & MB_EVENT_DISCRETE_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@@ -214,7 +214,7 @@ void app_main(void)
(uint32_t)reg_info.size);
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@@ -225,7 +225,7 @@ void app_main(void)
}
}
// Destroy of Modbus controller on alarm
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
ESP_LOGI(TAG,"Modbus controller destroyed.");
vTaskDelay(100);
ESP_ERROR_CHECK(mbc_slave_destroy());
}

View File

@@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import logging
import os
import re
@@ -69,7 +72,7 @@ class DutTestThread(Thread):
super(DutTestThread, self).__init__()
def __enter__(self):
logger.debug('Restart %s.' % self.tname)
logger.debug('Restart %s.', self.tname)
# Reset DUT first
self.dut.reset()
# Capture output from the DUT
@@ -80,7 +83,7 @@ class DutTestThread(Thread):
""" The exit method of context manager
"""
if exc_type is not None or exc_value is not None:
logger.info('Thread %s rised an exception type: %s, value: %s' % (self.tname, str(exc_type), str(exc_value)))
logger.info('Thread %s rised an exception type: %s, value: %s', self.tname, str(exc_type), str(exc_value))
def run(self):
""" The function implements thread functionality
@@ -95,7 +98,7 @@ class DutTestThread(Thread):
# Check DUT exceptions
dut_exceptions = self.dut.get_exceptions()
if 'Guru Meditation Error:' in dut_exceptions:
raise Exception('%s generated an exception: %s\n' % (str(self.dut), dut_exceptions))
raise RuntimeError('%s generated an exception(s): %s\n' % (str(self.dut), dut_exceptions))
# Mark thread has run to completion without any exceptions
self.data = self.dut.stop_capture_raw_data(capture_id=self.dut.name)
@@ -106,15 +109,17 @@ class DutTestThread(Thread):
message = r'.*Waiting IP([0-9]{1,2}) from stdin.*'
# Read all data from previous restart to get prompt correctly
self.dut.read()
result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
if int(result[0]) != index:
raise Exception('Incorrect index of IP=%d for %s\n' % (int(result[0]), str(self.dut)))
message = 'IP%s=%s' % (result[0], self.ip_addr)
self.dut.write(message, '\r\n', False)
logger.debug('Sent message for %s: %s' % (self.tname, message))
raise RuntimeError('Incorrect index of IP=%s for %s\n' % (result[0], str(self.dut)))
# Use the same slave IP address for all characteristics during the test
self.dut.write('IP0=' + self.ip_addr, '\n', False)
self.dut.write('IP1=' + self.ip_addr, '\n', False)
self.dut.write('IP2=' + self.ip_addr, '\n', False)
logger.debug('Set IP address=%s for %s', self.ip_addr, self.tname)
message = r'.*IP\([0-9]+\) = \[([0-9a-zA-Z\.\:]+)\] set from stdin.*'
result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
logger.debug('Thread %s initialized with slave IP (%s).' % (self.tname, result[0]))
result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
logger.debug('Thread %s initialized with slave IP=%s.', self.tname, self.ip_addr)
def test_start(self, timeout_value):
""" The method to initialize and handle test stages
@@ -122,37 +127,37 @@ class DutTestThread(Thread):
def handle_get_ip4(data):
""" Handle get_ip v4
"""
logger.debug('%s[STACK_IPV4]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_IPV4]: %s', self.tname, str(data))
self.test_stage = STACK_IPV4
def handle_get_ip6(data):
""" Handle get_ip v6
"""
logger.debug('%s[STACK_IPV6]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_IPV6]: %s', self.tname, str(data))
self.test_stage = STACK_IPV6
def handle_init(data):
""" Handle init
"""
logger.debug('%s[STACK_INIT]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_INIT]: %s', self.tname, str(data))
self.test_stage = STACK_INIT
def handle_connect(data):
""" Handle connect
"""
logger.debug('%s[STACK_CONNECT]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_CONNECT]: %s', self.tname, str(data))
self.test_stage = STACK_CONNECT
def handle_test_start(data):
""" Handle connect
"""
logger.debug('%s[STACK_START]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_START]: %s', self.tname, str(data))
self.test_stage = STACK_START
def handle_par_ok(data):
""" Handle parameter ok
"""
logger.debug('%s[READ_PAR_OK]: %s' % (self.tname, str(data)))
logger.debug('%s[READ_PAR_OK]: %s', self.tname, str(data))
if self.test_stage >= STACK_START:
self.param_ok_count += 1
self.test_stage = STACK_PAR_OK
@@ -160,14 +165,14 @@ class DutTestThread(Thread):
def handle_par_fail(data):
""" Handle parameter fail
"""
logger.debug('%s[READ_PAR_FAIL]: %s' % (self.tname, str(data)))
logger.debug('%s[READ_PAR_FAIL]: %s', self.tname, str(data))
self.param_fail_count += 1
self.test_stage = STACK_PAR_FAIL
def handle_destroy(data):
""" Handle destroy
"""
logger.debug('%s[DESTROY]: %s' % (self.tname, str(data)))
logger.debug('%s[DESTROY]: %s', self.tname, str(data))
self.test_stage = STACK_DESTROY
self.test_finish = True
@@ -183,7 +188,7 @@ class DutTestThread(Thread):
(re.compile(self.expected[STACK_DESTROY]), handle_destroy),
timeout=timeout_value)
except DUT.ExpectTimeout:
logger.debug('%s, expect timeout on stage #%d (%s seconds)' % (self.tname, self.test_stage, timeout_value))
logger.debug('%s, expect timeout on stage #%d (%s seconds)', self.tname, self.test_stage, timeout_value)
self.test_finish = True
@@ -193,14 +198,14 @@ def test_check_mode(dut=None, mode_str=None, value=None):
global logger
try:
opt = dut.app.get_sdkconfig()[mode_str]
logger.debug('%s {%s} = %s.\n' % (str(dut), mode_str, opt))
logger.debug('%s {%s} = %s.\n', str(dut), mode_str, opt)
return value == opt
except Exception:
logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.' % (str(dut), mode_str))
logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.', str(dut), mode_str)
return False
@ttfw_idf.idf_example_test(env_tag='Example_Modbus_TCP')
@ttfw_idf.idf_example_test(env_tag='Example_Modbus_TCP', target=['esp32'])
def test_modbus_communication(env, comm_mode):
global logger
@@ -235,7 +240,7 @@ def test_modbus_communication(env, comm_mode):
master_name = TEST_MASTER_TCP
else:
logger.error('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
raise Exception('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
raise RuntimeError('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
address = None
if test_check_mode(dut_master, 'CONFIG_MB_SLAVE_IP_FROM_STDIN', 'y'):
logger.info('ENV_TEST_INFO: Set slave IP address through STDIN.\n')
@@ -249,9 +254,9 @@ def test_modbus_communication(env, comm_mode):
if address is not None:
print('Found IP slave address: %s' % address[0])
else:
raise Exception('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
raise RuntimeError('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
else:
raise Exception('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
raise RuntimeError('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
# Create thread for each dut
with DutTestThread(dut=dut_master, name=master_name, ip_addr=address[0], expect=pattern_dict_master) as dut_master_thread:
@@ -265,32 +270,32 @@ def test_modbus_communication(env, comm_mode):
dut_slave_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
dut_master_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
if dut_slave_thread.isAlive():
logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
raise Exception('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
if dut_slave_thread.is_alive():
logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
raise RuntimeError('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
if dut_master_thread.isAlive():
logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
raise Exception('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
if dut_master_thread.is_alive():
logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
raise RuntimeError('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n' %
(dut_master_thread.tname, dut_master_thread.param_fail_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count))
logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n' %
(dut_master_thread.tname, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_ok_count))
logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n',
dut_master_thread.tname, dut_master_thread.param_fail_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count)
logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n',
dut_master_thread.tname, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_ok_count)
if ((dut_master_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
(dut_slave_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
(dut_slave_thread.param_ok_count == 0) or
(dut_master_thread.param_ok_count == 0)):
raise Exception('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
(dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
raise RuntimeError('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
(dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
logger.info('TEST_SUCCESS: The Modbus parameter test is completed successfully.\n')
finally:

View File

@@ -12,7 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "string.h"
// FreeModbus Master Example ESP32
#include <string.h>
#include <sys/queue.h>
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
@@ -44,14 +47,6 @@
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
#define MB_MDNS_PORT (502)
#define MASTER_TAG "MASTER_TEST"
#define MASTER_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
}
// 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))
@@ -76,12 +71,14 @@
#endif
#define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp"
static const char *TAG = "MASTER_TEST";
// Enumeration of modbus device addresses accessed by master device
// Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
enum {
MB_DEVICE_ADDR1 = 1, // Slave address 1
MB_DEVICE_COUNT
MB_DEVICE_ADDR2 = 200,
MB_DEVICE_ADDR3 = 35
};
// Enumeration of all supported CIDs for device (used in parameter definition table)
@@ -114,11 +111,11 @@ const mb_parameter_descriptor_t device_parameters[] = {
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 2,
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 2, 2,
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 4, 2,
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR2, MB_PARAM_INPUT, 4, 2,
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2,
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR3, MB_PARAM_HOLDING, 4, 2,
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 0, 8,
COIL_OFFSET(coils_port0), PARAM_TYPE_U16, 2, OPTS( BIT1, 0, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
@@ -127,20 +124,26 @@ const mb_parameter_descriptor_t device_parameters[] = {
};
// Calculate number of parameters in the table
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters[0]));
const uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
// This table represents slave IP addresses that correspond to the short address field of the slave in device_parameters structure
// Modbus TCP stack shall use these addresses to be able to connect and read parameters from slave
char* slave_ip_address_table[MB_DEVICE_COUNT] = {
char* slave_ip_address_table[] = {
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
"FROM_STDIN", // Address corresponds to MB_DEVICE_ADDR1 and set to predefined value by user
NULL
"FROM_STDIN", // Corresponds to characteristic MB_DEVICE_ADDR2
"FROM_STDIN", // Corresponds to characteristic MB_DEVICE_ADDR3
NULL // End of table condition (must be included)
#elif CONFIG_MB_MDNS_IP_RESOLVER
NULL,
NULL,
NULL,
NULL
#endif
};
const size_t ip_table_sz = (size_t)(sizeof(slave_ip_address_table) / sizeof(slave_ip_address_table[0]));
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
// Scan IP address according to IPV settings
@@ -191,8 +194,8 @@ static int master_get_slave_ip_stdin(char** addr_table)
fputc('\n', stdout);
ip_str = master_scan_addr(&index, buf);
if (ip_str != NULL) {
ESP_LOGI(MASTER_TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
if ((ip_cnt >= MB_DEVICE_COUNT) || (index != ip_cnt)) {
ESP_LOGI(TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
if ((ip_cnt >= ip_table_sz) || (index != ip_cnt)) {
addr_table[ip_cnt] = NULL;
break;
}
@@ -204,10 +207,10 @@ static int master_get_slave_ip_stdin(char** addr_table)
}
} else {
if (addr_table[ip_cnt]) {
ESP_LOGI(MASTER_TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
ESP_LOGI(TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
ip_cnt++;
} else {
ESP_LOGI(MASTER_TAG, "IP(%d) is not set in the table.", ip_cnt);
ESP_LOGI(TAG, "IP(%d) is not set in the table.", ip_cnt);
break;
}
}
@@ -217,6 +220,16 @@ static int master_get_slave_ip_stdin(char** addr_table)
#elif CONFIG_MB_MDNS_IP_RESOLVER
typedef struct slave_addr_entry_s {
uint16_t index;
char* ip_address;
uint8_t slave_addr;
void* p_data;
LIST_ENTRY(slave_addr_entry_s) entries;
} slave_addr_entry_t;
LIST_HEAD(slave_addr_, slave_addr_entry_s) slave_addr_list = LIST_HEAD_INITIALIZER(slave_addr_list);
// convert MAC from binary format to string
static inline char* gen_mac_str(const uint8_t* mac, char* pref, char* mac_str)
{
@@ -240,7 +253,7 @@ static void master_start_mdns_service()
ESP_ERROR_CHECK(mdns_init());
// set mDNS hostname (required if you want to advertise services)
ESP_ERROR_CHECK(mdns_hostname_set(hostname));
ESP_LOGI(MASTER_TAG, "mdns hostname set to: [%s]", hostname);
ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname);
// set default mDNS instance name
ESP_ERROR_CHECK(mdns_instance_name_set(MB_MDNS_INSTANCE("esp32_")));
@@ -281,15 +294,21 @@ static char* master_get_slave_ip_str(mdns_ip_addr_t* address, mb_tcp_addr_type_t
return slave_ip_str;
}
static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, char** resolved_ip,
static esp_err_t master_resolve_slave(uint8_t short_addr, mdns_result_t* result, char** resolved_ip,
mb_tcp_addr_type_t addr_type)
{
if (!name || !result) {
if (!short_addr || !result || !resolved_ip) {
return ESP_ERR_INVALID_ARG;
}
mdns_result_t* r = result;
int t;
char* slave_ip = NULL;
char slave_name[22] = {0};
if (sprintf(slave_name, "mb_slave_tcp_%02X", short_addr) < 0) {
ESP_LOGE(TAG, "Fail to create instance name for index: %d", short_addr);
abort();
}
for (; r ; r = r->next) {
if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
continue;
@@ -298,7 +317,7 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
}
// Check host name for Modbus short address and
// append it into slave ip address table
if ((strcmp(r->instance_name, name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
if ((strcmp(r->instance_name, slave_name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
printf(" PTR : %s\n", r->instance_name);
if (r->txt_count) {
printf(" TXT : [%u] ", r->txt_count);
@@ -309,92 +328,124 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
}
slave_ip = master_get_slave_ip_str(r->addr, addr_type);
if (slave_ip) {
ESP_LOGI(MASTER_TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
*resolved_ip = slave_ip;
return ESP_OK;
}
}
}
*resolved_ip = NULL;
ESP_LOGD(MASTER_TAG, "Fail to resolve slave: %s", name);
ESP_LOGD(TAG, "Fail to resolve slave: %s", slave_name);
return ESP_ERR_NOT_FOUND;
}
static int master_create_slave_list(mdns_result_t* results, char** addr_table,
mb_tcp_addr_type_t addr_type)
int addr_table_size, mb_tcp_addr_type_t addr_type)
{
if (!results) {
return -1;
}
int i, addr, resolved = 0;
int i, slave_addr, cid_resolve_cnt = 0;
int ip_index = 0;
const mb_parameter_descriptor_t* pdescr = &device_parameters[0];
char** ip_table = addr_table;
char slave_name[22] = {0};
char* slave_ip = NULL;
slave_addr_entry_t *it;
for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++) {
addr = pdescr->mb_slave_addr;
if (-1 == sprintf(slave_name, "mb_slave_tcp_%02X", addr)) {
ESP_LOGI(MASTER_TAG, "Fail to create instance name for index: %d", addr);
abort();
for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++)
{
slave_addr = pdescr->mb_slave_addr;
it = NULL;
// Is the slave address already registered?
LIST_FOREACH(it, &slave_addr_list, entries) {
if (slave_addr == it->slave_addr) {
break;
}
}
if (!ip_table[addr - 1]) {
esp_err_t err = master_resolve_slave(slave_name, results, &slave_ip, addr_type);
if (!it) {
// Resolve new slave IP address using its short address
esp_err_t err = master_resolve_slave(slave_addr, results, &slave_ip, addr_type);
if (err != ESP_OK) {
ESP_LOGE(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, failed to resolve!",
i, addr, slave_name);
ESP_LOGE(TAG, "Index: %d, sl_addr: %d, failed to resolve!", i, slave_addr);
// Set correspond index to NULL indicate host not resolved
ip_table[addr - 1] = NULL;
ip_table[ip_index] = NULL;
continue;
}
ip_table[addr - 1] = slave_ip; //slave_name;
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, resolve to IP: [%s]",
i, addr, slave_name, slave_ip);
resolved++;
// Register new slave address information
slave_addr_entry_t* new_slave_entry = (slave_addr_entry_t*) heap_caps_malloc(sizeof(slave_addr_entry_t),
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
MB_RETURN_ON_FALSE((new_slave_entry != NULL), ESP_ERR_NO_MEM,
TAG, "Can not allocate memory for slave entry.");
new_slave_entry->index = i;
new_slave_entry->ip_address = slave_ip;
new_slave_entry->slave_addr = slave_addr;
new_slave_entry->p_data = NULL;
LIST_INSERT_HEAD(&slave_addr_list, new_slave_entry, entries);
ip_table[ip_index] = slave_ip;
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, resolved to IP: [%s]",
i, slave_addr, slave_ip);
cid_resolve_cnt++;
if (ip_index < addr_table_size) {
ip_index++;
}
} else {
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, set to IP: [%s]",
i, addr, slave_name, ip_table[addr - 1]);
resolved++;
}
}
return resolved;
}
static void master_destroy_slave_list(char** table)
{
for (int i = 0; ((i < MB_DEVICE_COUNT) && table[i] != NULL); i++) {
if (table[i]) {
free(table[i]);
table[i] = NULL;
ip_table[ip_index] = it ? it->ip_address : ip_table[ip_index];
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, set to IP: [%s]",
i, slave_addr, ip_table[ip_index]);
cid_resolve_cnt++;
}
}
ESP_LOGI(TAG, "Resolved %d cids, with %d IP addresses", cid_resolve_cnt, ip_index);
return cid_resolve_cnt;
}
static int master_query_slave_service(const char * service_name, const char * proto,
mb_tcp_addr_type_t addr_type)
{
ESP_LOGI(MASTER_TAG, "Query PTR: %s.%s.local", service_name, proto);
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
mdns_result_t* results = NULL;
int count = 0;
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
if(err){
ESP_LOGE(MASTER_TAG, "Query Failed: %s", esp_err_to_name(err));
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
return count;
}
if(!results){
ESP_LOGW(MASTER_TAG, "No results found!");
ESP_LOGW(TAG, "No results found!");
return count;
}
count = master_create_slave_list(results, slave_ip_address_table, addr_type);
count = master_create_slave_list(results, slave_ip_address_table, ip_table_sz, addr_type);
mdns_query_results_free(results);
return count;
}
#endif
static void master_destroy_slave_list(char** table, size_t ip_table_size)
{
#if CONFIG_MB_MDNS_IP_RESOLVER
slave_addr_entry_t *it;
LIST_FOREACH(it, &slave_addr_list, entries) {
LIST_REMOVE(it, entries);
free(it);
}
#endif
for (int i = 0; ((i < ip_table_size) && table[i] != NULL); i++) {
if (table[i]) {
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
free(table[i]);
table[i] = "FROM_STDIN";
#elif CONFIG_MB_MDNS_IP_RESOLVER
table[i] = NULL;
#endif
}
}
}
// The function to get pointer to parameter storage (instance) according to parameter description table
static void* master_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
{
@@ -420,7 +471,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
break;
}
} else {
ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
@@ -434,7 +485,7 @@ static void master_operation_func(void *arg)
bool alarm_state = false;
const mb_parameter_descriptor_t* param_descriptor = NULL;
ESP_LOGI(MASTER_TAG, "Start modbus test...");
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)
@@ -454,7 +505,7 @@ static void master_operation_func(void *arg)
*(float*)temp_data_ptr = value;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@@ -468,7 +519,7 @@ static void master_operation_func(void *arg)
} else {
uint16_t state = *(uint16_t*)temp_data_ptr;
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@@ -480,7 +531,7 @@ static void master_operation_func(void *arg)
}
}
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = %d (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = %d (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@@ -493,13 +544,13 @@ static void master_operation_func(void *arg)
}
if (alarm_state) {
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
param_descriptor->cid);
} else {
ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
MASTER_MAX_RETRY);
}
ESP_LOGI(MASTER_TAG, "Destroy master...");
ESP_LOGI(TAG, "Destroy master...");
vTaskDelay(100);
}
@@ -510,15 +561,18 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
ESP_ERROR_CHECK(nvs_flash_erase());
result = nvs_flash_init();
}
MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_netif_init();
MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_event_loop_create_default();
MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_create_default fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_MB_MDNS_IP_RESOLVER
@@ -529,12 +583,14 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
// Read "Establishing Wi-Fi or Ethernet Connection" section in
// examples/protocols/README.md for more information about this function.
result = example_connect();
MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_connect fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_EXAMPLE_CONNECT_WIFI
result = esp_wifi_set_ps(WIFI_PS_NONE);
MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_wifi_set_ps fail, returns(0x%x).",
(uint32_t)result);
#endif
@@ -544,17 +600,17 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
}
if (res < num_device_parameters) {
ESP_LOGE(MASTER_TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
ESP_LOGE(MASTER_TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
ESP_LOGE(TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
ESP_LOGE(TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
return ESP_ERR_NOT_FOUND;
}
mdns_free();
#elif CONFIG_MB_SLAVE_IP_FROM_STDIN
int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table);
if (ip_cnt) {
ESP_LOGI(MASTER_TAG, "Configured %d IP addresse(s).", ip_cnt);
ESP_LOGI(TAG, "Configured %d IP addresse(s).", ip_cnt);
} else {
ESP_LOGE(MASTER_TAG, "Fail to get IP address from stdin. Continue.");
ESP_LOGE(TAG, "Fail to get IP address from stdin. Continue.");
return ESP_ERR_NOT_FOUND;
}
#endif
@@ -564,23 +620,26 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
static esp_err_t destroy_services(void)
{
esp_err_t err = ESP_OK;
#if CONFIG_MB_MDNS_IP_RESOLVER
master_destroy_slave_list(slave_ip_address_table);
#endif
master_destroy_slave_list(slave_ip_address_table, ip_table_sz);
err = example_disconnect();
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_disconnect fail, returns(0x%x).",
(uint32_t)err);
err = esp_event_loop_delete_default();
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_delete_default fail, returns(0x%x).",
(uint32_t)err);
err = esp_netif_deinit();
MASTER_CHECK((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_deinit fail, returns(0x%x).",
(uint32_t)err);
err = nvs_flash_deinit();
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_deinit fail, returns(0x%x).",
(uint32_t)err);
return err;
@@ -592,25 +651,30 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
void* master_handler = NULL;
esp_err_t err = mbc_master_init_tcp(&master_handler);
MASTER_CHECK((master_handler != NULL), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
TAG,
"mb controller initialization fail.");
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller initialization fail, returns(0x%x).",
(uint32_t)err);
err = mbc_master_setup((void*)comm_info);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller setup fail, returns(0x%x).",
(uint32_t)err);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller set descriptor fail, returns(0x%x).",
(uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
ESP_LOGI(TAG, "Modbus master stack initialized...");
err = mbc_master_start();
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller start fail, returns(0x%x).",
(uint32_t)err);
vTaskDelay(5);
@@ -620,10 +684,11 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
static esp_err_t master_destroy(void)
{
esp_err_t err = mbc_master_destroy();
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_master_destroy fail, returns(0x%x).",
(uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack destroy...");
ESP_LOGI(TAG, "Modbus master stack destroy...");
return err;
}

View File

@@ -2,7 +2,7 @@ menu "Modbus Example Configuration"
config MB_SLAVE_ADDR
int "Modbus slave address"
range 1 127
range 1 255
default 1
help
This is the Modbus slave address in the network.

View File

@@ -8,7 +8,6 @@
#include "esp_err.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
@@ -47,13 +46,7 @@
| MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
#define SLAVE_TAG "SLAVE_TEST"
#define SLAVE_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(SLAVE_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
}
static const char *TAG = "SLAVE_TEST";
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
@@ -167,8 +160,8 @@ static void slave_operation_func(void *arg)
{
mb_param_info_t reg_info; // keeps the Modbus registers access information
ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
ESP_LOGI(SLAVE_TAG, "Start modbus test...");
ESP_LOGI(TAG, "Modbus slave stack initialized.");
ESP_LOGI(TAG, "Start modbus test...");
// The cycle below will be terminated when parameter holding_data0
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
@@ -179,7 +172,7 @@ static void slave_operation_func(void *arg)
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
// Get parameter information from parameter queue
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@@ -197,7 +190,7 @@ static void slave_operation_func(void *arg)
}
} else if (event & MB_EVENT_INPUT_REG_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@@ -205,7 +198,7 @@ static void slave_operation_func(void *arg)
(uint32_t)reg_info.size);
} else if (event & MB_EVENT_DISCRETE_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@@ -213,7 +206,7 @@ static void slave_operation_func(void *arg)
(uint32_t)reg_info.size);
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@@ -224,7 +217,7 @@ static void slave_operation_func(void *arg)
}
}
// Destroy of Modbus controller on alarm
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
ESP_LOGI(TAG,"Modbus controller destroyed.");
vTaskDelay(100);
}
@@ -235,15 +228,18 @@ static esp_err_t init_services(void)
ESP_ERROR_CHECK(nvs_flash_erase());
result = nvs_flash_init();
}
SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_netif_init();
SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_event_loop_create_default();
SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_create_default fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_MB_MDNS_IP_RESOLVER
@@ -254,12 +250,14 @@ static esp_err_t init_services(void)
// Read "Establishing Wi-Fi or Ethernet Connection" section in
// examples/protocols/README.md for more information about this function.
result = example_connect();
SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_connect fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_EXAMPLE_CONNECT_WIFI
result = esp_wifi_set_ps(WIFI_PS_NONE);
SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_wifi_set_ps fail, returns(0x%x).",
(uint32_t)result);
#endif
@@ -271,19 +269,23 @@ static esp_err_t destroy_services(void)
esp_err_t err = ESP_OK;
err = example_disconnect();
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_disconnect fail, returns(0x%x).",
(uint32_t)err);
err = esp_event_loop_delete_default();
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_delete_default fail, returns(0x%x).",
(uint32_t)err);
err = esp_netif_deinit();
SLAVE_CHECK((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_deinit fail, returns(0x%x).",
(uint32_t)err);
err = nvs_flash_deinit();
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_deinit fail, returns(0x%x).",
(uint32_t)err);
#if CONFIG_MB_MDNS_IP_RESOLVER
@@ -301,7 +303,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
// Initialization of Modbus controller
esp_err_t err = mbc_slave_init_tcp(&slave_handler);
SLAVE_CHECK((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
TAG,
"mb controller initialization fail.");
comm_info->ip_addr = NULL; // Bind to any address
@@ -309,7 +312,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
// Setup communication parameters and start stack
err = mbc_slave_setup((void*)comm_info);
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_setup fail, returns(0x%x).",
(uint32_t)err);
@@ -324,7 +328,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
err = mbc_slave_set_descriptor(reg_area);
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@@ -333,7 +338,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
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
err = mbc_slave_set_descriptor(reg_area);
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@@ -343,7 +349,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&input_reg_params.input_data0;
reg_area.size = sizeof(float) << 2;
err = mbc_slave_set_descriptor(reg_area);
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
reg_area.type = MB_PARAM_INPUT;
@@ -351,7 +358,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&input_reg_params.input_data4;
reg_area.size = sizeof(float) << 2;
err = mbc_slave_set_descriptor(reg_area);
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@@ -361,7 +369,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&coil_reg_params;
reg_area.size = sizeof(coil_reg_params);
err = mbc_slave_set_descriptor(reg_area);
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@@ -371,7 +380,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&discrete_reg_params;
reg_area.size = sizeof(discrete_reg_params);
err = mbc_slave_set_descriptor(reg_area);
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@@ -380,7 +390,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
// Starts of modbus controller and stack
err = mbc_slave_start();
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_start fail, returns(0x%x).",
(uint32_t)err);
vTaskDelay(5);
@@ -390,7 +401,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
static esp_err_t slave_destroy(void)
{
esp_err_t err = mbc_slave_destroy();
SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_destroy fail, returns(0x%x).",
(uint32_t)err);
return err;
@@ -405,7 +417,7 @@ void app_main(void)
ESP_ERROR_CHECK(init_services());
// Set UART log level
esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
esp_log_level_set(TAG, ESP_LOG_INFO);
mb_communication_info_t comm_info = { 0 };