fix the custom commands support

This commit is contained in:
aleks
2025-03-05 10:19:59 +01:00
committed by Alex Lisitsyn
parent 38205ca78f
commit 37c750ec35
6 changed files with 68 additions and 26 deletions

View File

@@ -306,6 +306,38 @@ Initialization of master descriptor. The descriptor represents an array of type
The Data Dictionary can be initialized from SD card, MQTT or other source before start of stack. Once the initialization and setup is done, the Modbus controller allows the reading of complex parameters from any slave included in descriptor table using its CID.
Refer to :ref:`example TCP master <example_mb_tcp_master>`, :ref:`example Serial master <example_mb_master>` for more information.
The Data Dictionary and related API functions (:cpp:func:`mbc_master_get_parameter`, :cpp:func:`mbc_master_set_parameter`) support custom commands to be defined for read and write operations separately. In this case, the first two options (``param_opts.cust_cmd_read`` and ``param_opts.cust_cmd_write``) are treated as read/write Modbus commands accordingly if the :cpp:enumerator:`PAR_PERMS_CUST_CMD` flag is set in the ``access`` field for the characteristic.
.. note:: Please make sure that the requred commands are configured correctly in Modbus master and slave before using this feature. Refer to :ref:`modbus_api_master_handler_customization` for more information.
The below example explains this use case:
.. code:: c
enum {
CID_HOLD_CUSTOM1 = 0
};
const mb_parameter_descriptor_t device_parameters[] = {
// The commands `<0x03 - Read Multiple Holding Registers>`,
// `<0x06 - Write Single Holding Register>` will be used to read/write characteristic data accordingly.
{ CID_HOLD_CUSTOM1, STR("CustomHoldingRegister"), STR("__"),
MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 0, 1,
HOLD_OFFSET(custom_holding_reg), PARAM_TYPE_U16, 2,
OPTS(0x03, 0x06, 0x5555), PAR_PERMS_READ_WRITE_CUST_CMD },
... // other characteristics in the data dictionary
};
static void *master_handle = NULL; // Pointer to allocated interface structure
...
uint8_t temp_data[4];
esp_err_t err = mbc_master_get_parameter(master_handle, CID_HOLD_CUSTOM1, temp_data, &type);
if (err == ESP_OK) {
ESP_LOGI(TAG, "Characteristic read successful.");
}
err = mbc_master_set_parameter(master_handle, CID_HOLD_CUSTOM1, temp_data, &type);
if (err == ESP_OK) {
ESP_LOGI(TAG, "Set parameter data successfully.");
}
.. _modbus_api_master_handler_customization:
Master Customize Function Handlers

View File

@@ -29,7 +29,7 @@
#define MB_REG_HOLDING_START_AREA0 (HOLD_OFFSET(holding_data0))
#define MB_REG_HOLDING_START_AREA0_SIZE ((size_t)((HOLD_OFFSET(holding_data4) - HOLD_OFFSET(holding_data0)) << 1))
#define MB_REG_HOLDING_START_AREA1 (HOLD_OFFSET(holding_data4))
#define MB_REG_HOLDING_START_AREA1_SIZE ((size_t)((HOLD_OFFSET(holding_area1_end) - HOLD_OFFSET(holding_data4)) << 1))
#define MB_REG_HOLDING_START_AREA1_SIZE ((size_t)((HOLD_OFFSET(holding_area1_end) - HOLD_OFFSET(holding_data4)) << 1) + 2)
#define MB_REG_HOLDING_START_AREA2 (HOLD_OFFSET(holding_u8_a))
#define MB_REG_HOLDING_START_AREA2_SIZE ((size_t)((HOLD_OFFSET(holding_area2_end) - HOLD_OFFSET(holding_u8_a)) << 1))

View File

@@ -167,7 +167,7 @@ const mb_parameter_descriptor_t device_parameters[] = {
OPTS( TEST_HUMI_MIN, TEST_HUMI_MAX, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HOLD_CUSTOM1, STR("CustomHoldReg"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
TEST_HOLD_REG_START(holding_area1_end), 1,
HOLD_OFFSET(holding_area1_end), PARAM_TYPE_U16, 2,
HOLD_OFFSET(holding_area1_end), PARAM_TYPE_U16, 2,
OPTS( 0x03, 0x06, 0x5555 ), PAR_PERMS_READ_WRITE_CUST_CMD },
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING,
TEST_HOLD_REG_START(test_regs), TEST_ARR_REG_SZ,

View File

@@ -8,7 +8,8 @@
#include "esp_modbus_master.h" // for public interface defines
// Helper macro to set custom command
#define SET_CMD(mode, rd_cmd, wr_cmd) ((mode == MB_PARAM_WRITE) ? wr_cmd : (mode == MB_PARAM_READ) ? rd_cmd : 0)
#define GET_CMD(mode, access, rd_cmd, wr_cmd) (((mode == MB_PARAM_WRITE) && (access & PAR_PERMS_WRITE)) ? wr_cmd : \
((mode == MB_PARAM_READ) && (access & PAR_PERMS_READ)) ? rd_cmd : 0)
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_MASTER";
@@ -737,6 +738,8 @@ esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param
// Helper function to get configured Modbus command for each type of Modbus register area.
// Supports custom command options using the PAR_PERMS_CUST_CMD permission.
// The MB_PARAM_CUSTOM register type mimics the custom commands specificly handled with
// custom command handlers which have to be defined in command handling table.
uint8_t mbc_master_get_command(const mb_parameter_descriptor_t *pdescr, mb_param_mode_t mode)
{
MB_RETURN_ON_FALSE((pdescr), 0, TAG, "incorrect data pointer.");
@@ -744,31 +747,23 @@ uint8_t mbc_master_get_command(const mb_parameter_descriptor_t *pdescr, mb_param
switch(pdescr->mb_param_type)
{
case MB_PARAM_HOLDING:
if (pdescr->access & PAR_PERMS_CUST_CMD) {
command = SET_CMD(mode, (uint8_t)pdescr->param_opts.cust_cmd_read, (uint8_t)pdescr->param_opts.cust_cmd_write);
} else {
command = SET_CMD(mode, MB_FUNC_READ_HOLDING_REGISTER, MB_FUNC_WRITE_MULTIPLE_REGISTERS);
}
command = GET_CMD(mode, pdescr->access, MB_FUNC_READ_HOLDING_REGISTER, MB_FUNC_WRITE_MULTIPLE_REGISTERS);
break;
case MB_PARAM_INPUT:
if (pdescr->access & PAR_PERMS_CUST_CMD) {
command = SET_CMD(mode, (uint8_t)pdescr->param_opts.cust_cmd_read, 0);
} else {
command = SET_CMD(mode, MB_FUNC_READ_INPUT_REGISTER, 0);
}
command = GET_CMD(mode, pdescr->access, MB_FUNC_READ_INPUT_REGISTER, 0);
break;
case MB_PARAM_COIL:
if (pdescr->access & PAR_PERMS_CUST_CMD) {
command = SET_CMD(mode, (uint8_t)pdescr->param_opts.cust_cmd_read, (uint8_t)pdescr->param_opts.cust_cmd_write);
} else {
command = SET_CMD(mode, MB_FUNC_READ_COILS, MB_FUNC_WRITE_MULTIPLE_COILS);
}
command = GET_CMD(mode, pdescr->access, MB_FUNC_READ_COILS, MB_FUNC_WRITE_MULTIPLE_COILS);
break;
case MB_PARAM_DISCRETE:
command = GET_CMD(mode, pdescr->access, MB_FUNC_READ_DISCRETE_INPUTS, 0);
break;
case MB_PARAM_CUSTOM:
if (pdescr->access & PAR_PERMS_CUST_CMD) {
command = SET_CMD(mode, (uint8_t)pdescr->param_opts.cust_cmd_read, 0);
// Use custom command in the request for read or write
command = GET_CMD(mode, pdescr->access, (uint8_t)pdescr->param_opts.cust_cmd_read, (uint8_t)pdescr->param_opts.cust_cmd_write);
} else {
command = SET_CMD(mode, MB_FUNC_READ_DISCRETE_INPUTS, 0);
command = 0;
}
break;
default:

View File

@@ -150,11 +150,12 @@ typedef enum
* @brief Type of Modbus parameter
*/
typedef enum {
MB_PARAM_HOLDING = 0x00, /*!< Modbus Holding register. */
MB_PARAM_INPUT, /*!< Modbus Input register. */
MB_PARAM_COIL, /*!< Modbus Coils. */
MB_PARAM_DISCRETE, /*!< Modbus Discrete bits. */
MB_PARAM_HOLDING = 0x00, /*!< Modbus Holding register. */
MB_PARAM_INPUT, /*!< Modbus Input register. */
MB_PARAM_COIL, /*!< Modbus Coils. */
MB_PARAM_DISCRETE, /*!< Modbus Discrete bits. */
MB_PARAM_COUNT,
MB_PARAM_CUSTOM, /*!< Modbus custom commands (is not counted in area descriptors). */
MB_PARAM_UNKNOWN = 0xFF
} mb_param_type_t;

View File

@@ -71,7 +71,7 @@ typedef union {
struct {
int cust_cmd_read; /*!< Parameter custom read request command */
int cust_cmd_write; /*!< Parameter custom write request command */
int cust_cmd_not_used; /*!< Not used option for custom request */
int cust_cmd_other; /*!< Optional field for custom request */
};
} mb_parameter_opt_t;
@@ -179,7 +179,7 @@ typedef struct {
*/
typedef struct {
uint8_t slave_addr; /*!< Modbus slave address */
uint8_t command; /*!< Modbus command to send */
uint8_t command; /*!< Modbus command to send */
uint16_t reg_start; /*!< Modbus start register */
uint16_t reg_size; /*!< Modbus number of registers */
} mb_param_request_t;
@@ -482,6 +482,20 @@ mb_err_enum_t mbc_reg_coils_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint
*/
esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param_type, size_t param_size);
/**
* @brief The helper function to get supported modbus function code (command) according to parameter type
*
* @param[in] pdescr the pointer to the characteristic descriptor in data dictionary
* @param[in] mode access mode for characteristic
*
* @return
* - modbus function code, if the command is correctly configured
* - 0 - invalid argument or command not found
*/
uint8_t mbc_master_get_command(const mb_parameter_descriptor_t *pdescr, mb_param_mode_t mode);
#ifdef __cplusplus
}
#endif