mirror of
https://github.com/espressif/esp-modbus.git
synced 2025-08-02 20:04:27 +02:00
update examples
This commit is contained in:
@@ -58,6 +58,8 @@
|
|||||||
#define EACH_ITEM(array, length) \
|
#define EACH_ITEM(array, length) \
|
||||||
(typeof(*(array)) *pitem = (array); (pitem < &((array)[length])); pitem++)
|
(typeof(*(array)) *pitem = (array); (pitem < &((array)[length])); pitem++)
|
||||||
|
|
||||||
|
#define MB_CUST_DATA_LEN 100 // The length of custom command buffer
|
||||||
|
|
||||||
static const char *TAG = "MASTER_TEST";
|
static const char *TAG = "MASTER_TEST";
|
||||||
|
|
||||||
// Enumeration of modbus device addresses accessed by master device
|
// Enumeration of modbus device addresses accessed by master device
|
||||||
@@ -217,6 +219,8 @@ const mb_parameter_descriptor_t device_parameters[] = {
|
|||||||
// Calculate number of parameters in the table
|
// 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]));
|
||||||
|
|
||||||
|
static char my_custom_data[MB_CUST_DATA_LEN] = {0}; // the custom data buffer
|
||||||
|
|
||||||
static void *master_handle = NULL;
|
static void *master_handle = NULL;
|
||||||
|
|
||||||
// The function to get pointer to parameter storage (instance) according to parameter description table
|
// The function to get pointer to parameter storage (instance) according to parameter description table
|
||||||
@@ -301,6 +305,19 @@ static void *master_get_param_data(const mb_parameter_descriptor_t *param_descri
|
|||||||
} \
|
} \
|
||||||
))
|
))
|
||||||
|
|
||||||
|
mb_exception_t my_custom_handler(void *, uint8_t *frame_ptr, uint16_t *plen)
|
||||||
|
{
|
||||||
|
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen && *plen < (MB_CUST_DATA_LEN - 1)), MB_EX_CRITICAL, TAG,
|
||||||
|
"incorrect custom frame buffer");
|
||||||
|
ESP_LOGW(TAG, "Custom handler, Frame ptr: %p, len: %u", frame_ptr, *plen);
|
||||||
|
// This error handler will be executed to handle the request for the registered custom command
|
||||||
|
// Refer the handler functions in `esp-modbus/modbus/mb_objects/functions/mbfuncinput_master.c` for more information.
|
||||||
|
// Parameters: pframe: is pointer to incoming frame buffer, plen: is pointer to length including the function code
|
||||||
|
strncpy((char *)&my_custom_data[0], (char *)&frame_ptr[1], MB_CUST_DATA_LEN);
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("CUSTOM_DATA", &my_custom_data[0], (*plen - 1), ESP_LOG_WARN);
|
||||||
|
return MB_EX_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
// User operation function to read slave values and check alarm
|
// User operation function to read slave values and check alarm
|
||||||
static void master_operation_func(void *arg)
|
static void master_operation_func(void *arg)
|
||||||
{
|
{
|
||||||
@@ -310,6 +327,20 @@ static void master_operation_func(void *arg)
|
|||||||
|
|
||||||
ESP_LOGI(TAG, "Start modbus test...");
|
ESP_LOGI(TAG, "Start modbus test...");
|
||||||
|
|
||||||
|
char *pcustom_string = "Master";
|
||||||
|
mb_param_request_t req = {
|
||||||
|
.slave_addr = MB_DEVICE_ADDR1, // the slave UID to send the request
|
||||||
|
.command = 0x41, // the custom function code,
|
||||||
|
.reg_start = 0, // unused,
|
||||||
|
.reg_size = (strlen(pcustom_string) >> 1) // length of the data to send (registers)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the request with custom command (vendor speciic)
|
||||||
|
err = mbc_master_send_request(master_handle, &req, pcustom_string);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE("CUSTOM_DATA", "Send custom request fail.");
|
||||||
|
}
|
||||||
|
|
||||||
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED
|
#if MB_FUNC_OTHER_REP_SLAVEID_ENABLED
|
||||||
// Command - 17 (0x11) Report Slave ID
|
// Command - 17 (0x11) Report Slave ID
|
||||||
// The command contains vendor specific data and should be interpreted accordingly.
|
// The command contains vendor specific data and should be interpreted accordingly.
|
||||||
@@ -318,7 +349,7 @@ static void master_operation_func(void *arg)
|
|||||||
// The returned slave info data will be stored into the `info_buf`.
|
// The returned slave info data will be stored into the `info_buf`.
|
||||||
// Request fields: slave_addr - the UID of slave, reg_start - not used,
|
// Request fields: slave_addr - the UID of slave, reg_start - not used,
|
||||||
// reg_size = max size of buffer (registers).
|
// reg_size = max size of buffer (registers).
|
||||||
mb_param_request_t req = {
|
req = {
|
||||||
.slave_addr = MB_DEVICE_ADDR1, // slave UID to retrieve ID
|
.slave_addr = MB_DEVICE_ADDR1, // slave UID to retrieve ID
|
||||||
.command = 0x11, // the <Report Slave ID> command,
|
.command = 0x11, // the <Report Slave ID> command,
|
||||||
.reg_start = 0, // must be zero,
|
.reg_start = 0, // must be zero,
|
||||||
@@ -492,6 +523,18 @@ static esp_err_t master_init(void)
|
|||||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb controller initialization fail, returns(0x%x).", (int)err);
|
"mb controller initialization fail, returns(0x%x).", (int)err);
|
||||||
|
|
||||||
|
uint8_t override_command = 0x41;
|
||||||
|
err = mbc_master_set_handler(master_handle, override_command, NULL);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_INVALID_STATE), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not override handler, returned (0x%x).", (int)err);
|
||||||
|
err = mbc_master_set_handler(master_handle, override_command, my_custom_handler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not override handler, returned (0x%x).", (int)err);
|
||||||
|
mb_fn_handler_fp phandler = NULL;
|
||||||
|
err = mbc_master_get_handler(master_handle, override_command, &phandler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_handler), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not get handler for command %d, returned (0x%x).", (int)override_command, (int)err);
|
||||||
|
|
||||||
// Set UART pin numbers
|
// Set UART pin numbers
|
||||||
err = uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD,
|
err = uart_set_pin(MB_PORT_NUM, CONFIG_MB_UART_TXD, CONFIG_MB_UART_RXD,
|
||||||
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
|
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
|
||||||
|
@@ -43,7 +43,8 @@
|
|||||||
#define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR \
|
#define MB_WRITE_MASK (MB_EVENT_HOLDING_REG_WR \
|
||||||
| MB_EVENT_COILS_WR)
|
| MB_EVENT_COILS_WR)
|
||||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||||
#define MB_TEST_VALUE 12345.0
|
#define MB_TEST_VALUE (12345.0)
|
||||||
|
#define MB_CUST_DATA_MAX_LEN (100)
|
||||||
|
|
||||||
static const char *TAG = "SLAVE_TEST";
|
static const char *TAG = "SLAVE_TEST";
|
||||||
|
|
||||||
@@ -144,6 +145,22 @@ static void setup_reg_data(void)
|
|||||||
input_reg_params.input_data7 = 4.78;
|
input_reg_params.input_data7 = 4.78;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mb_exception_t my_custom_fc_handler(void *pinst, uint8_t *frame_ptr, uint16_t *plen)
|
||||||
|
{
|
||||||
|
char *str_append = ":Slave";
|
||||||
|
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen < (MB_CUST_DATA_MAX_LEN - strlen(str_append))), MB_EX_ILLEGAL_DATA_VALUE, TAG,
|
||||||
|
"incorrect custom frame");
|
||||||
|
//ESP_LOGW("CUSTOM_DATA", "Custom handler, frame ptr: %p, len: %u", frame_ptr, *plen);
|
||||||
|
//ESP_LOG_BUFFER_HEXDUMP("CUSTOM_DATA", frame_ptr, *plen, ESP_LOG_WARN);
|
||||||
|
// This command handler will be executed to check the request for the custom command
|
||||||
|
// See the `esp-modbus/modbus/mb_objects/functions/functions/mbfuncinput.c` for more information
|
||||||
|
// pframe is pointer to the buffer starting from function code, plen - is pointer to length of the data
|
||||||
|
frame_ptr[*plen] = '\0';
|
||||||
|
strcat((char *)&frame_ptr[1], str_append);
|
||||||
|
*plen = (strlen(str_append) + *plen); // the length of (response + command)
|
||||||
|
return MB_EX_NONE; // Set the exception code for slave appropriately
|
||||||
|
}
|
||||||
|
|
||||||
// An example application of Modbus slave. It is based on esp-modbus stack.
|
// An example application of Modbus slave. It is based on esp-modbus stack.
|
||||||
// See deviceparams.h file for more information about assigned Modbus parameters.
|
// See deviceparams.h file for more information about assigned Modbus parameters.
|
||||||
// These parameters can be accessed from main application and also can be changed
|
// These parameters can be accessed from main application and also can be changed
|
||||||
@@ -173,6 +190,18 @@ void app_main(void)
|
|||||||
|
|
||||||
ESP_ERROR_CHECK(mbc_slave_create_serial(&comm_config, &mbc_slave_handle)); // Initialization of Modbus controller
|
ESP_ERROR_CHECK(mbc_slave_create_serial(&comm_config, &mbc_slave_handle)); // Initialization of Modbus controller
|
||||||
|
|
||||||
|
uint8_t custom_command = 0x41; // The custom command to be sent to slave
|
||||||
|
esp_err_t err = mbc_slave_set_handler(mbc_slave_handle, custom_command, NULL);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_INVALID_STATE), ;, TAG,
|
||||||
|
"could not reset handler, returned (0x%x).", (int)err);
|
||||||
|
err = mbc_slave_set_handler(mbc_slave_handle, custom_command, my_custom_fc_handler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG,
|
||||||
|
"could not set or override handler, returned (0x%x).", (int)err);
|
||||||
|
mb_fn_handler_fp phandler = NULL;
|
||||||
|
err = mbc_slave_get_handler(mbc_slave_handle, custom_command, &phandler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_fc_handler), ;, TAG,
|
||||||
|
"could not get handler for command %d, returned (0x%x).", (int)custom_command, (int)err);
|
||||||
|
|
||||||
// The code below initializes Modbus register area descriptors
|
// The code below initializes Modbus register area descriptors
|
||||||
// for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
|
// for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
|
||||||
// Initialization should be done for each supported Modbus register area according to register map.
|
// Initialization should be done for each supported Modbus register area according to register map.
|
||||||
@@ -243,7 +272,7 @@ void app_main(void)
|
|||||||
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
|
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
|
||||||
|
|
||||||
// Starts of modbus controller and stack
|
// Starts of modbus controller and stack
|
||||||
esp_err_t err = mbc_slave_start(mbc_slave_handle);
|
err = mbc_slave_start(mbc_slave_handle);
|
||||||
|
|
||||||
#if CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT
|
#if CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT
|
||||||
// Initialize the new slave identificator structure (example)
|
// Initialize the new slave identificator structure (example)
|
||||||
|
@@ -14,8 +14,8 @@ from conftest import ModbusTestDut, Stages
|
|||||||
|
|
||||||
pattern_dict_slave = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_connect: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
pattern_dict_slave = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_connect: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||||
Stages.STACK_IPV6: (r'I \([0-9]+\) example_connect: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
Stages.STACK_IPV6: (r'I \([0-9]+\) example_connect: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
||||||
Stages.STACK_INIT: (r'I \(([0-9]+)\) MB_TCP_SLAVE_PORT: (Protocol stack initialized).'),
|
Stages.STACK_INIT: (r'I \(([0-9]+)\) SLAVE_TEST: (Modbus slave stack initialized)'),
|
||||||
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) MB_TCP_SLAVE_PORT: Socket \(#[0-9]+\), accept client connection from address: '
|
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) SLAVE_TEST: Socket \(#[0-9]+\), accept client connection from address: '
|
||||||
r'([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
r'([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||||
Stages.STACK_START: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Start modbus test)'),
|
Stages.STACK_START: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Start modbus test)'),
|
||||||
Stages.STACK_PAR_OK: (r'I\s\(([0-9]+)\) SLAVE_TEST: ([A-Z]+ [A-Z]+) \([a-zA-Z0-9_]+ us\),\s'
|
Stages.STACK_PAR_OK: (r'I\s\(([0-9]+)\) SLAVE_TEST: ([A-Z]+ [A-Z]+) \([a-zA-Z0-9_]+ us\),\s'
|
||||||
@@ -48,16 +48,16 @@ test_configs = [
|
|||||||
@pytest.mark.parametrize('config', test_configs, indirect=True)
|
@pytest.mark.parametrize('config', test_configs, indirect=True)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'count, app_path', [
|
'count, app_path', [
|
||||||
(2, f'{os.path.join(os.path.dirname(__file__), "mb_serial_master")}|{os.path.join(os.path.dirname(__file__), "mb_serial_slave")}')
|
(2, f'{os.path.join(os.path.dirname(__file__), "mb_serial_slave")}|{os.path.join(os.path.dirname(__file__), "mb_serial_master")}')
|
||||||
],
|
],
|
||||||
indirect=True
|
indirect=True
|
||||||
)
|
)
|
||||||
def test_modbus_serial_communication(config: str, dut: Tuple[ModbusTestDut, ModbusTestDut]) -> None:
|
def test_modbus_serial_communication(config: str, dut: Tuple[ModbusTestDut, ModbusTestDut]) -> None:
|
||||||
dut_slave = dut[1]
|
dut_slave = dut[0]
|
||||||
dut_master = dut[0]
|
dut_master = dut[1]
|
||||||
|
|
||||||
logger.info('DUT: %s start.', dut_master.dut_get_name())
|
|
||||||
logger.info('DUT: %s start.', dut_slave.dut_get_name())
|
logger.info('DUT: %s start.', dut_slave.dut_get_name())
|
||||||
|
logger.info('DUT: %s start.', dut_master.dut_get_name())
|
||||||
|
|
||||||
dut_slave.dut_test_start(dictionary=pattern_dict_slave)
|
dut_slave.dut_test_start(dictionary=pattern_dict_slave)
|
||||||
dut_master.dut_test_start(dictionary=pattern_dict_master)
|
dut_master.dut_test_start(dictionary=pattern_dict_master)
|
||||||
|
@@ -83,6 +83,8 @@
|
|||||||
#define EACH_ITEM(array, length) \
|
#define EACH_ITEM(array, length) \
|
||||||
(typeof(*(array)) *pitem = (array); (pitem < &((array)[length])); pitem++)
|
(typeof(*(array)) *pitem = (array); (pitem < &((array)[length])); pitem++)
|
||||||
|
|
||||||
|
#define MB_CUST_DATA_LEN 100 // The length of custom command buffer
|
||||||
|
|
||||||
static const char *TAG = "MASTER_TEST";
|
static const char *TAG = "MASTER_TEST";
|
||||||
|
|
||||||
// Enumeration of modbus device addresses accessed by master device
|
// Enumeration of modbus device addresses accessed by master device
|
||||||
@@ -268,6 +270,7 @@ char* slave_ip_address_table[MB_DEVICE_COUNT + 1] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const size_t ip_table_sz = (size_t)(sizeof(slave_ip_address_table) / sizeof(slave_ip_address_table[0]));
|
const size_t ip_table_sz = (size_t)(sizeof(slave_ip_address_table) / sizeof(slave_ip_address_table[0]));
|
||||||
|
static char my_custom_data[MB_CUST_DATA_LEN] = {0}; // custom data buffer to handle slave response
|
||||||
|
|
||||||
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
|
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
|
||||||
|
|
||||||
@@ -450,6 +453,20 @@ static void master_operation_func(void *arg)
|
|||||||
|
|
||||||
ESP_LOGI(TAG, "Start modbus test...");
|
ESP_LOGI(TAG, "Start modbus test...");
|
||||||
|
|
||||||
|
char *pcustom_string = "Master";
|
||||||
|
mb_param_request_t req = {
|
||||||
|
.slave_addr = MB_DEVICE_ADDR1, // the slave UID to send the request
|
||||||
|
.command = 0x41, // the custom function code,
|
||||||
|
.reg_start = 0, // unused,
|
||||||
|
.reg_size = (strlen(pcustom_string) >> 1) // length of the data to send (registers)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Send the request with custom command (vendor speciic)
|
||||||
|
err = mbc_master_send_request(master_handle, &req, pcustom_string);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
ESP_LOGE("CUSTOM_DATA", "Send custom request fail.");
|
||||||
|
}
|
||||||
|
|
||||||
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
||||||
// Read all found characteristics from slave(s)
|
// Read all found characteristics from slave(s)
|
||||||
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++) {
|
for (uint16_t cid = 0; (err != ESP_ERR_NOT_FOUND) && cid < MASTER_MAX_CIDS; cid++) {
|
||||||
@@ -658,6 +675,19 @@ static esp_err_t destroy_services(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mb_exception_t my_custom_fc_handler(void *pinst, uint8_t *frame_ptr, uint16_t *plen)
|
||||||
|
{
|
||||||
|
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen && *plen < (MB_CUST_DATA_LEN - 1)), MB_EX_CRITICAL, TAG,
|
||||||
|
"incorrect custom frame buffer");
|
||||||
|
ESP_LOGW(TAG, "Custom handler, Frame ptr: %p, len: %u", frame_ptr, *plen);
|
||||||
|
// This error handler will be executed to handle the request for the registered custom command
|
||||||
|
// Refer the handler functions in `esp-modbus/modbus/mb_objects/functions/mbfuncinput_master.c` for more information.
|
||||||
|
// Parameters: pframe: is pointer to incoming frame buffer, plen: is pointer to length including the function code
|
||||||
|
strncpy((char *)&my_custom_data[0], (char *)&frame_ptr[1], MB_CUST_DATA_LEN);
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("CUSTOM_DATA", &my_custom_data[0], (*plen - 1), ESP_LOG_WARN);
|
||||||
|
return MB_EX_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
// Modbus master initialization
|
// Modbus master initialization
|
||||||
static esp_err_t master_init(mb_communication_info_t *pcomm_info)
|
static esp_err_t master_init(mb_communication_info_t *pcomm_info)
|
||||||
{
|
{
|
||||||
@@ -670,6 +700,20 @@ static esp_err_t master_init(mb_communication_info_t *pcomm_info)
|
|||||||
"mb controller initialization fail, returns(0x%x).",
|
"mb controller initialization fail, returns(0x%x).",
|
||||||
(int)err);
|
(int)err);
|
||||||
|
|
||||||
|
// Add custom command handler
|
||||||
|
uint8_t custom_command = 0x41;
|
||||||
|
// Make sure the handler is undefined for the command
|
||||||
|
err = mbc_master_set_handler(master_handle, custom_command, NULL);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_INVALID_STATE), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not override handler, returned (0x%x).", (int)err);
|
||||||
|
err = mbc_master_set_handler(master_handle, custom_command, my_custom_fc_handler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not override handler, returned (0x%x).", (int)err);
|
||||||
|
mb_fn_handler_fp phandler = NULL;
|
||||||
|
err = mbc_master_get_handler(master_handle, custom_command, &phandler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_fc_handler), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not get handler for command %d, returned (0x%x).", (int)custom_command, (int)err);
|
||||||
|
|
||||||
err = mbc_master_set_descriptor(master_handle, &device_parameters[0], num_device_parameters);
|
err = mbc_master_set_descriptor(master_handle, &device_parameters[0], num_device_parameters);
|
||||||
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
TAG,
|
TAG,
|
||||||
|
@@ -43,8 +43,8 @@
|
|||||||
#define MB_REG_HOLDING_START_AREA2_SIZE ((size_t)((HOLD_OFFSET(holding_area2_end) - HOLD_OFFSET(holding_u8_a)) << 1))
|
#define MB_REG_HOLDING_START_AREA2_SIZE ((size_t)((HOLD_OFFSET(holding_area2_end) - HOLD_OFFSET(holding_u8_a)) << 1))
|
||||||
|
|
||||||
#define MB_PAR_INFO_GET_TOUT (10) // Timeout for get parameter info
|
#define MB_PAR_INFO_GET_TOUT (10) // Timeout for get parameter info
|
||||||
#define MB_CHAN_DATA_MAX_VAL (10)
|
#define MB_CHAN_DATA_MAX_VAL (50)
|
||||||
#define MB_CHAN_DATA_OFFSET (1.1f)
|
#define MB_CHAN_DATA_OFFSET (10.1f)
|
||||||
|
|
||||||
#define MB_READ_MASK (MB_EVENT_INPUT_REG_RD \
|
#define MB_READ_MASK (MB_EVENT_INPUT_REG_RD \
|
||||||
| MB_EVENT_HOLDING_REG_RD \
|
| MB_EVENT_HOLDING_REG_RD \
|
||||||
@@ -55,6 +55,7 @@
|
|||||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||||
#define MB_TEST_VALUE (12345.0)
|
#define MB_TEST_VALUE (12345.0)
|
||||||
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
|
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
|
||||||
|
#define MB_CUST_DATA_MAX_LEN (100)
|
||||||
|
|
||||||
static const char *TAG = "SLAVE_TEST";
|
static const char *TAG = "SLAVE_TEST";
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ static void slave_operation_func(void *arg)
|
|||||||
(unsigned)reg_info.size);
|
(unsigned)reg_info.size);
|
||||||
if (reg_info.address == (uint8_t*)&holding_reg_params.holding_data0)
|
if (reg_info.address == (uint8_t*)&holding_reg_params.holding_data0)
|
||||||
{
|
{
|
||||||
(void)mbc_slave_unlock(slave_handle);
|
(void)mbc_slave_lock(slave_handle);
|
||||||
holding_reg_params.holding_data0 += MB_CHAN_DATA_OFFSET;
|
holding_reg_params.holding_data0 += MB_CHAN_DATA_OFFSET;
|
||||||
if (holding_reg_params.holding_data0 >= (MB_CHAN_DATA_MAX_VAL - MB_CHAN_DATA_OFFSET)) {
|
if (holding_reg_params.holding_data0 >= (MB_CHAN_DATA_MAX_VAL - MB_CHAN_DATA_OFFSET)) {
|
||||||
coil_reg_params.coils_port1 = 0xFF;
|
coil_reg_params.coils_port1 = 0xFF;
|
||||||
@@ -266,6 +267,23 @@ static esp_err_t destroy_services(void)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This custom command handler will be executed to check the request for the custom command
|
||||||
|
// See the `esp-modbus/modbus/mb_objects/functions/mbfuncinput.c` for more information
|
||||||
|
// pframe is pointer to the buffer starting from function code, plen - is pointer to length of the data
|
||||||
|
mb_exception_t my_custom_fc_handler(void *pinst, uint8_t *frame_ptr, uint16_t *plen)
|
||||||
|
{
|
||||||
|
char *str_append = ":Slave";
|
||||||
|
MB_RETURN_ON_FALSE((frame_ptr && plen && *plen < (MB_CUST_DATA_MAX_LEN - strlen(str_append))),
|
||||||
|
MB_EX_ILLEGAL_DATA_VALUE, TAG,
|
||||||
|
"incorrect custom frame");
|
||||||
|
ESP_LOGW("CUSTOM_DATA", "Custom handler, frame ptr: %p, len: %u", frame_ptr, *plen);
|
||||||
|
ESP_LOG_BUFFER_HEXDUMP("CUSTOM_DATA", frame_ptr, *plen, ESP_LOG_WARN);
|
||||||
|
frame_ptr[*plen] = '\0';
|
||||||
|
strcat((char *)&frame_ptr[1], str_append);
|
||||||
|
*plen = (strlen(str_append) + *plen); // the length of (response + command)
|
||||||
|
return MB_EX_NONE; // Set the exception code for slave appropriately
|
||||||
|
}
|
||||||
|
|
||||||
// Modbus slave initialization
|
// Modbus slave initialization
|
||||||
static esp_err_t slave_init(mb_communication_info_t *pcomm_info)
|
static esp_err_t slave_init(mb_communication_info_t *pcomm_info)
|
||||||
{
|
{
|
||||||
@@ -277,6 +295,18 @@ static esp_err_t slave_init(mb_communication_info_t *pcomm_info)
|
|||||||
TAG,
|
TAG,
|
||||||
"mb controller create fail.");
|
"mb controller create fail.");
|
||||||
|
|
||||||
|
uint8_t custom_command = 0x41;
|
||||||
|
err = mbc_slave_set_handler(slave_handle, custom_command, NULL);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_INVALID_STATE), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not reset handler, returned (0x%x).", (int)err);
|
||||||
|
err = mbc_slave_set_handler(slave_handle, custom_command, my_custom_fc_handler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not set or override handler, returned (0x%x).", (int)err);
|
||||||
|
mb_fn_handler_fp phandler = NULL;
|
||||||
|
err = mbc_slave_get_handler(slave_handle, custom_command, &phandler);
|
||||||
|
MB_RETURN_ON_FALSE((err == ESP_OK && phandler == my_custom_fc_handler), ESP_ERR_INVALID_STATE, TAG,
|
||||||
|
"could not get handler for command %d, returned (0x%x).", (int)custom_command, (int)err);
|
||||||
|
|
||||||
// The code below initializes Modbus register area descriptors
|
// The code below initializes Modbus register area descriptors
|
||||||
// for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
|
// for Modbus Holding Registers, Input Registers, Coils and Discrete Inputs
|
||||||
// Initialization should be done for each supported Modbus register area according to register map.
|
// Initialization should be done for each supported Modbus register area according to register map.
|
||||||
|
@@ -14,7 +14,7 @@ from conftest import ModbusTestDut, Stages
|
|||||||
|
|
||||||
pattern_dict_slave = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_[a-z]+: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
pattern_dict_slave = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_[a-z]+: - IPv4 address: ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||||
Stages.STACK_IPV6: (r'I \([0-9]+\) example_[a-z]+: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
Stages.STACK_IPV6: (r'I \([0-9]+\) example_[a-z]+: - IPv6 address: (([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})'),
|
||||||
Stages.STACK_INIT: (r'I \(([0-9]+)\) MB_TCP_SLAVE_PORT: (Protocol stack initialized).'),
|
Stages.STACK_INIT: (r'I \(([0-9]+)\) SLAVE_TEST: (Modbus slave stack initialized)'),
|
||||||
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) MB_TCP_SLAVE_PORT: Socket \(#[0-9]+\), accept client connection from address: '
|
Stages.STACK_CONNECT: (r'I\s\(([0-9]+)\) MB_TCP_SLAVE_PORT: Socket \(#[0-9]+\), accept client connection from address: '
|
||||||
r'([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
r'([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})'),
|
||||||
Stages.STACK_START: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Start modbus test)'),
|
Stages.STACK_START: (r'I\s\(([0-9]+)\) SLAVE_TEST: (Start modbus test)'),
|
||||||
@@ -36,12 +36,11 @@ pattern_dict_master = {Stages.STACK_IPV4: (r'I \([0-9]+\) example_[a-z]+: - IPv4
|
|||||||
|
|
||||||
LOG_LEVEL = logging.DEBUG
|
LOG_LEVEL = logging.DEBUG
|
||||||
LOGGER_NAME = 'modbus_test'
|
LOGGER_NAME = 'modbus_test'
|
||||||
CONFORMANCE_TEST_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../tools/robot'))
|
|
||||||
logger = logging.getLogger(LOGGER_NAME)
|
logger = logging.getLogger(LOGGER_NAME)
|
||||||
|
|
||||||
test_configs = [
|
test_configs = [
|
||||||
'wifi',
|
'wifi',
|
||||||
'ethernet'
|
# 'ethernet'
|
||||||
]
|
]
|
||||||
|
|
||||||
@pytest.mark.esp32
|
@pytest.mark.esp32
|
||||||
@@ -49,16 +48,16 @@ test_configs = [
|
|||||||
@pytest.mark.parametrize('config', test_configs, indirect=True)
|
@pytest.mark.parametrize('config', test_configs, indirect=True)
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'count, app_path', [
|
'count, app_path', [
|
||||||
(2, f'{os.path.join(os.path.dirname(__file__), "mb_tcp_master")}|{os.path.join(os.path.dirname(__file__), "mb_tcp_slave")}')
|
(2, f'{os.path.join(os.path.dirname(__file__), "mb_tcp_slave")}|{os.path.join(os.path.dirname(__file__), "mb_tcp_master")}')
|
||||||
],
|
],
|
||||||
indirect=True
|
indirect=True
|
||||||
)
|
)
|
||||||
def test_modbus_tcp_communication(dut: Tuple[ModbusTestDut, ModbusTestDut]) -> None:
|
def test_modbus_tcp_communication(dut: Tuple[ModbusTestDut, ModbusTestDut]) -> None:
|
||||||
dut_slave = dut[1]
|
dut_slave = dut[0]
|
||||||
dut_master = dut[0]
|
dut_master = dut[1]
|
||||||
|
|
||||||
logger.info('DUT: %s start.', dut_master.dut_get_name())
|
|
||||||
logger.info('DUT: %s start.', dut_slave.dut_get_name())
|
logger.info('DUT: %s start.', dut_slave.dut_get_name())
|
||||||
|
logger.info('DUT: %s start.', dut_master.dut_get_name())
|
||||||
|
|
||||||
dut_slave_ip_address = dut_slave.dut_get_ip()
|
dut_slave_ip_address = dut_slave.dut_get_ip()
|
||||||
dut_master.dut_send_ip(dut_slave_ip_address)
|
dut_master.dut_send_ip(dut_slave_ip_address)
|
||||||
|
Reference in New Issue
Block a user