Adicionar primeiro
This commit is contained in:
@@ -0,0 +1,785 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// mbc_tcp_master.c
|
||||
// TCP 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 <sys/queue.h> // for list
|
||||
#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 and defines
|
||||
#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_tcp_master.h" // for tcp master create function and types
|
||||
#include "port_tcp_master.h" // for tcp master port defines and types
|
||||
|
||||
#if MB_MASTER_TCP_ENABLED
|
||||
|
||||
/*-----------------------Master mode use these variables----------------------*/
|
||||
|
||||
#define MB_TCP_CONNECTION_TOUT (pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000))
|
||||
|
||||
// Actual wait time depends on the response timer
|
||||
#define MB_TCP_API_RESP_TICS (pdMS_TO_TICKS(MB_MAX_RESPONSE_TIME_MS))
|
||||
|
||||
static mb_master_interface_t* mbm_interface_ptr = NULL;
|
||||
static const char *TAG = "MB_CONTROLLER_MASTER";
|
||||
|
||||
// Searches the slave address in the address info list and returns address info if found, else NULL
|
||||
static mb_slave_addr_entry_t* mbc_tcp_master_find_slave_addr(uint8_t slave_addr)
|
||||
{
|
||||
mb_slave_addr_entry_t* it;
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
|
||||
if (LIST_EMPTY(&mbm_opts->mbm_slave_list)) {
|
||||
return NULL;
|
||||
}
|
||||
LIST_FOREACH(it, &mbm_opts->mbm_slave_list, entries) {
|
||||
if (slave_addr == it->slave_addr) {
|
||||
return it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static esp_err_t mbc_tcp_master_add_slave(uint16_t index, uint8_t slave_addr, const char* ip_addr)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
// Initialize interface properties
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
|
||||
mb_slave_addr_entry_t* new_slave_entry = (mb_slave_addr_entry_t*) heap_caps_malloc(sizeof(mb_slave_addr_entry_t),
|
||||
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
MB_MASTER_CHECK((new_slave_entry != NULL), ESP_ERR_NO_MEM, "mb can not allocate memory for slave entry.");
|
||||
new_slave_entry->index = index;
|
||||
new_slave_entry->ip_address = ip_addr;
|
||||
new_slave_entry->slave_addr = slave_addr;
|
||||
new_slave_entry->p_data = NULL;
|
||||
LIST_INSERT_HEAD(&mbm_opts->mbm_slave_list, new_slave_entry, entries);
|
||||
MB_MASTER_CHECK((mbm_opts->mbm_slave_list_count < (MB_TCP_PORT_MAX_CONN - 1)),
|
||||
ESP_ERR_INVALID_STATE, "mb max number of slaves < %d.", MB_TCP_PORT_MAX_CONN);
|
||||
mbm_opts->mbm_slave_list_count++;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void mbc_tcp_master_free_slave_list(void)
|
||||
{
|
||||
mb_slave_addr_entry_t* it;
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
|
||||
// Initialize interface properties
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
|
||||
while ((it = LIST_FIRST(&mbm_opts->mbm_slave_list))) {
|
||||
LIST_REMOVE(it, entries);
|
||||
mbm_opts->mbm_slave_list_count--;
|
||||
free(it);
|
||||
}
|
||||
}
|
||||
|
||||
// Modbus event processing task
|
||||
static void modbus_tcp_master_task(void *pvParameters)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_ASSERT(mbm_opts != NULL);
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup Modbus controller parameters
|
||||
static esp_err_t mbc_tcp_master_setup(void* comm_info)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_CHECK((mbm_opts != NULL), ESP_ERR_INVALID_ARG, "mb incorrect options pointer.");
|
||||
|
||||
const mb_communication_info_t* comm_info_ptr = (mb_communication_info_t*)comm_info;
|
||||
// Check communication options
|
||||
MB_MASTER_CHECK((comm_info_ptr->ip_mode == MB_MODE_TCP),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect mode = (%u).", (unsigned)comm_info_ptr->ip_mode);
|
||||
MB_MASTER_CHECK((comm_info_ptr->ip_addr != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb wrong slave ip address table.");
|
||||
MB_MASTER_CHECK(((comm_info_ptr->ip_addr_type == MB_IPV4) || (comm_info_ptr->ip_addr_type == MB_IPV6)),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect addr type = (%u).", (unsigned)comm_info_ptr->ip_addr_type);
|
||||
MB_MASTER_CHECK((comm_info_ptr->ip_netif_ptr != NULL),
|
||||
ESP_ERR_INVALID_ARG, "mb incorrect iface address.");
|
||||
// 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_tcp_master_start(void)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
eMBErrorCode status = MB_EIO;
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_CHECK((mbm_opts != NULL), ESP_ERR_INVALID_ARG, "mb incorrect options pointer.");
|
||||
const mb_communication_info_t* comm_info = (mb_communication_info_t*)&mbm_opts->mbm_comm;
|
||||
|
||||
// Initialize Modbus stack using mbcontroller parameters
|
||||
status = eMBMasterTCPInit((USHORT)comm_info->ip_port);
|
||||
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack initialization failure, eMBMasterInit() returns (0x%x).", status);
|
||||
|
||||
MB_MASTER_CHECK((mbm_opts->mbm_param_descriptor_size >= 1), ESP_ERR_INVALID_ARG, "mb table size is incorrect.");
|
||||
|
||||
bool result = false;
|
||||
const char** comm_ip_table = (const char**)comm_info->ip_addr;
|
||||
MB_MASTER_CHECK((comm_ip_table != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
|
||||
|
||||
eMBPortProto proto = (comm_info->ip_mode == MB_MODE_TCP) ? MB_PROTO_TCP : MB_PROTO_UDP;
|
||||
eMBPortIpVer ip_ver = (comm_info->ip_addr_type == MB_IPV4) ? MB_PORT_IPV4 : MB_PORT_IPV6;
|
||||
vMBTCPPortMasterSetNetOpt(comm_info->ip_netif_ptr, ip_ver, proto);
|
||||
|
||||
status = eMBMasterEnable();
|
||||
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack enable failure, eMBMasterEnable() returned (0x%x).", (int)status);
|
||||
|
||||
// Add slave IP address for each slave to initialize connection
|
||||
mb_slave_addr_entry_t *p_slave_info;
|
||||
|
||||
LIST_FOREACH(p_slave_info, &mbm_opts->mbm_slave_list, entries) {
|
||||
result = (BOOL)xMBTCPPortMasterAddSlaveIp(p_slave_info->index, p_slave_info->ip_address, p_slave_info->slave_addr);
|
||||
MB_MASTER_CHECK(result, ESP_ERR_INVALID_STATE, "mb stack add slave IP failed: %s.", *comm_ip_table);
|
||||
}
|
||||
|
||||
// Add end of list condition
|
||||
(void)xMBTCPPortMasterAddSlaveIp(0xFF, NULL, 0xFF);
|
||||
|
||||
// Wait for connection done event
|
||||
bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED, MB_TCP_CONNECTION_TOUT);
|
||||
MB_MASTER_CHECK((start), ESP_ERR_INVALID_STATE,
|
||||
"mb stack could not connect to slaves for %d seconds.",
|
||||
CONFIG_FMB_TCP_CONNECTION_TOUT_SEC);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t mbc_tcp_master_destroy(void)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_CHECK((mbm_opts != NULL), ESP_ERR_INVALID_ARG, "mb incorrect options pointer.");
|
||||
eMBErrorCode mb_error = MB_ENOERR;
|
||||
|
||||
// Stop polling by clearing correspondent bit in the event group
|
||||
xEventGroupClearBits(mbm_opts->mbm_event_group,
|
||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||
|
||||
// Disable and then destroy the Modbus port
|
||||
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);
|
||||
mbm_opts->mbm_task_handle = NULL;
|
||||
|
||||
mb_error = eMBMasterClose();
|
||||
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||
"mb stack close failure returned (0x%x).", (int)mb_error);
|
||||
|
||||
(void)vEventGroupDelete(mbm_opts->mbm_event_group);
|
||||
mbm_opts->mbm_event_group = NULL;
|
||||
mbc_tcp_master_free_slave_list();
|
||||
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_tcp_master_set_descriptor(const mb_parameter_descriptor_t* descriptor, const uint16_t num_elements)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
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;
|
||||
MB_MASTER_CHECK((mbm_opts != NULL), ESP_ERR_INVALID_ARG, "mb options.");
|
||||
|
||||
const char** comm_ip_table = (const char**)mbm_opts->mbm_comm.ip_addr;
|
||||
MB_MASTER_CHECK((comm_ip_table != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
|
||||
|
||||
const mb_parameter_descriptor_t *reg_ptr = descriptor;
|
||||
uint16_t slave_cnt = 0;
|
||||
mb_slave_addr_entry_t* p_slave = NULL;
|
||||
|
||||
// Go through all items in the table to check all Modbus registers
|
||||
for (int idx = 0; idx < (num_elements); idx++, reg_ptr++)
|
||||
{
|
||||
// Below is the code to check consistency of the table format and required fields.
|
||||
MB_MASTER_CHECK((reg_ptr->cid == idx), 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.");
|
||||
// Is the slave already in the list?
|
||||
p_slave = mbc_tcp_master_find_slave_addr(reg_ptr->mb_slave_addr);
|
||||
// Add it to slave list if not there.
|
||||
if (!p_slave) {
|
||||
// Is the IP address correctly defined for the slave?
|
||||
MB_MASTER_CHECK((comm_ip_table[slave_cnt]), ESP_ERR_INVALID_STATE, "mb missing IP address for cid #%u.", (unsigned)reg_ptr->cid);
|
||||
// Add slave to the list
|
||||
MB_MASTER_ASSERT(mbc_tcp_master_add_slave(idx, reg_ptr->mb_slave_addr, comm_ip_table[slave_cnt++]) == ESP_OK);
|
||||
}
|
||||
}
|
||||
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_tcp_master_send_request(mb_param_request_t* request, void* data_ptr)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
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_MASTER_BUSY;
|
||||
esp_err_t error = ESP_FAIL;
|
||||
|
||||
if (xMBMasterRunResTake(MB_TCP_API_RESP_TICS)) {
|
||||
|
||||
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;
|
||||
|
||||
vMBMasterRunResRelease();
|
||||
|
||||
// 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_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_WRITE_SINGLE_COIL:
|
||||
mb_error = eMBMasterReqWriteCoil((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_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_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_DISCRETE_INPUTS:
|
||||
mb_error = eMBMasterReqReadDiscreteInputs((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_HOLDING_REGISTER:
|
||||
mb_error = eMBMasterReqReadHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_WRITE_REGISTER:
|
||||
mb_error = eMBMasterReqWriteHoldingRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
*(USHORT *)data_ptr, (LONG)MB_TCP_API_RESP_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_TCP_API_RESP_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_TCP_API_RESP_TICS);
|
||||
break;
|
||||
case MB_FUNC_READ_INPUT_REGISTER:
|
||||
mb_error = eMBMasterReqReadInputRegister((UCHAR)mb_slave_addr, (USHORT)mb_offset,
|
||||
(USHORT)mb_size, (LONG)MB_TCP_API_RESP_TICS);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ", __FUNCTION__, (unsigned)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(TAG, "%s: Incorrect return code (0x%x) ", __FUNCTION__, (unsigned)mb_error);
|
||||
error = ESP_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static esp_err_t mbc_tcp_master_get_cid_info(uint16_t cid, const mb_parameter_descriptor_t** param_buffer)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
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_tcp_master_get_command(mb_param_type_t param_type, mb_param_mode_t mode)
|
||||
{
|
||||
uint8_t command = 0;
|
||||
switch(param_type)
|
||||
{ //
|
||||
case MB_PARAM_HOLDING:
|
||||
command = (mode == MB_PARAM_WRITE) ? MB_FUNC_WRITE_MULTIPLE_REGISTERS : MB_FUNC_READ_HOLDING_REGISTER;
|
||||
break;
|
||||
case MB_PARAM_INPUT:
|
||||
command = MB_FUNC_READ_INPUT_REGISTER;
|
||||
break;
|
||||
case MB_PARAM_COIL:
|
||||
command = (mode == MB_PARAM_WRITE) ? MB_FUNC_WRITE_MULTIPLE_COILS : MB_FUNC_READ_COILS;
|
||||
break;
|
||||
case MB_PARAM_DISCRETE:
|
||||
if (mode != MB_PARAM_WRITE) {
|
||||
command = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (unsigned)mode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, (unsigned)param_type);
|
||||
break;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
// Helper to search parameter by name in the parameter description table and fills Modbus request fields accordingly
|
||||
static esp_err_t mbc_tcp_master_set_request(char* name, mb_param_mode_t mode, mb_param_request_t* request,
|
||||
mb_parameter_descriptor_t* reg_data)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
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_tcp_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_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t* value, 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.");
|
||||
MB_MASTER_CHECK((value != NULL), ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
|
||||
esp_err_t error = ESP_ERR_INVALID_RESPONSE;
|
||||
mb_param_request_t request ;
|
||||
mb_parameter_descriptor_t reg_info = { 0 };
|
||||
uint8_t* pdata = NULL;
|
||||
|
||||
error = mbc_tcp_master_set_request(name, MB_PARAM_READ, &request, ®_info);
|
||||
if ((error == ESP_OK) && (cid == reg_info.cid)) {
|
||||
// alloc buffer to store parameter data
|
||||
pdata = calloc(1, (reg_info.mb_size << 1));
|
||||
if (!pdata) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
error = mbc_tcp_master_send_request(&request, pdata);
|
||||
if (error == ESP_OK) {
|
||||
// If data pointer is NULL then we don't need to set value (it is still in the cache of cid)
|
||||
if (value != NULL) {
|
||||
error = mbc_master_set_param_data((void*)value, (void*)pdata,
|
||||
reg_info.param_type, reg_info.param_size);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||
error = ESP_ERR_INVALID_STATE;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
}
|
||||
free(pdata);
|
||||
// Set the type of parameter found in the table
|
||||
*type = reg_info.param_type;
|
||||
} else {
|
||||
ESP_LOGE(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_tcp_master_set_parameter(uint16_t cid, char* name, uint8_t* value, uint8_t *type)
|
||||
{
|
||||
MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
|
||||
MB_MASTER_CHECK((value != 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 };
|
||||
uint8_t* pdata = NULL;
|
||||
|
||||
error = mbc_tcp_master_set_request(name, MB_PARAM_WRITE, &request, ®_info);
|
||||
if ((error == ESP_OK) && (cid == reg_info.cid)) {
|
||||
pdata = calloc(1, (reg_info.mb_size << 1)); // alloc parameter buffer
|
||||
if (!pdata) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
// Transfer value of characteristic into parameter buffer
|
||||
error = mbc_master_set_param_data((void*)pdata, (void*)value,
|
||||
reg_info.param_type, reg_info.param_size);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||
free(pdata);
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
// Send request to write characteristic data
|
||||
error = mbc_tcp_master_send_request(&request, pdata);
|
||||
if (error == ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
|
||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||
}
|
||||
free(pdata);
|
||||
// Set the type of parameter found in the table
|
||||
*type = reg_info.param_type;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
|
||||
__FUNCTION__, (unsigned)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 eMBRegInputCBTcpMaster(UCHAR* pucRegBuffer, USHORT usAddress, USHORT usNRegs)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_ASSERT(pucRegBuffer != NULL);
|
||||
USHORT usRegInputNregs = (USHORT)mbm_opts->mbm_reg_buffer_size; // Number of input registers to be transferred
|
||||
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 eMBRegHoldingCBTcpMaster(UCHAR *pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNRegs, eMBRegisterMode eMode)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
mb_master_options_t *mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_ASSERT(pucRegBuffer != NULL);
|
||||
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 eMBRegCoilsCBTcpMaster(UCHAR *pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNCoils, eMBRegisterMode eMode)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_ASSERT(NULL != pucRegBuffer);
|
||||
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(pucRegCoilsBuf, iRegIndex - (usAddress % 8), 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(pucRegCoilsBuf, iRegIndex - (usAddress % 8), 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 eMBRegDiscreteCBTcpMaster(UCHAR * pucRegBuffer, USHORT usAddress,
|
||||
USHORT usNDiscrete)
|
||||
{
|
||||
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||
MB_MASTER_ASSERT(pucRegBuffer != NULL);
|
||||
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 - (usAddress % 8), 8, *pucRegBuffer++);
|
||||
iNReg--;
|
||||
}
|
||||
// last discrete
|
||||
usNDiscrete = usNDiscrete % 8;
|
||||
// xMBUtilSetBits has bug when ucNBits is zero
|
||||
if (usNDiscrete != 0)
|
||||
{
|
||||
xMBUtilSetBits(pucDiscreteInputBuf, iRegBitIndex - (usAddress % 8), usNDiscrete, *pucRegBuffer++);
|
||||
}
|
||||
} else {
|
||||
eStatus = MB_ENOREG;
|
||||
}
|
||||
return eStatus;
|
||||
}
|
||||
|
||||
// Initialization of resources for Modbus TCP master controller
|
||||
esp_err_t mbc_tcp_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_TCP_MASTER;
|
||||
|
||||
vMBPortSetMode((UCHAR)MB_PORT_TCP_MASTER);
|
||||
|
||||
mbm_opts->mbm_comm.ip_mode = MB_MODE_TCP;
|
||||
mbm_opts->mbm_comm.ip_port = MB_TCP_DEFAULT_PORT;
|
||||
|
||||
// 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 = xTaskCreate((void*)&modbus_tcp_master_task,
|
||||
"modbus_tcp_master_task",
|
||||
MB_CONTROLLER_STACK_SIZE,
|
||||
NULL, // No parameters
|
||||
MB_CONTROLLER_PRIORITY,
|
||||
&mbm_opts->mbm_task_handle);
|
||||
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 (%u).", (unsigned)status);
|
||||
}
|
||||
MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
|
||||
|
||||
LIST_INIT(&mbm_opts->mbm_slave_list); // Init slave address list
|
||||
mbm_opts->mbm_slave_list_count = 0;
|
||||
|
||||
// Initialize public interface methods of the interface
|
||||
mbm_interface_ptr->init = mbc_tcp_master_create;
|
||||
mbm_interface_ptr->destroy = mbc_tcp_master_destroy;
|
||||
mbm_interface_ptr->setup = mbc_tcp_master_setup;
|
||||
mbm_interface_ptr->start = mbc_tcp_master_start;
|
||||
mbm_interface_ptr->get_cid_info = mbc_tcp_master_get_cid_info;
|
||||
mbm_interface_ptr->get_parameter = mbc_tcp_master_get_parameter;
|
||||
mbm_interface_ptr->send_request = mbc_tcp_master_send_request;
|
||||
mbm_interface_ptr->set_descriptor = mbc_tcp_master_set_descriptor;
|
||||
mbm_interface_ptr->set_parameter = mbc_tcp_master_set_parameter;
|
||||
|
||||
mbm_interface_ptr->master_reg_cb_discrete = eMBRegDiscreteCBTcpMaster;
|
||||
mbm_interface_ptr->master_reg_cb_input = eMBRegInputCBTcpMaster;
|
||||
mbm_interface_ptr->master_reg_cb_holding = eMBRegHoldingCBTcpMaster;
|
||||
mbm_interface_ptr->master_reg_cb_coils = eMBRegCoilsCBTcpMaster;
|
||||
|
||||
*handler = mbm_interface_ptr;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif //#if MB_MASTER_TCP_ENABLED
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
// mbc_tcp_master.h Modbus controller TCP master implementation header file
|
||||
|
||||
#ifndef _MODBUS_TCP_CONTROLLER_MASTER
|
||||
#define _MODBUS_TCP_CONTROLLER_MASTER
|
||||
|
||||
#include <stdint.h> // for standard int types definition
|
||||
#include <stddef.h> // for NULL and std defines
|
||||
#include "esp_modbus_common.h" // for common defines
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
#define MB_INST_MIN_SIZE (2) // The minimal size of Modbus registers area in bytes
|
||||
#define MB_INST_MAX_SIZE (CONFIG_MB_INST_MAX_SIZE) // The maximum size of Modbus area in bytes
|
||||
|
||||
#define MB_CONTROLLER_NOTIFY_QUEUE_SIZE (CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE) // Number of messages in parameter notification queue
|
||||
#define MB_CONTROLLER_NOTIFY_TIMEOUT (pdMS_TO_TICKS(CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT)) // notification timeout
|
||||
|
||||
/**
|
||||
* @brief Create Modbus Master controller and stack for TCP port
|
||||
*
|
||||
* @param[out] handler handler(pointer) to master data structure
|
||||
* @return
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_NO_MEM Parameter error
|
||||
*/
|
||||
esp_err_t mbc_tcp_master_create(void** handler);
|
||||
|
||||
#endif // _MODBUS_TCP_CONTROLLER_SLAVE
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2006 Christian Walter
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*/
|
||||
/*
|
||||
* FreeModbus Libary: ESP32 TCP Port
|
||||
* Copyright (C) 2006 Christian Walter <wolti@sil.at>
|
||||
* Parts of crt0.S Copyright (c) 1995, 1996, 1998 Cygnus Support
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* IF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* File: $Id: port.h,v 1.2 2006/09/04 14:39:20 wolti Exp $
|
||||
*/
|
||||
|
||||
#ifndef _PORT_TCP_SLAVE_H
|
||||
#define _PORT_TCP_SLAVE_H
|
||||
|
||||
/* ----------------------- Platform includes --------------------------------*/
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "lwip/sys.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "port.h"
|
||||
|
||||
/* ----------------------- Defines ------------------------------------------*/
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_BEGIN_EXTERN_C
|
||||
#endif
|
||||
|
||||
/* ----------------------- Type definitions ---------------------------------*/
|
||||
|
||||
typedef struct {
|
||||
int xIndex; /*!< Slave information index */
|
||||
int xSockId; /*!< Socket ID of slave */
|
||||
int xError; /*!< Socket error */
|
||||
int xRcvErr; /*!< Socket receive error */
|
||||
const char* pcIpAddr; /*!< TCP/UDP IP address */
|
||||
UCHAR ucSlaveAddr; /*!< Slave short address */
|
||||
UCHAR* pucRcvBuf; /*!< Receive buffer pointer */
|
||||
USHORT usRcvPos; /*!< Receive buffer position */
|
||||
int pcPort; /*!< TCP/UDP port number */
|
||||
eMBPortProto xMbProto; /*!< Protocol type */
|
||||
int64_t xSendTimeStamp; /*!< Send request time stamp */
|
||||
int64_t xRecvTimeStamp; /*!< Receive response time stamp */
|
||||
uint16_t usTidCnt; /*!< Transaction identifier (TID) for slave */
|
||||
} MbSlaveInfo_t;
|
||||
|
||||
typedef struct {
|
||||
TaskHandle_t xMbTcpTaskHandle; /*!< Master TCP/UDP handling task handle */
|
||||
QueueHandle_t xConnectQueue; /*!< Master connection queue */
|
||||
USHORT usPort; /*!< Master TCP/UDP port number */
|
||||
USHORT usMbSlaveInfoCount; /*!< Master count of connected slaves */
|
||||
USHORT ucCurSlaveIndex; /*!< Master current processing slave index */
|
||||
eMBPortIpVer eMbIpVer; /*!< Master IP version */
|
||||
eMBPortProto eMbProto; /*!< Master protocol type */
|
||||
void* pvNetIface; /*!< Master netif interface pointer */
|
||||
MbSlaveInfo_t** pxMbSlaveInfo; /*!< Master information structure for each connected slave */
|
||||
MbSlaveInfo_t* pxMbSlaveCurrInfo; /*!< Master current slave information */
|
||||
} MbPortConfig_t;
|
||||
|
||||
typedef struct {
|
||||
USHORT usIndex; /*!< index of the address info */
|
||||
const char* pcIPAddr; /*!< represents the IP address of the slave */
|
||||
UCHAR ucSlaveAddr; /*!< slave unit ID (UID) field for MBAP frame */
|
||||
} MbSlaveAddrInfo_t;
|
||||
|
||||
/* ----------------------- Function prototypes ------------------------------*/
|
||||
|
||||
// The functions below are used by Modbus controller interface to configure Modbus port.
|
||||
/**
|
||||
* Registers slave IP address
|
||||
*
|
||||
* @param usIndex index of element in the configuration
|
||||
* @param pcIpStr IP address to register
|
||||
* @param ucSlaveAddress slave element index
|
||||
*
|
||||
* @return TRUE if address registered successfully, else FALSE
|
||||
*/
|
||||
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress);
|
||||
|
||||
/**
|
||||
* Keeps FSM event handle and mask then wait for Master stack to start
|
||||
*
|
||||
* @param xEventHandle Master event handle
|
||||
* @param xEvent event mask to start Modbus stack FSM
|
||||
* @param usTimeout - timeout in ticks to wait for stack to start
|
||||
*
|
||||
* @return TRUE if stack started, else FALSE
|
||||
*/
|
||||
BOOL xMBTCPPortMasterWaitEvent(EventGroupHandle_t xEventHandle, EventBits_t xEvent, USHORT usTimeout);
|
||||
|
||||
/**
|
||||
* Set network options for Master port
|
||||
*
|
||||
* @param pvNetIf netif interface pointer
|
||||
* @param xIpVersion IP version option for the Master port
|
||||
* @param xProto Protocol version option for the Master port
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void vMBTCPPortMasterSetNetOpt(void* pvNetIf, eMBPortIpVer xIpVersion, eMBPortProto xProto);
|
||||
|
||||
#ifdef __cplusplus
|
||||
PR_END_EXTERN_C
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user