mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
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
This commit is contained in:
committed by
Michael (XIAO Xufeng)
parent
445b1a6717
commit
96b77a28b1
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user