Contains two different component folders per each implementation (serial_master and serial_slave) with concrete ports. Added common public api for master and slave and common interface for master and slave implementation. Add support of cmake system (added cmake files). Added sdkconfig.defaults files for slave and master modbus examples. Updated make file and KConfig for freemodbus component Update according to review and fix doxygen warnings Fix Doxyfile to pass documentation build Update headers and change interface file names as per review comments Merge branch feature/freemodbus_move_rs485_mode_control Update after review: The stack modbus folder updated to support master and slave ports together and moved into freemodbus/modbus Stack and port files updated to remove duplicated simbols Make file, KConfig and CMakeLists.txt updated to compile master and slave stacks, common interface and concrete implementations of ports Stack callback functions execute callbacks using interface pointer from concrete port implementation User can instantiate any of concrete port using common API (only one concrete port at a time) and it does not require to select port by KConfig Port pins and mode configuration moved into example files from port files to allow user select pins and port mode (customer request) Changes tested using pymodbus, ModbusPoll and communication between two boards Updated DoxyFile according to public include path Fix maximum instance size for slave (merge from master of customer issue) Fix critical section issue TW#28622 (change spin lock based critical section to semaphore) Move serial port files into component port folder for master and slave accordingly Fix example issue showed in the log when IO slave is not configured correctly Fix conflicts while merging from origin/master Fix errors handling in modbus controller interface + some final corrections according to review Update maximum allowed number of slaves in the network segment Fix bug with incorrect coils read mask Closes https://github.com/espressif/esp-idf/issues/858
271 lines
No EOL
11 KiB
C
271 lines
No EOL
11 KiB
C
/* 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.
|
|
*/
|
|
|
|
#include "esp_err.h" // for esp_err_t
|
|
#include "mbc_master.h" // for master interface define
|
|
#include "esp_modbus_master.h" // for public interface defines
|
|
#include "mbc_serial_master.h" // for create function of the port
|
|
#include "esp_modbus_callbacks.h" // for callback functions
|
|
|
|
// This file implements public API for Modbus master controller.
|
|
// These functions are wrappers for interface functions of the controller
|
|
static mb_master_interface_t* master_interface_ptr = NULL;
|
|
|
|
/**
|
|
* Initialization of Modbus controller resources
|
|
*/
|
|
esp_err_t mbc_master_init(mb_port_type_t port_type, void** handler)
|
|
{
|
|
void* port_handler = NULL;
|
|
esp_err_t error = ESP_ERR_NOT_SUPPORTED;
|
|
switch(port_type)
|
|
{
|
|
case MB_PORT_SERIAL_MASTER:
|
|
error = mbc_serial_master_create(port_type, &port_handler);
|
|
break;
|
|
case MB_PORT_TCP_MASTER:
|
|
// TCP MAster is not yet supported
|
|
//error = mbc_tcp_master_create(port_type, &port_handler);
|
|
return ESP_ERR_NOT_SUPPORTED;
|
|
default:
|
|
return ESP_ERR_NOT_SUPPORTED;
|
|
}
|
|
MB_MASTER_CHECK((port_handler != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface initialization failure, error=(0x%x), port type=(0x%x).",
|
|
(uint16_t)error, (uint16_t)port_type);
|
|
|
|
if ((port_handler != NULL) && (error == ESP_OK)) {
|
|
master_interface_ptr = (mb_master_interface_t*) port_handler;
|
|
*handler = port_handler;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Modbus controller destroy function
|
|
*/
|
|
esp_err_t mbc_master_destroy()
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->destroy != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->destroy();
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master destroy failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
esp_err_t mbc_master_get_cid_info(uint16_t cid, const mb_parameter_descriptor_t** param_info)
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->get_cid_info != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->get_cid_info(cid, param_info);
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master get cid info failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Get parameter data for corresponding characteristic
|
|
*/
|
|
esp_err_t mbc_master_get_parameter(uint16_t cid, char* name, uint8_t* value, uint8_t* type)
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->get_parameter != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->get_parameter(cid, name, value, type);
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master get parameter failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Send custom Modbus request defined as mb_param_request_t structure
|
|
*/
|
|
esp_err_t mbc_master_send_request(mb_param_request_t* request, void* data_ptr)
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->send_request != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->send_request(request, data_ptr);
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master get parameter failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Set Modbus parameter description table
|
|
*/
|
|
esp_err_t mbc_master_set_descriptor(const mb_parameter_descriptor_t* descriptor, const uint16_t num_elements)
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->set_descriptor != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->set_descriptor(descriptor, num_elements);
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master set descriptor failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Set parameter value for characteristic selected by name and cid
|
|
*/
|
|
esp_err_t mbc_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uint8_t* type)
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->set_parameter != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->set_parameter(cid, name, value, type);
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master set parameter failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Setup Modbus controller parameters
|
|
*/
|
|
esp_err_t mbc_master_setup(void* comm_info)
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->setup != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->setup(comm_info);
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master setup failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
/**
|
|
* Modbus controller stack start function
|
|
*/
|
|
esp_err_t mbc_master_start()
|
|
{
|
|
esp_err_t error = ESP_OK;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->start != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->start();
|
|
MB_MASTER_CHECK((error == ESP_OK),
|
|
ESP_ERR_INVALID_STATE,
|
|
"SERIAL master start failure error=(0x%x).",
|
|
(uint16_t)error);
|
|
return error;
|
|
}
|
|
|
|
eMBErrorCode eMBMasterRegDiscreteCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
|
USHORT usNDiscrete)
|
|
{
|
|
eMBErrorCode error = MB_ENOERR;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->master_reg_cb_discrete != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->master_reg_cb_discrete(pucRegBuffer, usAddress, usNDiscrete);
|
|
return error;
|
|
}
|
|
|
|
eMBErrorCode eMBMasterRegCoilsCB(UCHAR* pucRegBuffer, USHORT usAddress,
|
|
USHORT usNCoils, eMBRegisterMode eMode)
|
|
{
|
|
eMBErrorCode error = MB_ENOERR;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->master_reg_cb_coils != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->master_reg_cb_coils(pucRegBuffer, usAddress,
|
|
usNCoils, eMode);
|
|
return error;
|
|
}
|
|
|
|
eMBErrorCode eMBMasterRegHoldingCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
|
USHORT usNRegs, eMBRegisterMode eMode)
|
|
{
|
|
eMBErrorCode error = MB_ENOERR;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->master_reg_cb_holding != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->master_reg_cb_holding(pucRegBuffer, usAddress,
|
|
usNRegs, eMode);
|
|
return error;
|
|
}
|
|
|
|
eMBErrorCode eMBMasterRegInputCB(UCHAR * pucRegBuffer, USHORT usAddress,
|
|
USHORT usNRegs)
|
|
{
|
|
eMBErrorCode error = MB_ENOERR;
|
|
MB_MASTER_CHECK((master_interface_ptr != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
MB_MASTER_CHECK((master_interface_ptr->master_reg_cb_input != NULL),
|
|
ESP_ERR_INVALID_STATE,
|
|
"Master interface is not correctly initialized.");
|
|
error = master_interface_ptr->master_reg_cb_input(pucRegBuffer, usAddress, usNRegs);
|
|
return error;
|
|
} |