Merge branch 'bugfix/modbus_allow_address_gaps_in_master_data_dict_v44' into 'release/v4.4'

freemodbus: allow address gaps in master data dictionary (support of UID field in MBAP) (backport v4.4)

See merge request espressif/esp-idf!16896
This commit is contained in:
Jiang Jiang Jian 2022-02-17 08:38:57 +00:00
commit 5ff09f0a06
20 changed files with 682 additions and 471 deletions

View File

@ -18,6 +18,8 @@
#include "esp_modbus_master.h" // for public interface defines
#include "esp_modbus_callbacks.h" // for callback functions
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_MASTER";
// This file implements public API for Modbus master controller.
// These functions are wrappers for interface functions of the controller
static mb_master_interface_t* master_interface_ptr = NULL;

View File

@ -43,6 +43,7 @@ static uint8_t mb_slave_id[] = { MB_ID_BYTE0(MB_CONTROLLER_SLAVE_ID),
// Common interface pointer for slave port
static mb_slave_interface_t* slave_interface_ptr = NULL;
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_SLAVE";
// 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)
@ -259,11 +260,11 @@ static esp_err_t mbc_slave_send_param_info(mb_event_group_t par_type, uint16_t m
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",
ESP_LOGD(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.");
ESP_LOGD(TAG, "Parameter queue is overflowed.");
}
return error;
}
@ -276,7 +277,7 @@ static esp_err_t mbc_slave_send_param_access_notification(mb_event_group_t event
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);
ESP_LOGD(TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event);
err = ESP_OK;
}
return err;

View File

@ -22,6 +22,24 @@
extern "C" {
#endif
#if __has_include("esp_check.h")
#include "esp_check.h"
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) ESP_RETURN_ON_FALSE(a, err_code, tag, format __VA_OPT__(,) __VA_ARGS__)
#else
// if cannot include esp_check then use custom check macro
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) do { \
if (!(a)) { \
ESP_LOGE(tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \
return err_code; \
} \
} while(0)
#endif
#define MB_CONTROLLER_STACK_SIZE (CONFIG_FMB_CONTROLLER_STACK_SIZE) // Stack size for Modbus controller
#define MB_CONTROLLER_PRIORITY (CONFIG_FMB_PORT_TASK_PRIO - 1) // priority of MB controller task

View File

@ -25,6 +25,12 @@
extern "C" {
#endif
#define MB_MASTER_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
#define MB_MASTER_ASSERT(con) do { \
if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
} while (0)
/*!
* \brief Modbus descriptor table parameter type defines.
*/

View File

@ -28,6 +28,12 @@
extern "C" {
#endif
#define MB_SLAVE_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
#define MB_SLAVE_ASSERT(con) do { \
if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
} while (0)
/**
* @brief Parameter access event information type
*/

View File

@ -12,9 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _MB_CONTROLLER_MASTER_H
#define _MB_CONTROLLER_MASTER_H
#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
@ -28,18 +30,6 @@
/* ----------------------- Defines ------------------------------------------*/
#define MB_MASTER_TAG "MB_CONTROLLER_MASTER"
#define MB_MASTER_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(MB_MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
}
#define MB_MASTER_ASSERT(con) do { \
if (!(con)) { ESP_LOGE(MB_MASTER_TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
} while (0)
/**
* @brief Request mode for parameter to use in data dictionary
*/
@ -59,6 +49,19 @@ typedef struct {
uart_parity_t parity; /*!< Modbus UART parity settings */
} mb_master_comm_info_t;
#if MB_MASTER_TCP_ENABLED
/**
* @brief Modbus slave addr list item for the master
*/
typedef struct mb_slave_addr_entry_s{
uint16_t index; /*!< Index of the slave address */
const char* ip_address; /*!< IP address string of the slave */
uint8_t slave_addr; /*!< Short slave address */
void* p_data; /*!< pointer to data structure */
LIST_ENTRY(mb_slave_addr_entry_s) entries; /*!< The slave address entry */
} mb_slave_addr_entry_t;
#endif
/**
* @brief Modbus controller handler structure
*/
@ -71,6 +74,10 @@ typedef struct {
EventGroupHandle_t mbm_event_group; /*!< Modbus controller event group */
const mb_parameter_descriptor_t* mbm_param_descriptor_table; /*!< Modbus controller parameter description table */
size_t mbm_param_descriptor_size; /*!< Modbus controller parameter description table size*/
#if MB_MASTER_TCP_ENABLED
LIST_HEAD(mbm_slave_addr_info_, mb_slave_addr_entry_s) mbm_slave_list; /*!< Slave address information list */
uint16_t mbm_slave_list_count;
#endif
} mb_master_options_t;
typedef esp_err_t (*iface_get_cid_info)(uint16_t, const mb_parameter_descriptor_t**); /*!< Interface get_cid_info method */

View File

@ -31,18 +31,6 @@
#define MB_CONTROLLER_NOTIFY_QUEUE_SIZE (CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE) // Number of messages in parameter notification queue
#define MB_CONTROLLER_NOTIFY_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT)) // notification timeout
#define MB_SLAVE_TAG "MB_CONTROLLER_SLAVE"
#define MB_SLAVE_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(MB_SLAVE_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
}
#define MB_SLAVE_ASSERT(con) do { \
if (!(con)) { ESP_LOGE(MB_SLAVE_TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
} while (0)
/**
* @brief Device communication parameters for master
*/

View File

@ -40,6 +40,7 @@ extern BOOL xMBMasterPortSerialTxPoll(void);
static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
static const char *TAG = "MB_CONTROLLER_MASTER";
// Modbus event processing task
static void modbus_master_task(void *pvParameters)
@ -238,7 +239,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
(USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
__FUNCTION__, mb_command);
mb_error = MB_MRE_NO_REG;
break;
@ -269,7 +270,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ",
__FUNCTION__, mb_error);
error = ESP_FAIL;
break;
@ -324,12 +325,12 @@ static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_para
if (mode != MB_PARAM_WRITE) {
command = MB_FUNC_READ_DISCRETE_INPUTS;
} else {
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)",
ESP_LOGE(TAG, "%s: Incorrect mode (%u)",
__FUNCTION__, (uint8_t)mode);
}
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)",
ESP_LOGE(TAG, "%s: Incorrect param type (%u)",
__FUNCTION__, param_type);
break;
}
@ -401,16 +402,16 @@ static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
// Send request to read characteristic data
error = mbc_serial_master_send_request(&request, value_ptr);
if (error == ESP_OK) {
ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
} else {
ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
}
// Set the type of parameter found in the table
*type = reg_info.param_type;
} else {
ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
__FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG;
}
@ -436,16 +437,16 @@ static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
// Send request to write characteristic data
error = mbc_serial_master_send_request(&request, value_ptr);
if (error == ESP_OK) {
ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
} else {
ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
}
// Set the type of parameter found in the table
*type = reg_info.param_type;
} else {
ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
__FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG;
}

View File

@ -29,6 +29,7 @@
// Shared pointer to interface structure
static mb_slave_interface_t* mbs_interface_ptr = NULL;
static const char *TAG = "MB_CONTROLLER_SLAVE";
// Modbus task function
static void modbus_slave_task(void *pvParameters)

View File

@ -19,6 +19,7 @@
#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
@ -42,6 +43,59 @@
#define MB_TCP_CONNECTION_TOUT pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000)
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;
LIST_FOREACH(it, &mbm_opts->mbm_slave_list, entries) {
LIST_REMOVE(it, entries);
mbm_opts->mbm_slave_list_count--;
free(it);
}
}
// Modbus event processing task
static void modbus_tcp_master_task(void *pvParameters)
@ -113,21 +167,21 @@ static esp_err_t mbc_tcp_master_start(void)
vMBTCPPortMasterSetNetOpt(comm_info->ip_netif_ptr, ip_ver, proto);
vMBTCPPortMasterTaskStart();
// Add slave IP address for each slave to initialise connection
for (int idx = 0; *comm_ip_table != NULL; idx++, comm_ip_table++)
{
result = (BOOL)xMBTCPPortMasterAddSlaveIp(*comm_ip_table);
// 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);
}
// Init polling event handlers and wait before start polling
xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group, (EventBits_t)MB_EVENT_STACK_STARTED, 1);
// Add end of list condition
(void)xMBTCPPortMasterAddSlaveIp(0xFF, NULL, 0xFF);
status = eMBMasterEnable();
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);
// Send end of list condition to start connection phase
(void)xMBTCPPortMasterAddSlaveIp(NULL);
// Wait for connection done event
bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group,
@ -160,6 +214,7 @@ static esp_err_t mbc_tcp_master_destroy(void)
mbm_opts->mbm_task_handle = NULL;
(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;
@ -179,14 +234,25 @@ static esp_err_t mbc_tcp_master_set_descriptor(const mb_parameter_descriptor_t*
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 (uint16_t counter = 0; counter < (num_elements); counter++, reg_ptr++)
for (int idx = 0; idx < (num_elements); idx++, reg_ptr++)
{
MB_MASTER_CHECK((comm_ip_table[reg_ptr->mb_slave_addr - 1] != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
// Below is the code to check consistency of the table format and required fields.
MB_MASTER_CHECK((reg_ptr->cid == counter), ESP_ERR_INVALID_ARG, "mb descriptor cid field is incorrect.");
MB_MASTER_CHECK((reg_ptr->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 #%d.", 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;
@ -258,7 +324,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
(USHORT)mb_size, (LONG) MB_RESPONSE_TIMEOUT );
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
__FUNCTION__, mb_command);
mb_error = MB_MRE_NO_REG;
break;
@ -289,7 +355,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, mb_error);
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, mb_error);
error = ESP_FAIL;
break;
}
@ -333,11 +399,11 @@ static uint8_t mbc_tcp_master_get_command(mb_param_type_t param_type, mb_param_m
if (mode != MB_PARAM_WRITE) {
command = MB_FUNC_READ_DISCRETE_INPUTS;
} else {
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (uint8_t)mode);
ESP_LOGE(TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (uint8_t)mode);
}
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)", __FUNCTION__, param_type);
ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, param_type);
break;
}
return command;
@ -368,7 +434,7 @@ static esp_err_t mbc_tcp_master_set_param_data(void* dest, void* src, mb_descr_t
memcpy((void*)dest, (void*)src, (size_t)param_size);
break;
default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u).",
ESP_LOGE(TAG, "%s: Incorrect param type (%u).",
__FUNCTION__, (uint16_t)param_type);
err = ESP_ERR_NOT_SUPPORTED;
break;
@ -420,31 +486,43 @@ static esp_err_t mbc_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t*
{
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 param_buffer[PARAM_MAX_SIZE] = { 0 };
uint8_t* pdata = NULL;
error = mbc_tcp_master_set_request(name, MB_PARAM_READ, &request, &reg_info);
if ((error == ESP_OK) && (cid == reg_info.cid)) {
error = mbc_tcp_master_send_request(&request, &param_buffer[0]);
// 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_tcp_master_set_param_data((void*)value, (void*)&param_buffer[0],
error = mbc_tcp_master_set_param_data((void*)value, (void*)pdata,
reg_info.param_type, reg_info.param_size);
MB_MASTER_CHECK((error == ESP_OK), ESP_ERR_INVALID_STATE, "fail to set parameter data.");
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));
}
}
ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
} else {
ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
error = ESP_ERR_INVALID_RESPONSE;
}
free(pdata);
// Set the type of parameter found in the table
*type = reg_info.param_type;
} else {
ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
__FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG;
}
@ -461,27 +539,36 @@ static esp_err_t mbc_tcp_master_set_parameter(uint16_t cid, char* name, uint8_t*
esp_err_t error = ESP_ERR_INVALID_RESPONSE;
mb_param_request_t request ;
mb_parameter_descriptor_t reg_info = { 0 };
uint8_t param_buffer[PARAM_MAX_SIZE] = { 0 };
uint8_t* pdata = NULL;
error = mbc_tcp_master_set_request(name, MB_PARAM_WRITE, &request, &reg_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_tcp_master_set_param_data((void*)&param_buffer[0], (void*)value,
error = mbc_tcp_master_set_param_data((void*)pdata, (void*)value,
reg_info.param_type, reg_info.param_size);
MB_MASTER_CHECK((error == ESP_OK), ESP_ERR_INVALID_STATE, "failure to set parameter data.");
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, &param_buffer[0]);
error = mbc_tcp_master_send_request(&request, pdata);
if (error == ESP_OK) {
ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
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(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
__FUNCTION__, 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(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
__FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG;
}
@ -709,6 +796,9 @@ esp_err_t mbc_tcp_master_create(void** handler)
}
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;

View File

@ -59,7 +59,6 @@
#define MB_TCP_CONNECTION_TIMEOUT_MS ( 20 ) // Connection timeout in mS
#define MB_TCP_RECONNECT_TIMEOUT ( 5000000 ) // Connection timeout in uS
#define MB_TCP_MASTER_PORT_TAG "MB_TCP_MASTER_PORT"
#define MB_EVENT_REQ_DONE_MASK ( EV_MASTER_PROCESS_SUCCESS | \
EV_MASTER_ERROR_RESPOND_TIMEOUT | \
EV_MASTER_ERROR_RECEIVE_DATA | \
@ -77,6 +76,7 @@
void vMBPortEventClose( void );
/* ----------------------- Static variables ---------------------------------*/
static const char *TAG = "MB_TCP_MASTER_PORT";
static MbPortConfig_t xMbPortConfig;
static EventGroupHandle_t xMasterEventHandle = NULL;
static SemaphoreHandle_t xShutdownSemaphore = NULL;
@ -107,7 +107,7 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
xMbPortConfig.pxMbSlaveInfo = calloc(MB_TCP_PORT_MAX_CONN, sizeof(MbSlaveInfo_t*));
if (!xMbPortConfig.pxMbSlaveInfo) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP slave info alloc failure.");
ESP_LOGE(TAG, "TCP slave info alloc failure.");
return FALSE;
}
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xMbPortConfig.pxMbSlaveInfo[idx] = NULL, idx++);
@ -116,12 +116,13 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
xMbPortConfig.usPort = usTCPPort;
xMbPortConfig.usMbSlaveInfoCount = 0;
xMbPortConfig.ucCurSlaveIndex = 1;
xMbPortConfig.pxMbSlaveCurrInfo = NULL;
xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(CHAR*));
xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(MbSlaveAddrInfo_t));
if (xMbPortConfig.xConnectQueue == 0)
{
// Queue was not created and must not be used.
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP master queue creation failure.");
ESP_LOGE(TAG, "TCP master queue creation failure.");
return FALSE;
}
@ -135,10 +136,10 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
MB_PORT_TASK_AFFINITY);
if (xErr != pdTRUE)
{
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP master task creation failure.");
ESP_LOGE(TAG, "TCP master task creation failure.");
(void)vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
} else {
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "TCP master stack initialized.");
ESP_LOGI(TAG, "TCP master stack initialized.");
bOkay = TRUE;
}
@ -146,9 +147,30 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
return bOkay;
}
static MbSlaveInfo_t* vMBTCPPortMasterFindSlaveInfo(UCHAR ucSlaveAddr)
{
int xIndex;
BOOL xFound = false;
for (xIndex = 0; xIndex < xMbPortConfig.usMbSlaveInfoCount; xIndex++) {
if (xMbPortConfig.pxMbSlaveInfo[xIndex]->ucSlaveAddr == ucSlaveAddr) {
xMbPortConfig.pxMbSlaveCurrInfo = xMbPortConfig.pxMbSlaveInfo[xIndex];
xFound = TRUE;
xMbPortConfig.ucCurSlaveIndex = xIndex;
}
}
if (!xFound) {
xMbPortConfig.pxMbSlaveCurrInfo = NULL;
ESP_LOGE(TAG, "Slave info for short address %d not found.", ucSlaveAddr);
}
return xMbPortConfig.pxMbSlaveCurrInfo;
}
static MbSlaveInfo_t* vMBTCPPortMasterGetCurrInfo(void)
{
return xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.ucCurSlaveIndex - 1];
if (!xMbPortConfig.pxMbSlaveCurrInfo) {
ESP_LOGE(TAG, "Incorrect current slave info.");
}
return xMbPortConfig.pxMbSlaveCurrInfo;
}
// Start Modbus event state machine
@ -159,10 +181,10 @@ static void vMBTCPPortMasterStartPoll(void)
EventBits_t xFlags = xEventGroupSetBits(xMasterEventHandle,
(EventBits_t)xMasterEvent);
if (!(xFlags & xMasterEvent)) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start TCP stack.");
ESP_LOGE(TAG, "Fail to start TCP stack.");
}
} else {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start polling. Incorrect event handle...");
ESP_LOGE(TAG, "Fail to start polling. Incorrect event handle...");
}
}
@ -174,10 +196,10 @@ static void vMBTCPPortMasterStopPoll(void)
EventBits_t xFlags = xEventGroupClearBits(xMasterEventHandle,
(EventBits_t)xMasterEvent);
if (!(xFlags & xMasterEvent)) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling.");
ESP_LOGE(TAG, "Fail to stop polling.");
}
} else {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling. Incorrect event handle...");
ESP_LOGE(TAG, "Fail to stop polling. Incorrect event handle...");
}
}
@ -208,11 +230,11 @@ static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t* pxInfo)
return FALSE;
}
if (pxInfo->xSockId == -1) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Wrong socket info or disconnected socket: %d, skip.", pxInfo->xSockId);
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d, skip.", pxInfo->xSockId);
return FALSE;
}
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Shutdown failed sock %d, errno=%d", pxInfo->xSockId, errno);
ESP_LOGV(TAG, "Shutdown failed sock %d, errno=%d", pxInfo->xSockId, errno);
}
close(pxInfo->xSockId);
pxInfo->xSockId = -1;
@ -282,12 +304,12 @@ static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t* pxInfo, UCHAR* pucDstBuf, USHOR
continue;
} else if (errno == ENOTCONN) {
// Socket connection closed
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) connection closed.",
ESP_LOGE(TAG, "Socket(#%d)(%s) connection closed.",
pxInfo->xSockId, pxInfo->pcIpAddr);
return ERR_CONN;
} else {
// Other error occurred during receiving
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) receive error, length=%d, errno=%d",
ESP_LOGE(TAG, "Socket(#%d)(%s) receive error, length=%d, errno=%d",
pxInfo->xSockId, pxInfo->pcIpAddr, xLength, errno);
return -1;
}
@ -318,7 +340,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
pxInfo->xRcvErr = xRet;
return xRet;
} else if (xRet != MB_TCP_UID) {
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s), Fail to read modbus header. ret=%d",
ESP_LOGD(TAG, "Socket (#%d)(%s), Fail to read modbus header. ret=%d",
pxInfo->xSockId, pxInfo->pcIpAddr, xRet);
pxInfo->xRcvErr = ERR_VAL;
return ERR_VAL;
@ -332,7 +354,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
return xRet;
} else if (xRet != xLength) {
// Received incorrect or fragmented packet.
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) incorrect packet, length=%d, TID=0x%02x, errno=%d(%s)",
ESP_LOGD(TAG, "Socket(#%d)(%s) incorrect packet, length=%d, TID=0x%02x, errno=%d(%s)",
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
usTidRcv, errno, strerror(errno));
pxInfo->xRcvErr = ERR_VAL;
@ -342,13 +364,13 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
// Check transaction identifier field in the incoming packet.
if ((pxInfo->usTidCnt - 1) != usTidRcv) {
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s), incorrect TID(0x%02x)!=(0x%02x) received, discard data.",
ESP_LOGD(TAG, "Socket (#%d)(%s), incorrect TID(0x%02x)!=(0x%02x) received, discard data.",
pxInfo->xSockId, pxInfo->pcIpAddr, usTidRcv, (pxInfo->usTidCnt - 1));
pxInfo->xRcvErr = ERR_BUF;
return ERR_BUF;
}
pxInfo->usRcvPos += xRet + MB_TCP_UID;
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) get data, length=%d, TID=0x%02x, errno=%d(%s)",
ESP_LOGD(TAG, "Socket(#%d)(%s) get data, length=%d, TID=0x%02x, errno=%d(%s)",
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
usTidRcv, errno, strerror(errno));
pxInfo->xRcvErr = ERR_OK;
@ -365,7 +387,7 @@ static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
// Set non blocking attribute for socket
ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), fcntl() call error=%d",
ESP_LOGE(TAG, "Socket(#%d)(%s), fcntl() call error=%d",
pxInfo->xSockId, pxInfo->pcIpAddr, errno);
return ERR_WOULDBLOCK;
}
@ -398,12 +420,12 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
if (errno == EINPROGRESS) {
xErr = ERR_INPROGRESS;
} else {
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
ESP_LOGV(TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
xErr = ERR_CONN;
}
} else if (xErr == 0) {
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
ESP_LOGV(TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
return ERR_INPROGRESS;
} else {
@ -412,11 +434,11 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
// Check socket error
xErr = getsockopt(pxInfo->xSockId, SOL_SOCKET, SO_ERROR, (void*)&xOptErr, (socklen_t*)&ulOptLen);
if (xOptErr != 0) {
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), sock error occurred (%d).",
ESP_LOGD(TAG, "Socket(#%d)(%s), sock error occurred (%d).",
pxInfo->xSockId, pxInfo->pcIpAddr, xOptErr);
return ERR_CONN;
}
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), is alive.",
ESP_LOGV(TAG, "Socket(#%d)(%s), is alive.",
pxInfo->xSockId, pxInfo->pcIpAddr);
return ERR_OK;
}
@ -446,7 +468,7 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
int xRet = getaddrinfo(pcHostStr, NULL, &xHint, &pxAddrList);
if (xRet != 0) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect host name or IP: %s", pcHostStr);
ESP_LOGE(TAG, "Incorrect host name or IP: %s", pcHostStr);
return FALSE;
}
if (pxAddrList->ai_family == AF_INET) {
@ -464,20 +486,24 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
if (pxHostAddr) {
*pxHostAddr = xTargetAddr;
}
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Host[IP]: \"%s\"[%s]", pxAddrList->ai_canonname, pcStr);
ESP_LOGI(TAG, "Host[IP]: \"%s\"[%s]", pxAddrList->ai_canonname, pcStr);
freeaddrinfo(pxAddrList);
return TRUE;
}
BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr)
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress)
{
BOOL xRes = FALSE;
MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
MB_PORT_CHECK(xMbPortConfig.xConnectQueue != NULL, FALSE, "Wrong slave IP address to add.");
if (pcIpStr) {
if (pcIpStr && (usIndex != 0xFF)) {
xRes = xMBTCPPortMasterCheckHost(pcIpStr, NULL);
}
if (xRes || !pcIpStr) {
BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (const void*)&pcIpStr, 100);
xSlaveAddrInfo.pcIPAddr = pcIpStr;
xSlaveAddrInfo.usIndex = usIndex;
xSlaveAddrInfo.ucSlaveAddr = ucSlaveAddress;
BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, 100);
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "FAIL to add slave IP address: [%s].", pcIpStr);
}
return xRes;
@ -515,7 +541,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
int xRet = getaddrinfo(pxInfo->pcIpAddr, pcStr, &xHint, &pxAddrList);
free(pcStr);
if (xRet != 0) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Cannot resolve host: %s", pxInfo->pcIpAddr);
ESP_LOGE(TAG, "Cannot resolve host: %s", pxInfo->pcIpAddr);
return ERR_CONN;
}
@ -538,12 +564,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
if (pxInfo->xSockId <= 0) {
pxInfo->xSockId = socket(pxCurAddr->ai_family, pxCurAddr->ai_socktype, pxCurAddr->ai_protocol);
if (pxInfo->xSockId < 0) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Unable to create socket: #%d, errno %d", pxInfo->xSockId, errno);
ESP_LOGE(TAG, "Unable to create socket: #%d, errno %d", pxInfo->xSockId, errno);
xErr = ERR_IF;
continue;
}
} else {
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s) created.", pxInfo->xSockId, cStr);
ESP_LOGV(TAG, "Socket (#%d)(%s) created.", pxInfo->xSockId, cStr);
}
// Set non blocking attribute for socket
@ -554,7 +580,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
xErr = connect(pxInfo->xSockId, (struct sockaddr*)pxCurAddr->ai_addr, pxCurAddr->ai_addrlen);
if ((xErr < 0) && (errno == EINPROGRESS || errno == EALREADY)) {
// The unblocking connect is pending (check status later) or already connected
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) connection is pending, errno %d (%s).",
ESP_LOGV(TAG, "Socket(#%d)(%s) connection is pending, errno %d (%s).",
pxInfo->xSockId, cStr, errno, strerror(errno));
// Set keep alive flag in socket options
@ -567,12 +593,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
continue;
} else if (xErr != ERR_OK) {
// Other error occurred during connection
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
ESP_LOGV(TAG, MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
pxInfo->xIndex, pxInfo->xSockId, cStr, xErr, errno, strerror(errno));
xMBTCPPortMasterCloseConnection(pxInfo);
xErr = ERR_CONN;
} else {
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", successfully connected."),
ESP_LOGI(TAG, MB_SLAVE_FMT(", successfully connected."),
pxInfo->xIndex, pxInfo->xSockId, cStr);
continue;
}
@ -614,7 +640,7 @@ static int xMBTCPPortMasterCheckConnState(fd_set* pxFdSet)
xErr = xMBTCPPortMasterCheckAlive(pxInfo, 0);
if ((xErr < 0) && (((xTime - pxInfo->xRecvTimeStamp) > MB_TCP_RECONNECT_TIMEOUT) ||
((xTime - pxInfo->xSendTimeStamp) > MB_TCP_RECONNECT_TIMEOUT))) {
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%ju][%ju]."),
ESP_LOGI(TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%ju][%ju]."),
pxInfo->xIndex,
pxInfo->xSockId,
pxInfo->pcIpAddr,
@ -636,9 +662,9 @@ static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMas
static void vMBTCPPortMasterTask(void *pvParameters)
{
CHAR* pcAddrStr = NULL;
MbSlaveInfo_t* pxInfo;
MbSlaveInfo_t* pxCurrInfo;
fd_set xConnSet;
fd_set xReadSet;
int xMaxSd = 0;
@ -648,51 +674,53 @@ static void vMBTCPPortMasterTask(void *pvParameters)
// Register each slave in the connection info structure
while (1) {
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&pcAddrStr, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
xMBTCPPortMasterCheckShutdown();
MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
xMBTCPPortMasterCheckShutdown();
if (xStatus != pdTRUE) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to register slave IP.");
ESP_LOGE(TAG, "Fail to register slave IP.");
} else {
if (pcAddrStr == NULL && xMbPortConfig.usMbSlaveInfoCount) {
if (xSlaveAddrInfo.pcIPAddr == NULL && xMbPortConfig.usMbSlaveInfoCount && xSlaveAddrInfo.usIndex == 0xFF) {
break;
}
if (xMbPortConfig.usMbSlaveInfoCount > MB_TCP_PORT_MAX_CONN) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Exceeds maximum connections limit=%d.", MB_TCP_PORT_MAX_CONN);
ESP_LOGE(TAG, "Exceeds maximum connections limit=%d.", MB_TCP_PORT_MAX_CONN);
break;
}
pxInfo = calloc(1, sizeof(MbSlaveInfo_t));
if (!pxInfo) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Slave(#%d), info structure allocation fail.",
ESP_LOGE(TAG, "Slave(#%d), info structure allocation fail.",
xMbPortConfig.usMbSlaveInfoCount);
free(pxInfo);
break;
}
pxInfo->pucRcvBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
if (!pxInfo->pucRcvBuf) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Slave(#%d), receive buffer allocation fail.",
ESP_LOGE(TAG, "Slave(#%d), receive buffer allocation fail.",
xMbPortConfig.usMbSlaveInfoCount);
free(pxInfo->pucRcvBuf);
break;
}
pxInfo->usRcvPos = 0;
pxInfo->pcIpAddr = pcAddrStr;
pxInfo->pcIpAddr = xSlaveAddrInfo.pcIPAddr;
pxInfo->xSockId = -1;
pxInfo->xError = -1;
pxInfo->xRecvTimeStamp = xMBTCPGetTimeStamp();
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
pxInfo->xMbProto = MB_PROTO_TCP;
pxInfo->xIndex = xMbPortConfig.usMbSlaveInfoCount;
pxInfo->ucSlaveAddr = xSlaveAddrInfo.ucSlaveAddr;
pxInfo->xIndex = xSlaveAddrInfo.usIndex;
pxInfo->usTidCnt = (USHORT)(xMbPortConfig.usMbSlaveInfoCount << 8U);
// Register slave
xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.usMbSlaveInfoCount++] = pxInfo;
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Add slave IP: %s", pcAddrStr);
ESP_LOGI(TAG, "Add slave IP: %s", xSlaveAddrInfo.pcIPAddr);
}
}
// Main connection cycle
while (1)
{
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connecting to slaves...");
ESP_LOGI(TAG, "Connecting to slaves...");
xTime = xMBTCPGetTimeStamp();
usSlaveConnCnt = 0;
CHAR ucDot = '.';
@ -705,7 +733,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
// if slave descriptor is NULL then it is end of list or connection closed.
if (!pxInfo) {
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Index: %d is not initialized, skip.", ucCnt);
ESP_LOGV(TAG, "Index: %d is not initialized, skip.", ucCnt);
if (xMbPortConfig.usMbSlaveInfoCount) {
continue;
}
@ -720,12 +748,12 @@ static void vMBTCPPortMasterTask(void *pvParameters)
// In case of connection errors remove the socket from set
if (FD_ISSET(pxInfo->xSockId, &xConnSet)) {
FD_CLR(pxInfo->xSockId, &xConnSet);
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" connect failed, error = %d."),
ESP_LOGE(TAG, MB_SLAVE_FMT(" connect failed, error = %d."),
pxInfo->xIndex, pxInfo->xSockId,
(char*)pxInfo->pcIpAddr, xErr);
if (usSlaveConnCnt) {
usSlaveConnCnt--;
}
if (usSlaveConnCnt) {
usSlaveConnCnt--;
}
}
break;
case ERR_OK:
@ -734,7 +762,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
FD_SET(pxInfo->xSockId, &xConnSet);
usSlaveConnCnt++;
xMaxSd = (pxInfo->xSockId > xMaxSd) ? pxInfo->xSockId : xMaxSd;
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", connected %d slave(s), error = %d."),
ESP_LOGD(TAG, MB_SLAVE_FMT(", connected %d slave(s), error = %d."),
pxInfo->xIndex, pxInfo->xSockId,
pxInfo->pcIpAddr,
usSlaveConnCnt, xErr);
@ -744,7 +772,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
}
break;
default:
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", unexpected error = %d."),
ESP_LOGE(TAG, MB_SLAVE_FMT(", unexpected error = %d."),
pxInfo->xIndex,
pxInfo->xSockId,
pxInfo->pcIpAddr, xErr);
@ -756,7 +784,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xMBTCPPortMasterCheckShutdown();
}
}
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
ESP_LOGI(TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
vMBTCPPortMasterStartPoll(); // Send event to start stack
@ -767,26 +795,26 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
// Synchronize state machine with send packet event
if (xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_SENT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS))) {
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "FSM Synchronized with sent event.");
ESP_LOGD(TAG, "FSM Synchronized with sent event.");
}
// Get slave info for the current slave.
pxCurrInfo = vMBTCPPortMasterGetCurrInfo();
if (!pxCurrInfo) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect connection options for slave index: %d.",
ESP_LOGE(TAG, "Incorrect connection options for slave index: %d.",
xMbPortConfig.ucCurSlaveIndex);
vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown();
break; // incorrect slave descriptor, reconnect.
}
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Set select timeout, left time: %ju ms.",
ESP_LOGD(TAG, "Set select timeout, left time: %ju ms.",
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
// Wait respond from current slave during respond timeout
int xRes = vMBTCPPortMasterRxCheck(pxCurrInfo->xSockId, &xReadSet, xTime);
if (xRes == ERR_TIMEOUT) {
// No respond from current slave, process timeout.
// Need to drop response later if it is received after timeout.
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Select timeout, left time: %ju ms.",
ESP_LOGD(TAG, "Select timeout, left time: %ju ms.",
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
// Wait completion of last transaction
@ -795,7 +823,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
continue;
} else if (xRes < 0) {
// Select error (slave connection or r/w failure).
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", socket select error. Slave disconnected?"),
ESP_LOGD(TAG, MB_SLAVE_FMT(", socket select error. Slave disconnected?"),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
// Wait completion of last transaction
@ -809,30 +837,30 @@ static void vMBTCPPortMasterTask(void *pvParameters)
} else {
// Check to make sure that active slave data is ready
if (FD_ISSET(pxCurrInfo->xSockId, &xReadSet)) {
xErr = ERR_BUF;
for (int retry = 0; (xErr == ERR_BUF) && (retry < MB_TCP_READ_BUF_RETRY_CNT); retry++) {
xErr = vMBTCPPortMasterReadPacket(pxCurrInfo);
int xRet = ERR_BUF;
for (int retry = 0; (xRet == ERR_BUF) && (retry < MB_TCP_READ_BUF_RETRY_CNT); retry++) {
xRet = vMBTCPPortMasterReadPacket(pxCurrInfo);
// The error ERR_BUF means received response to previous request
// (due to timeout) with the same socket ID and incorrect TID,
// then ignore it and try to get next response buffer.
}
if (xErr > 0) {
if (xRet > 0) {
// Response received correctly, send an event to stack
xMBTCPPortMasterFsmSetError(EV_ERROR_INIT, EV_MASTER_FRAME_RECEIVED);
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame received."),
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame received."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
} else if ((xErr == ERR_TIMEOUT) || (xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo) == 0)) {
} else if ((xRet == ERR_TIMEOUT) || (xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo) == 0)) {
// Timeout occurred when receiving frame, process respond timeout
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame read timeout."),
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame read timeout."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
} else if (xErr == ERR_BUF) {
} else if (xRet == ERR_BUF) {
// After retries a response with incorrect TID received, process failure.
xMBTCPPortMasterFsmSetError(EV_ERROR_RECEIVE_DATA, EV_MASTER_ERROR_PROCESS);
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame error."),
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame error."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
} else {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", critical error=%d."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xErr);
ESP_LOGE(TAG, MB_SLAVE_FMT(", critical error=%d."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xRet);
// Stop polling process
vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown();
@ -841,14 +869,14 @@ static void vMBTCPPortMasterTask(void *pvParameters)
break;
}
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Slave #%d, data processing left time %ju [ms].", pxCurrInfo->xIndex, xTime);
ESP_LOGD(TAG, "Slave #%d, data processing left time %ju [ms].", pxCurrInfo->xIndex, xTime);
// Wait completion of Modbus frame processing before start of new transaction.
if (xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime))) {
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", data processing completed."),
ESP_LOGD(TAG, MB_SLAVE_FMT(", data processing completed."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
}
xTime = xMBTCPGetTimeStamp() - pxCurrInfo->xSendTimeStamp;
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", processing time[us] = %ju."),
ESP_LOGD(TAG, MB_SLAVE_FMT(", processing time[us] = %ju."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
}
}
@ -885,7 +913,7 @@ vMBMasterTCPPortClose(void)
xShutdownSemaphore = xSemaphoreCreateBinary();
// if no semaphore (alloc issues) or couldn't acquire it, just delete the task
if (xShutdownSemaphore == NULL || xSemaphoreTake(xShutdownSemaphore, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)) != pdTRUE) {
ESP_LOGW(MB_TCP_MASTER_PORT_TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
ESP_LOGW(TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
}
if (xShutdownSemaphore) {
@ -923,13 +951,13 @@ int xMBMasterTCPPortWritePoll(MbSlaveInfo_t* pxInfo, const UCHAR * pucMBTCPFrame
int xRes = (int)xMBTCPPortMasterCheckAlive(pxInfo, xTimeout);
if ((xRes < 0) && (xRes != ERR_INPROGRESS))
{
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
ESP_LOGE(TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
return xRes;
}
xRes = send(pxInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
if (xRes < 0) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
}
return xRes;
@ -939,36 +967,41 @@ BOOL
xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
{
BOOL bFrameSent = FALSE;
xMbPortConfig.ucCurSlaveIndex = ucMBMasterGetDestAddress();
MbSlaveInfo_t* pxInfo = vMBTCPPortMasterGetCurrInfo();
USHORT ucCurSlaveIndex = ucMBMasterGetDestAddress();
MbSlaveInfo_t* pxInfo = vMBTCPPortMasterFindSlaveInfo(ucCurSlaveIndex);
// If socket active then send data
if (pxInfo->xSockId > -1) {
// Apply TID field to the frame before send
pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
if (xRes < 0) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
bFrameSent = FALSE;
pxInfo->xError = xRes;
} else {
bFrameSent = TRUE;
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data successful: TID=0x%02x, %d (bytes), errno %d"),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usTidCnt, xRes, errno);
pxInfo->xError = 0;
pxInfo->usRcvPos = 0;
if (pxInfo->usTidCnt < (USHRT_MAX - 1)) {
pxInfo->usTidCnt++;
} else {
pxInfo->usTidCnt = (USHORT)(pxInfo->xIndex << 8U);
}
}
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
} else {
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send to died slave, error = %d"),
// If the slave is correct and active then send data
// otherwise treat slave as died and skip
if (pxInfo != NULL) {
if (pxInfo->xSockId < 0) {
ESP_LOGD(TAG, MB_SLAVE_FMT(", send to died slave, error = %d"),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->xError);
} else {
// Apply TID field to the frame before send
pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
if (xRes < 0) {
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
bFrameSent = FALSE;
pxInfo->xError = xRes;
} else {
bFrameSent = TRUE;
ESP_LOGD(TAG, MB_SLAVE_FMT(", send data successful: TID=0x%02x, %d (bytes), errno %d"),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usTidCnt, xRes, errno);
pxInfo->xError = 0;
pxInfo->usRcvPos = 0;
if (pxInfo->usTidCnt < (USHRT_MAX - 1)) {
pxInfo->usTidCnt++;
} else {
pxInfo->usTidCnt = (USHORT)(pxInfo->xIndex << 8U);
}
}
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
}
} else {
ESP_LOGD(TAG, "Send data to died slave, address = %d", ucCurSlaveIndex);
}
vMBMasterPortTimersRespondTimeoutEnable();
xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);

View File

@ -67,6 +67,7 @@ typedef struct {
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 */
@ -77,28 +78,37 @@ typedef struct {
} 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 */
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 CHAR* pcIpStr);
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress);
/**
* Keeps FSM event handle and mask then wait for Master stack to start

View File

@ -32,6 +32,7 @@
// Shared pointer to interface structure
static mb_slave_interface_t* mbs_interface_ptr = NULL;
static const char *TAG = "MB_CONTROLLER_SLAVE";
// Modbus task function
static void modbus_tcp_slave_task(void *pvParameters)

View File

@ -61,13 +61,13 @@
/* ----------------------- Defines -----------------------------------------*/
#define MB_TCP_DISCONNECT_TIMEOUT ( CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000000 ) // disconnect timeout in uS
#define MB_TCP_RESP_TIMEOUT_MS ( MB_MASTER_TIMEOUT_MS_RESPOND - 2 ) // slave response time limit
#define MB_TCP_SLAVE_PORT_TAG "MB_TCP_SLAVE_PORT"
#define MB_TCP_NET_LISTEN_BACKLOG ( SOMAXCONN )
/* ----------------------- Prototypes ---------------------------------------*/
void vMBPortEventClose( void );
/* ----------------------- Static variables ---------------------------------*/
static const char *TAG = "MB_TCP_SLAVE_PORT";
static int xListenSock = -1;
static SemaphoreHandle_t xShutdownSemaphore = NULL;
static MbSlavePortConfig_t xConfig = { 0 };
@ -130,14 +130,14 @@ xMBTCPPortInit( USHORT usTCPPort )
xConfig.pxMbClientInfo = calloc(MB_TCP_PORT_MAX_CONN + 1, sizeof(MbClientInfo_t*));
if (!xConfig.pxMbClientInfo) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "TCP client info allocation failure.");
ESP_LOGE(TAG, "TCP client info allocation failure.");
return FALSE;
}
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xConfig.pxMbClientInfo[idx] = NULL, idx++);
xConfig.xRespQueueHandle = xMBTCPPortRespQueueCreate();
if (!xConfig.xRespQueueHandle) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Response queue allocation failure.");
ESP_LOGE(TAG, "Response queue allocation failure.");
return FALSE;
}
@ -158,10 +158,10 @@ xMBTCPPortInit( USHORT usTCPPort )
vTaskSuspend(xConfig.xMbTcpTaskHandle);
if (xErr != pdTRUE)
{
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Server task creation failure.");
ESP_LOGE(TAG, "Server task creation failure.");
vTaskDelete(xConfig.xMbTcpTaskHandle);
} else {
ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Protocol stack initialized.");
ESP_LOGI(TAG, "Protocol stack initialized.");
bOkay = TRUE;
}
return bOkay;
@ -196,7 +196,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
// Accept new socket connection if not active
xSockId = accept(xListenSockId, (struct sockaddr *)&xSrcAddr, &xSize);
if (xSockId < 0) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Unable to accept connection: errno=%d", errno);
ESP_LOGE(TAG, "Unable to accept connection: errno=%d", errno);
close(xSockId);
} else {
// Get the sender's ip address as string
@ -208,7 +208,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
inet6_ntoa_r(((struct sockaddr_in6 *)&xSrcAddr)->sin6_addr, cAddrStr, sizeof(cAddrStr) - 1);
}
#endif
ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), accept client connection from address: %s", xSockId, cAddrStr);
ESP_LOGI(TAG, "Socket (#%d), accept client connection from address: %s", xSockId, cAddrStr);
pcStr = calloc(1, strlen(cAddrStr) + 1);
if (pcStr && pcIPAddr) {
memcpy(pcStr, cAddrStr, strlen(cAddrStr));
@ -224,11 +224,11 @@ static BOOL xMBTCPPortCloseConnection(MbClientInfo_t* pxInfo)
MB_PORT_CHECK(pxInfo, FALSE, "Client info is NULL.");
if (pxInfo->xSockId == -1) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Wrong socket info or disconnected socket: %d.", pxInfo->xSockId);
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d.", pxInfo->xSockId);
return FALSE;
}
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), shutdown failed: errno %d", pxInfo->xSockId, errno);
ESP_LOGE(TAG, "Socket (#%d), shutdown failed: errno %d", pxInfo->xSockId, errno);
}
close(pxInfo->xSockId);
pxInfo->xSockId = -1;
@ -265,7 +265,7 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
} else if (xRet == 0) {
// timeout occurred
if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) {
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d) Read timeout.", pxClientInfo->xSockId);
ESP_LOGD(TAG, "Socket (#%d) Read timeout.", pxClientInfo->xSockId);
xRet = ERR_TIMEOUT;
break;
}
@ -280,12 +280,12 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
pxClientInfo->usTCPFrameBytesLeft, MSG_DONTWAIT);
if (xLength < 0) {
// If an error occurred during receiving
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Receive failed: length=%d, errno=%d", xLength, errno);
ESP_LOGE(TAG, "Receive failed: length=%d, errno=%d", xLength, errno);
xRet = (err_t)xLength;
break;
} else if (xLength == 0) {
// Socket connection closed
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), connection closed.",
ESP_LOGD(TAG, "Socket (#%d)(%s), connection closed.",
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
xRet = ERR_CLSD;
break;
@ -303,14 +303,14 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
pxClientInfo->usTCPFrameBytesLeft = xLength + MB_TCP_UID - pxClientInfo->usTCPBufPos;
} else if (pxClientInfo->usTCPBufPos == (MB_TCP_UID + xLength)) {
#if MB_TCP_DEBUG
prvvMBTCPLogFrame(MB_TCP_SLAVE_PORT_TAG, (UCHAR*)&pxClientInfo->pucTCPBuf[0], pxClientInfo->usTCPBufPos);
prvvMBTCPLogFrame(TAG, (UCHAR*)&pxClientInfo->pucTCPBuf[0], pxClientInfo->usTCPBufPos);
#endif
// Copy TID field from incoming packet
pxClientInfo->usTidCnt = MB_TCP_GET_FIELD(pxClientInfo->pucTCPBuf, MB_TCP_TID);
xRet = pxClientInfo->usTCPBufPos;
break;
} else if ((pxClientInfo->usTCPBufPos + xLength) >= MB_TCP_BUF_SIZE) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Incorrect buffer received (%u) bytes.", xLength);
ESP_LOGE(TAG, "Incorrect buffer received (%u) bytes.", xLength);
// This should not happen. We can't deal with such a client and
// drop the connection for security reasons.
xRet = ERR_BUF;
@ -395,7 +395,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
{
if (listen(xListenSockFd, MB_TCP_NET_LISTEN_BACKLOG) != 0)
{
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Error occurred during listen: errno=%d", errno);
ESP_LOGE(TAG, "Error occurred during listen: errno=%d", errno);
close(xListenSockFd);
xListenSockFd = -1;
continue;
@ -403,7 +403,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
}
// Bind was successful
pcStr = (pxCurAddr->ai_canonname == NULL) ? (CHAR*)"\0" : pxCurAddr->ai_canonname;
ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), listener %s on port: %d, errno=%d",
ESP_LOGI(TAG, "Socket (#%d), listener %s on port: %d, errno=%d",
xListenSockFd, pcStr, xConfig.usPort, errno);
break;
}
@ -474,11 +474,11 @@ static void vMBTCPPortServerTask(void *pvParameters)
vTaskDelete(NULL);
}
// error occurred during wait for read
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() errno = %d.", errno);
ESP_LOGE(TAG, "select() errno = %d.", errno);
continue;
} else if (xErr == 0) {
// If timeout happened, something is wrong
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() timeout, errno = %d.", errno);
ESP_LOGE(TAG, "select() timeout, errno = %d.", errno);
}
// If something happened on the master socket, then its an incoming connection.
@ -494,21 +494,21 @@ static void vMBTCPPortServerTask(void *pvParameters)
// if request for new connection but no space left
if (pxClientInfo != NULL) {
if (xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] == NULL) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to accept connection %d, only %d connections supported.", i + 1, MB_TCP_PORT_MAX_CONN);
ESP_LOGE(TAG, "Fail to accept connection %d, only %d connections supported.", i + 1, MB_TCP_PORT_MAX_CONN);
}
xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] = pxClientInfo; // set last connection info
} else {
// allocate memory for new client info
pxClientInfo = calloc(1, sizeof(MbClientInfo_t));
if (!pxClientInfo) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client info allocation fail.");
ESP_LOGE(TAG, "Client info allocation fail.");
vMBTCPPortFreeClientInfo(pxClientInfo);
pxClientInfo = NULL;
} else {
// Accept new client connection
pxClientInfo->xSockId = xMBTCPPortAcceptConnection(xListenSock, &pcClientIp);
if (pxClientInfo->xSockId < 0) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to accept connection for client %d.", (xConfig.usClientCount - 1));
ESP_LOGE(TAG, "Fail to accept connection for client %d.", (xConfig.usClientCount - 1));
// Accept connection fail, then free client info and continue polling.
vMBTCPPortFreeClientInfo(pxClientInfo);
pxClientInfo = NULL;
@ -516,7 +516,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
}
pxClientInfo->pucTCPBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
if (!pxClientInfo->pucTCPBuf) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to allocate buffer for client %d.", (xConfig.usClientCount - 1));
ESP_LOGE(TAG, "Fail to allocate buffer for client %d.", (xConfig.usClientCount - 1));
vMBTCPPortFreeClientInfo(pxClientInfo);
pxClientInfo = NULL;
continue;
@ -550,17 +550,17 @@ static void vMBTCPPortServerTask(void *pvParameters)
switch(xErr)
{
case ERR_TIMEOUT:
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %d, close active connection.",
ESP_LOGE(TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %d, close active connection.",
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
(int)(xTimeStamp - pxClientInfo->xRecvTimeStamp));
break;
case ERR_CLSD:
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), connection closed by peer.",
ESP_LOGE(TAG, "Socket (#%d)(%s), connection closed by peer.",
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
break;
case ERR_BUF:
default:
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), read data error: %d",
ESP_LOGE(TAG, "Socket (#%d)(%s), read data error: %d",
pxClientInfo->xSockId, pxClientInfo->pcIpAddr, xErr);
break;
}
@ -585,26 +585,26 @@ static void vMBTCPPortServerTask(void *pvParameters)
// Complete frame received, inform state machine to process frame
xMBPortEventPost(EV_FRAME_RECEIVED);
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), get packet TID=0x%X, %d bytes.",
ESP_LOGD(TAG, "Socket (#%d)(%s), get packet TID=0x%X, %d bytes.",
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
pxClientInfo->usTidCnt, xErr);
// Wait while response is not processed by stack by timeout
UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
if (pucSentBuffer == NULL) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Response time exceeds configured %d [ms], ignore packet.",
ESP_LOGE(TAG, "Response time exceeds configured %d [ms], ignore packet.",
MB_TCP_RESP_TIMEOUT_MS);
} else {
USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID);
if (usSentTid != pxClientInfo->usTidCnt) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Sent TID(%x) != Recv TID(%x), ignore packet.",
ESP_LOGE(TAG, "Sent TID(%x) != Recv TID(%x), ignore packet.",
usSentTid, pxClientInfo->usTidCnt);
}
}
// Get time stamp of last data update
pxClientInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Client %d, Socket(#%d), processing time = %d (us).",
ESP_LOGD(TAG, "Client %d, Socket(#%d), processing time = %d (us).",
pxClientInfo->xIndex, pxClientInfo->xSockId,
(int)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp));
}
@ -613,7 +613,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
// client is not ready to be read
int64_t xTime = xMBTCPGetTimeStamp() - pxClientInfo->xRecvTimeStamp;
if (xTime > MB_TCP_DISCONNECT_TIMEOUT) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client %d, Socket(#%d) do not answer for %d (us). Drop connection...",
ESP_LOGE(TAG, "Client %d, Socket(#%d) do not answer for %d (us). Drop connection...",
pxClientInfo->xIndex, pxClientInfo->xSockId, (int)(xTime));
xMBTCPPortCloseConnection(pxClientInfo);
@ -622,7 +622,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
xConfig.pxMbClientInfo[i] = NULL;
}
} else {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client %d is disconnected.", i);
ESP_LOGE(TAG, "Client %d is disconnected.", i);
}
}
} // if ((pxClientInfo != NULL)
@ -644,7 +644,7 @@ vMBTCPPortClose( )
vTaskResume(xConfig.xMbTcpTaskHandle);
if (xShutdownSemaphore == NULL || // if no semaphore (alloc issues) or couldn't acquire it, just delete the task
xSemaphoreTake(xShutdownSemaphore, 2*pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)) != pdTRUE) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Task couldn't exit gracefully within timeout -> abruptly deleting the task");
ESP_LOGE(TAG, "Task couldn't exit gracefully within timeout -> abruptly deleting the task");
vTaskDelete(xConfig.xMbTcpTaskHandle);
}
if (xShutdownSemaphore) {
@ -706,7 +706,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
// Check if socket writable
xErr = select(xConfig.pxCurClientInfo->xSockId + 1, NULL, &xWriteSet, &xErrorSet, &xTimeVal);
if ((xErr == -1) || FD_ISSET(xConfig.pxCurClientInfo->xSockId, &xErrorSet)) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket(#%d) , send select() error = %d.",
ESP_LOGE(TAG, "Socket(#%d) , send select() error = %d.",
xConfig.pxCurClientInfo->xSockId, errno);
return FALSE;
}
@ -718,7 +718,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
// Write message into socket and disable Nagle's algorithm
xErr = send(xConfig.pxCurClientInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
if (xErr < 0) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket(#%d), fail to send data, errno = %d",
ESP_LOGE(TAG, "Socket(#%d), fail to send data, errno = %d",
xConfig.pxCurClientInfo->xSockId, errno);
xConfig.pxCurClientInfo->xError = xErr;
} else {
@ -726,7 +726,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
}
} else {
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Port is not active. Release lock.");
ESP_LOGD(TAG, "Port is not active. Release lock.");
vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
}
return bFrameSent;

View File

@ -38,14 +38,6 @@
#define POLL_TIMEOUT_MS (1)
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
#define MASTER_TAG "MASTER_TEST"
#define MASTER_CHECK(a, ret_val, str, ...) \
if (!(a)) { \
ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
return (ret_val); \
}
// The macro to get offset for parameter in the appropriate structure
#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))
@ -57,6 +49,8 @@
// Options can be used as bit masks or parameter limits
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
static const char *TAG = "MASTER_TEST";
// Enumeration of modbus device addresses accessed by master device
enum {
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
@ -135,7 +129,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
break;
}
} else {
ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
@ -149,7 +143,7 @@ static void master_operation_func(void *arg)
bool alarm_state = false;
const mb_parameter_descriptor_t* param_descriptor = NULL;
ESP_LOGI(MASTER_TAG, "Start modbus test...");
ESP_LOGI(TAG, "Start modbus test...");
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
// Read all found characteristics from slave(s)
@ -169,7 +163,7 @@ static void master_operation_func(void *arg)
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)temp_data_ptr, &type);
if (err == ESP_OK) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@ -181,13 +175,13 @@ static void master_operation_func(void *arg)
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)temp_data_ptr, &type);
if (err == ESP_OK) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
*(uint32_t*)temp_data_ptr);
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@ -195,7 +189,7 @@ static void master_operation_func(void *arg)
}
}
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@ -208,7 +202,7 @@ static void master_operation_func(void *arg)
*(float*)temp_data_ptr = value;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@ -222,7 +216,7 @@ static void master_operation_func(void *arg)
} else {
uint16_t state = *(uint16_t*)temp_data_ptr;
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@ -234,7 +228,7 @@ static void master_operation_func(void *arg)
}
}
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@ -248,13 +242,13 @@ static void master_operation_func(void *arg)
}
if (alarm_state) {
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
param_descriptor->cid);
} else {
ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
MASTER_MAX_RETRY);
}
ESP_LOGI(MASTER_TAG, "Destroy master...");
ESP_LOGI(TAG, "Destroy master...");
ESP_ERROR_CHECK(mbc_master_destroy());
}
@ -275,13 +269,13 @@ static esp_err_t master_init(void)
void* master_handler = NULL;
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
MASTER_CHECK((master_handler != NULL), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail.");
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller initialization fail, returns(0x%x).",
(uint32_t)err);
err = mbc_master_setup((void*)&comm);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller setup fail, returns(0x%x).",
(uint32_t)err);
@ -290,23 +284,23 @@ static esp_err_t master_init(void)
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
err = mbc_master_start();
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller start fail, returns(0x%x).",
(uint32_t)err);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (uint32_t)err);
// Set driver mode to Half Duplex
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err);
vTaskDelay(5);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
"mb controller set descriptor fail, returns(0x%x).",
(uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
ESP_LOGI(TAG, "Modbus master stack initialized...");
return err;
}

View File

@ -40,7 +40,7 @@
| MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
static const char *SLAVE_TAG = "SLAVE_TEST";
static const char *TAG = "SLAVE_TEST";
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
@ -92,7 +92,7 @@ void app_main(void)
mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
// Set UART log level
esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
esp_log_level_set(TAG, ESP_LOG_INFO);
void* mbc_slave_handler = NULL;
ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller
@ -166,8 +166,8 @@ void app_main(void)
// Set UART driver mode to Half Duplex
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
ESP_LOGI(SLAVE_TAG, "Start modbus test...");
ESP_LOGI(TAG, "Modbus slave stack initialized.");
ESP_LOGI(TAG, "Start modbus test...");
// The cycle below will be terminated when parameter holdingRegParams.dataChan0
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
@ -180,7 +180,7 @@ void app_main(void)
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
// Get parameter information from parameter queue
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@ -198,7 +198,7 @@ void app_main(void)
}
} else if (event & MB_EVENT_INPUT_REG_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@ -206,7 +206,7 @@ void app_main(void)
(uint32_t)reg_info.size);
} else if (event & MB_EVENT_DISCRETE_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@ -214,7 +214,7 @@ void app_main(void)
(uint32_t)reg_info.size);
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@ -225,7 +225,7 @@ void app_main(void)
}
}
// Destroy of Modbus controller on alarm
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
ESP_LOGI(TAG,"Modbus controller destroyed.");
vTaskDelay(100);
ESP_ERROR_CHECK(mbc_slave_destroy());
}

View File

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Apache-2.0
import logging
import os
import re
@ -69,7 +72,7 @@ class DutTestThread(Thread):
super(DutTestThread, self).__init__()
def __enter__(self):
logger.debug('Restart %s.' % self.tname)
logger.debug('Restart %s.', self.tname)
# Reset DUT first
self.dut.reset()
# Capture output from the DUT
@ -80,7 +83,7 @@ class DutTestThread(Thread):
""" The exit method of context manager
"""
if exc_type is not None or exc_value is not None:
logger.info('Thread %s rised an exception type: %s, value: %s' % (self.tname, str(exc_type), str(exc_value)))
logger.info('Thread %s rised an exception type: %s, value: %s', self.tname, str(exc_type), str(exc_value))
def run(self):
""" The function implements thread functionality
@ -95,7 +98,7 @@ class DutTestThread(Thread):
# Check DUT exceptions
dut_exceptions = self.dut.get_exceptions()
if 'Guru Meditation Error:' in dut_exceptions:
raise Exception('%s generated an exception: %s\n' % (str(self.dut), dut_exceptions))
raise RuntimeError('%s generated an exception(s): %s\n' % (str(self.dut), dut_exceptions))
# Mark thread has run to completion without any exceptions
self.data = self.dut.stop_capture_raw_data(capture_id=self.dut.name)
@ -106,15 +109,17 @@ class DutTestThread(Thread):
message = r'.*Waiting IP([0-9]{1,2}) from stdin.*'
# Read all data from previous restart to get prompt correctly
self.dut.read()
result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
if int(result[0]) != index:
raise Exception('Incorrect index of IP=%d for %s\n' % (int(result[0]), str(self.dut)))
message = 'IP%s=%s' % (result[0], self.ip_addr)
self.dut.write(message, '\r\n', False)
logger.debug('Sent message for %s: %s' % (self.tname, message))
raise RuntimeError('Incorrect index of IP=%s for %s\n' % (result[0], str(self.dut)))
# Use the same slave IP address for all characteristics during the test
self.dut.write('IP0=' + self.ip_addr, '\n', False)
self.dut.write('IP1=' + self.ip_addr, '\n', False)
self.dut.write('IP2=' + self.ip_addr, '\n', False)
logger.debug('Set IP address=%s for %s', self.ip_addr, self.tname)
message = r'.*IP\([0-9]+\) = \[([0-9a-zA-Z\.\:]+)\] set from stdin.*'
result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
logger.debug('Thread %s initialized with slave IP (%s).' % (self.tname, result[0]))
result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
logger.debug('Thread %s initialized with slave IP=%s.', self.tname, self.ip_addr)
def test_start(self, timeout_value):
""" The method to initialize and handle test stages
@ -122,37 +127,37 @@ class DutTestThread(Thread):
def handle_get_ip4(data):
""" Handle get_ip v4
"""
logger.debug('%s[STACK_IPV4]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_IPV4]: %s', self.tname, str(data))
self.test_stage = STACK_IPV4
def handle_get_ip6(data):
""" Handle get_ip v6
"""
logger.debug('%s[STACK_IPV6]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_IPV6]: %s', self.tname, str(data))
self.test_stage = STACK_IPV6
def handle_init(data):
""" Handle init
"""
logger.debug('%s[STACK_INIT]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_INIT]: %s', self.tname, str(data))
self.test_stage = STACK_INIT
def handle_connect(data):
""" Handle connect
"""
logger.debug('%s[STACK_CONNECT]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_CONNECT]: %s', self.tname, str(data))
self.test_stage = STACK_CONNECT
def handle_test_start(data):
""" Handle connect
"""
logger.debug('%s[STACK_START]: %s' % (self.tname, str(data)))
logger.debug('%s[STACK_START]: %s', self.tname, str(data))
self.test_stage = STACK_START
def handle_par_ok(data):
""" Handle parameter ok
"""
logger.debug('%s[READ_PAR_OK]: %s' % (self.tname, str(data)))
logger.debug('%s[READ_PAR_OK]: %s', self.tname, str(data))
if self.test_stage >= STACK_START:
self.param_ok_count += 1
self.test_stage = STACK_PAR_OK
@ -160,14 +165,14 @@ class DutTestThread(Thread):
def handle_par_fail(data):
""" Handle parameter fail
"""
logger.debug('%s[READ_PAR_FAIL]: %s' % (self.tname, str(data)))
logger.debug('%s[READ_PAR_FAIL]: %s', self.tname, str(data))
self.param_fail_count += 1
self.test_stage = STACK_PAR_FAIL
def handle_destroy(data):
""" Handle destroy
"""
logger.debug('%s[DESTROY]: %s' % (self.tname, str(data)))
logger.debug('%s[DESTROY]: %s', self.tname, str(data))
self.test_stage = STACK_DESTROY
self.test_finish = True
@ -183,7 +188,7 @@ class DutTestThread(Thread):
(re.compile(self.expected[STACK_DESTROY]), handle_destroy),
timeout=timeout_value)
except DUT.ExpectTimeout:
logger.debug('%s, expect timeout on stage #%d (%s seconds)' % (self.tname, self.test_stage, timeout_value))
logger.debug('%s, expect timeout on stage #%d (%s seconds)', self.tname, self.test_stage, timeout_value)
self.test_finish = True
@ -193,14 +198,14 @@ def test_check_mode(dut=None, mode_str=None, value=None):
global logger
try:
opt = dut.app.get_sdkconfig()[mode_str]
logger.debug('%s {%s} = %s.\n' % (str(dut), mode_str, opt))
logger.debug('%s {%s} = %s.\n', str(dut), mode_str, opt)
return value == opt
except Exception:
logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.' % (str(dut), mode_str))
logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.', str(dut), mode_str)
return False
@ttfw_idf.idf_example_test(env_tag='Example_Modbus_TCP')
@ttfw_idf.idf_example_test(env_tag='Example_Modbus_TCP', target=['esp32'])
def test_modbus_communication(env, comm_mode):
global logger
@ -235,7 +240,7 @@ def test_modbus_communication(env, comm_mode):
master_name = TEST_MASTER_TCP
else:
logger.error('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
raise Exception('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
raise RuntimeError('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
address = None
if test_check_mode(dut_master, 'CONFIG_MB_SLAVE_IP_FROM_STDIN', 'y'):
logger.info('ENV_TEST_INFO: Set slave IP address through STDIN.\n')
@ -249,9 +254,9 @@ def test_modbus_communication(env, comm_mode):
if address is not None:
print('Found IP slave address: %s' % address[0])
else:
raise Exception('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
raise RuntimeError('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
else:
raise Exception('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
raise RuntimeError('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
# Create thread for each dut
with DutTestThread(dut=dut_master, name=master_name, ip_addr=address[0], expect=pattern_dict_master) as dut_master_thread:
@ -265,32 +270,32 @@ def test_modbus_communication(env, comm_mode):
dut_slave_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
dut_master_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
if dut_slave_thread.isAlive():
logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
raise Exception('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
if dut_slave_thread.is_alive():
logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
raise RuntimeError('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
if dut_master_thread.isAlive():
logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
raise Exception('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
if dut_master_thread.is_alive():
logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
raise RuntimeError('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n' %
(dut_master_thread.tname, dut_master_thread.param_fail_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count))
logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n' %
(dut_master_thread.tname, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_ok_count))
logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n',
dut_master_thread.tname, dut_master_thread.param_fail_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count)
logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n',
dut_master_thread.tname, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_ok_count)
if ((dut_master_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
(dut_slave_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
(dut_slave_thread.param_ok_count == 0) or
(dut_master_thread.param_ok_count == 0)):
raise Exception('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
(dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
raise RuntimeError('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
(dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
logger.info('TEST_SUCCESS: The Modbus parameter test is completed successfully.\n')
finally:

View File

@ -1,20 +1,14 @@
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "string.h"
// FreeModbus Master Example ESP32
#include <string.h>
#include <sys/queue.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
@ -45,8 +39,6 @@
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
#define MB_MDNS_PORT (502)
#define MASTER_TAG "MASTER_TEST"
// The macro to get offset for parameter in the appropriate structure
#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))
@ -71,12 +63,14 @@
#endif
#define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp"
static const char *TAG = "MASTER_TEST";
// Enumeration of modbus device addresses accessed by master device
// Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
enum {
MB_DEVICE_ADDR1 = 1, // Slave address 1
MB_DEVICE_COUNT
MB_DEVICE_ADDR2 = 200,
MB_DEVICE_ADDR3 = 35
};
// Enumeration of all supported CIDs for device (used in parameter definition table)
@ -109,11 +103,11 @@ const mb_parameter_descriptor_t device_parameters[] = {
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 2,
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 2, 2,
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 4, 2,
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR2, MB_PARAM_INPUT, 4, 2,
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2,
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR3, MB_PARAM_HOLDING, 4, 2,
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
{ CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 0, 8,
COIL_OFFSET(coils_port0), PARAM_TYPE_U16, 2, OPTS( BIT1, 0, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
@ -122,20 +116,26 @@ const mb_parameter_descriptor_t device_parameters[] = {
};
// Calculate number of parameters in the table
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters[0]));
const uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
// This table represents slave IP addresses that correspond to the short address field of the slave in device_parameters structure
// Modbus TCP stack shall use these addresses to be able to connect and read parameters from slave
char* slave_ip_address_table[MB_DEVICE_COUNT] = {
char* slave_ip_address_table[] = {
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
"FROM_STDIN", // Address corresponds to MB_DEVICE_ADDR1 and set to predefined value by user
NULL
"FROM_STDIN", // Corresponds to characteristic MB_DEVICE_ADDR2
"FROM_STDIN", // Corresponds to characteristic MB_DEVICE_ADDR3
NULL // End of table condition (must be included)
#elif CONFIG_MB_MDNS_IP_RESOLVER
NULL,
NULL,
NULL,
NULL
#endif
};
const size_t ip_table_sz = (size_t)(sizeof(slave_ip_address_table) / sizeof(slave_ip_address_table[0]));
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
// Scan IP address according to IPV settings
@ -186,8 +186,8 @@ static int master_get_slave_ip_stdin(char** addr_table)
fputc('\n', stdout);
ip_str = master_scan_addr(&index, buf);
if (ip_str != NULL) {
ESP_LOGI(MASTER_TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
if ((ip_cnt >= MB_DEVICE_COUNT) || (index != ip_cnt)) {
ESP_LOGI(TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
if ((ip_cnt >= ip_table_sz) || (index != ip_cnt)) {
addr_table[ip_cnt] = NULL;
break;
}
@ -199,10 +199,10 @@ static int master_get_slave_ip_stdin(char** addr_table)
}
} else {
if (addr_table[ip_cnt]) {
ESP_LOGI(MASTER_TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
ESP_LOGI(TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
ip_cnt++;
} else {
ESP_LOGI(MASTER_TAG, "IP(%d) is not set in the table.", ip_cnt);
ESP_LOGI(TAG, "IP(%d) is not set in the table.", ip_cnt);
break;
}
}
@ -212,6 +212,16 @@ static int master_get_slave_ip_stdin(char** addr_table)
#elif CONFIG_MB_MDNS_IP_RESOLVER
typedef struct slave_addr_entry_s {
uint16_t index;
char* ip_address;
uint8_t slave_addr;
void* p_data;
LIST_ENTRY(slave_addr_entry_s) entries;
} slave_addr_entry_t;
LIST_HEAD(slave_addr_, slave_addr_entry_s) slave_addr_list = LIST_HEAD_INITIALIZER(slave_addr_list);
// convert MAC from binary format to string
static inline char* gen_mac_str(const uint8_t* mac, char* pref, char* mac_str)
{
@ -235,7 +245,7 @@ static void master_start_mdns_service()
ESP_ERROR_CHECK(mdns_init());
// set mDNS hostname (required if you want to advertise services)
ESP_ERROR_CHECK(mdns_hostname_set(hostname));
ESP_LOGI(MASTER_TAG, "mdns hostname set to: [%s]", hostname);
ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname);
// set default mDNS instance name
ESP_ERROR_CHECK(mdns_instance_name_set(MB_MDNS_INSTANCE("esp32_")));
@ -276,15 +286,21 @@ static char* master_get_slave_ip_str(mdns_ip_addr_t* address, mb_tcp_addr_type_t
return slave_ip_str;
}
static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, char** resolved_ip,
static esp_err_t master_resolve_slave(uint8_t short_addr, mdns_result_t* result, char** resolved_ip,
mb_tcp_addr_type_t addr_type)
{
if (!name || !result) {
if (!short_addr || !result || !resolved_ip) {
return ESP_ERR_INVALID_ARG;
}
mdns_result_t* r = result;
int t;
char* slave_ip = NULL;
char slave_name[22] = {0};
if (sprintf(slave_name, "mb_slave_tcp_%02X", short_addr) < 0) {
ESP_LOGE(TAG, "Fail to create instance name for index: %d", short_addr);
abort();
}
for (; r ; r = r->next) {
if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
continue;
@ -293,7 +309,7 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
}
// Check host name for Modbus short address and
// append it into slave ip address table
if ((strcmp(r->instance_name, name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
if ((strcmp(r->instance_name, slave_name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
printf(" PTR : %s\n", r->instance_name);
if (r->txt_count) {
printf(" TXT : [%u] ", r->txt_count);
@ -304,92 +320,124 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
}
slave_ip = master_get_slave_ip_str(r->addr, addr_type);
if (slave_ip) {
ESP_LOGI(MASTER_TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
*resolved_ip = slave_ip;
return ESP_OK;
}
}
}
*resolved_ip = NULL;
ESP_LOGD(MASTER_TAG, "Fail to resolve slave: %s", name);
ESP_LOGD(TAG, "Fail to resolve slave: %s", slave_name);
return ESP_ERR_NOT_FOUND;
}
static int master_create_slave_list(mdns_result_t* results, char** addr_table,
mb_tcp_addr_type_t addr_type)
int addr_table_size, mb_tcp_addr_type_t addr_type)
{
if (!results) {
return -1;
}
int i, addr, resolved = 0;
int i, slave_addr, cid_resolve_cnt = 0;
int ip_index = 0;
const mb_parameter_descriptor_t* pdescr = &device_parameters[0];
char** ip_table = addr_table;
char slave_name[22] = {0};
char* slave_ip = NULL;
slave_addr_entry_t *it;
for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++) {
addr = pdescr->mb_slave_addr;
if (-1 == sprintf(slave_name, "mb_slave_tcp_%02X", addr)) {
ESP_LOGI(MASTER_TAG, "Fail to create instance name for index: %d", addr);
abort();
for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++)
{
slave_addr = pdescr->mb_slave_addr;
it = NULL;
// Is the slave address already registered?
LIST_FOREACH(it, &slave_addr_list, entries) {
if (slave_addr == it->slave_addr) {
break;
}
}
if (!ip_table[addr - 1]) {
esp_err_t err = master_resolve_slave(slave_name, results, &slave_ip, addr_type);
if (!it) {
// Resolve new slave IP address using its short address
esp_err_t err = master_resolve_slave(slave_addr, results, &slave_ip, addr_type);
if (err != ESP_OK) {
ESP_LOGE(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, failed to resolve!",
i, addr, slave_name);
ESP_LOGE(TAG, "Index: %d, sl_addr: %d, failed to resolve!", i, slave_addr);
// Set correspond index to NULL indicate host not resolved
ip_table[addr - 1] = NULL;
ip_table[ip_index] = NULL;
continue;
}
ip_table[addr - 1] = slave_ip; //slave_name;
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, resolve to IP: [%s]",
i, addr, slave_name, slave_ip);
resolved++;
// Register new slave address information
slave_addr_entry_t* new_slave_entry = (slave_addr_entry_t*) heap_caps_malloc(sizeof(slave_addr_entry_t),
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
MB_RETURN_ON_FALSE((new_slave_entry != NULL), ESP_ERR_NO_MEM,
TAG, "Can not allocate memory for slave entry.");
new_slave_entry->index = i;
new_slave_entry->ip_address = slave_ip;
new_slave_entry->slave_addr = slave_addr;
new_slave_entry->p_data = NULL;
LIST_INSERT_HEAD(&slave_addr_list, new_slave_entry, entries);
ip_table[ip_index] = slave_ip;
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, resolved to IP: [%s]",
i, slave_addr, slave_ip);
cid_resolve_cnt++;
if (ip_index < addr_table_size) {
ip_index++;
}
} else {
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, set to IP: [%s]",
i, addr, slave_name, ip_table[addr - 1]);
resolved++;
}
}
return resolved;
}
static void master_destroy_slave_list(char** table)
{
for (int i = 0; ((i < MB_DEVICE_COUNT) && table[i] != NULL); i++) {
if (table[i]) {
free(table[i]);
table[i] = NULL;
ip_table[ip_index] = it ? it->ip_address : ip_table[ip_index];
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, set to IP: [%s]",
i, slave_addr, ip_table[ip_index]);
cid_resolve_cnt++;
}
}
ESP_LOGI(TAG, "Resolved %d cids, with %d IP addresses", cid_resolve_cnt, ip_index);
return cid_resolve_cnt;
}
static int master_query_slave_service(const char * service_name, const char * proto,
mb_tcp_addr_type_t addr_type)
{
ESP_LOGI(MASTER_TAG, "Query PTR: %s.%s.local", service_name, proto);
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
mdns_result_t* results = NULL;
int count = 0;
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
if(err){
ESP_LOGE(MASTER_TAG, "Query Failed: %s", esp_err_to_name(err));
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
return count;
}
if(!results){
ESP_LOGW(MASTER_TAG, "No results found!");
ESP_LOGW(TAG, "No results found!");
return count;
}
count = master_create_slave_list(results, slave_ip_address_table, addr_type);
count = master_create_slave_list(results, slave_ip_address_table, ip_table_sz, addr_type);
mdns_query_results_free(results);
return count;
}
#endif
static void master_destroy_slave_list(char** table, size_t ip_table_size)
{
#if CONFIG_MB_MDNS_IP_RESOLVER
slave_addr_entry_t *it;
LIST_FOREACH(it, &slave_addr_list, entries) {
LIST_REMOVE(it, entries);
free(it);
}
#endif
for (int i = 0; ((i < ip_table_size) && table[i] != NULL); i++) {
if (table[i]) {
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
free(table[i]);
table[i] = "FROM_STDIN";
#elif CONFIG_MB_MDNS_IP_RESOLVER
table[i] = NULL;
#endif
}
}
}
// The function to get pointer to parameter storage (instance) according to parameter description table
static void* master_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
{
@ -415,7 +463,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
break;
}
} else {
ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
assert(instance_ptr != NULL);
}
return instance_ptr;
@ -429,7 +477,7 @@ static void master_operation_func(void *arg)
bool alarm_state = false;
const mb_parameter_descriptor_t* param_descriptor = NULL;
ESP_LOGI(MASTER_TAG, "Start modbus test...");
ESP_LOGI(TAG, "Start modbus test...");
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
// Read all found characteristics from slave(s)
@ -449,7 +497,7 @@ static void master_operation_func(void *arg)
*(float*)temp_data_ptr = value;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@ -463,7 +511,7 @@ static void master_operation_func(void *arg)
} else {
uint16_t state = *(uint16_t*)temp_data_ptr;
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(char*)param_descriptor->param_units,
@ -475,7 +523,7 @@ static void master_operation_func(void *arg)
}
}
} else {
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = %d (%s).",
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = %d (%s).",
param_descriptor->cid,
(char*)param_descriptor->param_key,
(int)err,
@ -488,13 +536,13 @@ static void master_operation_func(void *arg)
}
if (alarm_state) {
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
param_descriptor->cid);
} else {
ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
MASTER_MAX_RETRY);
}
ESP_LOGI(MASTER_TAG, "Destroy master...");
ESP_LOGI(TAG, "Destroy master...");
vTaskDelay(100);
}
@ -505,18 +553,18 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
ESP_ERROR_CHECK(nvs_flash_erase());
result = nvs_flash_init();
}
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_netif_init();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_event_loop_create_default();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_create_default fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_MB_MDNS_IP_RESOLVER
@ -527,14 +575,14 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
// Read "Establishing Wi-Fi or Ethernet Connection" section in
// examples/protocols/README.md for more information about this function.
result = example_connect();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_connect fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_EXAMPLE_CONNECT_WIFI
result = esp_wifi_set_ps(WIFI_PS_NONE);
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_wifi_set_ps fail, returns(0x%x).",
(uint32_t)result);
#endif
@ -544,17 +592,17 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
}
if (res < num_device_parameters) {
ESP_LOGE(MASTER_TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
ESP_LOGE(MASTER_TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
ESP_LOGE(TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
ESP_LOGE(TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
return ESP_ERR_NOT_FOUND;
}
mdns_free();
#elif CONFIG_MB_SLAVE_IP_FROM_STDIN
int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table);
if (ip_cnt) {
ESP_LOGI(MASTER_TAG, "Configured %d IP addresse(s).", ip_cnt);
ESP_LOGI(TAG, "Configured %d IP addresse(s).", ip_cnt);
} else {
ESP_LOGE(MASTER_TAG, "Fail to get IP address from stdin. Continue.");
ESP_LOGE(TAG, "Fail to get IP address from stdin. Continue.");
return ESP_ERR_NOT_FOUND;
}
#endif
@ -564,27 +612,26 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
static esp_err_t destroy_services(void)
{
esp_err_t err = ESP_OK;
#if CONFIG_MB_MDNS_IP_RESOLVER
master_destroy_slave_list(slave_ip_address_table);
#endif
master_destroy_slave_list(slave_ip_address_table, ip_table_sz);
err = example_disconnect();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_disconnect fail, returns(0x%x).",
(uint32_t)err);
err = esp_event_loop_delete_default();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_delete_default fail, returns(0x%x).",
(uint32_t)err);
err = esp_netif_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_deinit fail, returns(0x%x).",
(uint32_t)err);
err = nvs_flash_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_deinit fail, returns(0x%x).",
(uint32_t)err);
return err;
@ -596,30 +643,30 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
void* master_handler = NULL;
esp_err_t err = mbc_master_init_tcp(&master_handler);
ESP_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
TAG,
"mb controller initialization fail.");
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller initialization fail, returns(0x%x).",
(uint32_t)err);
err = mbc_master_setup((void*)comm_info);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller setup fail, returns(0x%x).",
(uint32_t)err);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller set descriptor fail, returns(0x%x).",
(uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
ESP_LOGI(TAG, "Modbus master stack initialized...");
err = mbc_master_start();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mb controller start fail, returns(0x%x).",
(uint32_t)err);
vTaskDelay(5);
@ -629,11 +676,11 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
static esp_err_t master_destroy(void)
{
esp_err_t err = mbc_master_destroy();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_master_destroy fail, returns(0x%x).",
(uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack destroy...");
ESP_LOGI(TAG, "Modbus master stack destroy...");
return err;
}

View File

@ -2,7 +2,7 @@ menu "Modbus Example Configuration"
config MB_SLAVE_ADDR
int "Modbus slave address"
range 1 127
range 1 255
default 1
help
This is the Modbus slave address in the network.

View File

@ -1,14 +1,15 @@
/* FreeModbus Slave Example ESP32
/*
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// FreeModbus Slave Example ESP32
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "esp_err.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_check.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
@ -47,7 +48,7 @@
| MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
#define SLAVE_TAG "SLAVE_TEST"
static const char *TAG = "SLAVE_TEST";
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
@ -161,8 +162,8 @@ static void slave_operation_func(void *arg)
{
mb_param_info_t reg_info; // keeps the Modbus registers access information
ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
ESP_LOGI(SLAVE_TAG, "Start modbus test...");
ESP_LOGI(TAG, "Modbus slave stack initialized.");
ESP_LOGI(TAG, "Start modbus test...");
// The cycle below will be terminated when parameter holding_data0
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
@ -173,7 +174,7 @@ static void slave_operation_func(void *arg)
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
// Get parameter information from parameter queue
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@ -191,7 +192,7 @@ static void slave_operation_func(void *arg)
}
} else if (event & MB_EVENT_INPUT_REG_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@ -199,7 +200,7 @@ static void slave_operation_func(void *arg)
(uint32_t)reg_info.size);
} else if (event & MB_EVENT_DISCRETE_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type,
@ -207,7 +208,7 @@ static void slave_operation_func(void *arg)
(uint32_t)reg_info.size);
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT));
ESP_LOGI(SLAVE_TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
rw_str,
(uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset,
@ -218,7 +219,7 @@ static void slave_operation_func(void *arg)
}
}
// Destroy of Modbus controller on alarm
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
ESP_LOGI(TAG,"Modbus controller destroyed.");
vTaskDelay(100);
}
@ -229,18 +230,18 @@ static esp_err_t init_services(void)
ESP_ERROR_CHECK(nvs_flash_erase());
result = nvs_flash_init();
}
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_netif_init();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_init fail, returns(0x%x).",
(uint32_t)result);
result = esp_event_loop_create_default();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_create_default fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_MB_MDNS_IP_RESOLVER
@ -251,14 +252,14 @@ static esp_err_t init_services(void)
// Read "Establishing Wi-Fi or Ethernet Connection" section in
// examples/protocols/README.md for more information about this function.
result = example_connect();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_connect fail, returns(0x%x).",
(uint32_t)result);
#if CONFIG_EXAMPLE_CONNECT_WIFI
result = esp_wifi_set_ps(WIFI_PS_NONE);
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_wifi_set_ps fail, returns(0x%x).",
(uint32_t)result);
#endif
@ -270,23 +271,23 @@ static esp_err_t destroy_services(void)
esp_err_t err = ESP_OK;
err = example_disconnect();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"example_disconnect fail, returns(0x%x).",
(uint32_t)err);
err = esp_event_loop_delete_default();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"esp_event_loop_delete_default fail, returns(0x%x).",
(uint32_t)err);
err = esp_netif_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
TAG,
"esp_netif_deinit fail, returns(0x%x).",
(uint32_t)err);
err = nvs_flash_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"nvs_flash_deinit fail, returns(0x%x).",
(uint32_t)err);
#if CONFIG_MB_MDNS_IP_RESOLVER
@ -304,8 +305,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
// Initialization of Modbus controller
esp_err_t err = mbc_slave_init_tcp(&slave_handler);
ESP_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
TAG,
"mb controller initialization fail.");
comm_info->ip_addr = NULL; // Bind to any address
@ -313,8 +314,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
// Setup communication parameters and start stack
err = mbc_slave_setup((void*)comm_info);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_setup fail, returns(0x%x).",
(uint32_t)err);
@ -329,8 +330,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
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
err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@ -339,8 +340,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
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
err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@ -350,8 +351,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&input_reg_params.input_data0;
reg_area.size = sizeof(float) << 2;
err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
reg_area.type = MB_PARAM_INPUT;
@ -359,8 +360,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&input_reg_params.input_data4;
reg_area.size = sizeof(float) << 2;
err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@ -370,8 +371,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&coil_reg_params;
reg_area.size = sizeof(coil_reg_params);
err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@ -381,8 +382,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
reg_area.address = (void*)&discrete_reg_params;
reg_area.size = sizeof(discrete_reg_params);
err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err);
@ -391,8 +392,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
// Starts of modbus controller and stack
err = mbc_slave_start();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_start fail, returns(0x%x).",
(uint32_t)err);
vTaskDelay(5);
@ -402,8 +403,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
static esp_err_t slave_destroy(void)
{
esp_err_t err = mbc_slave_destroy();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG,
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
TAG,
"mbc_slave_destroy fail, returns(0x%x).",
(uint32_t)err);
return err;
@ -418,7 +419,7 @@ void app_main(void)
ESP_ERROR_CHECK(init_services());
// Set UART log level
esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
esp_log_level_set(TAG, ESP_LOG_INFO);
mb_communication_info_t comm_info = { 0 };