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

This commit is contained in:
Alex Lisitsyn
2022-02-17 08:38:56 +00:00
committed by Jiang Jiang Jian
parent 0b46ac1732
commit d2399f6d8c
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_master.h" // for public interface defines
#include "esp_modbus_callbacks.h" // for callback functions #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. // This file implements public API for Modbus master controller.
// These functions are wrappers for interface functions of the controller // These functions are wrappers for interface functions of the controller
static mb_master_interface_t* master_interface_ptr = NULL; 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 // Common interface pointer for slave port
static mb_slave_interface_t* slave_interface_ptr = NULL; 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 // 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) 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; par_info.mb_offset = mb_offset;
BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, &par_info, MB_PAR_INFO_TOUT); BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, &par_info, MB_PAR_INFO_TOUT);
if (pdTRUE == status) { 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); par_type, (uint32_t)par_address, par_size);
error = ESP_OK; error = ESP_OK;
} else if (errQUEUE_FULL == status) { } else if (errQUEUE_FULL == status) {
ESP_LOGD(MB_SLAVE_TAG, "Parameter queue is overflowed."); ESP_LOGD(TAG, "Parameter queue is overflowed.");
} }
return error; 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; esp_err_t err = ESP_FAIL;
mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, (EventBits_t)event); mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, (EventBits_t)event);
if (bits & 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; err = ESP_OK;
} }
return err; return err;

View File

@@ -22,6 +22,24 @@
extern "C" { extern "C" {
#endif #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_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 #define MB_CONTROLLER_PRIORITY (CONFIG_FMB_PORT_TASK_PRIO - 1) // priority of MB controller task

View File

@@ -25,6 +25,12 @@
extern "C" { extern "C" {
#endif #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. * \brief Modbus descriptor table parameter type defines.
*/ */

View File

@@ -28,6 +28,12 @@
extern "C" { extern "C" {
#endif #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 * @brief Parameter access event information type
*/ */

View File

@@ -12,9 +12,11 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef _MB_CONTROLLER_MASTER_H #ifndef _MB_CONTROLLER_MASTER_H
#define _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/FreeRTOS.h" // for task creation and queue access
#include "freertos/task.h" // for task api access #include "freertos/task.h" // for task api access
#include "freertos/event_groups.h" // for event groups #include "freertos/event_groups.h" // for event groups
@@ -28,18 +30,6 @@
/* ----------------------- Defines ------------------------------------------*/ /* ----------------------- 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 * @brief Request mode for parameter to use in data dictionary
*/ */
@@ -59,6 +49,19 @@ typedef struct {
uart_parity_t parity; /*!< Modbus UART parity settings */ uart_parity_t parity; /*!< Modbus UART parity settings */
} mb_master_comm_info_t; } 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 * @brief Modbus controller handler structure
*/ */
@@ -71,6 +74,10 @@ typedef struct {
EventGroupHandle_t mbm_event_group; /*!< Modbus controller event group */ EventGroupHandle_t mbm_event_group; /*!< Modbus controller event group */
const mb_parameter_descriptor_t* mbm_param_descriptor_table; /*!< Modbus controller parameter description table */ 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*/ 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; } mb_master_options_t;
typedef esp_err_t (*iface_get_cid_info)(uint16_t, const mb_parameter_descriptor_t**); /*!< Interface get_cid_info method */ 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_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_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 * @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 mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
static const char *TAG = "MB_CONTROLLER_MASTER";
// Modbus event processing task // Modbus event processing task
static void modbus_master_task(void *pvParameters) 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 ); (USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
break; break;
default: default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ", ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
__FUNCTION__, mb_command); __FUNCTION__, mb_command);
mb_error = MB_MRE_NO_REG; mb_error = MB_MRE_NO_REG;
break; break;
@@ -269,7 +270,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
break; break;
default: default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ", ESP_LOGE(TAG, "%s: Incorrect return code (%x) ",
__FUNCTION__, mb_error); __FUNCTION__, mb_error);
error = ESP_FAIL; error = ESP_FAIL;
break; 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) { if (mode != MB_PARAM_WRITE) {
command = MB_FUNC_READ_DISCRETE_INPUTS; command = MB_FUNC_READ_DISCRETE_INPUTS;
} else { } else {
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)", ESP_LOGE(TAG, "%s: Incorrect mode (%u)",
__FUNCTION__, (uint8_t)mode); __FUNCTION__, (uint8_t)mode);
} }
break; break;
default: default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)", ESP_LOGE(TAG, "%s: Incorrect param type (%u)",
__FUNCTION__, param_type); __FUNCTION__, param_type);
break; 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 // Send request to read characteristic data
error = mbc_serial_master_send_request(&request, value_ptr); error = mbc_serial_master_send_request(&request, value_ptr);
if (error == ESP_OK) { 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)); __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
} else { } 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)); __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
} }
// Set the type of parameter found in the table // Set the type of parameter found in the table
*type = reg_info.param_type; *type = reg_info.param_type;
} else { } 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); __FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG; 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 // Send request to write characteristic data
error = mbc_serial_master_send_request(&request, value_ptr); error = mbc_serial_master_send_request(&request, value_ptr);
if (error == ESP_OK) { 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)); __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
} else { } 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)); __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
} }
// Set the type of parameter found in the table // Set the type of parameter found in the table
*type = reg_info.param_type; *type = reg_info.param_type;
} else { } 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); __FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG; error = ESP_ERR_INVALID_ARG;
} }

View File

@@ -29,6 +29,7 @@
// Shared pointer to interface structure // Shared pointer to interface structure
static mb_slave_interface_t* mbs_interface_ptr = NULL; static mb_slave_interface_t* mbs_interface_ptr = NULL;
static const char *TAG = "MB_CONTROLLER_SLAVE";
// Modbus task function // Modbus task function
static void modbus_slave_task(void *pvParameters) 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 <sys/time.h> // for calculation of time stamp in milliseconds
#include "esp_log.h" // for log_write #include "esp_log.h" // for log_write
#include <string.h> // for memcpy #include <string.h> // for memcpy
#include <sys/queue.h> // for list
#include "freertos/FreeRTOS.h" // for task creation and queue access #include "freertos/FreeRTOS.h" // for task creation and queue access
#include "freertos/task.h" // for task api access #include "freertos/task.h" // for task api access
#include "freertos/event_groups.h" // for event groups #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) #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 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 // Modbus event processing task
static void modbus_tcp_master_task(void *pvParameters) 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); vMBTCPPortMasterSetNetOpt(comm_info->ip_netif_ptr, ip_ver, proto);
vMBTCPPortMasterTaskStart(); vMBTCPPortMasterTaskStart();
// Add slave IP address for each slave to initialise connection // Add slave IP address for each slave to initialize connection
for (int idx = 0; *comm_ip_table != NULL; idx++, comm_ip_table++) mb_slave_addr_entry_t *p_slave_info;
{
result = (BOOL)xMBTCPPortMasterAddSlaveIp(*comm_ip_table); 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); 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(); status = eMBMasterEnable();
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE, MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
"mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status); "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 // Wait for connection done event
bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group, 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; mbm_opts->mbm_task_handle = NULL;
(void)vEventGroupDelete(mbm_opts->mbm_event_group); (void)vEventGroupDelete(mbm_opts->mbm_event_group);
mbm_opts->mbm_event_group = NULL; mbm_opts->mbm_event_group = NULL;
mbc_tcp_master_free_slave_list();
free(mbm_interface_ptr); // free the memory allocated for options free(mbm_interface_ptr); // free the memory allocated for options
vMBPortSetMode((UCHAR)MB_PORT_INACTIVE); vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
mbm_interface_ptr = NULL; 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."); 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; 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 // 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. // 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->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."); 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_table = descriptor;
mbm_opts->mbm_param_descriptor_size = num_elements; 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 ); (USHORT)mb_size, (LONG) MB_RESPONSE_TIMEOUT );
break; break;
default: default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ", ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
__FUNCTION__, mb_command); __FUNCTION__, mb_command);
mb_error = MB_MRE_NO_REG; mb_error = MB_MRE_NO_REG;
break; break;
@@ -289,7 +355,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
break; break;
default: 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; error = ESP_FAIL;
break; 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) { if (mode != MB_PARAM_WRITE) {
command = MB_FUNC_READ_DISCRETE_INPUTS; command = MB_FUNC_READ_DISCRETE_INPUTS;
} else { } 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; break;
default: 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; break;
} }
return command; 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); memcpy((void*)dest, (void*)src, (size_t)param_size);
break; break;
default: default:
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u).", ESP_LOGE(TAG, "%s: Incorrect param type (%u).",
__FUNCTION__, (uint16_t)param_type); __FUNCTION__, (uint16_t)param_type);
err = ESP_ERR_NOT_SUPPORTED; err = ESP_ERR_NOT_SUPPORTED;
break; 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((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((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; esp_err_t error = ESP_ERR_INVALID_RESPONSE;
mb_param_request_t request ; mb_param_request_t request ;
mb_parameter_descriptor_t reg_info = { 0 }; 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); error = mbc_tcp_master_set_request(name, MB_PARAM_READ, &request, &reg_info);
if ((error == ESP_OK) && (cid == reg_info.cid)) { 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 (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 data pointer is NULL then we don't need to set value (it is still in the cache of cid)
if (value != NULL) { 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); 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 { } 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)); __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 // Set the type of parameter found in the table
*type = reg_info.param_type; *type = reg_info.param_type;
} else { } 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); __FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG; 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; esp_err_t error = ESP_ERR_INVALID_RESPONSE;
mb_param_request_t request ; mb_param_request_t request ;
mb_parameter_descriptor_t reg_info = { 0 }; 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); error = mbc_tcp_master_set_request(name, MB_PARAM_WRITE, &request, &reg_info);
if ((error == ESP_OK) && (cid == reg_info.cid)) { 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 // 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); 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 // 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) { 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)); __FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
} else { } 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)); __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
} }
free(pdata);
// Set the type of parameter found in the table // Set the type of parameter found in the table
*type = reg_info.param_type; *type = reg_info.param_type;
} else { } 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); __FUNCTION__, reg_info.cid);
error = ESP_ERR_INVALID_ARG; 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 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 // Initialize public interface methods of the interface
mbm_interface_ptr->init = mbc_tcp_master_create; mbm_interface_ptr->init = mbc_tcp_master_create;
mbm_interface_ptr->destroy = mbc_tcp_master_destroy; mbm_interface_ptr->destroy = mbc_tcp_master_destroy;

View File

@@ -58,7 +58,6 @@
#define MB_TCP_CONNECTION_TIMEOUT_MS ( 20 ) // Connection timeout in mS #define MB_TCP_CONNECTION_TIMEOUT_MS ( 20 ) // Connection timeout in mS
#define MB_TCP_RECONNECT_TIMEOUT ( 5000000 ) // Connection timeout in uS #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 | \ #define MB_EVENT_REQ_DONE_MASK ( EV_MASTER_PROCESS_SUCCESS | \
EV_MASTER_ERROR_RESPOND_TIMEOUT | \ EV_MASTER_ERROR_RESPOND_TIMEOUT | \
EV_MASTER_ERROR_RECEIVE_DATA | \ EV_MASTER_ERROR_RECEIVE_DATA | \
@@ -76,6 +75,7 @@
void vMBPortEventClose( void ); void vMBPortEventClose( void );
/* ----------------------- Static variables ---------------------------------*/ /* ----------------------- Static variables ---------------------------------*/
static const char *TAG = "MB_TCP_MASTER_PORT";
static MbPortConfig_t xMbPortConfig; static MbPortConfig_t xMbPortConfig;
static EventGroupHandle_t xMasterEventHandle = NULL; static EventGroupHandle_t xMasterEventHandle = NULL;
static SemaphoreHandle_t xShutdownSemaphore = NULL; static SemaphoreHandle_t xShutdownSemaphore = NULL;
@@ -106,7 +106,7 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
xMbPortConfig.pxMbSlaveInfo = calloc(MB_TCP_PORT_MAX_CONN, sizeof(MbSlaveInfo_t*)); xMbPortConfig.pxMbSlaveInfo = calloc(MB_TCP_PORT_MAX_CONN, sizeof(MbSlaveInfo_t*));
if (!xMbPortConfig.pxMbSlaveInfo) { 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; return FALSE;
} }
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xMbPortConfig.pxMbSlaveInfo[idx] = NULL, idx++); for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xMbPortConfig.pxMbSlaveInfo[idx] = NULL, idx++);
@@ -115,12 +115,13 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
xMbPortConfig.usPort = usTCPPort; xMbPortConfig.usPort = usTCPPort;
xMbPortConfig.usMbSlaveInfoCount = 0; xMbPortConfig.usMbSlaveInfoCount = 0;
xMbPortConfig.ucCurSlaveIndex = 1; xMbPortConfig.ucCurSlaveIndex = 1;
xMbPortConfig.pxMbSlaveCurrInfo = NULL;
xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(CHAR*)); xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(MbSlaveAddrInfo_t));
if (xMbPortConfig.xConnectQueue == 0) if (xMbPortConfig.xConnectQueue == 0)
{ {
// Queue was not created and must not be used. // 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; return FALSE;
} }
@@ -134,10 +135,10 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
MB_PORT_TASK_AFFINITY); MB_PORT_TASK_AFFINITY);
if (xErr != pdTRUE) 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); (void)vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
} else { } else {
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "TCP master stack initialized."); ESP_LOGI(TAG, "TCP master stack initialized.");
bOkay = TRUE; bOkay = TRUE;
} }
@@ -145,9 +146,30 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
return bOkay; 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) 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 // Start Modbus event state machine
@@ -158,10 +180,10 @@ static void vMBTCPPortMasterStartPoll(void)
EventBits_t xFlags = xEventGroupSetBits(xMasterEventHandle, EventBits_t xFlags = xEventGroupSetBits(xMasterEventHandle,
(EventBits_t)xMasterEvent); (EventBits_t)xMasterEvent);
if (!(xFlags & 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 { } 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...");
} }
} }
@@ -173,10 +195,10 @@ static void vMBTCPPortMasterStopPoll(void)
EventBits_t xFlags = xEventGroupClearBits(xMasterEventHandle, EventBits_t xFlags = xEventGroupClearBits(xMasterEventHandle,
(EventBits_t)xMasterEvent); (EventBits_t)xMasterEvent);
if (!(xFlags & xMasterEvent)) { if (!(xFlags & xMasterEvent)) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling."); ESP_LOGE(TAG, "Fail to stop polling.");
} }
} else { } 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...");
} }
} }
@@ -207,11 +229,11 @@ static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t* pxInfo)
return FALSE; return FALSE;
} }
if (pxInfo->xSockId == -1) { 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; return FALSE;
} }
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) { 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); close(pxInfo->xSockId);
pxInfo->xSockId = -1; pxInfo->xSockId = -1;
@@ -281,12 +303,12 @@ static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t* pxInfo, UCHAR* pucDstBuf, USHOR
continue; continue;
} else if (errno == ENOTCONN) { } else if (errno == ENOTCONN) {
// Socket connection closed // 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); pxInfo->xSockId, pxInfo->pcIpAddr);
return ERR_CONN; return ERR_CONN;
} else { } else {
// Other error occurred during receiving // 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); pxInfo->xSockId, pxInfo->pcIpAddr, xLength, errno);
return -1; return -1;
} }
@@ -317,7 +339,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
pxInfo->xRcvErr = xRet; pxInfo->xRcvErr = xRet;
return xRet; return xRet;
} else if (xRet != MB_TCP_UID) { } 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->xSockId, pxInfo->pcIpAddr, xRet);
pxInfo->xRcvErr = ERR_VAL; pxInfo->xRcvErr = ERR_VAL;
return ERR_VAL; return ERR_VAL;
@@ -331,7 +353,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
return xRet; return xRet;
} else if (xRet != xLength) { } else if (xRet != xLength) {
// Received incorrect or fragmented packet. // 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, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
usTidRcv, errno, strerror(errno)); usTidRcv, errno, strerror(errno));
pxInfo->xRcvErr = ERR_VAL; pxInfo->xRcvErr = ERR_VAL;
@@ -341,13 +363,13 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
// Check transaction identifier field in the incoming packet. // Check transaction identifier field in the incoming packet.
if ((pxInfo->usTidCnt - 1) != usTidRcv) { 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->xSockId, pxInfo->pcIpAddr, usTidRcv, (pxInfo->usTidCnt - 1));
pxInfo->xRcvErr = ERR_BUF; pxInfo->xRcvErr = ERR_BUF;
return ERR_BUF; return ERR_BUF;
} }
pxInfo->usRcvPos += xRet + MB_TCP_UID; 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, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
usTidRcv, errno, strerror(errno)); usTidRcv, errno, strerror(errno));
pxInfo->xRcvErr = ERR_OK; pxInfo->xRcvErr = ERR_OK;
@@ -364,7 +386,7 @@ static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
// Set non blocking attribute for socket // Set non blocking attribute for socket
ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL); ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) { 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); pxInfo->xSockId, pxInfo->pcIpAddr, errno);
return ERR_WOULDBLOCK; return ERR_WOULDBLOCK;
} }
@@ -397,12 +419,12 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
if (errno == EINPROGRESS) { if (errno == EINPROGRESS) {
xErr = ERR_INPROGRESS; xErr = ERR_INPROGRESS;
} else { } 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); pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
xErr = ERR_CONN; xErr = ERR_CONN;
} }
} else if (xErr == 0) { } 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); pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
return ERR_INPROGRESS; return ERR_INPROGRESS;
} else { } else {
@@ -411,11 +433,11 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
// Check socket error // Check socket error
xErr = getsockopt(pxInfo->xSockId, SOL_SOCKET, SO_ERROR, (void*)&xOptErr, (socklen_t*)&ulOptLen); xErr = getsockopt(pxInfo->xSockId, SOL_SOCKET, SO_ERROR, (void*)&xOptErr, (socklen_t*)&ulOptLen);
if (xOptErr != 0) { 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); pxInfo->xSockId, pxInfo->pcIpAddr, xOptErr);
return ERR_CONN; 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); pxInfo->xSockId, pxInfo->pcIpAddr);
return ERR_OK; return ERR_OK;
} }
@@ -445,7 +467,7 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
int xRet = getaddrinfo(pcHostStr, NULL, &xHint, &pxAddrList); int xRet = getaddrinfo(pcHostStr, NULL, &xHint, &pxAddrList);
if (xRet != 0) { 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; return FALSE;
} }
if (pxAddrList->ai_family == AF_INET) { if (pxAddrList->ai_family == AF_INET) {
@@ -463,20 +485,24 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
if (pxHostAddr) { if (pxHostAddr) {
*pxHostAddr = xTargetAddr; *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); freeaddrinfo(pxAddrList);
return TRUE; return TRUE;
} }
BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr) BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress)
{ {
BOOL xRes = FALSE; BOOL xRes = FALSE;
MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
MB_PORT_CHECK(xMbPortConfig.xConnectQueue != NULL, FALSE, "Wrong slave IP address to add."); MB_PORT_CHECK(xMbPortConfig.xConnectQueue != NULL, FALSE, "Wrong slave IP address to add.");
if (pcIpStr) { if (pcIpStr && (usIndex != 0xFF)) {
xRes = xMBTCPPortMasterCheckHost(pcIpStr, NULL); xRes = xMBTCPPortMasterCheckHost(pcIpStr, NULL);
} }
if (xRes || !pcIpStr) { 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); MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "FAIL to add slave IP address: [%s].", pcIpStr);
} }
return xRes; return xRes;
@@ -514,7 +540,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
int xRet = getaddrinfo(pxInfo->pcIpAddr, pcStr, &xHint, &pxAddrList); int xRet = getaddrinfo(pxInfo->pcIpAddr, pcStr, &xHint, &pxAddrList);
free(pcStr); free(pcStr);
if (xRet != 0) { 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; return ERR_CONN;
} }
@@ -537,12 +563,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
if (pxInfo->xSockId <= 0) { if (pxInfo->xSockId <= 0) {
pxInfo->xSockId = socket(pxCurAddr->ai_family, pxCurAddr->ai_socktype, pxCurAddr->ai_protocol); pxInfo->xSockId = socket(pxCurAddr->ai_family, pxCurAddr->ai_socktype, pxCurAddr->ai_protocol);
if (pxInfo->xSockId < 0) { 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; xErr = ERR_IF;
continue; continue;
} }
} else { } 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 // Set non blocking attribute for socket
@@ -553,7 +579,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
xErr = connect(pxInfo->xSockId, (struct sockaddr*)pxCurAddr->ai_addr, pxCurAddr->ai_addrlen); xErr = connect(pxInfo->xSockId, (struct sockaddr*)pxCurAddr->ai_addr, pxCurAddr->ai_addrlen);
if ((xErr < 0) && (errno == EINPROGRESS || errno == EALREADY)) { if ((xErr < 0) && (errno == EINPROGRESS || errno == EALREADY)) {
// The unblocking connect is pending (check status later) or already connected // 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)); pxInfo->xSockId, cStr, errno, strerror(errno));
// Set keep alive flag in socket options // Set keep alive flag in socket options
@@ -566,12 +592,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
continue; continue;
} else if (xErr != ERR_OK) { } else if (xErr != ERR_OK) {
// Other error occurred during connection // 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)); pxInfo->xIndex, pxInfo->xSockId, cStr, xErr, errno, strerror(errno));
xMBTCPPortMasterCloseConnection(pxInfo); xMBTCPPortMasterCloseConnection(pxInfo);
xErr = ERR_CONN; xErr = ERR_CONN;
} else { } 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); pxInfo->xIndex, pxInfo->xSockId, cStr);
continue; continue;
} }
@@ -613,7 +639,7 @@ static int xMBTCPPortMasterCheckConnState(fd_set* pxFdSet)
xErr = xMBTCPPortMasterCheckAlive(pxInfo, 0); xErr = xMBTCPPortMasterCheckAlive(pxInfo, 0);
if ((xErr < 0) && (((xTime - pxInfo->xRecvTimeStamp) > MB_TCP_RECONNECT_TIMEOUT) || if ((xErr < 0) && (((xTime - pxInfo->xRecvTimeStamp) > MB_TCP_RECONNECT_TIMEOUT) ||
((xTime - pxInfo->xSendTimeStamp) > 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->xIndex,
pxInfo->xSockId, pxInfo->xSockId,
pxInfo->pcIpAddr, pxInfo->pcIpAddr,
@@ -635,9 +661,9 @@ static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMas
static void vMBTCPPortMasterTask(void *pvParameters) static void vMBTCPPortMasterTask(void *pvParameters)
{ {
CHAR* pcAddrStr = NULL;
MbSlaveInfo_t* pxInfo; MbSlaveInfo_t* pxInfo;
MbSlaveInfo_t* pxCurrInfo; MbSlaveInfo_t* pxCurrInfo;
fd_set xConnSet; fd_set xConnSet;
fd_set xReadSet; fd_set xReadSet;
int xMaxSd = 0; int xMaxSd = 0;
@@ -647,51 +673,53 @@ static void vMBTCPPortMasterTask(void *pvParameters)
// Register each slave in the connection info structure // Register each slave in the connection info structure
while (1) { while (1) {
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&pcAddrStr, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)); MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
xMBTCPPortMasterCheckShutdown(); BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
xMBTCPPortMasterCheckShutdown();
if (xStatus != pdTRUE) { if (xStatus != pdTRUE) {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to register slave IP."); ESP_LOGE(TAG, "Fail to register slave IP.");
} else { } else {
if (pcAddrStr == NULL && xMbPortConfig.usMbSlaveInfoCount) { if (xSlaveAddrInfo.pcIPAddr == NULL && xMbPortConfig.usMbSlaveInfoCount && xSlaveAddrInfo.usIndex == 0xFF) {
break; break;
} }
if (xMbPortConfig.usMbSlaveInfoCount > MB_TCP_PORT_MAX_CONN) { 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; break;
} }
pxInfo = calloc(1, sizeof(MbSlaveInfo_t)); pxInfo = calloc(1, sizeof(MbSlaveInfo_t));
if (!pxInfo) { 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); xMbPortConfig.usMbSlaveInfoCount);
free(pxInfo); free(pxInfo);
break; break;
} }
pxInfo->pucRcvBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR)); pxInfo->pucRcvBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
if (!pxInfo->pucRcvBuf) { 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); xMbPortConfig.usMbSlaveInfoCount);
free(pxInfo->pucRcvBuf); free(pxInfo->pucRcvBuf);
break; break;
} }
pxInfo->usRcvPos = 0; pxInfo->usRcvPos = 0;
pxInfo->pcIpAddr = pcAddrStr; pxInfo->pcIpAddr = xSlaveAddrInfo.pcIPAddr;
pxInfo->xSockId = -1; pxInfo->xSockId = -1;
pxInfo->xError = -1; pxInfo->xError = -1;
pxInfo->xRecvTimeStamp = xMBTCPGetTimeStamp(); pxInfo->xRecvTimeStamp = xMBTCPGetTimeStamp();
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp(); pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
pxInfo->xMbProto = MB_PROTO_TCP; pxInfo->xMbProto = MB_PROTO_TCP;
pxInfo->xIndex = xMbPortConfig.usMbSlaveInfoCount; pxInfo->ucSlaveAddr = xSlaveAddrInfo.ucSlaveAddr;
pxInfo->xIndex = xSlaveAddrInfo.usIndex;
pxInfo->usTidCnt = (USHORT)(xMbPortConfig.usMbSlaveInfoCount << 8U); pxInfo->usTidCnt = (USHORT)(xMbPortConfig.usMbSlaveInfoCount << 8U);
// Register slave // Register slave
xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.usMbSlaveInfoCount++] = pxInfo; 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 // Main connection cycle
while (1) while (1)
{ {
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connecting to slaves..."); ESP_LOGI(TAG, "Connecting to slaves...");
xTime = xMBTCPGetTimeStamp(); xTime = xMBTCPGetTimeStamp();
usSlaveConnCnt = 0; usSlaveConnCnt = 0;
CHAR ucDot = '.'; CHAR ucDot = '.';
@@ -704,7 +732,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt]; pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
// if slave descriptor is NULL then it is end of list or connection closed. // if slave descriptor is NULL then it is end of list or connection closed.
if (!pxInfo) { 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) { if (xMbPortConfig.usMbSlaveInfoCount) {
continue; continue;
} }
@@ -719,12 +747,12 @@ static void vMBTCPPortMasterTask(void *pvParameters)
// In case of connection errors remove the socket from set // In case of connection errors remove the socket from set
if (FD_ISSET(pxInfo->xSockId, &xConnSet)) { if (FD_ISSET(pxInfo->xSockId, &xConnSet)) {
FD_CLR(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, pxInfo->xIndex, pxInfo->xSockId,
(char*)pxInfo->pcIpAddr, xErr); (char*)pxInfo->pcIpAddr, xErr);
if (usSlaveConnCnt) { if (usSlaveConnCnt) {
usSlaveConnCnt--; usSlaveConnCnt--;
} }
} }
break; break;
case ERR_OK: case ERR_OK:
@@ -733,7 +761,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
FD_SET(pxInfo->xSockId, &xConnSet); FD_SET(pxInfo->xSockId, &xConnSet);
usSlaveConnCnt++; usSlaveConnCnt++;
xMaxSd = (pxInfo->xSockId > xMaxSd) ? pxInfo->xSockId : xMaxSd; 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->xIndex, pxInfo->xSockId,
pxInfo->pcIpAddr, pxInfo->pcIpAddr,
usSlaveConnCnt, xErr); usSlaveConnCnt, xErr);
@@ -743,7 +771,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
} }
break; break;
default: 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->xIndex,
pxInfo->xSockId, pxInfo->xSockId,
pxInfo->pcIpAddr, xErr); pxInfo->pcIpAddr, xErr);
@@ -755,7 +783,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xMBTCPPortMasterCheckShutdown(); 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 vMBTCPPortMasterStartPoll(); // Send event to start stack
@@ -766,26 +794,26 @@ static void vMBTCPPortMasterTask(void *pvParameters)
xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)); xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
// Synchronize state machine with send packet event // Synchronize state machine with send packet event
if (xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_SENT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS))) { 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. // Get slave info for the current slave.
pxCurrInfo = vMBTCPPortMasterGetCurrInfo(); pxCurrInfo = vMBTCPPortMasterGetCurrInfo();
if (!pxCurrInfo) { 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); xMbPortConfig.ucCurSlaveIndex);
vMBTCPPortMasterStopPoll(); vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown(); xMBTCPPortMasterCheckShutdown();
break; // incorrect slave descriptor, reconnect. break; // incorrect slave descriptor, reconnect.
} }
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo); 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)); xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
// Wait respond from current slave during respond timeout // Wait respond from current slave during respond timeout
int xRes = vMBTCPPortMasterRxCheck(pxCurrInfo->xSockId, &xReadSet, xTime); int xRes = vMBTCPPortMasterRxCheck(pxCurrInfo->xSockId, &xReadSet, xTime);
if (xRes == ERR_TIMEOUT) { if (xRes == ERR_TIMEOUT) {
// No respond from current slave, process timeout. // No respond from current slave, process timeout.
// Need to drop response later if it is received after 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)); xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo); xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
// Wait completion of last transaction // Wait completion of last transaction
@@ -794,7 +822,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
continue; continue;
} else if (xRes < 0) { } else if (xRes < 0) {
// Select error (slave connection or r/w failure). // 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); pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo); xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
// Wait completion of last transaction // Wait completion of last transaction
@@ -808,30 +836,30 @@ static void vMBTCPPortMasterTask(void *pvParameters)
} else { } else {
// Check to make sure that active slave data is ready // Check to make sure that active slave data is ready
if (FD_ISSET(pxCurrInfo->xSockId, &xReadSet)) { if (FD_ISSET(pxCurrInfo->xSockId, &xReadSet)) {
xErr = ERR_BUF; int xRet = ERR_BUF;
for (int retry = 0; (xErr == ERR_BUF) && (retry < MB_TCP_READ_BUF_RETRY_CNT); retry++) { for (int retry = 0; (xRet == ERR_BUF) && (retry < MB_TCP_READ_BUF_RETRY_CNT); retry++) {
xErr = vMBTCPPortMasterReadPacket(pxCurrInfo); xRet = vMBTCPPortMasterReadPacket(pxCurrInfo);
// The error ERR_BUF means received response to previous request // The error ERR_BUF means received response to previous request
// (due to timeout) with the same socket ID and incorrect TID, // (due to timeout) with the same socket ID and incorrect TID,
// then ignore it and try to get next response buffer. // then ignore it and try to get next response buffer.
} }
if (xErr > 0) { if (xRet > 0) {
// Response received correctly, send an event to stack // Response received correctly, send an event to stack
xMBTCPPortMasterFsmSetError(EV_ERROR_INIT, EV_MASTER_FRAME_RECEIVED); 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); 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 // 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); 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. // After retries a response with incorrect TID received, process failure.
xMBTCPPortMasterFsmSetError(EV_ERROR_RECEIVE_DATA, EV_MASTER_ERROR_PROCESS); 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); pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
} else { } else {
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", critical error=%d."), ESP_LOGE(TAG, MB_SLAVE_FMT(", critical error=%d."),
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xErr); pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xRet);
// Stop polling process // Stop polling process
vMBTCPPortMasterStopPoll(); vMBTCPPortMasterStopPoll();
xMBTCPPortMasterCheckShutdown(); xMBTCPPortMasterCheckShutdown();
@@ -840,14 +868,14 @@ static void vMBTCPPortMasterTask(void *pvParameters)
break; break;
} }
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo); 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. // Wait completion of Modbus frame processing before start of new transaction.
if (xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime))) { 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); pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
} }
xTime = xMBTCPGetTimeStamp() - pxCurrInfo->xSendTimeStamp; 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); pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
} }
} }
@@ -884,7 +912,7 @@ vMBMasterTCPPortClose(void)
xShutdownSemaphore = xSemaphoreCreateBinary(); xShutdownSemaphore = xSemaphoreCreateBinary();
// if no semaphore (alloc issues) or couldn't acquire it, just delete the task // 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) { 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); vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
} }
if (xShutdownSemaphore) { if (xShutdownSemaphore) {
@@ -922,13 +950,13 @@ int xMBMasterTCPPortWritePoll(MbSlaveInfo_t* pxInfo, const UCHAR * pucMBTCPFrame
int xRes = (int)xMBTCPPortMasterCheckAlive(pxInfo, xTimeout); int xRes = (int)xMBTCPPortMasterCheckAlive(pxInfo, xTimeout);
if ((xRes < 0) && (xRes != ERR_INPROGRESS)) 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); pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
return xRes; return xRes;
} }
xRes = send(pxInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY); xRes = send(pxInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
if (xRes < 0) { 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); pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
} }
return xRes; return xRes;
@@ -938,36 +966,41 @@ BOOL
xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength ) xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
{ {
BOOL bFrameSent = FALSE; BOOL bFrameSent = FALSE;
xMbPortConfig.ucCurSlaveIndex = ucMBMasterGetDestAddress(); USHORT ucCurSlaveIndex = ucMBMasterGetDestAddress();
MbSlaveInfo_t* pxInfo = vMBTCPPortMasterGetCurrInfo(); MbSlaveInfo_t* pxInfo = vMBTCPPortMasterFindSlaveInfo(ucCurSlaveIndex);
// If socket active then send data // If the slave is correct and active then send data
if (pxInfo->xSockId > -1) { // otherwise treat slave as died and skip
// Apply TID field to the frame before send if (pxInfo != NULL) {
pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U); if (pxInfo->xSockId < 0) {
pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF); ESP_LOGD(TAG, MB_SLAVE_FMT(", send to died slave, error = %d"),
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"),
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->xError); 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(); vMBMasterPortTimersRespondTimeoutEnable();
xMBMasterPortEventPost(EV_MASTER_FRAME_SENT); xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);

View File

@@ -66,6 +66,7 @@ typedef struct {
int xError; /*!< Socket error */ int xError; /*!< Socket error */
int xRcvErr; /*!< Socket receive error */ int xRcvErr; /*!< Socket receive error */
const char* pcIpAddr; /*!< TCP/UDP IP address */ const char* pcIpAddr; /*!< TCP/UDP IP address */
UCHAR ucSlaveAddr; /*!< Slave short address */
UCHAR* pucRcvBuf; /*!< Receive buffer pointer */ UCHAR* pucRcvBuf; /*!< Receive buffer pointer */
USHORT usRcvPos; /*!< Receive buffer position */ USHORT usRcvPos; /*!< Receive buffer position */
int pcPort; /*!< TCP/UDP port number */ int pcPort; /*!< TCP/UDP port number */
@@ -76,28 +77,37 @@ typedef struct {
} MbSlaveInfo_t; } MbSlaveInfo_t;
typedef struct { typedef struct {
TaskHandle_t xMbTcpTaskHandle; /*!< Master TCP/UDP handling task handle */ TaskHandle_t xMbTcpTaskHandle; /*!< Master TCP/UDP handling task handle */
QueueHandle_t xConnectQueue; /*!< Master connection queue */ QueueHandle_t xConnectQueue; /*!< Master connection queue */
USHORT usPort; /*!< Master TCP/UDP port number */ USHORT usPort; /*!< Master TCP/UDP port number */
USHORT usMbSlaveInfoCount; /*!< Master count of connected slaves */ USHORT usMbSlaveInfoCount; /*!< Master count of connected slaves */
USHORT ucCurSlaveIndex; /*!< Master current processing slave index */ USHORT ucCurSlaveIndex; /*!< Master current processing slave index */
eMBPortIpVer eMbIpVer; /*!< Master IP version */ eMBPortIpVer eMbIpVer; /*!< Master IP version */
eMBPortProto eMbProto; /*!< Master protocol type */ eMBPortProto eMbProto; /*!< Master protocol type */
void* pvNetIface; /*!< Master netif interface pointer */ void* pvNetIface; /*!< Master netif interface pointer */
MbSlaveInfo_t** pxMbSlaveInfo; /*!< Master information structure for each connected slave */ MbSlaveInfo_t** pxMbSlaveInfo; /*!< Master information structure for each connected slave */
MbSlaveInfo_t* pxMbSlaveCurrInfo; /*!< Master current slave information */
} MbPortConfig_t; } 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 ------------------------------*/ /* ----------------------- Function prototypes ------------------------------*/
// The functions below are used by Modbus controller interface to configure Modbus port. // The functions below are used by Modbus controller interface to configure Modbus port.
/** /**
* Registers slave IP address * Registers slave IP address
* *
* @param usIndex index of element in the configuration
* @param pcIpStr IP address to register * @param pcIpStr IP address to register
* @param ucSlaveAddress slave element index
* *
* @return TRUE if address registered successfully, else FALSE * @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 * Keeps FSM event handle and mask then wait for Master stack to start

View File

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

View File

@@ -60,13 +60,13 @@
/* ----------------------- Defines -----------------------------------------*/ /* ----------------------- Defines -----------------------------------------*/
#define MB_TCP_DISCONNECT_TIMEOUT ( CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000000 ) // disconnect timeout in uS #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_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 ) #define MB_TCP_NET_LISTEN_BACKLOG ( SOMAXCONN )
/* ----------------------- Prototypes ---------------------------------------*/ /* ----------------------- Prototypes ---------------------------------------*/
void vMBPortEventClose( void ); void vMBPortEventClose( void );
/* ----------------------- Static variables ---------------------------------*/ /* ----------------------- Static variables ---------------------------------*/
static const char *TAG = "MB_TCP_SLAVE_PORT";
static int xListenSock = -1; static int xListenSock = -1;
static SemaphoreHandle_t xShutdownSemaphore = NULL; static SemaphoreHandle_t xShutdownSemaphore = NULL;
static MbSlavePortConfig_t xConfig = { 0 }; static MbSlavePortConfig_t xConfig = { 0 };
@@ -129,14 +129,14 @@ xMBTCPPortInit( USHORT usTCPPort )
xConfig.pxMbClientInfo = calloc(MB_TCP_PORT_MAX_CONN + 1, sizeof(MbClientInfo_t*)); xConfig.pxMbClientInfo = calloc(MB_TCP_PORT_MAX_CONN + 1, sizeof(MbClientInfo_t*));
if (!xConfig.pxMbClientInfo) { 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; return FALSE;
} }
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xConfig.pxMbClientInfo[idx] = NULL, idx++); for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xConfig.pxMbClientInfo[idx] = NULL, idx++);
xConfig.xRespQueueHandle = xMBTCPPortRespQueueCreate(); xConfig.xRespQueueHandle = xMBTCPPortRespQueueCreate();
if (!xConfig.xRespQueueHandle) { if (!xConfig.xRespQueueHandle) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Response queue allocation failure."); ESP_LOGE(TAG, "Response queue allocation failure.");
return FALSE; return FALSE;
} }
@@ -157,10 +157,10 @@ xMBTCPPortInit( USHORT usTCPPort )
vTaskSuspend(xConfig.xMbTcpTaskHandle); vTaskSuspend(xConfig.xMbTcpTaskHandle);
if (xErr != pdTRUE) if (xErr != pdTRUE)
{ {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Server task creation failure."); ESP_LOGE(TAG, "Server task creation failure.");
vTaskDelete(xConfig.xMbTcpTaskHandle); vTaskDelete(xConfig.xMbTcpTaskHandle);
} else { } else {
ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Protocol stack initialized."); ESP_LOGI(TAG, "Protocol stack initialized.");
bOkay = TRUE; bOkay = TRUE;
} }
return bOkay; return bOkay;
@@ -195,7 +195,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
// Accept new socket connection if not active // Accept new socket connection if not active
xSockId = accept(xListenSockId, (struct sockaddr *)&xSrcAddr, &xSize); xSockId = accept(xListenSockId, (struct sockaddr *)&xSrcAddr, &xSize);
if (xSockId < 0) { 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); close(xSockId);
} else { } else {
// Get the sender's ip address as string // Get the sender's ip address as string
@@ -207,7 +207,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
inet6_ntoa_r(((struct sockaddr_in6 *)&xSrcAddr)->sin6_addr, cAddrStr, sizeof(cAddrStr) - 1); inet6_ntoa_r(((struct sockaddr_in6 *)&xSrcAddr)->sin6_addr, cAddrStr, sizeof(cAddrStr) - 1);
} }
#endif #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); pcStr = calloc(1, strlen(cAddrStr) + 1);
if (pcStr && pcIPAddr) { if (pcStr && pcIPAddr) {
memcpy(pcStr, cAddrStr, strlen(cAddrStr)); memcpy(pcStr, cAddrStr, strlen(cAddrStr));
@@ -223,11 +223,11 @@ static BOOL xMBTCPPortCloseConnection(MbClientInfo_t* pxInfo)
MB_PORT_CHECK(pxInfo, FALSE, "Client info is NULL."); MB_PORT_CHECK(pxInfo, FALSE, "Client info is NULL.");
if (pxInfo->xSockId == -1) { 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; return FALSE;
} }
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) { 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); close(pxInfo->xSockId);
pxInfo->xSockId = -1; pxInfo->xSockId = -1;
@@ -264,7 +264,7 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
} else if (xRet == 0) { } else if (xRet == 0) {
// timeout occurred // timeout occurred
if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) { 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; xRet = ERR_TIMEOUT;
break; break;
} }
@@ -279,12 +279,12 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
pxClientInfo->usTCPFrameBytesLeft, MSG_DONTWAIT); pxClientInfo->usTCPFrameBytesLeft, MSG_DONTWAIT);
if (xLength < 0) { if (xLength < 0) {
// If an error occurred during receiving // 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; xRet = (err_t)xLength;
break; break;
} else if (xLength == 0) { } else if (xLength == 0) {
// Socket connection closed // 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); pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
xRet = ERR_CLSD; xRet = ERR_CLSD;
break; break;
@@ -302,14 +302,14 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
pxClientInfo->usTCPFrameBytesLeft = xLength + MB_TCP_UID - pxClientInfo->usTCPBufPos; pxClientInfo->usTCPFrameBytesLeft = xLength + MB_TCP_UID - pxClientInfo->usTCPBufPos;
} else if (pxClientInfo->usTCPBufPos == (MB_TCP_UID + xLength)) { } else if (pxClientInfo->usTCPBufPos == (MB_TCP_UID + xLength)) {
#if MB_TCP_DEBUG #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 #endif
// Copy TID field from incoming packet // Copy TID field from incoming packet
pxClientInfo->usTidCnt = MB_TCP_GET_FIELD(pxClientInfo->pucTCPBuf, MB_TCP_TID); pxClientInfo->usTidCnt = MB_TCP_GET_FIELD(pxClientInfo->pucTCPBuf, MB_TCP_TID);
xRet = pxClientInfo->usTCPBufPos; xRet = pxClientInfo->usTCPBufPos;
break; break;
} else if ((pxClientInfo->usTCPBufPos + xLength) >= MB_TCP_BUF_SIZE) { } 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 // This should not happen. We can't deal with such a client and
// drop the connection for security reasons. // drop the connection for security reasons.
xRet = ERR_BUF; xRet = ERR_BUF;
@@ -394,7 +394,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
{ {
if (listen(xListenSockFd, MB_TCP_NET_LISTEN_BACKLOG) != 0) 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); close(xListenSockFd);
xListenSockFd = -1; xListenSockFd = -1;
continue; continue;
@@ -402,7 +402,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
} }
// Bind was successful // Bind was successful
pcStr = (pxCurAddr->ai_canonname == NULL) ? (CHAR*)"\0" : pxCurAddr->ai_canonname; 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); xListenSockFd, pcStr, xConfig.usPort, errno);
break; break;
} }
@@ -473,11 +473,11 @@ static void vMBTCPPortServerTask(void *pvParameters)
vTaskDelete(NULL); vTaskDelete(NULL);
} }
// error occurred during wait for read // 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; continue;
} else if (xErr == 0) { } else if (xErr == 0) {
// If timeout happened, something is wrong // 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. // If something happened on the master socket, then its an incoming connection.
@@ -493,21 +493,21 @@ static void vMBTCPPortServerTask(void *pvParameters)
// if request for new connection but no space left // if request for new connection but no space left
if (pxClientInfo != NULL) { if (pxClientInfo != NULL) {
if (xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] == 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 xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] = pxClientInfo; // set last connection info
} else { } else {
// allocate memory for new client info // allocate memory for new client info
pxClientInfo = calloc(1, sizeof(MbClientInfo_t)); pxClientInfo = calloc(1, sizeof(MbClientInfo_t));
if (!pxClientInfo) { if (!pxClientInfo) {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client info allocation fail."); ESP_LOGE(TAG, "Client info allocation fail.");
vMBTCPPortFreeClientInfo(pxClientInfo); vMBTCPPortFreeClientInfo(pxClientInfo);
pxClientInfo = NULL; pxClientInfo = NULL;
} else { } else {
// Accept new client connection // Accept new client connection
pxClientInfo->xSockId = xMBTCPPortAcceptConnection(xListenSock, &pcClientIp); pxClientInfo->xSockId = xMBTCPPortAcceptConnection(xListenSock, &pcClientIp);
if (pxClientInfo->xSockId < 0) { 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. // Accept connection fail, then free client info and continue polling.
vMBTCPPortFreeClientInfo(pxClientInfo); vMBTCPPortFreeClientInfo(pxClientInfo);
pxClientInfo = NULL; pxClientInfo = NULL;
@@ -515,7 +515,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
} }
pxClientInfo->pucTCPBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR)); pxClientInfo->pucTCPBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
if (!pxClientInfo->pucTCPBuf) { 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); vMBTCPPortFreeClientInfo(pxClientInfo);
pxClientInfo = NULL; pxClientInfo = NULL;
continue; continue;
@@ -549,17 +549,17 @@ static void vMBTCPPortServerTask(void *pvParameters)
switch(xErr) switch(xErr)
{ {
case ERR_TIMEOUT: 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, pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
(int)(xTimeStamp - pxClientInfo->xRecvTimeStamp)); (int)(xTimeStamp - pxClientInfo->xRecvTimeStamp));
break; break;
case ERR_CLSD: 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); pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
break; break;
case ERR_BUF: case ERR_BUF:
default: 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); pxClientInfo->xSockId, pxClientInfo->pcIpAddr, xErr);
break; break;
} }
@@ -584,26 +584,26 @@ static void vMBTCPPortServerTask(void *pvParameters)
// Complete frame received, inform state machine to process frame // Complete frame received, inform state machine to process frame
xMBPortEventPost(EV_FRAME_RECEIVED); 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->xSockId, pxClientInfo->pcIpAddr,
pxClientInfo->usTidCnt, xErr); pxClientInfo->usTidCnt, xErr);
// Wait while response is not processed by stack by timeout // Wait while response is not processed by stack by timeout
UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle); UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
if (pucSentBuffer == NULL) { 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); MB_TCP_RESP_TIMEOUT_MS);
} else { } else {
USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID); USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID);
if (usSentTid != pxClientInfo->usTidCnt) { 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); usSentTid, pxClientInfo->usTidCnt);
} }
} }
// Get time stamp of last data update // Get time stamp of last data update
pxClientInfo->xSendTimeStamp = xMBTCPGetTimeStamp(); 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, pxClientInfo->xIndex, pxClientInfo->xSockId,
(int)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp)); (int)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp));
} }
@@ -612,7 +612,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
// client is not ready to be read // client is not ready to be read
int64_t xTime = xMBTCPGetTimeStamp() - pxClientInfo->xRecvTimeStamp; int64_t xTime = xMBTCPGetTimeStamp() - pxClientInfo->xRecvTimeStamp;
if (xTime > MB_TCP_DISCONNECT_TIMEOUT) { 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)); pxClientInfo->xIndex, pxClientInfo->xSockId, (int)(xTime));
xMBTCPPortCloseConnection(pxClientInfo); xMBTCPPortCloseConnection(pxClientInfo);
@@ -621,7 +621,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
xConfig.pxMbClientInfo[i] = NULL; xConfig.pxMbClientInfo[i] = NULL;
} }
} else { } else {
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client %d is disconnected.", i); ESP_LOGE(TAG, "Client %d is disconnected.", i);
} }
} }
} // if ((pxClientInfo != NULL) } // if ((pxClientInfo != NULL)
@@ -643,7 +643,7 @@ vMBTCPPortClose( )
vTaskResume(xConfig.xMbTcpTaskHandle); vTaskResume(xConfig.xMbTcpTaskHandle);
if (xShutdownSemaphore == NULL || // if no semaphore (alloc issues) or couldn't acquire it, just delete the task 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) { 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); vTaskDelete(xConfig.xMbTcpTaskHandle);
} }
if (xShutdownSemaphore) { if (xShutdownSemaphore) {
@@ -705,7 +705,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
// Check if socket writable // Check if socket writable
xErr = select(xConfig.pxCurClientInfo->xSockId + 1, NULL, &xWriteSet, &xErrorSet, &xTimeVal); xErr = select(xConfig.pxCurClientInfo->xSockId + 1, NULL, &xWriteSet, &xErrorSet, &xTimeVal);
if ((xErr == -1) || FD_ISSET(xConfig.pxCurClientInfo->xSockId, &xErrorSet)) { 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); xConfig.pxCurClientInfo->xSockId, errno);
return FALSE; return FALSE;
} }
@@ -717,7 +717,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
// Write message into socket and disable Nagle's algorithm // Write message into socket and disable Nagle's algorithm
xErr = send(xConfig.pxCurClientInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY); xErr = send(xConfig.pxCurClientInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
if (xErr < 0) { 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->xSockId, errno);
xConfig.pxCurClientInfo->xError = xErr; xConfig.pxCurClientInfo->xError = xErr;
} else { } else {
@@ -725,7 +725,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame); vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
} }
} else { } 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); vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
} }
return bFrameSent; return bFrameSent;

View File

@@ -38,14 +38,6 @@
#define POLL_TIMEOUT_MS (1) #define POLL_TIMEOUT_MS (1)
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS) #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 // 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 HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1)) #define 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 // 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 } #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 // Enumeration of modbus device addresses accessed by master device
enum { enum {
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here) 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; break;
} }
} else { } 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); assert(instance_ptr != NULL);
} }
return instance_ptr; return instance_ptr;
@@ -149,7 +143,7 @@ static void master_operation_func(void *arg)
bool alarm_state = false; bool alarm_state = false;
const mb_parameter_descriptor_t* param_descriptor = NULL; 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++) { for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
// Read all found characteristics from slave(s) // 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, err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)temp_data_ptr, &type); (uint8_t*)temp_data_ptr, &type);
if (err == ESP_OK) { 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(char*)param_descriptor->param_units, (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, err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
(uint8_t*)temp_data_ptr, &type); (uint8_t*)temp_data_ptr, &type);
if (err == ESP_OK) { 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(char*)param_descriptor->param_units, (char*)param_descriptor->param_units,
*(uint32_t*)temp_data_ptr); *(uint32_t*)temp_data_ptr);
} else { } 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(int)err, (int)err,
@@ -195,7 +189,7 @@ static void master_operation_func(void *arg)
} }
} }
} else { } 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(int)err, (int)err,
@@ -208,7 +202,7 @@ static void master_operation_func(void *arg)
*(float*)temp_data_ptr = value; *(float*)temp_data_ptr = value;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) || if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) { (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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(char*)param_descriptor->param_units, (char*)param_descriptor->param_units,
@@ -222,7 +216,7 @@ static void master_operation_func(void *arg)
} else { } else {
uint16_t state = *(uint16_t*)temp_data_ptr; uint16_t state = *(uint16_t*)temp_data_ptr;
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF"; 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(char*)param_descriptor->param_units, (char*)param_descriptor->param_units,
@@ -234,7 +228,7 @@ static void master_operation_func(void *arg)
} }
} }
} else { } 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(int)err, (int)err,
@@ -248,13 +242,13 @@ static void master_operation_func(void *arg)
} }
if (alarm_state) { if (alarm_state) {
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.", ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
param_descriptor->cid); param_descriptor->cid);
} else { } 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); MASTER_MAX_RETRY);
} }
ESP_LOGI(MASTER_TAG, "Destroy master..."); ESP_LOGI(TAG, "Destroy master...");
ESP_ERROR_CHECK(mbc_master_destroy()); ESP_ERROR_CHECK(mbc_master_destroy());
} }
@@ -275,13 +269,13 @@ static esp_err_t master_init(void)
void* master_handler = NULL; void* master_handler = NULL;
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler); 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."); "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).", "mb controller initialization fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = mbc_master_setup((void*)&comm); 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).", "mb controller setup fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
@@ -290,23 +284,23 @@ static esp_err_t master_init(void)
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE); CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
err = mbc_master_start(); 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).", "mb controller start fail, returns(0x%x).",
(uint32_t)err); (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); "mb serial set pin failure, uart_set_pin() returned (0x%x).", (uint32_t)err);
// Set driver mode to Half Duplex // Set driver mode to Half Duplex
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_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); "mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err);
vTaskDelay(5); vTaskDelay(5);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters); 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).", "mb controller set descriptor fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized..."); ESP_LOGI(TAG, "Modbus master stack initialized...");
return err; return err;
} }

View File

@@ -40,7 +40,7 @@
| MB_EVENT_COILS_WR) | MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK) #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; 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 mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
// Set UART log level // 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; void* mbc_slave_handler = NULL;
ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller 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 // Set UART driver mode to Half Duplex
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_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(TAG, "Modbus slave stack initialized.");
ESP_LOGI(SLAVE_TAG, "Start modbus test..."); ESP_LOGI(TAG, "Start modbus test...");
// The cycle below will be terminated when parameter holdingRegParams.dataChan0 // The cycle below will be terminated when parameter holdingRegParams.dataChan0
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value. // 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)) { if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
// Get parameter information from parameter queue // Get parameter information from parameter queue
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT)); 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, rw_str,
(uint32_t)reg_info.time_stamp, (uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset, (uint32_t)reg_info.mb_offset,
@@ -198,7 +198,7 @@ void app_main(void)
} }
} else if (event & MB_EVENT_INPUT_REG_RD) { } else if (event & MB_EVENT_INPUT_REG_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT)); 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.time_stamp,
(uint32_t)reg_info.mb_offset, (uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type, (uint32_t)reg_info.type,
@@ -206,7 +206,7 @@ void app_main(void)
(uint32_t)reg_info.size); (uint32_t)reg_info.size);
} else if (event & MB_EVENT_DISCRETE_RD) { } else if (event & MB_EVENT_DISCRETE_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT)); 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.time_stamp,
(uint32_t)reg_info.mb_offset, (uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type, (uint32_t)reg_info.type,
@@ -214,7 +214,7 @@ void app_main(void)
(uint32_t)reg_info.size); (uint32_t)reg_info.size);
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) { } 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_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, rw_str,
(uint32_t)reg_info.time_stamp, (uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset, (uint32_t)reg_info.mb_offset,
@@ -225,7 +225,7 @@ void app_main(void)
} }
} }
// Destroy of Modbus controller on alarm // Destroy of Modbus controller on alarm
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed."); ESP_LOGI(TAG,"Modbus controller destroyed.");
vTaskDelay(100); vTaskDelay(100);
ESP_ERROR_CHECK(mbc_slave_destroy()); 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 logging
import os import os
import re import re
@@ -69,7 +72,7 @@ class DutTestThread(Thread):
super(DutTestThread, self).__init__() super(DutTestThread, self).__init__()
def __enter__(self): def __enter__(self):
logger.debug('Restart %s.' % self.tname) logger.debug('Restart %s.', self.tname)
# Reset DUT first # Reset DUT first
self.dut.reset() self.dut.reset()
# Capture output from the DUT # Capture output from the DUT
@@ -80,7 +83,7 @@ class DutTestThread(Thread):
""" The exit method of context manager """ The exit method of context manager
""" """
if exc_type is not None or exc_value is not None: 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): def run(self):
""" The function implements thread functionality """ The function implements thread functionality
@@ -95,7 +98,7 @@ class DutTestThread(Thread):
# Check DUT exceptions # Check DUT exceptions
dut_exceptions = self.dut.get_exceptions() dut_exceptions = self.dut.get_exceptions()
if 'Guru Meditation Error:' in dut_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 # Mark thread has run to completion without any exceptions
self.data = self.dut.stop_capture_raw_data(capture_id=self.dut.name) 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.*' message = r'.*Waiting IP([0-9]{1,2}) from stdin.*'
# Read all data from previous restart to get prompt correctly # Read all data from previous restart to get prompt correctly
self.dut.read() 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: if int(result[0]) != index:
raise Exception('Incorrect index of IP=%d for %s\n' % (int(result[0]), str(self.dut))) raise RuntimeError('Incorrect index of IP=%s for %s\n' % (result[0], str(self.dut)))
message = 'IP%s=%s' % (result[0], self.ip_addr) # Use the same slave IP address for all characteristics during the test
self.dut.write(message, '\r\n', False) self.dut.write('IP0=' + self.ip_addr, '\n', False)
logger.debug('Sent message for %s: %s' % (self.tname, message)) 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.*' message = r'.*IP\([0-9]+\) = \[([0-9a-zA-Z\.\:]+)\] set from stdin.*'
result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT) result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
logger.debug('Thread %s initialized with slave IP (%s).' % (self.tname, result[0])) logger.debug('Thread %s initialized with slave IP=%s.', self.tname, self.ip_addr)
def test_start(self, timeout_value): def test_start(self, timeout_value):
""" The method to initialize and handle test stages """ The method to initialize and handle test stages
@@ -122,37 +127,37 @@ class DutTestThread(Thread):
def handle_get_ip4(data): def handle_get_ip4(data):
""" Handle get_ip v4 """ 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 self.test_stage = STACK_IPV4
def handle_get_ip6(data): def handle_get_ip6(data):
""" Handle get_ip v6 """ 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 self.test_stage = STACK_IPV6
def handle_init(data): def handle_init(data):
""" Handle init """ 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 self.test_stage = STACK_INIT
def handle_connect(data): def handle_connect(data):
""" Handle connect """ 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 self.test_stage = STACK_CONNECT
def handle_test_start(data): def handle_test_start(data):
""" Handle connect """ 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 self.test_stage = STACK_START
def handle_par_ok(data): def handle_par_ok(data):
""" Handle parameter ok """ 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: if self.test_stage >= STACK_START:
self.param_ok_count += 1 self.param_ok_count += 1
self.test_stage = STACK_PAR_OK self.test_stage = STACK_PAR_OK
@@ -160,14 +165,14 @@ class DutTestThread(Thread):
def handle_par_fail(data): def handle_par_fail(data):
""" Handle parameter fail """ 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.param_fail_count += 1
self.test_stage = STACK_PAR_FAIL self.test_stage = STACK_PAR_FAIL
def handle_destroy(data): def handle_destroy(data):
""" Handle destroy """ 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_stage = STACK_DESTROY
self.test_finish = True self.test_finish = True
@@ -183,7 +188,7 @@ class DutTestThread(Thread):
(re.compile(self.expected[STACK_DESTROY]), handle_destroy), (re.compile(self.expected[STACK_DESTROY]), handle_destroy),
timeout=timeout_value) timeout=timeout_value)
except DUT.ExpectTimeout: 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 self.test_finish = True
@@ -193,14 +198,14 @@ def test_check_mode(dut=None, mode_str=None, value=None):
global logger global logger
try: try:
opt = dut.app.get_sdkconfig()[mode_str] 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 return value == opt
except Exception: 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 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): def test_modbus_communication(env, comm_mode):
global logger global logger
@@ -235,7 +240,7 @@ def test_modbus_communication(env, comm_mode):
master_name = TEST_MASTER_TCP master_name = TEST_MASTER_TCP
else: else:
logger.error('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n') 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 address = None
if test_check_mode(dut_master, 'CONFIG_MB_SLAVE_IP_FROM_STDIN', 'y'): 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') 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: if address is not None:
print('Found IP slave address: %s' % address[0]) print('Found IP slave address: %s' % address[0])
else: 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: 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 # 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: 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_slave_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
dut_master_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT) dut_master_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
if dut_slave_thread.isAlive(): if dut_slave_thread.is_alive():
logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' % logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT)) dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
raise Exception('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' % raise RuntimeError('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT)) (dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
if dut_master_thread.isAlive(): if dut_master_thread.is_alive():
logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' % logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT)) dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
raise Exception('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' % raise RuntimeError('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT)) (dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n' % logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n',
(dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.tname, dut_master_thread.param_fail_count,
dut_slave_thread.tname, dut_slave_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' % logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n',
(dut_master_thread.tname, dut_master_thread.param_ok_count, dut_master_thread.tname, dut_master_thread.param_ok_count,
dut_slave_thread.tname, dut_slave_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 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_fail_count > TEST_READ_MAX_ERR_COUNT) or
(dut_slave_thread.param_ok_count == 0) or (dut_slave_thread.param_ok_count == 0) or
(dut_master_thread.param_ok_count == 0)): (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' % 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_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)) 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') logger.info('TEST_SUCCESS: The Modbus parameter test is completed successfully.\n')
finally: finally:

View File

@@ -1,20 +1,14 @@
// Copyright 2016-2019 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "string.h" // FreeModbus Master Example ESP32
#include <string.h>
#include <sys/queue.h>
#include "esp_log.h" #include "esp_log.h"
#include "esp_check.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_event.h" #include "esp_event.h"
@@ -45,8 +39,6 @@
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS) #define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
#define MB_MDNS_PORT (502) #define MB_MDNS_PORT (502)
#define MASTER_TAG "MASTER_TEST"
// The macro to get offset for parameter in the appropriate structure // 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 HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1)) #define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
@@ -71,12 +63,14 @@
#endif #endif
#define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp" #define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp"
static const char *TAG = "MASTER_TEST";
// Enumeration of modbus device addresses accessed by master device // 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 // Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
enum { enum {
MB_DEVICE_ADDR1 = 1, // Slave address 1 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) // 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 }, 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, { 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 }, 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 }, 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 }, 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 }, 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, { 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 }, 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 // 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 // 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 // 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 #if CONFIG_MB_SLAVE_IP_FROM_STDIN
"FROM_STDIN", // Address corresponds to MB_DEVICE_ADDR1 and set to predefined value by user "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 #elif CONFIG_MB_MDNS_IP_RESOLVER
NULL,
NULL,
NULL, NULL,
NULL NULL
#endif #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 #if CONFIG_MB_SLAVE_IP_FROM_STDIN
// Scan IP address according to IPV settings // Scan IP address according to IPV settings
@@ -186,8 +186,8 @@ static int master_get_slave_ip_stdin(char** addr_table)
fputc('\n', stdout); fputc('\n', stdout);
ip_str = master_scan_addr(&index, buf); ip_str = master_scan_addr(&index, buf);
if (ip_str != NULL) { if (ip_str != NULL) {
ESP_LOGI(MASTER_TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str); ESP_LOGI(TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
if ((ip_cnt >= MB_DEVICE_COUNT) || (index != ip_cnt)) { if ((ip_cnt >= ip_table_sz) || (index != ip_cnt)) {
addr_table[ip_cnt] = NULL; addr_table[ip_cnt] = NULL;
break; break;
} }
@@ -199,10 +199,10 @@ static int master_get_slave_ip_stdin(char** addr_table)
} }
} else { } else {
if (addr_table[ip_cnt]) { 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++; ip_cnt++;
} else { } 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; break;
} }
} }
@@ -212,6 +212,16 @@ static int master_get_slave_ip_stdin(char** addr_table)
#elif CONFIG_MB_MDNS_IP_RESOLVER #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 // convert MAC from binary format to string
static inline char* gen_mac_str(const uint8_t* mac, char* pref, char* mac_str) 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()); ESP_ERROR_CHECK(mdns_init());
// set mDNS hostname (required if you want to advertise services) // set mDNS hostname (required if you want to advertise services)
ESP_ERROR_CHECK(mdns_hostname_set(hostname)); 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 // set default mDNS instance name
ESP_ERROR_CHECK(mdns_instance_name_set(MB_MDNS_INSTANCE("esp32_"))); 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; 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) mb_tcp_addr_type_t addr_type)
{ {
if (!name || !result) { if (!short_addr || !result || !resolved_ip) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
mdns_result_t* r = result; mdns_result_t* r = result;
int t; int t;
char* slave_ip = NULL; 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) { for (; r ; r = r->next) {
if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) { if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
continue; 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 // Check host name for Modbus short address and
// append it into slave ip address table // 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); printf(" PTR : %s\n", r->instance_name);
if (r->txt_count) { if (r->txt_count) {
printf(" TXT : [%u] ", 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); slave_ip = master_get_slave_ip_str(r->addr, addr_type);
if (slave_ip) { 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; *resolved_ip = slave_ip;
return ESP_OK; return ESP_OK;
} }
} }
} }
*resolved_ip = NULL; *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; return ESP_ERR_NOT_FOUND;
} }
static int master_create_slave_list(mdns_result_t* results, char** addr_table, 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) { if (!results) {
return -1; 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]; const mb_parameter_descriptor_t* pdescr = &device_parameters[0];
char** ip_table = addr_table; char** ip_table = addr_table;
char slave_name[22] = {0};
char* slave_ip = NULL; char* slave_ip = NULL;
slave_addr_entry_t *it;
for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++) { 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)) { slave_addr = pdescr->mb_slave_addr;
ESP_LOGI(MASTER_TAG, "Fail to create instance name for index: %d", addr);
abort(); 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]) { if (!it) {
esp_err_t err = master_resolve_slave(slave_name, results, &slave_ip, addr_type); // 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) { if (err != ESP_OK) {
ESP_LOGE(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, failed to resolve!", ESP_LOGE(TAG, "Index: %d, sl_addr: %d, failed to resolve!", i, slave_addr);
i, addr, slave_name);
// Set correspond index to NULL indicate host not resolved // Set correspond index to NULL indicate host not resolved
ip_table[addr - 1] = NULL; ip_table[ip_index] = NULL;
continue; continue;
} }
ip_table[addr - 1] = slave_ip; //slave_name; // Register new slave address information
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, resolve to IP: [%s]", slave_addr_entry_t* new_slave_entry = (slave_addr_entry_t*) heap_caps_malloc(sizeof(slave_addr_entry_t),
i, addr, slave_name, slave_ip); MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
resolved++; 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 { } else {
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, set to IP: [%s]", ip_table[ip_index] = it ? it->ip_address : ip_table[ip_index];
i, addr, slave_name, ip_table[addr - 1]); ESP_LOGI(TAG, "Index: %d, sl_addr: %d, set to IP: [%s]",
resolved++; i, slave_addr, ip_table[ip_index]);
} cid_resolve_cnt++;
}
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;
} }
} }
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, static int master_query_slave_service(const char * service_name, const char * proto,
mb_tcp_addr_type_t addr_type) 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; mdns_result_t* results = NULL;
int count = 0; int count = 0;
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results); esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
if(err){ 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; return count;
} }
if(!results){ if(!results){
ESP_LOGW(MASTER_TAG, "No results found!"); ESP_LOGW(TAG, "No results found!");
return count; 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); mdns_query_results_free(results);
return count; return count;
} }
#endif #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 // 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) 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; break;
} }
} else { } 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); assert(instance_ptr != NULL);
} }
return instance_ptr; return instance_ptr;
@@ -429,7 +477,7 @@ static void master_operation_func(void *arg)
bool alarm_state = false; bool alarm_state = false;
const mb_parameter_descriptor_t* param_descriptor = NULL; 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++) { for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
// Read all found characteristics from slave(s) // Read all found characteristics from slave(s)
@@ -449,7 +497,7 @@ static void master_operation_func(void *arg)
*(float*)temp_data_ptr = value; *(float*)temp_data_ptr = value;
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) || if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) { (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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(char*)param_descriptor->param_units, (char*)param_descriptor->param_units,
@@ -463,7 +511,7 @@ static void master_operation_func(void *arg)
} else { } else {
uint16_t state = *(uint16_t*)temp_data_ptr; uint16_t state = *(uint16_t*)temp_data_ptr;
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF"; 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(char*)param_descriptor->param_units, (char*)param_descriptor->param_units,
@@ -475,7 +523,7 @@ static void master_operation_func(void *arg)
} }
} }
} else { } 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, param_descriptor->cid,
(char*)param_descriptor->param_key, (char*)param_descriptor->param_key,
(int)err, (int)err,
@@ -488,13 +536,13 @@ static void master_operation_func(void *arg)
} }
if (alarm_state) { if (alarm_state) {
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.", ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
param_descriptor->cid); param_descriptor->cid);
} else { } 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); MASTER_MAX_RETRY);
} }
ESP_LOGI(MASTER_TAG, "Destroy master..."); ESP_LOGI(TAG, "Destroy master...");
vTaskDelay(100); 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()); ESP_ERROR_CHECK(nvs_flash_erase());
result = nvs_flash_init(); result = nvs_flash_init();
} }
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"nvs_flash_init fail, returns(0x%x).", "nvs_flash_init fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
result = esp_netif_init(); result = esp_netif_init();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"esp_netif_init fail, returns(0x%x).", "esp_netif_init fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
result = esp_event_loop_create_default(); result = esp_event_loop_create_default();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"esp_event_loop_create_default fail, returns(0x%x).", "esp_event_loop_create_default fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
#if CONFIG_MB_MDNS_IP_RESOLVER #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 // Read "Establishing Wi-Fi or Ethernet Connection" section in
// examples/protocols/README.md for more information about this function. // examples/protocols/README.md for more information about this function.
result = example_connect(); result = example_connect();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"example_connect fail, returns(0x%x).", "example_connect fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
#if CONFIG_EXAMPLE_CONNECT_WIFI #if CONFIG_EXAMPLE_CONNECT_WIFI
result = esp_wifi_set_ps(WIFI_PS_NONE); result = esp_wifi_set_ps(WIFI_PS_NONE);
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"esp_wifi_set_ps fail, returns(0x%x).", "esp_wifi_set_ps fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
#endif #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); res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
} }
if (res < num_device_parameters) { 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(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, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
return ESP_ERR_NOT_FOUND; return ESP_ERR_NOT_FOUND;
} }
mdns_free(); mdns_free();
#elif CONFIG_MB_SLAVE_IP_FROM_STDIN #elif CONFIG_MB_SLAVE_IP_FROM_STDIN
int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table); int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table);
if (ip_cnt) { 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 { } 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; return ESP_ERR_NOT_FOUND;
} }
#endif #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) static esp_err_t destroy_services(void)
{ {
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
#if CONFIG_MB_MDNS_IP_RESOLVER master_destroy_slave_list(slave_ip_address_table, ip_table_sz);
master_destroy_slave_list(slave_ip_address_table);
#endif
err = example_disconnect(); err = example_disconnect();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"example_disconnect fail, returns(0x%x).", "example_disconnect fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = esp_event_loop_delete_default(); err = esp_event_loop_delete_default();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"esp_event_loop_delete_default fail, returns(0x%x).", "esp_event_loop_delete_default fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = esp_netif_deinit(); err = esp_netif_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"esp_netif_deinit fail, returns(0x%x).", "esp_netif_deinit fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = nvs_flash_deinit(); err = nvs_flash_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"nvs_flash_deinit fail, returns(0x%x).", "nvs_flash_deinit fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
return err; return err;
@@ -596,30 +643,30 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
void* master_handler = NULL; void* master_handler = NULL;
esp_err_t err = mbc_master_init_tcp(&master_handler); esp_err_t err = mbc_master_init_tcp(&master_handler);
ESP_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"mb controller initialization fail."); "mb controller initialization fail.");
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"mb controller initialization fail, returns(0x%x).", "mb controller initialization fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = mbc_master_setup((void*)comm_info); err = mbc_master_setup((void*)comm_info);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"mb controller setup fail, returns(0x%x).", "mb controller setup fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters); err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"mb controller set descriptor fail, returns(0x%x).", "mb controller set descriptor fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized..."); ESP_LOGI(TAG, "Modbus master stack initialized...");
err = mbc_master_start(); err = mbc_master_start();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"mb controller start fail, returns(0x%x).", "mb controller start fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
vTaskDelay(5); 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) static esp_err_t master_destroy(void)
{ {
esp_err_t err = mbc_master_destroy(); esp_err_t err = mbc_master_destroy();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
MASTER_TAG, TAG,
"mbc_master_destroy fail, returns(0x%x).", "mbc_master_destroy fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
ESP_LOGI(MASTER_TAG, "Modbus master stack destroy..."); ESP_LOGI(TAG, "Modbus master stack destroy...");
return err; return err;
} }

View File

@@ -2,7 +2,7 @@ menu "Modbus Example Configuration"
config MB_SLAVE_ADDR config MB_SLAVE_ADDR
int "Modbus slave address" int "Modbus slave address"
range 1 127 range 1 255
default 1 default 1
help help
This is the Modbus slave address in the network. 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 <stdio.h>
#include "esp_err.h" #include "esp_err.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_check.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_event.h" #include "esp_event.h"
@@ -47,7 +48,7 @@
| MB_EVENT_COILS_WR) | MB_EVENT_COILS_WR)
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK) #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; 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 mb_param_info_t reg_info; // keeps the Modbus registers access information
ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized."); ESP_LOGI(TAG, "Modbus slave stack initialized.");
ESP_LOGI(SLAVE_TAG, "Start modbus test..."); ESP_LOGI(TAG, "Start modbus test...");
// The cycle below will be terminated when parameter holding_data0 // The cycle below will be terminated when parameter holding_data0
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value. // incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) { 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)) { if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
// Get parameter information from parameter queue // Get parameter information from parameter queue
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT)); 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, rw_str,
(uint32_t)reg_info.time_stamp, (uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset, (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) { } else if (event & MB_EVENT_INPUT_REG_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT)); 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.time_stamp,
(uint32_t)reg_info.mb_offset, (uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type, (uint32_t)reg_info.type,
@@ -199,7 +200,7 @@ static void slave_operation_func(void *arg)
(uint32_t)reg_info.size); (uint32_t)reg_info.size);
} else if (event & MB_EVENT_DISCRETE_RD) { } else if (event & MB_EVENT_DISCRETE_RD) {
ESP_ERROR_CHECK(mbc_slave_get_param_info(&reg_info, MB_PAR_INFO_GET_TOUT)); 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.time_stamp,
(uint32_t)reg_info.mb_offset, (uint32_t)reg_info.mb_offset,
(uint32_t)reg_info.type, (uint32_t)reg_info.type,
@@ -207,7 +208,7 @@ static void slave_operation_func(void *arg)
(uint32_t)reg_info.size); (uint32_t)reg_info.size);
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) { } 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_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, rw_str,
(uint32_t)reg_info.time_stamp, (uint32_t)reg_info.time_stamp,
(uint32_t)reg_info.mb_offset, (uint32_t)reg_info.mb_offset,
@@ -218,7 +219,7 @@ static void slave_operation_func(void *arg)
} }
} }
// Destroy of Modbus controller on alarm // Destroy of Modbus controller on alarm
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed."); ESP_LOGI(TAG,"Modbus controller destroyed.");
vTaskDelay(100); vTaskDelay(100);
} }
@@ -229,18 +230,18 @@ static esp_err_t init_services(void)
ESP_ERROR_CHECK(nvs_flash_erase()); ESP_ERROR_CHECK(nvs_flash_erase());
result = nvs_flash_init(); result = nvs_flash_init();
} }
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"nvs_flash_init fail, returns(0x%x).", "nvs_flash_init fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
result = esp_netif_init(); result = esp_netif_init();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"esp_netif_init fail, returns(0x%x).", "esp_netif_init fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
result = esp_event_loop_create_default(); result = esp_event_loop_create_default();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"esp_event_loop_create_default fail, returns(0x%x).", "esp_event_loop_create_default fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
#if CONFIG_MB_MDNS_IP_RESOLVER #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 // Read "Establishing Wi-Fi or Ethernet Connection" section in
// examples/protocols/README.md for more information about this function. // examples/protocols/README.md for more information about this function.
result = example_connect(); result = example_connect();
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"example_connect fail, returns(0x%x).", "example_connect fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
#if CONFIG_EXAMPLE_CONNECT_WIFI #if CONFIG_EXAMPLE_CONNECT_WIFI
result = esp_wifi_set_ps(WIFI_PS_NONE); result = esp_wifi_set_ps(WIFI_PS_NONE);
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"esp_wifi_set_ps fail, returns(0x%x).", "esp_wifi_set_ps fail, returns(0x%x).",
(uint32_t)result); (uint32_t)result);
#endif #endif
@@ -270,23 +271,23 @@ static esp_err_t destroy_services(void)
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
err = example_disconnect(); err = example_disconnect();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"example_disconnect fail, returns(0x%x).", "example_disconnect fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = esp_event_loop_delete_default(); err = esp_event_loop_delete_default();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"esp_event_loop_delete_default fail, returns(0x%x).", "esp_event_loop_delete_default fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = esp_netif_deinit(); err = esp_netif_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"esp_netif_deinit fail, returns(0x%x).", "esp_netif_deinit fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
err = nvs_flash_deinit(); err = nvs_flash_deinit();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"nvs_flash_deinit fail, returns(0x%x).", "nvs_flash_deinit fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
#if CONFIG_MB_MDNS_IP_RESOLVER #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 // Initialization of Modbus controller
esp_err_t err = mbc_slave_init_tcp(&slave_handler); esp_err_t err = mbc_slave_init_tcp(&slave_handler);
ESP_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mb controller initialization fail."); "mb controller initialization fail.");
comm_info->ip_addr = NULL; // Bind to any address 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 // Setup communication parameters and start stack
err = mbc_slave_setup((void*)comm_info); err = mbc_slave_setup((void*)comm_info);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_setup fail, returns(0x%x).", "mbc_slave_setup fail, returns(0x%x).",
(uint32_t)err); (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.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 reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
err = mbc_slave_set_descriptor(reg_area); err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).", "mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err); (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.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 reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
err = mbc_slave_set_descriptor(reg_area); err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).", "mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err); (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.address = (void*)&input_reg_params.input_data0;
reg_area.size = sizeof(float) << 2; reg_area.size = sizeof(float) << 2;
err = mbc_slave_set_descriptor(reg_area); err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).", "mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
reg_area.type = MB_PARAM_INPUT; 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.address = (void*)&input_reg_params.input_data4;
reg_area.size = sizeof(float) << 2; reg_area.size = sizeof(float) << 2;
err = mbc_slave_set_descriptor(reg_area); err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).", "mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err); (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.address = (void*)&coil_reg_params;
reg_area.size = sizeof(coil_reg_params); reg_area.size = sizeof(coil_reg_params);
err = mbc_slave_set_descriptor(reg_area); err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).", "mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err); (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.address = (void*)&discrete_reg_params;
reg_area.size = sizeof(discrete_reg_params); reg_area.size = sizeof(discrete_reg_params);
err = mbc_slave_set_descriptor(reg_area); err = mbc_slave_set_descriptor(reg_area);
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_set_descriptor fail, returns(0x%x).", "mbc_slave_set_descriptor fail, returns(0x%x).",
(uint32_t)err); (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 // Starts of modbus controller and stack
err = mbc_slave_start(); err = mbc_slave_start();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_start fail, returns(0x%x).", "mbc_slave_start fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
vTaskDelay(5); 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) static esp_err_t slave_destroy(void)
{ {
esp_err_t err = mbc_slave_destroy(); esp_err_t err = mbc_slave_destroy();
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
SLAVE_TAG, TAG,
"mbc_slave_destroy fail, returns(0x%x).", "mbc_slave_destroy fail, returns(0x%x).",
(uint32_t)err); (uint32_t)err);
return err; return err;
@@ -418,7 +419,7 @@ void app_main(void)
ESP_ERROR_CHECK(init_services()); ESP_ERROR_CHECK(init_services());
// Set UART log level // 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 }; mb_communication_info_t comm_info = { 0 };