add custom commands into master data dict v2

This commit is contained in:
aleks
2025-01-10 12:54:07 +01:00
parent 3117942fe3
commit 12dc0b46eb
7 changed files with 110 additions and 100 deletions

View File

@ -73,6 +73,7 @@ enum {
CID_HOLD_DATA_1,
CID_INP_DATA_2,
CID_HOLD_DATA_2,
CID_HOLD_CUSTOM1,
CID_HOLD_TEST_REG,
CID_RELAY_P1,
CID_RELAY_P2,
@ -133,6 +134,10 @@ const mb_parameter_descriptor_t device_parameters[] = {
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_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,
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,
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, (TEST_ARR_REG_SZ * 2),
@ -320,8 +325,9 @@ static void master_operation_func(void *arg)
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)) {
if ((param_descriptor->cid >= CID_HOLD_CUSTOM1)
&& (param_descriptor->cid <= CID_HOLD_TEST_REG)) {
// Check test parameters
if (TEST_VERIFY_VALUES(master_handle, param_descriptor, (uint32_t *)temp_data_ptr) == ESP_OK) {
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx32 ") read successful.",
(int)param_descriptor->cid,

View File

@ -102,6 +102,7 @@ enum {
CID_HOLD_DATA_1,
CID_INP_DATA_2,
CID_HOLD_DATA_2,
CID_HOLD_CUSTOM1,
CID_HOLD_TEST_REG,
CID_RELAY_P1,
CID_RELAY_P2,
@ -162,6 +163,10 @@ const mb_parameter_descriptor_t device_parameters[] = {
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_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,
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,
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, (TEST_ARR_REG_SZ * 2),
@ -460,8 +465,9 @@ static void master_operation_func(void *arg)
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)) {
if ((param_descriptor->cid >= CID_HOLD_CUSTOM1)
&& (param_descriptor->cid <= CID_HOLD_TEST_REG)) {
// Check test parameters
if (TEST_VERIFY_VALUES(master_handle, param_descriptor, (uint32_t *)temp_data_ptr) == ESP_OK) {
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%" PRIx32 ") read successful.",
(int)param_descriptor->cid,

View File

@ -8,6 +8,9 @@
#include "mbc_master.h" // for master interface define
#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)
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_MASTER";
// This file implements public API for Modbus master controller.
@ -714,3 +717,46 @@ esp_err_t mbc_master_set_param_data(void* dest, void* src, mb_descr_type_t param
}
return err;
}
// 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.
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.");
uint8_t command = 0;
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);
}
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);
}
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);
}
break;
case MB_PARAM_DISCRETE:
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_DISCRETE_INPUTS, 0);
}
break;
default:
ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, (unsigned)pdescr->mb_param_type);
break;
}
return command;
}

View File

@ -45,6 +45,37 @@ extern "C" {
#define MB_EACH_ELEM(psrc, pdest, arr_size, elem_size) \
(int i = 0; (i < (arr_size / elem_size)); i++, pdest += elem_size, psrc += elem_size)
/**
* @brief Request mode for parameter to use in data dictionary
*/
typedef enum {
MB_PARAM_READ, /*!< Read parameter values. */
MB_PARAM_WRITE /*!< Write parameter values. */
} mb_param_mode_t;
/*!
* \brief Modbus parameter options for description table
*/
typedef union {
struct {
int opt1; /*!< Parameter option1 */
int opt2; /*!< Parameter option2 */
int opt3; /*!< Parameter option3 */
};
struct {
int min; /*!< Parameter minimum value */
int max; /*!< Parameter maximum value */
int step; /*!< Step of parameter change tracking */
};
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 */
};
} mb_parameter_opt_t;
/*!
* \brief Modbus descriptor table parameter type defines.
*/
@ -109,23 +140,6 @@ typedef enum {
PARAM_MAX_SIZE
} mb_descr_size_t;
/*!
* \brief Modbus parameter options for description table (associated with the characteristic).
* and can be used in user application to process data.
*/
typedef union {
struct {
int opt1; /*!< Parameter option1 */
int opt2; /*!< Parameter option2 */
int opt3; /*!< Parameter option3 */
}; /*!< Parameter options version 1 */
struct {
int min; /*!< Parameter minimum value */
int max; /*!< Parameter maximum value */
int step; /*!< Step of parameter change tracking */
}; /*!< Parameter options version 2 */
} mb_parameter_opt_t;
/**
* @brief Permissions for the characteristics
*/
@ -133,12 +147,15 @@ typedef enum {
PAR_PERMS_READ = 1 << BIT0, /**< the characteristic of the device are readable */
PAR_PERMS_WRITE = 1 << BIT1, /**< the characteristic of the device are writable*/
PAR_PERMS_TRIGGER = 1 << BIT2, /**< the characteristic of the device are triggerable */
PAR_PERMS_CUST_CMD = 1 << BIT3, /**< the characteristic uses custom commands */
PAR_PERMS_READ_WRITE = PAR_PERMS_READ | PAR_PERMS_WRITE, /**< the characteristic of the device are readable & writable */
PAR_PERMS_READ_TRIGGER = PAR_PERMS_READ | PAR_PERMS_TRIGGER, /**< the characteristic of the device are readable & triggerable */
PAR_PERMS_WRITE_TRIGGER = PAR_PERMS_WRITE | PAR_PERMS_TRIGGER, /**< the characteristic of the device are writable & triggerable */
PAR_PERMS_READ_WRITE_TRIGGER = PAR_PERMS_READ_WRITE | PAR_PERMS_TRIGGER, /**< the characteristic of the device are readable & writable & triggerable */
PAR_PERMS_READ_WRITE_CUST_CMD = PAR_PERMS_READ_WRITE | PAR_PERMS_CUST_CMD /**< the characteristic supports custom read/write commands */
} mb_param_perms_t;
/**
* @brief Characteristics descriptor type is used to describe characteristic and
* link it with Modbus parameters that reflect its data.
@ -466,6 +483,18 @@ 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

View File

@ -31,14 +31,6 @@ extern "C" {
// will be dependent on response time set by timer + convertion time if the command is received
#define MB_MAX_RESP_DELAY_MS (3000)
/**
* @brief Request mode for parameter to use in data dictionary
*/
typedef enum {
MB_PARAM_READ, /*!< Read parameter values. */
MB_PARAM_WRITE /*!< Write parameter values. */
} mb_param_mode_t;
/**
* @brief Modbus controller handler structure
*/

View File

@ -312,40 +312,6 @@ static esp_err_t mbc_serial_master_get_cid_info(void *ctx, uint16_t cid, const m
return ESP_OK;
}
// Helper function to get modbus command for each type of Modbus register area
static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_param_mode_t mode)
{
uint8_t command = 0;
switch (param_type)
{
case MB_PARAM_HOLDING:
command = (mode == MB_PARAM_WRITE) ? MB_FUNC_WRITE_MULTIPLE_REGISTERS : MB_FUNC_READ_HOLDING_REGISTER;
break;
case MB_PARAM_INPUT:
command = MB_FUNC_READ_INPUT_REGISTER;
break;
case MB_PARAM_COIL:
command = (mode == MB_PARAM_WRITE) ? MB_FUNC_WRITE_MULTIPLE_COILS : MB_FUNC_READ_COILS;
break;
case MB_PARAM_DISCRETE:
if (mode != MB_PARAM_WRITE)
{
command = MB_FUNC_READ_DISCRETE_INPUTS;
}
else
{
ESP_LOGE(TAG, "%s: Incorrect mode (%u)",
__FUNCTION__, (unsigned)mode);
}
break;
default:
ESP_LOGE(TAG, "%s: Incorrect param type (%u)",
__FUNCTION__, (unsigned)param_type);
break;
}
return command;
}
// Helper to search parameter by name in the parameter description table
// and fills Modbus request fields accordingly
static esp_err_t mbc_serial_master_set_request(void *ctx, uint16_t cid, mb_param_mode_t mode,
@ -365,7 +331,7 @@ static esp_err_t mbc_serial_master_set_request(void *ctx, uint16_t cid, mb_param
request->slave_addr = reg_ptr->mb_slave_addr;
request->reg_start = reg_ptr->mb_reg_start;
request->reg_size = reg_ptr->mb_size;
request->command = mbc_serial_master_get_command(reg_ptr->mb_param_type, mode);
request->command = mbc_master_get_command(reg_ptr, mode);
MB_RETURN_ON_FALSE((request->command > 0), ESP_ERR_INVALID_ARG, TAG, "mb incorrect command or parameter type.");
if (reg_data)
{

View File

@ -317,41 +317,6 @@ static esp_err_t mbc_tcp_master_get_cid_info(void *ctx, uint16_t cid, const mb_p
return ESP_OK;
}
// Helper function to get modbus command for each type of Modbus register area
static uint8_t mbc_tcp_master_get_command(mb_param_type_t param_type, mb_param_mode_t mode)
{
uint8_t command = 0;
switch(param_type){ // Check commands
case MB_PARAM_HOLDING:
command = (mode == MB_PARAM_WRITE) ?
MB_FUNC_WRITE_MULTIPLE_REGISTERS :
MB_FUNC_READ_HOLDING_REGISTER;
break;
case MB_PARAM_INPUT:
command = MB_FUNC_READ_INPUT_REGISTER;
break;
case MB_PARAM_COIL:
command = (mode == MB_PARAM_WRITE) ?
MB_FUNC_WRITE_MULTIPLE_COILS :
MB_FUNC_READ_COILS;
break;
case MB_PARAM_DISCRETE:
if (mode != MB_PARAM_WRITE) {
command = MB_FUNC_READ_DISCRETE_INPUTS;
} else {
ESP_LOGE(TAG, "%s: Incorrect mode (%u)",
__FUNCTION__, (unsigned)mode);
}
break;
default:
ESP_LOGE(TAG, "%s: Incorrect param type (%u)",
__FUNCTION__, (unsigned)param_type);
break;
}
return command;
}
// Helper to search parameter in the parameter description table and fills Modbus request fields accordingly
static esp_err_t mbc_tcp_master_set_request(void *ctx, uint16_t cid, mb_param_mode_t mode, mb_param_request_t *request,
mb_parameter_descriptor_t *reg_data)
@ -368,7 +333,7 @@ static esp_err_t mbc_tcp_master_set_request(void *ctx, uint16_t cid, mb_param_mo
request->slave_addr = reg_ptr->mb_slave_addr;
request->reg_start = reg_ptr->mb_reg_start;
request->reg_size = reg_ptr->mb_size;
request->command = mbc_tcp_master_get_command(reg_ptr->mb_param_type, mode);
request->command = mbc_master_get_command(reg_ptr, mode);
MB_RETURN_ON_FALSE((request->command > 0), ESP_ERR_INVALID_ARG, TAG, "mb incorrect command or parameter type.");
if (reg_data) {
*reg_data = *reg_ptr; // Set the cid registered parameter data