| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710 |
- /* Copyright 2018 Espressif Systems (Shanghai) PTE LTD
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- // mbc_serial_master.c
- // Serial master implementation of the Modbus controller
- #include <sys/time.h> // for calculation of time stamp in milliseconds
- #include "esp_log.h" // for log_write
- #include <string.h> // for memcpy
- #include "freertos/FreeRTOS.h" // for task creation and queue access
- #include "freertos/task.h" // for task api access
- #include "freertos/event_groups.h" // for event groups
- #include "freertos/queue.h" // for queue api access
- #include "mb_m.h" // for modbus stack master types definition
- #include "port.h" // for port callback functions
- #include "mbutils.h" // for mbutils functions definition for stack callback
- #include "sdkconfig.h" // for KConfig values
- #include "esp_modbus_common.h" // for common types
- #include "esp_modbus_master.h" // for public master types
- #include "mbc_master.h" // for private master types
- #include "mbc_serial_master.h" // for serial master create function and types
- // The Modbus Transmit Poll function defined in port
- extern BOOL xMBMasterPortSerialTxPoll(void);
- /*-----------------------Master mode use these variables----------------------*/
- #define MB_RESPONSE_TICS pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND + 10)
- static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
- // Modbus event processing task
- static void modbus_master_task(void *pvParameters)
- {
- // The interface must be initialized before start of state machine
- MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- // Main Modbus stack processing cycle
- for (;;) {
- // Wait for poll events
- BaseType_t status = xEventGroupWaitBits(mbm_opts->mbm_event_group,
- (BaseType_t)(MB_EVENT_STACK_STARTED),
- pdFALSE, // do not clear bits
- pdFALSE,
- portMAX_DELAY);
- // Check if stack started then poll for data
- if (status & MB_EVENT_STACK_STARTED) {
- (void)eMBMasterPoll(); // Allow stack to process data
- // Send response buffer if ready to be sent
- BOOL xSentState = xMBMasterPortSerialTxPoll();
- if (xSentState) {
- // Let state machine know that request frame was transmitted out
- (void)xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
- }
- }
- }
- }
- // Setup Modbus controller parameters
- static esp_err_t mbc_serial_master_setup(void* comm_info)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- ESP_ERR_INVALID_STATE,
- "Master interface uninitialized.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- const mb_master_comm_info_t* comm_info_ptr = (mb_master_comm_info_t*)comm_info;
- // Check communication options
- MB_MASTER_CHECK(((comm_info_ptr->mode == MB_MODE_RTU) || (comm_info_ptr->mode == MB_MODE_ASCII)),
- ESP_ERR_INVALID_ARG, "mb incorrect mode = (0x%x).",
- (uint32_t)comm_info_ptr->mode);
- MB_MASTER_CHECK((comm_info_ptr->port <= UART_NUM_MAX), ESP_ERR_INVALID_ARG,
- "mb wrong port to set = (0x%x).", (uint32_t)comm_info_ptr->port);
- MB_MASTER_CHECK((comm_info_ptr->parity <= UART_PARITY_ODD), ESP_ERR_INVALID_ARG,
- "mb wrong parity option = (0x%x).", (uint32_t)comm_info_ptr->parity);
- // Save the communication options
- mbm_opts->mbm_comm = *(mb_communication_info_t*)comm_info_ptr;
- return ESP_OK;
- }
- // Modbus controller stack start function
- static esp_err_t mbc_serial_master_start(void)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- ESP_ERR_INVALID_STATE,
- "Master interface uninitialized.");
- eMBErrorCode status = MB_EIO;
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- const mb_communication_info_t* comm_info = (mb_communication_info_t*)&mbm_opts->mbm_comm;
- // Initialize Modbus stack using mbcontroller parameters
- status = eMBMasterSerialInit((eMBMode)comm_info->mode, (UCHAR)comm_info->port,
- (ULONG)comm_info->baudrate,
- MB_PORT_PARITY_GET(comm_info->parity));
- MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
- "mb stack initialization failure, eMBInit() returns (0x%x).", status);
- status = eMBMasterEnable();
- MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
- "mb stack set slave ID failure, eMBEnable() returned (0x%x).", (uint32_t)status);
- // Set the mbcontroller start flag
- EventBits_t flag = xEventGroupSetBits(mbm_opts->mbm_event_group,
- (EventBits_t)MB_EVENT_STACK_STARTED);
- MB_MASTER_CHECK((flag & MB_EVENT_STACK_STARTED),
- ESP_ERR_INVALID_STATE, "mb stack start event set error.");
- return ESP_OK;
- }
- // Modbus controller destroy function
- static esp_err_t mbc_serial_master_destroy(void)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- ESP_ERR_INVALID_STATE,
- "Master interface uninitialized.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- eMBErrorCode mb_error = MB_ENOERR;
- // Stop polling by clearing correspondent bit in the event group
- EventBits_t flag = xEventGroupClearBits(mbm_opts->mbm_event_group,
- (EventBits_t)MB_EVENT_STACK_STARTED);
- MB_MASTER_CHECK((flag & MB_EVENT_STACK_STARTED),
- ESP_ERR_INVALID_STATE, "mb stack stop event failure.");
- // Desable and then destroy the Modbus stack
- mb_error = eMBMasterDisable();
- MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE, "mb stack disable failure.");
- (void)vTaskDelete(mbm_opts->mbm_task_handle);
- (void)vEventGroupDelete(mbm_opts->mbm_event_group);
- mb_error = eMBMasterClose();
- MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
- "mb stack close failure returned (0x%x).", (uint32_t)mb_error);
- free(mbm_interface_ptr); // free the memory allocated for options
- vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
- mbm_interface_ptr = NULL;
- return ESP_OK;
- }
- // Set Modbus parameter description table
- static esp_err_t mbc_serial_master_set_descriptor(const mb_parameter_descriptor_t* descriptor, const uint16_t num_elements)
- {
- MB_MASTER_CHECK((descriptor != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
- MB_MASTER_CHECK((num_elements >= 1),
- ESP_ERR_INVALID_ARG, "mb table size is incorrect.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- const mb_parameter_descriptor_t *reg_ptr = descriptor;
- // Go through all items in the table to check all Modbus registers
- for (uint16_t counter = 0; counter < (num_elements); counter++, reg_ptr++)
- {
- // Below is the code to check consistency of the table format and required fields.
- MB_MASTER_CHECK((reg_ptr->cid == counter),
- ESP_ERR_INVALID_ARG, "mb descriptor cid field is incorrect.");
- MB_MASTER_CHECK((reg_ptr->param_key != NULL),
- ESP_ERR_INVALID_ARG, "mb descriptor param key is incorrect.");
- MB_MASTER_CHECK((reg_ptr->mb_size > 0),
- ESP_ERR_INVALID_ARG, "mb descriptor param size is incorrect.");
- }
- mbm_opts->mbm_param_descriptor_table = descriptor;
- mbm_opts->mbm_param_descriptor_size = num_elements;
- return ESP_OK;
- }
- // Send custom Modbus request defined as mb_param_request_t structure
- static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, void* data_ptr)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- ESP_ERR_INVALID_STATE,
- "Master interface uninitialized.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- MB_MASTER_CHECK((request != NULL),
- ESP_ERR_INVALID_ARG, "mb request structure.");
- MB_MASTER_CHECK((data_ptr != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect data pointer.");
- eMBMasterReqErrCode mb_error = MB_MRE_NO_REG;
- esp_err_t error = ESP_FAIL;
- uint8_t mb_slave_addr = request->slave_addr;
- uint8_t mb_command = request->command;
- uint16_t mb_offset = request->reg_start;
- uint16_t mb_size = request->reg_size;
- // Set the buffer for callback function processing of received data
- mbm_opts->mbm_reg_buffer_ptr = (uint8_t*)data_ptr;
- mbm_opts->mbm_reg_buffer_size = mb_size;
- // Calls appropriate request function to send request and waits response
- switch(mb_command)
- {
- case MB_FUNC_READ_COILS:
- mb_error = eMBMasterReqReadCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size , (LONG)MB_RESPONSE_TICS );
- break;
- case MB_FUNC_WRITE_SINGLE_COIL:
- mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
- break;
- case MB_FUNC_WRITE_MULTIPLE_COILS:
- mb_error = eMBMasterReqWriteMultipleCoils((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (UCHAR*)data_ptr, (LONG)MB_RESPONSE_TICS);
- break;
- case MB_FUNC_READ_DISCRETE_INPUTS:
- mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
- break;
- case MB_FUNC_READ_HOLDING_REGISTER:
- mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG)MB_RESPONSE_TICS );
- break;
- case MB_FUNC_WRITE_REGISTER:
- mb_error = eMBMasterReqWriteHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
- *(USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
- break;
- case MB_FUNC_WRITE_MULTIPLE_REGISTERS:
- mb_error = eMBMasterReqWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr,
- (USHORT)mb_offset, (USHORT)mb_size,
- (USHORT*)data_ptr, (LONG)MB_RESPONSE_TICS );
- break;
- case MB_FUNC_READWRITE_MULTIPLE_REGISTERS:
- mb_error = eMBMasterReqReadWriteMultipleHoldingRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (USHORT*)data_ptr,
- (USHORT)mb_offset, (USHORT)mb_size,
- (LONG)MB_RESPONSE_TICS );
- break;
- case MB_FUNC_READ_INPUT_REGISTER:
- mb_error = eMBMasterReqReadInputRegister( (UCHAR)mb_slave_addr, (USHORT)mb_offset,
- (USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
- break;
- default:
- ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
- __FUNCTION__, mb_command);
- mb_error = MB_MRE_NO_REG;
- break;
- }
- // Propagate the Modbus errors to higher level
- switch(mb_error)
- {
- case MB_MRE_NO_ERR:
- error = ESP_OK;
- break;
- case MB_MRE_NO_REG:
- error = ESP_ERR_NOT_SUPPORTED; // Invalid register request
- break;
- case MB_MRE_TIMEDOUT:
- error = ESP_ERR_TIMEOUT; // Slave did not send response
- break;
- case MB_MRE_EXE_FUN:
- case MB_MRE_REV_DATA:
- error = ESP_ERR_INVALID_RESPONSE; // Invalid response from slave
- break;
- case MB_MRE_MASTER_BUSY:
- error = ESP_ERR_INVALID_STATE; // Master is busy (previous request is pending)
- break;
- default:
- ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
- __FUNCTION__, mb_error);
- error = ESP_FAIL;
- break;
- }
- return error;
- }
- static esp_err_t mbc_serial_master_get_cid_info(uint16_t cid, const mb_parameter_descriptor_t** param_buffer)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- ESP_ERR_INVALID_STATE,
- "Master interface uninitialized.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- MB_MASTER_CHECK((param_buffer != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect data buffer pointer.");
- MB_MASTER_CHECK((mbm_opts->mbm_param_descriptor_table != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect descriptor table or not set.");
- MB_MASTER_CHECK((cid < mbm_opts->mbm_param_descriptor_size),
- ESP_ERR_NOT_FOUND, "mb incorrect cid of characteristic.");
- // It is assumed that characteristics cid increased in the table
- const mb_parameter_descriptor_t* reg_info = &mbm_opts->mbm_param_descriptor_table[cid];
- MB_MASTER_CHECK((reg_info->param_key != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect characteristic key.");
- *param_buffer = reg_info;
- 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(MB_MASTER_TAG, "%s: Incorrect mode (%u)",
- __FUNCTION__, (uint8_t)mode);
- }
- break;
- default:
- ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)",
- __FUNCTION__, 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(char* name, mb_param_mode_t mode,
- mb_param_request_t* request,
- mb_parameter_descriptor_t* reg_data)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- ESP_ERR_INVALID_STATE,
- "Master interface uninitialized.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- esp_err_t error = ESP_ERR_NOT_FOUND;
- MB_MASTER_CHECK((name != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect parameter name.");
- MB_MASTER_CHECK((request != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect request parameter.");
- MB_MASTER_CHECK((mode <= MB_PARAM_WRITE),
- ESP_ERR_INVALID_ARG, "mb incorrect mode.");
- MB_MASTER_ASSERT(mbm_opts->mbm_param_descriptor_table != NULL);
- const mb_parameter_descriptor_t* reg_ptr = mbm_opts->mbm_param_descriptor_table;
- for (uint16_t counter = 0; counter < (mbm_opts->mbm_param_descriptor_size); counter++, reg_ptr++)
- {
- // Check the cid of the parameter is equal to record number in the table
- // Check the length of name and parameter key strings from table
- size_t param_key_len = strlen((const char*)reg_ptr->param_key);
- if (param_key_len != strlen((const char*)name)) {
- continue; // The length of strings is different then check next record in the table
- }
- // Compare the name of parameter with parameter key from table
- int comp_result = memcmp((const void*)name, (const void*)reg_ptr->param_key, (size_t)param_key_len);
- if (comp_result == 0) {
- // The correct line is found in the table and reg_ptr points to the found parameter description
- 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);
- MB_MASTER_CHECK((request->command > 0),
- ESP_ERR_INVALID_ARG,
- "mb incorrect command or parameter type.");
- if (reg_data != NULL) {
- *reg_data = *reg_ptr; // Set the cid registered parameter data
- }
- error = ESP_OK;
- break;
- }
- }
- return error;
- }
- // Get parameter data for corresponding characteristic
- static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
- uint8_t* value_ptr, uint8_t *type)
- {
- MB_MASTER_CHECK((name != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
- MB_MASTER_CHECK((type != NULL),
- ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
- esp_err_t error = ESP_ERR_INVALID_RESPONSE;
- mb_param_request_t request ;
- mb_parameter_descriptor_t reg_info = { 0 };
- error = mbc_serial_master_set_request(name, MB_PARAM_READ, &request, ®_info);
- if ((error == ESP_OK) && (cid == reg_info.cid)) {
- // Send request to read characteristic data
- error = mbc_serial_master_send_request(&request, value_ptr);
- if (error == ESP_OK) {
- ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
- __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
- } else {
- ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
- __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
- }
- // Set the type of parameter found in the table
- *type = reg_info.param_type;
- } else {
- ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
- __FUNCTION__, reg_info.cid);
- error = ESP_ERR_INVALID_ARG;
- }
- return error;
- }
- // Set parameter value for characteristic selected by name and cid
- static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
- uint8_t* value_ptr, uint8_t *type)
- {
- MB_MASTER_CHECK((name != NULL),
- ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
- MB_MASTER_CHECK((value_ptr != NULL),
- ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
- MB_MASTER_CHECK((type != NULL),
- ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
- esp_err_t error = ESP_ERR_INVALID_RESPONSE;
- mb_param_request_t request ;
- mb_parameter_descriptor_t reg_info = { 0 };
- error = mbc_serial_master_set_request(name, MB_PARAM_WRITE, &request, ®_info);
- if ((error == ESP_OK) && (cid == reg_info.cid)) {
- // Send request to write characteristic data
- error = mbc_serial_master_send_request(&request, value_ptr);
- if (error == ESP_OK) {
- ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
- __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
- } else {
- ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
- __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
- }
- // Set the type of parameter found in the table
- *type = reg_info.param_type;
- } else {
- ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
- __FUNCTION__, reg_info.cid);
- error = ESP_ERR_INVALID_ARG;
- }
- return error;
- }
- /* ----------------------- Callback functions for Modbus stack ---------------------------------*/
- // These are executed by modbus stack to read appropriate type of registers.
- /**
- * Modbus master input register callback function.
- *
- * @param pucRegBuffer input register buffer
- * @param usAddress input register address
- * @param usNRegs input register number
- *
- * @return result
- */
- // Callback function for reading of MB Input Registers
- eMBErrorCode eMBRegInputCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
- USHORT usNRegs)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- MB_EILLSTATE,
- "Master interface uninitialized.");
- MB_MASTER_CHECK((pucRegBuffer != NULL), MB_EINVAL,
- "Master stack processing error.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- // Number of input registers to be transferred
- USHORT usRegInputNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
- UCHAR* pucInputBuffer = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr; // Get instance address
- USHORT usRegs = usNRegs;
- eMBErrorCode eStatus = MB_ENOERR;
- // If input or configuration parameters are incorrect then return an error to stack layer
- if ((pucInputBuffer != NULL)
- && (usNRegs >= 1)
- && (usRegInputNregs == usRegs)) {
- while (usRegs > 0) {
- _XFER_2_RD(pucInputBuffer, pucRegBuffer);
- usRegs -= 1;
- }
- } else {
- eStatus = MB_ENOREG;
- }
- return eStatus;
- }
- /**
- * Modbus master holding register callback function.
- *
- * @param pucRegBuffer holding register buffer
- * @param usAddress holding register address
- * @param usNRegs holding register number
- * @param eMode read or write
- *
- * @return result
- */
- // Callback function for reading of MB Holding Registers
- // Executed by stack when request to read/write holding registers is received
- eMBErrorCode eMBRegHoldingCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
- USHORT usNRegs, eMBRegisterMode eMode)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- MB_EILLSTATE,
- "Master interface uninitialized.");
- MB_MASTER_CHECK((pucRegBuffer != NULL), MB_EINVAL,
- "Master stack processing error.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- USHORT usRegHoldingNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
- UCHAR* pucHoldingBuffer = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
- eMBErrorCode eStatus = MB_ENOERR;
- USHORT usRegs = usNRegs;
- // Check input and configuration parameters for correctness
- if ((pucHoldingBuffer != NULL)
- && (usRegHoldingNregs == usNRegs)
- && (usNRegs >= 1)) {
- switch (eMode) {
- case MB_REG_WRITE:
- while (usRegs > 0) {
- _XFER_2_RD(pucRegBuffer, pucHoldingBuffer);
- usRegs -= 1;
- };
- break;
- case MB_REG_READ:
- while (usRegs > 0) {
- _XFER_2_WR(pucHoldingBuffer, pucRegBuffer);
- pucHoldingBuffer += 2;
- usRegs -= 1;
- };
- break;
- }
- } else {
- eStatus = MB_ENOREG;
- }
- return eStatus;
- }
- /**
- * Modbus master coils callback function.
- *
- * @param pucRegBuffer coils buffer
- * @param usAddress coils address
- * @param usNCoils coils number
- * @param eMode read or write
- *
- * @return result
- */
- // Callback function for reading of MB Coils Registers
- eMBErrorCode eMBRegCoilsCBSerialMaster(UCHAR* pucRegBuffer, USHORT usAddress,
- USHORT usNCoils, eMBRegisterMode eMode)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- MB_EILLSTATE, "Master interface uninitialized.");
- MB_MASTER_CHECK((pucRegBuffer != NULL),
- MB_EINVAL, "Master stack processing error.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- USHORT usRegCoilNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
- UCHAR* pucRegCoilsBuf = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
- eMBErrorCode eStatus = MB_ENOERR;
- USHORT iRegIndex;
- USHORT usCoils = usNCoils;
- usAddress--; // The address is already + 1
- if ((usRegCoilNregs >= 1)
- && (pucRegCoilsBuf != NULL)
- && (usNCoils == usRegCoilNregs)) {
- iRegIndex = (usAddress % 8);
- switch (eMode) {
- case MB_REG_WRITE:
- while (usCoils > 0) {
- UCHAR ucResult = xMBUtilGetBits((UCHAR*)pucRegCoilsBuf, iRegIndex, 1);
- xMBUtilSetBits(pucRegBuffer, iRegIndex - (usAddress % 8) , 1, ucResult);
- iRegIndex++;
- usCoils--;
- }
- break;
- case MB_REG_READ:
- while (usCoils > 0) {
- UCHAR ucResult = xMBUtilGetBits(pucRegBuffer, iRegIndex - (usAddress % 8), 1);
- xMBUtilSetBits((uint8_t*)pucRegCoilsBuf, iRegIndex, 1, ucResult);
- iRegIndex++;
- usCoils--;
- }
- break;
- } // switch ( eMode )
- } else {
- // If the configuration or input parameters are incorrect then return error to stack
- eStatus = MB_ENOREG;
- }
- return eStatus;
- }
- /**
- * Modbus master discrete callback function.
- *
- * @param pucRegBuffer discrete buffer
- * @param usAddress discrete address
- * @param usNDiscrete discrete number
- *
- * @return result
- */
- // Callback function for reading of MB Discrete Input Registers
- eMBErrorCode eMBRegDiscreteCBSerialMaster(UCHAR * pucRegBuffer, USHORT usAddress,
- USHORT usNDiscrete)
- {
- MB_MASTER_CHECK((mbm_interface_ptr != NULL),
- MB_EILLSTATE, "Master interface uninitialized.");
- MB_MASTER_CHECK((pucRegBuffer != NULL),
- MB_EINVAL, "Master stack processing error.");
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- USHORT usRegDiscreteNregs = (USHORT)mbm_opts->mbm_reg_buffer_size;
- UCHAR* pucRegDiscreteBuf = (UCHAR*)mbm_opts->mbm_reg_buffer_ptr;
- eMBErrorCode eStatus = MB_ENOERR;
- USHORT iRegBitIndex, iNReg;
- UCHAR* pucDiscreteInputBuf;
- iNReg = usNDiscrete / 8 + 1;
- pucDiscreteInputBuf = (UCHAR*) pucRegDiscreteBuf;
- // It is already plus one in Modbus function method.
- usAddress--;
- if ((usRegDiscreteNregs >= 1)
- && (pucRegDiscreteBuf != NULL)
- && (usNDiscrete >= 1)) {
- iRegBitIndex = (USHORT)(usAddress) % 8; // Get bit index
- while (iNReg > 1)
- {
- xMBUtilSetBits(pucDiscreteInputBuf++, iRegBitIndex, 8, *pucRegBuffer++);
- iNReg--;
- }
- // last discrete
- usNDiscrete = usNDiscrete % 8;
- // xMBUtilSetBits has bug when ucNBits is zero
- if (usNDiscrete != 0)
- {
- xMBUtilSetBits(pucDiscreteInputBuf, iRegBitIndex, usNDiscrete, *pucRegBuffer++);
- }
- } else {
- eStatus = MB_ENOREG;
- }
- return eStatus;
- }
- // Initialization of resources for Modbus serial master controller
- esp_err_t mbc_serial_master_create(void** handler)
- {
- // Allocate space for master interface structure
- if (mbm_interface_ptr == NULL) {
- mbm_interface_ptr = malloc(sizeof(mb_master_interface_t));
- }
- MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
- // Initialize interface properties
- mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
- mbm_opts->port_type = MB_PORT_SERIAL_MASTER;
- vMBPortSetMode((UCHAR)MB_PORT_SERIAL_MASTER);
- mbm_opts->mbm_comm.mode = MB_MODE_RTU;
- mbm_opts->mbm_comm.port = MB_UART_PORT;
- mbm_opts->mbm_comm.baudrate = MB_DEVICE_SPEED;
- mbm_opts->mbm_comm.parity = MB_PARITY_NONE;
- // Initialization of active context of the modbus controller
- BaseType_t status = 0;
- // Parameter change notification queue
- mbm_opts->mbm_event_group = xEventGroupCreate();
- MB_MASTER_CHECK((mbm_opts->mbm_event_group != NULL),
- ESP_ERR_NO_MEM, "mb event group error.");
- // Create modbus controller task
- status = xTaskCreatePinnedToCore((void*)&modbus_master_task,
- "modbus_matask",
- MB_CONTROLLER_STACK_SIZE,
- NULL, // No parameters
- MB_CONTROLLER_PRIORITY,
- &mbm_opts->mbm_task_handle,
- MB_PORT_TASK_AFFINITY);
- if (status != pdPASS) {
- vTaskDelete(mbm_opts->mbm_task_handle);
- MB_MASTER_CHECK((status == pdPASS), ESP_ERR_NO_MEM,
- "mb controller task creation error, xTaskCreate() returns (0x%x).",
- (uint32_t)status);
- }
- MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
- // Initialize public interface methods of the interface
- mbm_interface_ptr->init = mbc_serial_master_create;
- mbm_interface_ptr->destroy = mbc_serial_master_destroy;
- mbm_interface_ptr->setup = mbc_serial_master_setup;
- mbm_interface_ptr->start = mbc_serial_master_start;
- mbm_interface_ptr->get_cid_info = mbc_serial_master_get_cid_info;
- mbm_interface_ptr->get_parameter = mbc_serial_master_get_parameter;
- mbm_interface_ptr->send_request = mbc_serial_master_send_request;
- mbm_interface_ptr->set_descriptor = mbc_serial_master_set_descriptor;
- mbm_interface_ptr->set_parameter = mbc_serial_master_set_parameter;
- mbm_interface_ptr->master_reg_cb_discrete = eMBRegDiscreteCBSerialMaster;
- mbm_interface_ptr->master_reg_cb_input = eMBRegInputCBSerialMaster;
- mbm_interface_ptr->master_reg_cb_holding = eMBRegHoldingCBSerialMaster;
- mbm_interface_ptr->master_reg_cb_coils = eMBRegCoilsCBSerialMaster;
- *handler = mbm_interface_ptr;
- return ESP_OK;
- }
|