From 96b77a28b1ee1750181a73c81e8c6bf419fb0342 Mon Sep 17 00:00:00 2001 From: Alex Lisitsyn Date: Thu, 28 Jan 2021 12:29:32 +0800 Subject: [PATCH] freemodbus: add support for list of area descriptors for each register area add multi register area descriptors into concrete port (initial) add create/destroy of area descriptors into concrete port add the list of descriptors in common slave interface structure and init/destroy in concrete slave port move r/w callback functions into common slave final update of common slave interface wrappers add override API option in concrete port update slave examples to check new feature --- .../freemodbus/common/esp_modbus_slave.c | 380 ++++++++++++++++-- components/freemodbus/common/mbc_slave.h | 15 +- .../modbus_controller/mbc_serial_slave.c | 328 ++------------- .../modbus_controller/mbc_tcp_slave.c | 274 +------------ .../mb_example_common/include/modbus_params.h | 18 +- .../modbus/serial/mb_slave/main/slave.c | 53 ++- .../modbus/tcp/mb_tcp_slave/main/tcp_slave.c | 52 ++- 7 files changed, 483 insertions(+), 637 deletions(-) diff --git a/components/freemodbus/common/esp_modbus_slave.c b/components/freemodbus/common/esp_modbus_slave.c index 85a869e36a..a5b055860f 100644 --- a/components/freemodbus/common/esp_modbus_slave.c +++ b/components/freemodbus/common/esp_modbus_slave.c @@ -13,9 +13,11 @@ * limitations under the License. */ -#include "esp_err.h" // for esp_err_t -#include "sdkconfig.h" // for KConfig defines +#include "esp_err.h" // for esp_err_t +#include "sdkconfig.h" // for KConfig defines + #include "mbc_slave.h" // for slave private type definitions +#include "mbutils.h" // for stack bit setting utilities #include "esp_modbus_common.h" // for common defines #include "esp_modbus_slave.h" // for public slave defines #include "esp_modbus_callbacks.h" // for modbus callbacks function pointers declaration @@ -37,12 +39,59 @@ static uint8_t mb_slave_id[] = { MB_ID_BYTE0(MB_CONTROLLER_SLAVE_ID), #endif +#define REG_SIZE(type, nregs) ((type == MB_PARAM_INPUT) || (type == MB_PARAM_HOLDING)) ? (nregs >> 1) : (nregs << 3) + // Common interface pointer for slave port static mb_slave_interface_t* slave_interface_ptr = NULL; +// Searches the register in the area specified by type, returns descriptor if found, else NULL +static mb_descr_entry_t* mbc_slave_find_reg_descriptor(mb_param_type_t type, uint16_t addr, size_t regs) +{ + mb_descr_entry_t* it; + uint16_t reg_size = 0; + + mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts; + + if (LIST_EMPTY(&mbs_opts->mbs_area_descriptors[type])) { + return NULL; + } + + // search for the register in each area + for (it = LIST_FIRST(&mbs_opts->mbs_area_descriptors[type]); it != NULL; it = LIST_NEXT(it, entries)) { + reg_size = REG_SIZE(type, it->size); + if ((addr >= it->start_offset) + && (it->p_data) + && (regs >= 1) + && ((addr + regs) <= (it->start_offset + reg_size + 1)) + && (reg_size >= 1)) { + return it; + } + } + return NULL; +} + +static void mbc_slave_free_descriptors(void) { + + mb_descr_entry_t* it; + mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts; + + for (int descr_type = 0; descr_type < MB_PARAM_COUNT; descr_type++) { + for (it = LIST_FIRST(&mbs_opts->mbs_area_descriptors[descr_type]); it != NULL; it = LIST_NEXT(it, entries)) { + LIST_REMOVE(it, entries); + free(it); + } + } +} + void mbc_slave_init_iface(void* handler) { slave_interface_ptr = (mb_slave_interface_t*) handler; + mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts; + // Initialize list head for register areas + LIST_INIT(&mbs_opts->mbs_area_descriptors[MB_PARAM_INPUT]); + LIST_INIT(&mbs_opts->mbs_area_descriptors[MB_PARAM_HOLDING]); + LIST_INIT(&mbs_opts->mbs_area_descriptors[MB_PARAM_COIL]); + LIST_INIT(&mbs_opts->mbs_area_descriptors[MB_PARAM_DISCRETE]); } /** @@ -65,6 +114,10 @@ esp_err_t mbc_slave_destroy(void) ESP_ERR_INVALID_STATE, "Slave destroy failure error=(0x%x).", error); + // Destroy all opened descriptors + mbc_slave_free_descriptors(); + free(slave_interface_ptr); + slave_interface_ptr = NULL; return error; } @@ -157,75 +210,328 @@ esp_err_t mbc_slave_set_descriptor(mb_register_area_descriptor_t descr_data) MB_SLAVE_CHECK((slave_interface_ptr != NULL), ESP_ERR_INVALID_STATE, "Slave interface is not correctly initialized."); - MB_SLAVE_CHECK((slave_interface_ptr->set_descriptor != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - error = slave_interface_ptr->set_descriptor(descr_data); - MB_SLAVE_CHECK((error == ESP_OK), - ESP_ERR_INVALID_STATE, - "Slave set descriptor failure error=(0x%x).", - (uint16_t)error); + + if (slave_interface_ptr->set_descriptor != NULL) { + error = slave_interface_ptr->set_descriptor(descr_data); + MB_SLAVE_CHECK((error == ESP_OK), + ESP_ERR_INVALID_STATE, + "Slave set descriptor failure error=(0x%x).", + (uint16_t)error); + } else { + mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts; + // Check if the address is already in the descriptor list + mb_descr_entry_t* it = mbc_slave_find_reg_descriptor(descr_data.type, descr_data.start_offset, 1); + MB_SLAVE_CHECK((it == NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor or already defined."); + + mb_descr_entry_t* new_descr = (mb_descr_entry_t*) heap_caps_malloc(sizeof(mb_descr_entry_t), + MALLOC_CAP_INTERNAL|MALLOC_CAP_8BIT); + MB_SLAVE_CHECK((new_descr != NULL), ESP_ERR_NO_MEM, "mb can not allocate memory for descriptor."); + new_descr->start_offset = descr_data.start_offset; + new_descr->type = descr_data.type; + new_descr->p_data = descr_data.address; + new_descr->size = descr_data.size; + LIST_INSERT_HEAD(&mbs_opts->mbs_area_descriptors[descr_data.type], new_descr, entries); + error = ESP_OK; + } return error; } -/** - * Below are stack callback functions to read/write registers +// The helper function to get time stamp in microseconds +static uint64_t mbc_slave_get_time_stamp(void) +{ + uint64_t time_stamp = esp_timer_get_time(); + return time_stamp; +} + +// Helper function to send parameter information to application task +static esp_err_t mbc_slave_send_param_info(mb_event_group_t par_type, uint16_t mb_offset, + uint8_t* par_address, uint16_t par_size) +{ + MB_SLAVE_ASSERT(slave_interface_ptr != NULL); + mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts; + esp_err_t error = ESP_FAIL; + mb_param_info_t par_info; + // Check if queue is not full the send parameter information + par_info.type = par_type; + par_info.size = par_size; + par_info.address = par_address; + par_info.time_stamp = mbc_slave_get_time_stamp(); + par_info.mb_offset = mb_offset; + BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, &par_info, MB_PAR_INFO_TOUT); + if (pdTRUE == status) { + ESP_LOGD(MB_SLAVE_TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d", + par_type, (uint32_t)par_address, par_size); + error = ESP_OK; + } else if (errQUEUE_FULL == status) { + ESP_LOGD(MB_SLAVE_TAG, "Parameter queue is overflowed."); + } + return error; +} + +// Helper function to send notification +static esp_err_t mbc_slave_send_param_access_notification(mb_event_group_t event) +{ + MB_SLAVE_ASSERT(slave_interface_ptr != NULL); + mb_slave_options_t* mbs_opts = &slave_interface_ptr->opts; + esp_err_t err = ESP_FAIL; + mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, (EventBits_t)event); + if (bits & event) { + ESP_LOGD(MB_SLAVE_TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event); + err = ESP_OK; + } + return err; +} + +/* + * Below are the common slave read/write register callback functions + * The concrete slave port can override them using interface function pointers */ -eMBErrorCode eMBRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNDiscrete) + +// Callback function for reading of MB Input Registers +eMBErrorCode mbc_reg_input_slave_cb(UCHAR * reg_buffer, USHORT address, USHORT n_regs) +{ + MB_SLAVE_CHECK((slave_interface_ptr != NULL), + MB_EILLSTATE, "Slave stack uninitialized."); + MB_SLAVE_CHECK((reg_buffer != NULL), + MB_EINVAL, "Slave stack call failed."); + eMBErrorCode status = MB_ENOERR; + address--; // address of register is already +1 + mb_descr_entry_t* it = mbc_slave_find_reg_descriptor(MB_PARAM_INPUT, address, n_regs); + if (it != NULL) { + uint16_t input_reg_start = (uint16_t)it->start_offset; // Get Modbus start address + uint8_t* input_buffer = (uint8_t*)it->p_data; // Get instance address + uint16_t regs = n_regs; + uint16_t reg_index; + // If input or configuration parameters are incorrect then return an error to stack layer + reg_index = (uint16_t)(address - input_reg_start); + reg_index <<= 1; // register Address to byte address + input_buffer += reg_index; + uint8_t* buffer_start = input_buffer; + while (regs > 0) { + _XFER_2_RD(reg_buffer, input_buffer); + reg_index += 2; + regs -= 1; + } + // Send access notification + (void)mbc_slave_send_param_access_notification(MB_EVENT_INPUT_REG_RD); + // Send parameter info to application task + (void)mbc_slave_send_param_info(MB_EVENT_INPUT_REG_RD, (uint16_t)address, + (uint8_t*)buffer_start, (uint16_t)n_regs); + } else { + status = MB_ENOREG; + } + return status; +} + +// Callback function for reading of MB Holding Registers +// Executed by stack when request to read/write holding registers is received +eMBErrorCode mbc_reg_holding_slave_cb(UCHAR * reg_buffer, USHORT address, USHORT n_regs, eMBRegisterMode mode) +{ + MB_SLAVE_CHECK((slave_interface_ptr != NULL), + MB_EILLSTATE, "Slave stack uninitialized."); + MB_SLAVE_CHECK((reg_buffer != NULL), + MB_EINVAL, "Slave stack call failed."); + eMBErrorCode status = MB_ENOERR; + uint16_t reg_index; + address--; // address of register is already +1 + mb_descr_entry_t* it = mbc_slave_find_reg_descriptor(MB_PARAM_HOLDING, address, n_regs); + if (it != NULL) { + uint16_t reg_holding_start = (uint16_t)it->start_offset; // Get Modbus start address + uint8_t* holding_buffer = (uint8_t*)it->p_data; // Get instance address + uint16_t regs = n_regs; + reg_index = (uint16_t) (address - reg_holding_start); + reg_index <<= 1; // register Address to byte address + holding_buffer += reg_index; + uint8_t* buffer_start = holding_buffer; + switch (mode) { + case MB_REG_READ: + while (regs > 0) { + _XFER_2_RD(reg_buffer, holding_buffer); + reg_index += 2; + regs -= 1; + }; + // Send access notification + (void)mbc_slave_send_param_access_notification(MB_EVENT_HOLDING_REG_RD); + // Send parameter info + (void)mbc_slave_send_param_info(MB_EVENT_HOLDING_REG_RD, (uint16_t)address, + (uint8_t*)buffer_start, (uint16_t)n_regs); + break; + case MB_REG_WRITE: + while (regs > 0) { + _XFER_2_WR(holding_buffer, reg_buffer); + holding_buffer += 2; + reg_index += 2; + regs -= 1; + }; + // Send access notification + (void)mbc_slave_send_param_access_notification(MB_EVENT_HOLDING_REG_WR); + // Send parameter info + (void)mbc_slave_send_param_info(MB_EVENT_HOLDING_REG_WR, (uint16_t)address, + (uint8_t*)buffer_start, (uint16_t)n_regs); + break; + } + } else { + status = MB_ENOREG; + } + return status; +} + +// Callback function for reading of MB Coils Registers +eMBErrorCode mbc_reg_coils_slave_cb(UCHAR* reg_buffer, USHORT address, USHORT n_coils, eMBRegisterMode mode) +{ + MB_SLAVE_CHECK((slave_interface_ptr != NULL), + MB_EILLSTATE, "Slave stack uninitialized."); + MB_SLAVE_CHECK((reg_buffer != NULL), + MB_EINVAL, "Slave stack call failed."); + eMBErrorCode status = MB_ENOERR; + uint16_t reg_index; + uint16_t coils = n_coils; + address--; // The address is already +1 + mb_descr_entry_t* it = mbc_slave_find_reg_descriptor(MB_PARAM_COIL, address, n_coils); + if (it != NULL) { + uint16_t reg_coils_start = (uint16_t)it->start_offset; // MB offset of coils + uint8_t* reg_coils_buf = (uint8_t*)it->p_data; + reg_index = (uint16_t) (address - it->start_offset); + CHAR* coils_data_buf = (CHAR*)(reg_coils_buf + (reg_index >> 3)); + switch (mode) { + case MB_REG_READ: + while (coils > 0) { + uint8_t result = xMBUtilGetBits((uint8_t*)reg_coils_buf, reg_index, 1); + xMBUtilSetBits(reg_buffer, reg_index - (address - reg_coils_start), 1, result); + reg_index++; + coils--; + } + // Send an event to notify application task about event + (void)mbc_slave_send_param_access_notification(MB_EVENT_COILS_RD); + (void)mbc_slave_send_param_info(MB_EVENT_COILS_RD, (uint16_t)address, + (uint8_t*)(coils_data_buf), (uint16_t)n_coils); + break; + case MB_REG_WRITE: + while (coils > 0) { + uint8_t result = xMBUtilGetBits(reg_buffer, + reg_index - (address - reg_coils_start), 1); + xMBUtilSetBits((uint8_t*)reg_coils_buf, reg_index, 1, result); + reg_index++; + coils--; + } + // Send an event to notify application task about event + (void)mbc_slave_send_param_access_notification(MB_EVENT_COILS_WR); + (void)mbc_slave_send_param_info(MB_EVENT_COILS_WR, (uint16_t)address, + (uint8_t*)coils_data_buf, (uint16_t)n_coils); + break; + } // switch ( eMode ) + } else { + // If the configuration or input parameters are incorrect then return error to stack + status = MB_ENOREG; + } + return status; +} + +// Callback function for reading of MB Discrete Input Registers +eMBErrorCode mbc_reg_discrete_slave_cb(UCHAR* reg_buffer, USHORT address, USHORT n_discrete) +{ + MB_SLAVE_CHECK((slave_interface_ptr != NULL), + MB_EILLSTATE, "Slave stack uninitialized."); + MB_SLAVE_CHECK((reg_buffer != NULL), + MB_EINVAL, "Slave stack call failed."); + + eMBErrorCode status = MB_ENOERR; + uint16_t reg_index; + uint16_t reg_bit_index; + uint16_t n_reg; + uint8_t* discrete_input_buf; + // It already plus one in modbus function method. + address--; + mb_descr_entry_t* it = mbc_slave_find_reg_descriptor(MB_PARAM_DISCRETE, address, n_discrete); + if (it != NULL) { + uint16_t reg_discrete_start = (uint16_t)it->start_offset; // MB offset of registers + n_reg = (n_discrete >> 3) + 1; + discrete_input_buf = (uint8_t*)it->p_data; // the storage address + reg_index = (uint16_t) (address - reg_discrete_start) / 8; // Get register index in the buffer for bit number + reg_bit_index = (uint16_t)(address - reg_discrete_start) % 8; // Get bit index + uint8_t* temp_buf = &discrete_input_buf[reg_index]; + while (n_reg > 0) { + *reg_buffer++ = xMBUtilGetBits(&discrete_input_buf[reg_index++], reg_bit_index, 8); + n_reg--; + } + reg_buffer--; + // Last discrete + n_discrete = n_discrete % 8; + // Filling zero to high bit + *reg_buffer = *reg_buffer << (8 - n_discrete); + *reg_buffer = *reg_buffer >> (8 - n_discrete); + // Send an event to notify application task about event + (void)mbc_slave_send_param_access_notification(MB_EVENT_DISCRETE_RD); + (void)mbc_slave_send_param_info(MB_EVENT_DISCRETE_RD, (uint16_t)address, + (uint8_t*)temp_buf, (uint16_t)n_discrete); + } else { + status = MB_ENOREG; + } + return status; +} + +/** + * Below are the stack callback functions to read/write registers + */ +eMBErrorCode eMBRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete) { eMBErrorCode error = MB_ENOERR; MB_SLAVE_CHECK((slave_interface_ptr != NULL), ESP_ERR_INVALID_STATE, "Slave interface is not correctly initialized."); - MB_SLAVE_CHECK((slave_interface_ptr->slave_reg_cb_discrete != NULL), - error, - "Slave interface is not correctly initialized."); - error = slave_interface_ptr->slave_reg_cb_discrete(pucRegBuffer, usAddress, usNDiscrete); + // Check if the callback is overridden in concrete port + if (slave_interface_ptr->slave_reg_cb_discrete) { + error = slave_interface_ptr->slave_reg_cb_discrete(pucRegBuffer, usAddress, usNDiscrete); + } else { + error = mbc_reg_discrete_slave_cb(pucRegBuffer, usAddress, usNDiscrete); + } return error; } eMBErrorCode eMBRegCoilsCB(UCHAR* pucRegBuffer, USHORT usAddress, - USHORT usNCoils, eMBRegisterMode eMode) + USHORT usNCoils, eMBRegisterMode eMode) { eMBErrorCode error = MB_ENOERR; MB_SLAVE_CHECK((slave_interface_ptr != NULL), ESP_ERR_INVALID_STATE, "Slave interface is not correctly initialized."); - MB_SLAVE_CHECK((slave_interface_ptr->slave_reg_cb_coils != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - error = slave_interface_ptr->slave_reg_cb_coils(pucRegBuffer, usAddress, - usNCoils, eMode); + + if (slave_interface_ptr->slave_reg_cb_coils) { + error = slave_interface_ptr->slave_reg_cb_coils(pucRegBuffer, usAddress, usNCoils, eMode); + } else { + error = mbc_reg_coils_slave_cb(pucRegBuffer, usAddress, usNCoils, eMode); + } return error; } eMBErrorCode eMBRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs, eMBRegisterMode eMode) + USHORT usNRegs, eMBRegisterMode eMode) { eMBErrorCode error = MB_ENOERR; MB_SLAVE_CHECK((slave_interface_ptr != NULL), ESP_ERR_INVALID_STATE, "Slave interface is not correctly initialized."); - MB_SLAVE_CHECK((slave_interface_ptr->slave_reg_cb_holding != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - error = slave_interface_ptr->slave_reg_cb_holding(pucRegBuffer, usAddress, - usNRegs, eMode); + + if (slave_interface_ptr->slave_reg_cb_holding) { + error = slave_interface_ptr->slave_reg_cb_holding(pucRegBuffer, usAddress, usNRegs, eMode); + } else { + error = mbc_reg_holding_slave_cb(pucRegBuffer, usAddress, usNRegs, eMode); + } return error; } -eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs) +eMBErrorCode eMBRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs) { - eMBErrorCode error = MB_ENOERR; + eMBErrorCode error = ESP_ERR_INVALID_STATE; MB_SLAVE_CHECK((slave_interface_ptr != NULL), ESP_ERR_INVALID_STATE, "Slave interface is not correctly initialized."); - MB_SLAVE_CHECK((slave_interface_ptr->slave_reg_cb_input != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - error = slave_interface_ptr->slave_reg_cb_input(pucRegBuffer, usAddress, usNRegs); + + if (slave_interface_ptr->slave_reg_cb_input) { + error = slave_interface_ptr->slave_reg_cb_input(pucRegBuffer, usAddress, usNRegs); + } else { + error = mbc_reg_input_slave_cb(pucRegBuffer, usAddress, usNRegs); + } return error; } diff --git a/components/freemodbus/common/mbc_slave.h b/components/freemodbus/common/mbc_slave.h index 1565da1a73..a116314f9a 100644 --- a/components/freemodbus/common/mbc_slave.h +++ b/components/freemodbus/common/mbc_slave.h @@ -17,8 +17,10 @@ #include "driver/uart.h" // for uart defines #include "errno.h" // for errno +#include "sys/queue.h" // for list #include "esp_log.h" // for log write #include "string.h" // for strerror() + #include "esp_modbus_slave.h" // for public type defines #include "esp_modbus_callbacks.h" // for callback functions @@ -52,6 +54,17 @@ typedef struct { uart_parity_t parity; /*!< Modbus UART parity settings */ } mb_slave_comm_info_t; +/** + * @brief Modbus area descriptor list item + */ +typedef struct mb_descr_entry_s{ + uint16_t start_offset; /*!< Modbus start address for area descriptor */ + mb_param_type_t type; /*!< Type of storage area descriptor */ + void* p_data; /*!< Instance address for storage area descriptor */ + size_t size; /*!< Instance size for area descriptor (bytes) */ + LIST_ENTRY(mb_descr_entry_s) entries; /*!< The Modbus area descriptor entry */ +} mb_descr_entry_t; + /** * @brief Modbus controller handler structure */ @@ -61,7 +74,7 @@ typedef struct { TaskHandle_t mbs_task_handle; /*!< task handle */ EventGroupHandle_t mbs_event_group; /*!< controller event group */ QueueHandle_t mbs_notification_queue_handle; /*!< controller notification queue */ - mb_register_area_descriptor_t mbs_area_descriptors[MB_PARAM_COUNT]; /*!< register area descriptors */ + LIST_HEAD(mbs_area_descriptors_, mb_descr_entry_s) mbs_area_descriptors[MB_PARAM_COUNT]; /*!< register area descriptors */ } mb_slave_options_t; typedef mb_event_group_t (*iface_check_event)(mb_event_group_t); /*!< Interface method check_event */ diff --git a/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c b/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c index eae69e2fe2..8c6dbff428 100644 --- a/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c +++ b/components/freemodbus/serial_slave/modbus_controller/mbc_serial_slave.c @@ -110,104 +110,6 @@ static esp_err_t mbc_serial_slave_start(void) return ESP_OK; } -// Modbus controller destroy function -static esp_err_t mbc_serial_slave_destroy(void) -{ - MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - eMBErrorCode mb_error = MB_ENOERR; - // Stop polling by clearing correspondent bit in the event group - EventBits_t flag = xEventGroupClearBits(mbs_opts->mbs_event_group, - (EventBits_t)MB_EVENT_STACK_STARTED); - MB_SLAVE_CHECK((flag & MB_EVENT_STACK_STARTED), - ESP_ERR_INVALID_STATE, "mb stack stop event failure."); - // Disable and then destroy the Modbus stack - mb_error = eMBDisable(); - MB_SLAVE_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure."); - (void)vTaskDelete(mbs_opts->mbs_task_handle); - (void)vQueueDelete(mbs_opts->mbs_notification_queue_handle); - (void)vEventGroupDelete(mbs_opts->mbs_event_group); - mb_error = eMBClose(); - MB_SLAVE_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, - "mb stack close failure returned (0x%x).", (uint32_t)mb_error); - free(mbs_interface_ptr); - vMBPortSetMode((UCHAR)MB_PORT_INACTIVE); - mbs_interface_ptr = NULL; - return ESP_OK; -} - -esp_err_t mbc_serial_slave_set_descriptor(const mb_register_area_descriptor_t descr_info) -{ - MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - MB_SLAVE_CHECK(((descr_info.type < MB_PARAM_COUNT) && (descr_info.type >= MB_PARAM_HOLDING)), - ESP_ERR_INVALID_ARG, "mb incorrect modbus instance type = (0x%x).", - (uint32_t)descr_info.type); - MB_SLAVE_CHECK((descr_info.address != NULL), - ESP_ERR_INVALID_ARG, "mb instance pointer is NULL."); - MB_SLAVE_CHECK((descr_info.size >= MB_INST_MIN_SIZE) && (descr_info.size < (MB_INST_MAX_SIZE)), - ESP_ERR_INVALID_ARG, "mb instance size is incorrect = (0x%x).", - (uint32_t)descr_info.size); - mbs_opts->mbs_area_descriptors[descr_info.type] = descr_info; - return ESP_OK; -} - -// The helper function to get time stamp in microseconds -static uint64_t get_time_stamp(void) -{ - uint64_t time_stamp = esp_timer_get_time(); - return time_stamp; -} - -// Helper function to send parameter information to application task -static esp_err_t send_param_info(mb_event_group_t par_type, uint16_t mb_offset, - uint8_t* par_address, uint16_t par_size) -{ - MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - esp_err_t error = ESP_FAIL; - mb_param_info_t par_info; - // Check if queue is not full the send parameter information - par_info.type = par_type; - par_info.size = par_size; - par_info.address = par_address; - par_info.time_stamp = get_time_stamp(); - par_info.mb_offset = mb_offset; - BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, - &par_info, MB_PAR_INFO_TOUT); - if (pdTRUE == status) { - ESP_LOGD(MB_SLAVE_TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d", - par_type, (uint32_t)par_address, par_size); - error = ESP_OK; - } else if (errQUEUE_FULL == status) { - ESP_LOGD(MB_SLAVE_TAG, "Parameter queue is overflowed."); - } - return error; -} - -// Helper function to send notification -static esp_err_t send_param_access_notification(mb_event_group_t event) -{ - MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - ESP_ERR_INVALID_STATE, - "Slave interface is not correctly initialized."); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - esp_err_t err = ESP_FAIL; - mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, - (EventBits_t)event); - if (bits & event) { - ESP_LOGD(MB_SLAVE_TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event); - err = ESP_OK; - } - return err; -} - // Blocking function to get event on parameter group change for application task static mb_event_group_t mbc_serial_slave_check_event(mb_event_group_t group) { @@ -246,211 +148,33 @@ static esp_err_t mbc_serial_slave_get_param_info(mb_param_info_t* reg_info, uint // This is required to suppress warning when register start address is zero #pragma GCC diagnostic ignored "-Wtype-limits" -// Callback function for reading of MB Input Registers -eMBErrorCode eMBRegInputCBSerialSlave(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs) +// Modbus controller destroy function +static esp_err_t mbc_serial_slave_destroy(void) { MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - MB_EILLSTATE, "Slave stack uninitialized."); - MB_SLAVE_CHECK((pucRegBuffer != NULL), - MB_EINVAL, "Slave stack call failed."); + ESP_ERR_INVALID_STATE, + "Slave interface is not correctly initialized."); mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - USHORT usRegInputNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_INPUT].size >> 1); // Number of input registers - USHORT usInputRegStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_INPUT].start_offset; // Get Modbus start address - UCHAR* pucInputBuffer = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_INPUT].address; // Get instance address - USHORT usRegs = usNRegs; - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex; - // If input or configuration parameters are incorrect then return an error to stack layer - if ((usAddress >= usInputRegStart) - && (pucInputBuffer != NULL) - && (usNRegs >= 1) - && ((usAddress + usRegs) <= (usInputRegStart + usRegInputNregs + 1)) - && (usRegInputNregs >= 1)) { - iRegIndex = (USHORT)(usAddress - usInputRegStart - 1); - iRegIndex <<= 1; // register Address to byte address - pucInputBuffer += iRegIndex; - UCHAR* pucBufferStart = pucInputBuffer; - while (usRegs > 0) { - _XFER_2_RD(pucRegBuffer, pucInputBuffer); - iRegIndex += 2; - usRegs -= 1; - } - // Send access notification - (void)send_param_access_notification(MB_EVENT_INPUT_REG_RD); - // Send parameter info to application task - (void)send_param_info(MB_EVENT_INPUT_REG_RD, (uint16_t)usAddress, - (uint8_t*)pucBufferStart, (uint16_t)usNRegs); - } else { - eStatus = MB_ENOREG; - } - return eStatus; -} + eMBErrorCode mb_error = MB_ENOERR; + // Stop polling by clearing correspondent bit in the event group + EventBits_t flag = xEventGroupClearBits(mbs_opts->mbs_event_group, + (EventBits_t)MB_EVENT_STACK_STARTED); + MB_SLAVE_CHECK((flag & MB_EVENT_STACK_STARTED), + ESP_ERR_INVALID_STATE, "mb stack stop event failure."); + // Disable and then destroy the Modbus stack + mb_error = eMBDisable(); + MB_SLAVE_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure."); + (void)vTaskDelete(mbs_opts->mbs_task_handle); + (void)vQueueDelete(mbs_opts->mbs_notification_queue_handle); + (void)vEventGroupDelete(mbs_opts->mbs_event_group); + mb_error = eMBClose(); + MB_SLAVE_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, + "mb stack close failure returned (0x%x).", (uint32_t)mb_error); -// Callback function for reading of MB Holding Registers -// Executed by stack when request to read/write holding registers is received -eMBErrorCode eMBRegHoldingCBSerialSlave(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs, eMBRegisterMode eMode) -{ - MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - MB_EILLSTATE, "Slave stack uninitialized."); - MB_SLAVE_CHECK((pucRegBuffer != NULL), - MB_EINVAL, "Slave stack call failed."); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - USHORT usRegHoldingNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_HOLDING].size >> 1); - USHORT usRegHoldingStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_HOLDING].start_offset; - UCHAR* pucHoldingBuffer = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_HOLDING].address; - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex; - USHORT usRegs = usNRegs; - // Check input and configuration parameters for correctness - if ((usAddress >= usRegHoldingStart) - && (pucHoldingBuffer != NULL) - && ((usAddress + usRegs) <= (usRegHoldingStart + usRegHoldingNregs + 1)) - && (usRegHoldingNregs >= 1) - && (usNRegs >= 1)) { - iRegIndex = (USHORT) (usAddress - usRegHoldingStart - 1); - iRegIndex <<= 1; // register Address to byte address - pucHoldingBuffer += iRegIndex; - UCHAR* pucBufferStart = pucHoldingBuffer; - switch (eMode) { - case MB_REG_READ: - while (usRegs > 0) { - _XFER_2_RD(pucRegBuffer, pucHoldingBuffer); - iRegIndex += 2; - usRegs -= 1; - }; - // Send access notification - (void)send_param_access_notification(MB_EVENT_HOLDING_REG_RD); - // Send parameter info - (void)send_param_info(MB_EVENT_HOLDING_REG_RD, (uint16_t)usAddress, - (uint8_t*)pucBufferStart, (uint16_t)usNRegs); - break; - case MB_REG_WRITE: - while (usRegs > 0) { - _XFER_2_WR(pucHoldingBuffer, pucRegBuffer); - pucHoldingBuffer += 2; - iRegIndex += 2; - usRegs -= 1; - }; - // Send access notification - (void)send_param_access_notification(MB_EVENT_HOLDING_REG_WR); - // Send parameter info - (void)send_param_info(MB_EVENT_HOLDING_REG_WR, (uint16_t)usAddress, - (uint8_t*)pucBufferStart, (uint16_t)usNRegs); - break; - } - } else { - eStatus = MB_ENOREG; - } - return eStatus; + vMBPortSetMode((UCHAR)MB_PORT_INACTIVE); + return ESP_OK; } -// Callback function for reading of MB Coils Registers -eMBErrorCode eMBRegCoilsCBSerialSlave(UCHAR* pucRegBuffer, USHORT usAddress, - USHORT usNCoils, eMBRegisterMode eMode) -{ - MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - MB_EILLSTATE, "Slave stack uninitialized."); - MB_SLAVE_CHECK((pucRegBuffer != NULL), - MB_EINVAL, "Slave stack call failed."); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - USHORT usRegCoilNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_COIL].size >> 1); // number of registers in storage area - USHORT usRegCoilsStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_COIL].start_offset; // MB offset of coils registers - UCHAR* pucRegCoilsBuf = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_COIL].address; - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex; - USHORT usCoils = usNCoils; - usAddress--; // The address is already +1 - if ((usAddress >= usRegCoilsStart) - && (usRegCoilNregs >= 1) - && ((usAddress + usCoils) <= (usRegCoilsStart + (usRegCoilNregs << 4) + 1)) - && (pucRegCoilsBuf != NULL) - && (usNCoils >= 1)) { - iRegIndex = (USHORT) (usAddress - usRegCoilsStart); - CHAR* pucCoilsDataBuf = (CHAR*)(pucRegCoilsBuf + (iRegIndex >> 3)); - switch (eMode) { - case MB_REG_READ: - while (usCoils > 0) { - UCHAR ucResult = xMBUtilGetBits((UCHAR*)pucRegCoilsBuf, iRegIndex, 1); - xMBUtilSetBits(pucRegBuffer, iRegIndex - (usAddress - usRegCoilsStart), 1, ucResult); - iRegIndex++; - usCoils--; - } - // Send an event to notify application task about event - (void)send_param_access_notification(MB_EVENT_COILS_RD); - (void)send_param_info(MB_EVENT_COILS_RD, (uint16_t)usAddress, - (uint8_t*)(pucCoilsDataBuf), (uint16_t)usNCoils); - break; - case MB_REG_WRITE: - while (usCoils > 0) { - UCHAR ucResult = xMBUtilGetBits(pucRegBuffer, - iRegIndex - (usAddress - usRegCoilsStart), 1); - xMBUtilSetBits((uint8_t*)pucRegCoilsBuf, iRegIndex, 1, ucResult); - iRegIndex++; - usCoils--; - } - // Send an event to notify application task about event - (void)send_param_access_notification(MB_EVENT_COILS_WR); - (void)send_param_info(MB_EVENT_COILS_WR, (uint16_t)usAddress, - (uint8_t*)pucCoilsDataBuf, (uint16_t)usNCoils); - break; - } // switch ( eMode ) - } else { - // If the configuration or input parameters are incorrect then return error to stack - eStatus = MB_ENOREG; - } - return eStatus; -} - -// Callback function for reading of MB Discrete Input Registers -eMBErrorCode eMBRegDiscreteCBSerialSlave(UCHAR* pucRegBuffer, USHORT usAddress, - USHORT usNDiscrete) -{ - MB_SLAVE_CHECK((mbs_interface_ptr != NULL), - MB_EILLSTATE, "Slave stack uninitialized."); - MB_SLAVE_CHECK((pucRegBuffer != NULL), - MB_EINVAL, "Slave stack call failed."); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - USHORT usRegDiscreteNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_DISCRETE].size >> 1); // number of registers in storage area - USHORT usRegDiscreteStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_DISCRETE].start_offset; // MB offset of registers - UCHAR* pucRegDiscreteBuf = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_DISCRETE].address; // the storage address - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex, iRegBitIndex, iNReg; - UCHAR* pucDiscreteInputBuf; - iNReg = usNDiscrete / 8 + 1; - pucDiscreteInputBuf = (UCHAR*) pucRegDiscreteBuf; - // It already plus one in modbus function method. - usAddress--; - if ((usAddress >= usRegDiscreteStart) - && (usRegDiscreteNregs >= 1) - && (pucRegDiscreteBuf != NULL) - && ((usAddress + usNDiscrete) <= (usRegDiscreteStart + (usRegDiscreteNregs * 16))) - && (usNDiscrete >= 1)) { - iRegIndex = (USHORT) (usAddress - usRegDiscreteStart) / 8; // Get register index in the buffer for bit number - iRegBitIndex = (USHORT)(usAddress - usRegDiscreteStart) % 8; // Get bit index - UCHAR* pucTempBuf = &pucDiscreteInputBuf[iRegIndex]; - while (iNReg > 0) { - *pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8); - iNReg--; - } - pucRegBuffer--; - // Last discrete - usNDiscrete = usNDiscrete % 8; - // Filling zero to high bit - *pucRegBuffer = *pucRegBuffer << (8 - usNDiscrete); - *pucRegBuffer = *pucRegBuffer >> (8 - usNDiscrete); - // Send an event to notify application task about event - (void)send_param_access_notification(MB_EVENT_DISCRETE_RD); - (void)send_param_info(MB_EVENT_DISCRETE_RD, (uint16_t)usAddress, - (uint8_t*)pucTempBuf, (uint16_t)usNDiscrete); - } else { - eStatus = MB_ENOREG; - } - return eStatus; -} -#pragma GCC diagnostic pop // require GCC - // Initialization of Modbus controller esp_err_t mbc_serial_slave_create(void** handler) { @@ -504,15 +228,15 @@ esp_err_t mbc_serial_slave_create(void** handler) mbs_interface_ptr->destroy = mbc_serial_slave_destroy; mbs_interface_ptr->get_param_info = mbc_serial_slave_get_param_info; mbs_interface_ptr->init = mbc_serial_slave_create; - mbs_interface_ptr->set_descriptor = mbc_serial_slave_set_descriptor; + mbs_interface_ptr->set_descriptor = NULL; // Use common set descriptor function mbs_interface_ptr->setup = mbc_serial_slave_setup; mbs_interface_ptr->start = mbc_serial_slave_start; // Initialize stack callback function pointers - mbs_interface_ptr->slave_reg_cb_discrete = eMBRegDiscreteCBSerialSlave; - mbs_interface_ptr->slave_reg_cb_input = eMBRegInputCBSerialSlave; - mbs_interface_ptr->slave_reg_cb_holding = eMBRegHoldingCBSerialSlave; - mbs_interface_ptr->slave_reg_cb_coils = eMBRegCoilsCBSerialSlave; + mbs_interface_ptr->slave_reg_cb_discrete = NULL; // implemented in common layer + mbs_interface_ptr->slave_reg_cb_input = NULL; + mbs_interface_ptr->slave_reg_cb_holding = NULL; + mbs_interface_ptr->slave_reg_cb_coils = NULL; *handler = (void*)mbs_interface_ptr; diff --git a/components/freemodbus/tcp_slave/modbus_controller/mbc_tcp_slave.c b/components/freemodbus/tcp_slave/modbus_controller/mbc_tcp_slave.c index 6104a03216..f0db0c96f1 100644 --- a/components/freemodbus/tcp_slave/modbus_controller/mbc_tcp_slave.c +++ b/components/freemodbus/tcp_slave/modbus_controller/mbc_tcp_slave.c @@ -31,13 +31,6 @@ // Shared pointer to interface structure static mb_slave_interface_t* mbs_interface_ptr = NULL; -// The helper function to get time stamp in microseconds -static uint64_t get_time_stamp(void) -{ - uint64_t time_stamp = esp_timer_get_time(); - return time_stamp; -} - // Modbus task function static void modbus_tcp_slave_task(void *pvParameters) { @@ -123,69 +116,11 @@ static esp_err_t mbc_tcp_slave_destroy(void) (void)vQueueDelete(mbs_opts->mbs_notification_queue_handle); (void)vEventGroupDelete(mbs_opts->mbs_event_group); (void)vMBTCPPortClose(); - free(mbs_interface_ptr); + vMBPortSetMode((UCHAR)MB_PORT_INACTIVE); - mbs_interface_ptr = NULL; return ESP_OK; } -esp_err_t mbc_tcp_slave_set_descriptor(const mb_register_area_descriptor_t descr_info) -{ - MB_SLAVE_ASSERT(mbs_interface_ptr != NULL); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - MB_SLAVE_CHECK(((descr_info.type < MB_PARAM_COUNT) && (descr_info.type >= MB_PARAM_HOLDING)), - ESP_ERR_INVALID_ARG, "mb incorrect modbus instance type = (0x%x).", - (uint32_t)descr_info.type); - MB_SLAVE_CHECK((descr_info.address != NULL), - ESP_ERR_INVALID_ARG, "mb instance pointer is NULL."); - MB_SLAVE_CHECK((descr_info.size >= MB_INST_MIN_SIZE) && (descr_info.size < (MB_INST_MAX_SIZE)), - ESP_ERR_INVALID_ARG, "mb instance size is incorrect = (0x%x).", - (uint32_t)descr_info.size); - mbs_opts->mbs_area_descriptors[descr_info.type] = descr_info; - return ESP_OK; -} - -// Helper function to send parameter information to application task -static esp_err_t send_param_info(mb_event_group_t par_type, uint16_t mb_offset, - uint8_t* par_address, uint16_t par_size) -{ - MB_SLAVE_ASSERT(mbs_interface_ptr != NULL); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - esp_err_t error = ESP_FAIL; - mb_param_info_t par_info; - // Check if queue is not full the send parameter information - par_info.type = par_type; - par_info.size = par_size; - par_info.address = par_address; - par_info.time_stamp = get_time_stamp(); - par_info.mb_offset = mb_offset; - BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, - &par_info, MB_PAR_INFO_TOUT); - if (pdTRUE == status) { - ESP_LOGD(MB_SLAVE_TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d", - par_type, (uint32_t)par_address, par_size); - error = ESP_OK; - } else if (errQUEUE_FULL == status) { - ESP_LOGD(MB_SLAVE_TAG, "Parameter queue is overflowed."); - } - return error; -} - -// Helper function to send notification -static esp_err_t send_param_access_notification(mb_event_group_t event) -{ - MB_SLAVE_ASSERT(mbs_interface_ptr != NULL); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - esp_err_t err = ESP_FAIL; - mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, - (EventBits_t)event); - if (bits & event) { - ESP_LOGD(MB_SLAVE_TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event); - err = ESP_OK; - } - return err; -} - // Blocking function to get event on parameter group change for application task static mb_event_group_t mbc_tcp_slave_check_event(mb_event_group_t group) { @@ -220,203 +155,6 @@ static esp_err_t mbc_tcp_slave_get_param_info(mb_param_info_t* reg_info, uint32_ // This is required to suppress warning when register start address is zero #pragma GCC diagnostic ignored "-Wtype-limits" -// Callback function for reading of MB Input Registers -eMBErrorCode eMBRegInputCBTcpSlave(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs) -{ - MB_SLAVE_ASSERT(mbs_interface_ptr != NULL); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - MB_SLAVE_ASSERT(pucRegBuffer != NULL); - USHORT usRegInputNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_INPUT].size >> 1); // Number of input registers - USHORT usInputRegStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_INPUT].start_offset; // Get Modbus start address - UCHAR* pucInputBuffer = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_INPUT].address; // Get instance address - USHORT usRegs = usNRegs; - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex; - // If input or configuration parameters are incorrect then return an error to stack layer - if ((usAddress >= usInputRegStart) - && (pucInputBuffer != NULL) - && (usNRegs >= 1) - && ((usAddress + usRegs) <= (usInputRegStart + usRegInputNregs + 1)) - && (usRegInputNregs >= 1)) { - iRegIndex = (USHORT)(usAddress - usInputRegStart - 1); - iRegIndex <<= 1; // register Address to byte address - pucInputBuffer += iRegIndex; - UCHAR* pucBufferStart = pucInputBuffer; - while (usRegs > 0) { - _XFER_2_RD(pucRegBuffer, pucInputBuffer); - iRegIndex += 2; - usRegs -= 1; - } - // Send access notification - (void)send_param_access_notification(MB_EVENT_INPUT_REG_RD); - // Send parameter info to application task - (void)send_param_info(MB_EVENT_INPUT_REG_RD, (uint16_t)usAddress, - (uint8_t*)pucBufferStart, (uint16_t)usNRegs); - } else { - eStatus = MB_ENOREG; - } - return eStatus; -} - -// Callback function for reading of MB Holding Registers -// Executed by stack when request to read/write holding registers is received -eMBErrorCode eMBRegHoldingCBTcpSlave(UCHAR * pucRegBuffer, USHORT usAddress, - USHORT usNRegs, eMBRegisterMode eMode) -{ - MB_SLAVE_ASSERT(mbs_interface_ptr != NULL); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - MB_SLAVE_ASSERT(pucRegBuffer != NULL); - USHORT usRegHoldingNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_HOLDING].size >> 1); - USHORT usRegHoldingStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_HOLDING].start_offset; - UCHAR* pucHoldingBuffer = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_HOLDING].address; - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex; - USHORT usRegs = usNRegs; - // Check input and configuration parameters for correctness - if ((usAddress >= usRegHoldingStart) - && (pucHoldingBuffer != NULL) - && ((usAddress + usRegs) <= (usRegHoldingStart + usRegHoldingNregs + 1)) - && (usRegHoldingNregs >= 1) - && (usNRegs >= 1)) { - iRegIndex = (USHORT) (usAddress - usRegHoldingStart - 1); - iRegIndex <<= 1; // register Address to byte address - pucHoldingBuffer += iRegIndex; - UCHAR* pucBufferStart = pucHoldingBuffer; - switch (eMode) { - case MB_REG_READ: - while (usRegs > 0) { - _XFER_2_RD(pucRegBuffer, pucHoldingBuffer); - iRegIndex += 2; - usRegs -= 1; - }; - // Send access notification - (void)send_param_access_notification(MB_EVENT_HOLDING_REG_RD); - // Send parameter info - (void)send_param_info(MB_EVENT_HOLDING_REG_RD, (uint16_t)usAddress, - (uint8_t*)pucBufferStart, (uint16_t)usNRegs); - break; - case MB_REG_WRITE: - while (usRegs > 0) { - _XFER_2_WR(pucHoldingBuffer, pucRegBuffer); - pucHoldingBuffer += 2; - iRegIndex += 2; - usRegs -= 1; - }; - // Send access notification - (void)send_param_access_notification(MB_EVENT_HOLDING_REG_WR); - // Send parameter info - (void)send_param_info(MB_EVENT_HOLDING_REG_WR, (uint16_t)usAddress, - (uint8_t*)pucBufferStart, (uint16_t)usNRegs); - break; - } - } else { - eStatus = MB_ENOREG; - } - return eStatus; -} - -// Callback function for reading of MB Coils Registers -eMBErrorCode eMBRegCoilsCBTcpSlave(UCHAR* pucRegBuffer, USHORT usAddress, - USHORT usNCoils, eMBRegisterMode eMode) -{ - MB_SLAVE_ASSERT(mbs_interface_ptr != NULL); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - MB_SLAVE_ASSERT(NULL != pucRegBuffer); - USHORT usRegCoilNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_COIL].size >> 1); // number of registers in storage area - USHORT usRegCoilsStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_COIL].start_offset; // MB offset of coils registers - UCHAR* pucRegCoilsBuf = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_COIL].address; - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex; - USHORT usCoils = usNCoils; - usAddress--; // The address is already +1 - if ((usAddress >= usRegCoilsStart) - && (usRegCoilNregs >= 1) - && ((usAddress + usCoils) <= (usRegCoilsStart + (usRegCoilNregs << 4) + 1)) - && (pucRegCoilsBuf != NULL) - && (usNCoils >= 1)) { - iRegIndex = (USHORT) (usAddress - usRegCoilsStart); - CHAR* pucCoilsDataBuf = (CHAR*)(pucRegCoilsBuf + (iRegIndex >> 3)); - switch (eMode) { - case MB_REG_READ: - while (usCoils > 0) { - UCHAR ucResult = xMBUtilGetBits((UCHAR*)pucRegCoilsBuf, iRegIndex, 1); - xMBUtilSetBits(pucRegBuffer, iRegIndex - (usAddress - usRegCoilsStart), 1, ucResult); - iRegIndex++; - usCoils--; - } - // Send an event to notify application task about event - (void)send_param_access_notification(MB_EVENT_COILS_RD); - (void)send_param_info(MB_EVENT_COILS_RD, (uint16_t)usAddress, - (uint8_t*)(pucCoilsDataBuf), (uint16_t)usNCoils); - break; - case MB_REG_WRITE: - while (usCoils > 0) { - UCHAR ucResult = xMBUtilGetBits(pucRegBuffer, - iRegIndex - (usAddress - usRegCoilsStart), 1); - xMBUtilSetBits((uint8_t*)pucRegCoilsBuf, iRegIndex, 1, ucResult); - iRegIndex++; - usCoils--; - } - // Send an event to notify application task about event - (void)send_param_access_notification(MB_EVENT_COILS_WR); - (void)send_param_info(MB_EVENT_COILS_WR, (uint16_t)usAddress, - (uint8_t*)pucCoilsDataBuf, (uint16_t)usNCoils); - break; - } // switch ( eMode ) - } else { - // If the configuration or input parameters are incorrect then return error to stack - eStatus = MB_ENOREG; - } - return eStatus; -} - -// Callback function for reading of MB Discrete Input Registers -eMBErrorCode eMBRegDiscreteCBTcpSlave(UCHAR* pucRegBuffer, USHORT usAddress, - USHORT usNDiscrete) -{ - MB_SLAVE_ASSERT(mbs_interface_ptr != NULL); - mb_slave_options_t* mbs_opts = &mbs_interface_ptr->opts; - MB_SLAVE_ASSERT(pucRegBuffer != NULL); - USHORT usRegDiscreteNregs = (USHORT)(mbs_opts->mbs_area_descriptors[MB_PARAM_DISCRETE].size >> 1); // number of registers in storage area - USHORT usRegDiscreteStart = (USHORT)mbs_opts->mbs_area_descriptors[MB_PARAM_DISCRETE].start_offset; // MB offset of registers - UCHAR* pucRegDiscreteBuf = (UCHAR*)mbs_opts->mbs_area_descriptors[MB_PARAM_DISCRETE].address; // the storage address - eMBErrorCode eStatus = MB_ENOERR; - USHORT iRegIndex, iRegBitIndex, iNReg; - UCHAR* pucDiscreteInputBuf; - iNReg = usNDiscrete / 8 + 1; - pucDiscreteInputBuf = (UCHAR*) pucRegDiscreteBuf; - // It already plus one in modbus function method. - usAddress--; - if ((usAddress >= usRegDiscreteStart) - && (usRegDiscreteNregs >= 1) - && (pucRegDiscreteBuf != NULL) - && ((usAddress + usNDiscrete) <= (usRegDiscreteStart + (usRegDiscreteNregs * 16))) - && (usNDiscrete >= 1)) { - iRegIndex = (USHORT) (usAddress - usRegDiscreteStart) / 8; // Get register index in the buffer for bit number - iRegBitIndex = (USHORT)(usAddress - usRegDiscreteStart) % 8; // Get bit index - UCHAR* pucTempBuf = &pucDiscreteInputBuf[iRegIndex]; - while (iNReg > 0) { - *pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++], iRegBitIndex, 8); - iNReg--; - } - pucRegBuffer--; - // Last discrete - usNDiscrete = usNDiscrete % 8; - // Filling zero to high bit - *pucRegBuffer = *pucRegBuffer << (8 - usNDiscrete); - *pucRegBuffer = *pucRegBuffer >> (8 - usNDiscrete); - // Send an event to notify application task about event - (void)send_param_access_notification(MB_EVENT_DISCRETE_RD); - (void)send_param_info(MB_EVENT_DISCRETE_RD, (uint16_t)usAddress, - (uint8_t*)pucTempBuf, (uint16_t)usNDiscrete); - } else { - eStatus = MB_ENOREG; - } - return eStatus; -} -#pragma GCC diagnostic pop // require GCC - // Initialization of Modbus controller esp_err_t mbc_tcp_slave_create(void** handler) { @@ -470,13 +208,13 @@ esp_err_t mbc_tcp_slave_create(void** handler) mbs_interface_ptr->start = mbc_tcp_slave_start; mbs_interface_ptr->check_event = mbc_tcp_slave_check_event; mbs_interface_ptr->get_param_info = mbc_tcp_slave_get_param_info; - mbs_interface_ptr->set_descriptor = mbc_tcp_slave_set_descriptor; + mbs_interface_ptr->set_descriptor = NULL; // Use common descriptor setter // Initialize stack callback function pointers - mbs_interface_ptr->slave_reg_cb_discrete = eMBRegDiscreteCBTcpSlave; - mbs_interface_ptr->slave_reg_cb_input = eMBRegInputCBTcpSlave; - mbs_interface_ptr->slave_reg_cb_holding = eMBRegHoldingCBTcpSlave; - mbs_interface_ptr->slave_reg_cb_coils = eMBRegCoilsCBTcpSlave; + mbs_interface_ptr->slave_reg_cb_discrete = NULL; // implemented in common layer + mbs_interface_ptr->slave_reg_cb_input = NULL; + mbs_interface_ptr->slave_reg_cb_holding = NULL; + mbs_interface_ptr->slave_reg_cb_coils = NULL; *handler = (void*)mbs_interface_ptr; diff --git a/examples/protocols/modbus/mb_example_common/include/modbus_params.h b/examples/protocols/modbus/mb_example_common/include/modbus_params.h index f75996f3e2..37ee53d84a 100644 --- a/examples/protocols/modbus/mb_example_common/include/modbus_params.h +++ b/examples/protocols/modbus/mb_example_common/include/modbus_params.h @@ -35,11 +35,15 @@ typedef struct #pragma pack(push, 1) typedef struct { - float input_data0; - float input_data1; - float input_data2; - float input_data3; - uint16_t data[150]; + float input_data0; // 0 + float input_data1; // 2 + float input_data2; // 4 + float input_data3; // 6 + uint16_t data[150]; // 8 + 150 = 158 + float input_data4; // 158 + float input_data5; + float input_data6; + float input_data7; } input_reg_params_t; #pragma pack(pop) @@ -51,6 +55,10 @@ typedef struct float holding_data2; float holding_data3; uint16_t test_regs[150]; + float holding_data4; + float holding_data5; + float holding_data6; + float holding_data7; } holding_reg_params_t; #pragma pack(pop) diff --git a/examples/protocols/modbus/serial/mb_slave/main/slave.c b/examples/protocols/modbus/serial/mb_slave/main/slave.c index 9d8763a238..0c0372bbe1 100644 --- a/examples/protocols/modbus/serial/mb_slave/main/slave.c +++ b/examples/protocols/modbus/serial/mb_slave/main/slave.c @@ -20,10 +20,14 @@ // Please refer to documentation for selected board and target to configure pins using Kconfig. // Defines below are used to define register start address for each type of Modbus registers +#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) >> 1)) +#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) >> 1)) #define MB_REG_DISCRETE_INPUT_START (0x0000) -#define MB_REG_INPUT_START (0x0000) -#define MB_REG_HOLDING_START (0x0000) #define MB_REG_COILS_START (0x0000) +#define MB_REG_INPUT_START_AREA0 (INPUT_OFFSET(input_data0)) // register offset input area 0 +#define MB_REG_INPUT_START_AREA1 (INPUT_OFFSET(input_data4)) // register offset input area 1 +#define MB_REG_HOLDING_START_AREA0 (HOLD_OFFSET(holding_data0)) +#define MB_REG_HOLDING_START_AREA1 (HOLD_OFFSET(holding_data4)) #define MB_PAR_INFO_GET_TOUT (10) // Timeout for get parameter info #define MB_CHAN_DATA_MAX_VAL (6) @@ -44,16 +48,25 @@ static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED; static void setup_reg_data(void) { // Define initial state of parameters - discrete_reg_params.discrete_input1 = 1; - discrete_reg_params.discrete_input3 = 1; - discrete_reg_params.discrete_input5 = 1; - discrete_reg_params.discrete_input7 = 1; + discrete_reg_params.discrete_input0 = 1; + discrete_reg_params.discrete_input1 = 0; + discrete_reg_params.discrete_input2 = 1; + discrete_reg_params.discrete_input3 = 0; + discrete_reg_params.discrete_input4 = 1; + discrete_reg_params.discrete_input5 = 0; + discrete_reg_params.discrete_input6 = 1; + discrete_reg_params.discrete_input7 = 0; holding_reg_params.holding_data0 = 1.34; holding_reg_params.holding_data1 = 2.56; holding_reg_params.holding_data2 = 3.78; holding_reg_params.holding_data3 = 4.90; + holding_reg_params.holding_data4 = 5.67; + holding_reg_params.holding_data5 = 6.78; + holding_reg_params.holding_data6 = 7.79; + holding_reg_params.holding_data7 = 8.80; + coil_reg_params.coils_port0 = 0x55; coil_reg_params.coils_port1 = 0xAA; @@ -61,6 +74,11 @@ static void setup_reg_data(void) input_reg_params.input_data1 = 2.34; input_reg_params.input_data2 = 3.56; input_reg_params.input_data3 = 4.78; + + input_reg_params.input_data4 = 1.12; + input_reg_params.input_data5 = 2.34; + input_reg_params.input_data6 = 3.56; + input_reg_params.input_data7 = 4.78; } // An example application of Modbus slave. It is based on freemodbus stack. @@ -98,16 +116,27 @@ void app_main(void) // by mbc_slave_set_descriptor() API call then Modbus stack // will send exception response for this register area. reg_area.type = MB_PARAM_HOLDING; // Set type of register area - reg_area.start_offset = MB_REG_HOLDING_START; // Offset of register area in Modbus protocol - reg_area.address = (void*)&holding_reg_params; // Set pointer to storage instance - reg_area.size = sizeof(holding_reg_params); // Set the size of register storage instance + reg_area.start_offset = MB_REG_HOLDING_START_AREA0; // Offset of register area in Modbus protocol + reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance + reg_area.size = sizeof(float) << 2; // Set the size of register storage instance + ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); + reg_area.type = MB_PARAM_HOLDING; // Set type of register area + reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol + reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance + reg_area.size = sizeof(float) << 2; // Set the size of register storage instance ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); // Initialization of Input Registers area reg_area.type = MB_PARAM_INPUT; - reg_area.start_offset = MB_REG_INPUT_START; - reg_area.address = (void*)&input_reg_params; - reg_area.size = sizeof(input_reg_params); + reg_area.start_offset = MB_REG_INPUT_START_AREA0; + reg_area.address = (void*)&input_reg_params.input_data0; + reg_area.size = sizeof(float) << 2; + ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); + // Initialization of Input Registers area + reg_area.type = MB_PARAM_INPUT; + reg_area.start_offset = MB_REG_INPUT_START_AREA1; + reg_area.address = (void*)&input_reg_params.input_data4; + reg_area.size = sizeof(float) << 2; ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); // Initialization of Coils register area diff --git a/examples/protocols/modbus/tcp/mb_tcp_slave/main/tcp_slave.c b/examples/protocols/modbus/tcp/mb_tcp_slave/main/tcp_slave.c index b1c1085591..8c032d1da8 100644 --- a/examples/protocols/modbus/tcp/mb_tcp_slave/main/tcp_slave.c +++ b/examples/protocols/modbus/tcp/mb_tcp_slave/main/tcp_slave.c @@ -26,10 +26,14 @@ #define MB_MDNS_PORT (502) // Defines below are used to define register start address for each type of Modbus registers +#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) >> 1)) +#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) >> 1)) #define MB_REG_DISCRETE_INPUT_START (0x0000) -#define MB_REG_INPUT_START (0x0000) -#define MB_REG_HOLDING_START (0x0000) #define MB_REG_COILS_START (0x0000) +#define MB_REG_INPUT_START_AREA0 (INPUT_OFFSET(input_data0)) // register offset input area 0 +#define MB_REG_INPUT_START_AREA1 (INPUT_OFFSET(input_data4)) // register offset input area 1 +#define MB_REG_HOLDING_START_AREA0 (HOLD_OFFSET(holding_data0)) +#define MB_REG_HOLDING_START_AREA1 (HOLD_OFFSET(holding_data4)) #define MB_PAR_INFO_GET_TOUT (10) // Timeout for get parameter info #define MB_CHAN_DATA_MAX_VAL (10) @@ -117,16 +121,24 @@ static void start_mdns_service() static void setup_reg_data(void) { // Define initial state of parameters - discrete_reg_params.discrete_input1 = 1; - discrete_reg_params.discrete_input3 = 1; - discrete_reg_params.discrete_input5 = 1; - discrete_reg_params.discrete_input7 = 1; + discrete_reg_params.discrete_input0 = 1; + discrete_reg_params.discrete_input1 = 0; + discrete_reg_params.discrete_input2 = 1; + discrete_reg_params.discrete_input3 = 0; + discrete_reg_params.discrete_input4 = 1; + discrete_reg_params.discrete_input5 = 0; + discrete_reg_params.discrete_input6 = 1; + discrete_reg_params.discrete_input7 = 0; holding_reg_params.holding_data0 = 1.34; holding_reg_params.holding_data1 = 2.56; holding_reg_params.holding_data2 = 3.78; holding_reg_params.holding_data3 = 4.90; + holding_reg_params.holding_data4 = 5.67; + holding_reg_params.holding_data5 = 6.78; + holding_reg_params.holding_data6 = 7.79; + holding_reg_params.holding_data7 = 8.80; coil_reg_params.coils_port0 = 0x55; coil_reg_params.coils_port1 = 0xAA; @@ -134,6 +146,10 @@ static void setup_reg_data(void) input_reg_params.input_data1 = 2.34; input_reg_params.input_data2 = 3.56; input_reg_params.input_data3 = 4.78; + input_reg_params.input_data4 = 1.12; + input_reg_params.input_data5 = 2.34; + input_reg_params.input_data6 = 3.56; + input_reg_params.input_data7 = 4.78; } // An example application of Modbus slave. It is based on freemodbus stack. @@ -192,16 +208,28 @@ void app_main(void) // by mbc_slave_set_descriptor() API call then Modbus stack // will send exception response for this register area. reg_area.type = MB_PARAM_HOLDING; // Set type of register area - reg_area.start_offset = MB_REG_HOLDING_START; // Offset of register area in Modbus protocol - reg_area.address = (void*)&holding_reg_params; // Set pointer to storage instance - reg_area.size = sizeof(holding_reg_params); // Set the size of register storage instance + reg_area.start_offset = MB_REG_HOLDING_START_AREA0; // Offset of register area in Modbus protocol + reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance + reg_area.size = sizeof(float) << 2; // Set the size of register storage instance + ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); + + reg_area.type = MB_PARAM_HOLDING; // Set type of register area + reg_area.start_offset = MB_REG_HOLDING_START_AREA1; // Offset of register area in Modbus protocol + reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance + reg_area.size = sizeof(float) << 2; // Set the size of register storage instance ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); // Initialization of Input Registers area reg_area.type = MB_PARAM_INPUT; - reg_area.start_offset = MB_REG_INPUT_START; - reg_area.address = (void*)&input_reg_params; - reg_area.size = sizeof(input_reg_params); + reg_area.start_offset = MB_REG_INPUT_START_AREA0; + reg_area.address = (void*)&input_reg_params.input_data0; + reg_area.size = sizeof(float) << 2; + ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); + // Initialization of Input Registers area + reg_area.type = MB_PARAM_INPUT; + reg_area.start_offset = MB_REG_INPUT_START_AREA1; + reg_area.address = (void*)&input_reg_params.input_data4; + reg_area.size = sizeof(float) << 2; ESP_ERROR_CHECK(mbc_slave_set_descriptor(reg_area)); // Initialization of Coils register area