mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 06:11:06 +00:00 
			
		
		
		
	freemodbus: allow address gaps in master data dictionary (support of UID field in MBAP) (backport v4.3)
This commit is contained in:
		
				
					committed by
					
						
						Jiang Jiang Jian
					
				
			
			
				
	
			
			
			
						parent
						
							5bad27d0d5
						
					
				
				
					commit
					073da59d27
				
			@@ -18,6 +18,8 @@
 | 
			
		||||
#include "esp_modbus_master.h"  // for public interface defines
 | 
			
		||||
#include "esp_modbus_callbacks.h"   // for callback functions
 | 
			
		||||
 | 
			
		||||
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_MASTER";
 | 
			
		||||
 | 
			
		||||
// This file implements public API for Modbus master controller.
 | 
			
		||||
// These functions are wrappers for interface functions of the controller
 | 
			
		||||
static mb_master_interface_t* master_interface_ptr = NULL;
 | 
			
		||||
 
 | 
			
		||||
@@ -43,6 +43,7 @@ static uint8_t mb_slave_id[] = { MB_ID_BYTE0(MB_CONTROLLER_SLAVE_ID),
 | 
			
		||||
 | 
			
		||||
// Common interface pointer for slave port
 | 
			
		||||
static mb_slave_interface_t* slave_interface_ptr = NULL;
 | 
			
		||||
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_SLAVE";
 | 
			
		||||
 | 
			
		||||
// Searches the register in the area specified by type, returns descriptor if found, else NULL
 | 
			
		||||
static mb_descr_entry_t* mbc_slave_find_reg_descriptor(mb_param_type_t type, uint16_t addr, size_t regs)
 | 
			
		||||
@@ -259,11 +260,11 @@ static esp_err_t mbc_slave_send_param_info(mb_event_group_t par_type, uint16_t m
 | 
			
		||||
    par_info.mb_offset = mb_offset;
 | 
			
		||||
    BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, &par_info, MB_PAR_INFO_TOUT);
 | 
			
		||||
    if (pdTRUE == status) {
 | 
			
		||||
        ESP_LOGD(MB_SLAVE_TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d",
 | 
			
		||||
        ESP_LOGD(TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d",
 | 
			
		||||
                par_type, (uint32_t)par_address, par_size);
 | 
			
		||||
        error = ESP_OK;
 | 
			
		||||
    } else if (errQUEUE_FULL == status) {
 | 
			
		||||
        ESP_LOGD(MB_SLAVE_TAG, "Parameter queue is overflowed.");
 | 
			
		||||
        ESP_LOGD(TAG, "Parameter queue is overflowed.");
 | 
			
		||||
    }
 | 
			
		||||
    return error;
 | 
			
		||||
}
 | 
			
		||||
@@ -276,7 +277,7 @@ static esp_err_t mbc_slave_send_param_access_notification(mb_event_group_t event
 | 
			
		||||
    esp_err_t err = ESP_FAIL;
 | 
			
		||||
    mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, (EventBits_t)event);
 | 
			
		||||
    if (bits & event) {
 | 
			
		||||
        ESP_LOGD(MB_SLAVE_TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event);
 | 
			
		||||
        ESP_LOGD(TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event);
 | 
			
		||||
        err = ESP_OK;
 | 
			
		||||
    }
 | 
			
		||||
    return err;
 | 
			
		||||
 
 | 
			
		||||
@@ -22,6 +22,24 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if __has_include("esp_check.h")
 | 
			
		||||
#include "esp_check.h"
 | 
			
		||||
 | 
			
		||||
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) ESP_RETURN_ON_FALSE(a, err_code, tag, format __VA_OPT__(,) __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
// if cannot include esp_check then use custom check macro
 | 
			
		||||
 | 
			
		||||
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) do {                                         \
 | 
			
		||||
        if (!(a)) {                                                                              \
 | 
			
		||||
            ESP_LOGE(tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__);        \
 | 
			
		||||
            return err_code;                                                                               \
 | 
			
		||||
        }                                                                                                  \
 | 
			
		||||
} while(0)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MB_CONTROLLER_STACK_SIZE            (CONFIG_FMB_CONTROLLER_STACK_SIZE)   // Stack size for Modbus controller
 | 
			
		||||
#define MB_CONTROLLER_PRIORITY              (CONFIG_FMB_PORT_TASK_PRIO - 1)    // priority of MB controller task
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,12 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MB_MASTER_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
#define MB_MASTER_ASSERT(con) do { \
 | 
			
		||||
        if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
/*!
 | 
			
		||||
 * \brief Modbus descriptor table parameter type defines.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,12 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MB_SLAVE_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
 | 
			
		||||
 | 
			
		||||
#define MB_SLAVE_ASSERT(con) do { \
 | 
			
		||||
        if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Parameter access event information type
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -12,9 +12,11 @@
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _MB_CONTROLLER_MASTER_H
 | 
			
		||||
#define _MB_CONTROLLER_MASTER_H
 | 
			
		||||
 | 
			
		||||
#include <sys/queue.h>              // for list
 | 
			
		||||
#include "freertos/FreeRTOS.h"      // for task creation and queue access
 | 
			
		||||
#include "freertos/task.h"          // for task api access
 | 
			
		||||
#include "freertos/event_groups.h"  // for event groups
 | 
			
		||||
@@ -28,18 +30,6 @@
 | 
			
		||||
 | 
			
		||||
/* ----------------------- Defines ------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
#define MB_MASTER_TAG "MB_CONTROLLER_MASTER"
 | 
			
		||||
 | 
			
		||||
#define MB_MASTER_CHECK(a, ret_val, str, ...) \
 | 
			
		||||
    if (!(a)) { \
 | 
			
		||||
        ESP_LOGE(MB_MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
 | 
			
		||||
        return (ret_val); \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define MB_MASTER_ASSERT(con) do { \
 | 
			
		||||
        if (!(con)) { ESP_LOGE(MB_MASTER_TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Request mode for parameter to use in data dictionary
 | 
			
		||||
 */
 | 
			
		||||
@@ -59,6 +49,19 @@ typedef struct {
 | 
			
		||||
    uart_parity_t parity;                   /*!< Modbus UART parity settings */
 | 
			
		||||
} mb_master_comm_info_t;
 | 
			
		||||
 | 
			
		||||
#if MB_MASTER_TCP_ENABLED
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Modbus slave addr list item for the master
 | 
			
		||||
 */
 | 
			
		||||
typedef struct mb_slave_addr_entry_s{
 | 
			
		||||
    uint16_t index;                             /*!< Index of the slave address */
 | 
			
		||||
    const char* ip_address;                     /*!< IP address string of the slave */
 | 
			
		||||
    uint8_t slave_addr;                         /*!< Short slave address */
 | 
			
		||||
    void* p_data;                               /*!< pointer to data structure */
 | 
			
		||||
    LIST_ENTRY(mb_slave_addr_entry_s) entries;  /*!< The slave address entry */
 | 
			
		||||
} mb_slave_addr_entry_t;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Modbus controller handler structure
 | 
			
		||||
 */
 | 
			
		||||
@@ -71,6 +74,10 @@ typedef struct {
 | 
			
		||||
    EventGroupHandle_t mbm_event_group;                 /*!< Modbus controller event group */
 | 
			
		||||
    const mb_parameter_descriptor_t* mbm_param_descriptor_table; /*!< Modbus controller parameter description table */
 | 
			
		||||
    size_t mbm_param_descriptor_size;                   /*!< Modbus controller parameter description table size*/
 | 
			
		||||
#if MB_MASTER_TCP_ENABLED
 | 
			
		||||
    LIST_HEAD(mbm_slave_addr_info_, mb_slave_addr_entry_s) mbm_slave_list; /*!< Slave address information list */
 | 
			
		||||
    uint16_t mbm_slave_list_count;
 | 
			
		||||
#endif
 | 
			
		||||
} mb_master_options_t;
 | 
			
		||||
 | 
			
		||||
typedef esp_err_t (*iface_get_cid_info)(uint16_t, const mb_parameter_descriptor_t**); /*!< Interface get_cid_info method */
 | 
			
		||||
 
 | 
			
		||||
@@ -31,18 +31,6 @@
 | 
			
		||||
#define MB_CONTROLLER_NOTIFY_QUEUE_SIZE     (CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE) // Number of messages in parameter notification queue
 | 
			
		||||
#define MB_CONTROLLER_NOTIFY_TIMEOUT        (pdMS_TO_TICKS(CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT)) // notification timeout
 | 
			
		||||
 | 
			
		||||
#define MB_SLAVE_TAG "MB_CONTROLLER_SLAVE"
 | 
			
		||||
 | 
			
		||||
#define MB_SLAVE_CHECK(a, ret_val, str, ...) \
 | 
			
		||||
    if (!(a)) { \
 | 
			
		||||
        ESP_LOGE(MB_SLAVE_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
 | 
			
		||||
        return (ret_val); \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#define MB_SLAVE_ASSERT(con) do { \
 | 
			
		||||
        if (!(con)) { ESP_LOGE(MB_SLAVE_TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Device communication parameters for master
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ extern BOOL xMBMasterPortSerialTxPoll(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
 | 
			
		||||
static const char *TAG = "MB_CONTROLLER_MASTER";
 | 
			
		||||
 | 
			
		||||
// Modbus event processing task
 | 
			
		||||
static void modbus_master_task(void *pvParameters)
 | 
			
		||||
@@ -238,7 +239,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
 | 
			
		||||
                                                        (USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
 | 
			
		||||
            ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
 | 
			
		||||
                                                    __FUNCTION__, mb_command);
 | 
			
		||||
            mb_error = MB_MRE_NO_REG;
 | 
			
		||||
            break;
 | 
			
		||||
@@ -269,7 +270,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
 | 
			
		||||
            ESP_LOGE(TAG, "%s: Incorrect return code (%x) ",
 | 
			
		||||
                                                                __FUNCTION__, mb_error);
 | 
			
		||||
            error = ESP_FAIL;
 | 
			
		||||
            break;
 | 
			
		||||
@@ -324,12 +325,12 @@ static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_para
 | 
			
		||||
            if (mode != MB_PARAM_WRITE) {
 | 
			
		||||
                command = MB_FUNC_READ_DISCRETE_INPUTS;
 | 
			
		||||
            } else {
 | 
			
		||||
                ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)",
 | 
			
		||||
                ESP_LOGE(TAG, "%s: Incorrect mode (%u)",
 | 
			
		||||
                            __FUNCTION__, (uint8_t)mode);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)",
 | 
			
		||||
            ESP_LOGE(TAG, "%s: Incorrect param type (%u)",
 | 
			
		||||
                            __FUNCTION__, param_type);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
@@ -401,16 +402,16 @@ static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
 | 
			
		||||
        // Send request to read characteristic data
 | 
			
		||||
        error = mbc_serial_master_send_request(&request, value_ptr);
 | 
			
		||||
        if (error == ESP_OK) {
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
 | 
			
		||||
            ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
 | 
			
		||||
                                    __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
        } else {
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
 | 
			
		||||
            ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
 | 
			
		||||
                                            __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
        }
 | 
			
		||||
        // Set the type of parameter found in the table
 | 
			
		||||
        *type = reg_info.param_type;
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
 | 
			
		||||
        ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
 | 
			
		||||
                                                    __FUNCTION__, reg_info.cid);
 | 
			
		||||
        error = ESP_ERR_INVALID_ARG;
 | 
			
		||||
    }
 | 
			
		||||
@@ -436,16 +437,16 @@ static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
 | 
			
		||||
        // Send request to write characteristic data
 | 
			
		||||
        error = mbc_serial_master_send_request(&request, value_ptr);
 | 
			
		||||
        if (error == ESP_OK) {
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
 | 
			
		||||
            ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
 | 
			
		||||
                                    __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
        } else {
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
 | 
			
		||||
            ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
 | 
			
		||||
                                    __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
        }
 | 
			
		||||
        // Set the type of parameter found in the table
 | 
			
		||||
        *type = reg_info.param_type;
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
 | 
			
		||||
        ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
 | 
			
		||||
                                    __FUNCTION__, reg_info.cid);
 | 
			
		||||
        error = ESP_ERR_INVALID_ARG;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -29,6 +29,7 @@
 | 
			
		||||
 | 
			
		||||
// Shared pointer to interface structure
 | 
			
		||||
static mb_slave_interface_t* mbs_interface_ptr = NULL;
 | 
			
		||||
static const char *TAG = "MB_CONTROLLER_SLAVE";
 | 
			
		||||
 | 
			
		||||
// Modbus task function
 | 
			
		||||
static void modbus_slave_task(void *pvParameters)
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@
 | 
			
		||||
#include <sys/time.h>               // for calculation of time stamp in milliseconds
 | 
			
		||||
#include "esp_log.h"                // for log_write
 | 
			
		||||
#include <string.h>                 // for memcpy
 | 
			
		||||
#include <sys/queue.h>              // for list
 | 
			
		||||
#include "freertos/FreeRTOS.h"      // for task creation and queue access
 | 
			
		||||
#include "freertos/task.h"          // for task api access
 | 
			
		||||
#include "freertos/event_groups.h"  // for event groups
 | 
			
		||||
@@ -42,6 +43,59 @@
 | 
			
		||||
#define MB_TCP_CONNECTION_TOUT pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000)
 | 
			
		||||
 | 
			
		||||
static mb_master_interface_t* mbm_interface_ptr = NULL;
 | 
			
		||||
static const char *TAG = "MB_CONTROLLER_MASTER";
 | 
			
		||||
 | 
			
		||||
// Searches the slave address in the address info list and returns address info if found, else NULL
 | 
			
		||||
static mb_slave_addr_entry_t* mbc_tcp_master_find_slave_addr(uint8_t slave_addr)
 | 
			
		||||
{
 | 
			
		||||
    mb_slave_addr_entry_t* it;
 | 
			
		||||
    mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
 | 
			
		||||
 | 
			
		||||
    if (LIST_EMPTY(&mbm_opts->mbm_slave_list)) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    LIST_FOREACH(it, &mbm_opts->mbm_slave_list, entries) {
 | 
			
		||||
        if (slave_addr == it->slave_addr) {
 | 
			
		||||
            return it;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static esp_err_t mbc_tcp_master_add_slave(uint16_t index, uint8_t slave_addr, const char* ip_addr)
 | 
			
		||||
{
 | 
			
		||||
    MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
 | 
			
		||||
    // Initialize interface properties
 | 
			
		||||
    mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
 | 
			
		||||
 | 
			
		||||
    mb_slave_addr_entry_t* new_slave_entry = (mb_slave_addr_entry_t*) heap_caps_malloc(sizeof(mb_slave_addr_entry_t),
 | 
			
		||||
                                               MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
 | 
			
		||||
    MB_MASTER_CHECK((new_slave_entry != NULL), ESP_ERR_NO_MEM, "mb can not allocate memory for slave entry.");
 | 
			
		||||
    new_slave_entry->index = index;
 | 
			
		||||
    new_slave_entry->ip_address = ip_addr;
 | 
			
		||||
    new_slave_entry->slave_addr = slave_addr;
 | 
			
		||||
    new_slave_entry->p_data = NULL;
 | 
			
		||||
    LIST_INSERT_HEAD(&mbm_opts->mbm_slave_list, new_slave_entry, entries);
 | 
			
		||||
    MB_MASTER_CHECK((mbm_opts->mbm_slave_list_count < (MB_TCP_PORT_MAX_CONN - 1)),
 | 
			
		||||
                        ESP_ERR_INVALID_STATE, "mb max number of slaves < %d.", MB_TCP_PORT_MAX_CONN);
 | 
			
		||||
    mbm_opts->mbm_slave_list_count++;
 | 
			
		||||
    return ESP_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void mbc_tcp_master_free_slave_list(void)
 | 
			
		||||
{
 | 
			
		||||
    mb_slave_addr_entry_t* it;
 | 
			
		||||
    MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
 | 
			
		||||
 | 
			
		||||
    // Initialize interface properties
 | 
			
		||||
    mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
 | 
			
		||||
 | 
			
		||||
    LIST_FOREACH(it, &mbm_opts->mbm_slave_list, entries) {
 | 
			
		||||
        LIST_REMOVE(it, entries);
 | 
			
		||||
        mbm_opts->mbm_slave_list_count--;
 | 
			
		||||
        free(it);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Modbus event processing task
 | 
			
		||||
static void modbus_tcp_master_task(void *pvParameters)
 | 
			
		||||
@@ -113,21 +167,21 @@ static esp_err_t mbc_tcp_master_start(void)
 | 
			
		||||
    vMBTCPPortMasterSetNetOpt(comm_info->ip_netif_ptr, ip_ver, proto);
 | 
			
		||||
    vMBTCPPortMasterTaskStart();
 | 
			
		||||
 | 
			
		||||
    // Add slave IP address for each slave to initialise connection
 | 
			
		||||
    for (int idx = 0; *comm_ip_table != NULL; idx++, comm_ip_table++)
 | 
			
		||||
    {
 | 
			
		||||
        result = (BOOL)xMBTCPPortMasterAddSlaveIp(*comm_ip_table);
 | 
			
		||||
    // Add slave IP address for each slave to initialize connection
 | 
			
		||||
    mb_slave_addr_entry_t *p_slave_info;
 | 
			
		||||
 | 
			
		||||
    LIST_FOREACH(p_slave_info, &mbm_opts->mbm_slave_list, entries) {
 | 
			
		||||
        result = (BOOL)xMBTCPPortMasterAddSlaveIp(p_slave_info->index, p_slave_info->ip_address, p_slave_info->slave_addr);
 | 
			
		||||
        MB_MASTER_CHECK(result, ESP_ERR_INVALID_STATE, "mb stack add slave IP failed: %s.", *comm_ip_table);
 | 
			
		||||
    }
 | 
			
		||||
    // Init polling event handlers and wait before start polling
 | 
			
		||||
    xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group, (EventBits_t)MB_EVENT_STACK_STARTED, 1);
 | 
			
		||||
 | 
			
		||||
    // Add end of list condition
 | 
			
		||||
    (void)xMBTCPPortMasterAddSlaveIp(0xFF, NULL, 0xFF);
 | 
			
		||||
 | 
			
		||||
    status = eMBMasterEnable();
 | 
			
		||||
    MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
 | 
			
		||||
            "mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);
 | 
			
		||||
 | 
			
		||||
    // Send end of list condition to start connection phase
 | 
			
		||||
    (void)xMBTCPPortMasterAddSlaveIp(NULL);
 | 
			
		||||
 | 
			
		||||
    // Wait for connection done event
 | 
			
		||||
    bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group,
 | 
			
		||||
@@ -160,6 +214,7 @@ static esp_err_t mbc_tcp_master_destroy(void)
 | 
			
		||||
    mbm_opts->mbm_task_handle = NULL;
 | 
			
		||||
    (void)vEventGroupDelete(mbm_opts->mbm_event_group);
 | 
			
		||||
    mbm_opts->mbm_event_group = NULL;
 | 
			
		||||
    mbc_tcp_master_free_slave_list();
 | 
			
		||||
    free(mbm_interface_ptr); // free the memory allocated for options
 | 
			
		||||
    vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
 | 
			
		||||
    mbm_interface_ptr = NULL;
 | 
			
		||||
@@ -179,14 +234,25 @@ static esp_err_t mbc_tcp_master_set_descriptor(const mb_parameter_descriptor_t*
 | 
			
		||||
    MB_MASTER_CHECK((comm_ip_table != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
 | 
			
		||||
 | 
			
		||||
    const mb_parameter_descriptor_t *reg_ptr = descriptor;
 | 
			
		||||
    uint16_t slave_cnt = 0;
 | 
			
		||||
    mb_slave_addr_entry_t* p_slave = NULL;
 | 
			
		||||
 | 
			
		||||
    // Go through all items in the table to check all Modbus registers
 | 
			
		||||
    for (uint16_t counter = 0; counter < (num_elements); counter++, reg_ptr++)
 | 
			
		||||
    for (int idx = 0; idx < (num_elements); idx++, reg_ptr++)
 | 
			
		||||
    {
 | 
			
		||||
        MB_MASTER_CHECK((comm_ip_table[reg_ptr->mb_slave_addr - 1] != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
 | 
			
		||||
        // Below is the code to check consistency of the table format and required fields.
 | 
			
		||||
        MB_MASTER_CHECK((reg_ptr->cid == counter), ESP_ERR_INVALID_ARG, "mb descriptor cid field is incorrect.");
 | 
			
		||||
        MB_MASTER_CHECK((reg_ptr->cid == idx), ESP_ERR_INVALID_ARG, "mb descriptor cid field is incorrect.");
 | 
			
		||||
        MB_MASTER_CHECK((reg_ptr->param_key != NULL), ESP_ERR_INVALID_ARG, "mb descriptor param key is incorrect.");
 | 
			
		||||
        MB_MASTER_CHECK((reg_ptr->mb_size > 0), ESP_ERR_INVALID_ARG, "mb descriptor param size is incorrect.");
 | 
			
		||||
        // Is the slave already in the list?
 | 
			
		||||
        p_slave = mbc_tcp_master_find_slave_addr(reg_ptr->mb_slave_addr);
 | 
			
		||||
        // Add it to slave list if not there.
 | 
			
		||||
        if (!p_slave) {
 | 
			
		||||
            // Is the IP address correctly defined for the slave?
 | 
			
		||||
            MB_MASTER_CHECK((comm_ip_table[slave_cnt]), ESP_ERR_INVALID_STATE, "mb missing IP address for cid #%d.", reg_ptr->cid);
 | 
			
		||||
            // Add slave to the list
 | 
			
		||||
            MB_MASTER_ASSERT(mbc_tcp_master_add_slave(idx, reg_ptr->mb_slave_addr, comm_ip_table[slave_cnt++]) == ESP_OK);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    mbm_opts->mbm_param_descriptor_table = descriptor;
 | 
			
		||||
    mbm_opts->mbm_param_descriptor_size = num_elements;
 | 
			
		||||
@@ -258,7 +324,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
 | 
			
		||||
                                                        (USHORT)mb_size, (LONG) MB_RESPONSE_TIMEOUT );
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
 | 
			
		||||
            ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
 | 
			
		||||
                                                    __FUNCTION__, mb_command);
 | 
			
		||||
            mb_error = MB_MRE_NO_REG;
 | 
			
		||||
            break;
 | 
			
		||||
@@ -289,7 +355,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, mb_error);
 | 
			
		||||
            ESP_LOGE(TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, mb_error);
 | 
			
		||||
            error = ESP_FAIL;
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
@@ -333,11 +399,11 @@ static uint8_t mbc_tcp_master_get_command(mb_param_type_t param_type, mb_param_m
 | 
			
		||||
            if (mode != MB_PARAM_WRITE) {
 | 
			
		||||
                command = MB_FUNC_READ_DISCRETE_INPUTS;
 | 
			
		||||
            } else {
 | 
			
		||||
                ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (uint8_t)mode);
 | 
			
		||||
                ESP_LOGE(TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (uint8_t)mode);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)", __FUNCTION__, param_type);
 | 
			
		||||
            ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, param_type);
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    return command;
 | 
			
		||||
@@ -368,7 +434,7 @@ static esp_err_t mbc_tcp_master_set_param_data(void* dest, void* src, mb_descr_t
 | 
			
		||||
            memcpy((void*)dest, (void*)src, (size_t)param_size);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u).",
 | 
			
		||||
            ESP_LOGE(TAG, "%s: Incorrect param type (%u).",
 | 
			
		||||
                        __FUNCTION__, (uint16_t)param_type);
 | 
			
		||||
            err = ESP_ERR_NOT_SUPPORTED;
 | 
			
		||||
            break;
 | 
			
		||||
@@ -420,31 +486,43 @@ static esp_err_t mbc_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t*
 | 
			
		||||
{
 | 
			
		||||
    MB_MASTER_CHECK((name != NULL), ESP_ERR_INVALID_ARG, "mb incorrect descriptor.");
 | 
			
		||||
    MB_MASTER_CHECK((type != NULL), ESP_ERR_INVALID_ARG, "type pointer is incorrect.");
 | 
			
		||||
    MB_MASTER_CHECK((value != NULL), ESP_ERR_INVALID_ARG, "value pointer is incorrect.");
 | 
			
		||||
    esp_err_t error = ESP_ERR_INVALID_RESPONSE;
 | 
			
		||||
    mb_param_request_t request ;
 | 
			
		||||
    mb_parameter_descriptor_t reg_info = { 0 };
 | 
			
		||||
    uint8_t param_buffer[PARAM_MAX_SIZE] = { 0 };
 | 
			
		||||
    uint8_t* pdata = NULL;
 | 
			
		||||
 | 
			
		||||
    error = mbc_tcp_master_set_request(name, MB_PARAM_READ, &request, ®_info);
 | 
			
		||||
    if ((error == ESP_OK) && (cid == reg_info.cid)) {
 | 
			
		||||
        error = mbc_tcp_master_send_request(&request, ¶m_buffer[0]);
 | 
			
		||||
        // alloc buffer to store parameter data
 | 
			
		||||
        pdata = calloc(1, (reg_info.mb_size << 1));
 | 
			
		||||
        if (!pdata) {
 | 
			
		||||
            return ESP_ERR_INVALID_STATE;
 | 
			
		||||
        }
 | 
			
		||||
        error = mbc_tcp_master_send_request(&request, pdata);
 | 
			
		||||
        if (error == ESP_OK) {
 | 
			
		||||
            // If data pointer is NULL then we don't need to set value (it is still in the cache of cid)
 | 
			
		||||
            if (value != NULL) {
 | 
			
		||||
                error = mbc_tcp_master_set_param_data((void*)value, (void*)¶m_buffer[0],
 | 
			
		||||
                error = mbc_tcp_master_set_param_data((void*)value, (void*)pdata,
 | 
			
		||||
                                                    reg_info.param_type, reg_info.param_size);
 | 
			
		||||
                MB_MASTER_CHECK((error == ESP_OK), ESP_ERR_INVALID_STATE, "fail to set parameter data.");
 | 
			
		||||
                if (error != ESP_OK) {
 | 
			
		||||
                    ESP_LOGE(TAG, "fail to set parameter data.");
 | 
			
		||||
                    error = ESP_ERR_INVALID_STATE;
 | 
			
		||||
                } else {
 | 
			
		||||
                    ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
 | 
			
		||||
                                                        __FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
 | 
			
		||||
                                    __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
        } else {
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
 | 
			
		||||
            ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
 | 
			
		||||
                                            __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
            error = ESP_ERR_INVALID_RESPONSE;
 | 
			
		||||
        }
 | 
			
		||||
        free(pdata);
 | 
			
		||||
        // Set the type of parameter found in the table
 | 
			
		||||
        *type = reg_info.param_type;
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
 | 
			
		||||
        ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
 | 
			
		||||
                                                    __FUNCTION__, reg_info.cid);
 | 
			
		||||
        error = ESP_ERR_INVALID_ARG;
 | 
			
		||||
    }
 | 
			
		||||
@@ -461,27 +539,36 @@ static esp_err_t mbc_tcp_master_set_parameter(uint16_t cid, char* name, uint8_t*
 | 
			
		||||
    esp_err_t error = ESP_ERR_INVALID_RESPONSE;
 | 
			
		||||
    mb_param_request_t request ;
 | 
			
		||||
    mb_parameter_descriptor_t reg_info = { 0 };
 | 
			
		||||
    uint8_t param_buffer[PARAM_MAX_SIZE] = { 0 };
 | 
			
		||||
    uint8_t* pdata = NULL;
 | 
			
		||||
 | 
			
		||||
    error = mbc_tcp_master_set_request(name, MB_PARAM_WRITE, &request, ®_info);
 | 
			
		||||
    if ((error == ESP_OK) && (cid == reg_info.cid)) {
 | 
			
		||||
        pdata = calloc(1, (reg_info.mb_size << 1)); // alloc parameter buffer
 | 
			
		||||
        if (!pdata) {
 | 
			
		||||
            return ESP_ERR_INVALID_STATE;
 | 
			
		||||
        }
 | 
			
		||||
        // Transfer value of characteristic into parameter buffer
 | 
			
		||||
        error = mbc_tcp_master_set_param_data((void*)¶m_buffer[0], (void*)value,
 | 
			
		||||
        error = mbc_tcp_master_set_param_data((void*)pdata, (void*)value,
 | 
			
		||||
                                                reg_info.param_type, reg_info.param_size);
 | 
			
		||||
        MB_MASTER_CHECK((error == ESP_OK), ESP_ERR_INVALID_STATE, "failure to set parameter data.");
 | 
			
		||||
        if (error != ESP_OK) {
 | 
			
		||||
            ESP_LOGE(TAG, "fail to set parameter data.");
 | 
			
		||||
            free(pdata);
 | 
			
		||||
            return ESP_ERR_INVALID_STATE;
 | 
			
		||||
        }
 | 
			
		||||
        // Send request to write characteristic data
 | 
			
		||||
        error = mbc_tcp_master_send_request(&request, ¶m_buffer[0]);
 | 
			
		||||
        error = mbc_tcp_master_send_request(&request, pdata);
 | 
			
		||||
        if (error == ESP_OK) {
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
 | 
			
		||||
                                    __FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
            ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
 | 
			
		||||
                                    __FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
        } else {
 | 
			
		||||
            ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
 | 
			
		||||
            ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
 | 
			
		||||
                                    __FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
 | 
			
		||||
        }
 | 
			
		||||
        free(pdata);
 | 
			
		||||
        // Set the type of parameter found in the table
 | 
			
		||||
        *type = reg_info.param_type;
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
 | 
			
		||||
        ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
 | 
			
		||||
                                    __FUNCTION__, reg_info.cid);
 | 
			
		||||
        error = ESP_ERR_INVALID_ARG;
 | 
			
		||||
    }
 | 
			
		||||
@@ -709,6 +796,9 @@ esp_err_t mbc_tcp_master_create(void** handler)
 | 
			
		||||
    }
 | 
			
		||||
    MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
 | 
			
		||||
 | 
			
		||||
    LIST_INIT(&mbm_opts->mbm_slave_list); // Init slave address list
 | 
			
		||||
    mbm_opts->mbm_slave_list_count = 0;
 | 
			
		||||
 | 
			
		||||
    // Initialize public interface methods of the interface
 | 
			
		||||
    mbm_interface_ptr->init = mbc_tcp_master_create;
 | 
			
		||||
    mbm_interface_ptr->destroy = mbc_tcp_master_destroy;
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,6 @@
 | 
			
		||||
#define MB_TCP_CONNECTION_TIMEOUT_MS    ( 20 )      // Connection timeout in mS
 | 
			
		||||
#define MB_TCP_RECONNECT_TIMEOUT        ( 5000000 ) // Connection timeout in uS
 | 
			
		||||
 | 
			
		||||
#define MB_TCP_MASTER_PORT_TAG          "MB_TCP_MASTER_PORT"
 | 
			
		||||
#define MB_EVENT_REQ_DONE_MASK          (   EV_MASTER_PROCESS_SUCCESS | \
 | 
			
		||||
                                            EV_MASTER_ERROR_RESPOND_TIMEOUT | \
 | 
			
		||||
                                            EV_MASTER_ERROR_RECEIVE_DATA | \
 | 
			
		||||
@@ -84,6 +83,7 @@
 | 
			
		||||
void vMBPortEventClose( void );
 | 
			
		||||
 | 
			
		||||
/* ----------------------- Static variables ---------------------------------*/
 | 
			
		||||
static const char *TAG = "MB_TCP_MASTER_PORT";
 | 
			
		||||
static MbPortConfig_t xMbPortConfig;
 | 
			
		||||
static EventGroupHandle_t xMasterEventHandle = NULL;
 | 
			
		||||
static SemaphoreHandle_t xShutdownSemaphore = NULL;
 | 
			
		||||
@@ -114,7 +114,7 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
 | 
			
		||||
 | 
			
		||||
    xMbPortConfig.pxMbSlaveInfo = calloc(MB_TCP_PORT_MAX_CONN, sizeof(MbSlaveInfo_t*));
 | 
			
		||||
    if (!xMbPortConfig.pxMbSlaveInfo) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP slave info alloc failure.");
 | 
			
		||||
        ESP_LOGE(TAG, "TCP slave info alloc failure.");
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xMbPortConfig.pxMbSlaveInfo[idx] = NULL, idx++);
 | 
			
		||||
@@ -123,12 +123,13 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
 | 
			
		||||
    xMbPortConfig.usPort = usTCPPort;
 | 
			
		||||
    xMbPortConfig.usMbSlaveInfoCount = 0;
 | 
			
		||||
    xMbPortConfig.ucCurSlaveIndex = 1;
 | 
			
		||||
    xMbPortConfig.pxMbSlaveCurrInfo = NULL;
 | 
			
		||||
 | 
			
		||||
    xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(CHAR*));
 | 
			
		||||
    xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(MbSlaveAddrInfo_t));
 | 
			
		||||
    if (xMbPortConfig.xConnectQueue == 0)
 | 
			
		||||
    {
 | 
			
		||||
        // Queue was not created and must not be used.
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP master queue creation failure.");
 | 
			
		||||
        ESP_LOGE(TAG, "TCP master queue creation failure.");
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -142,10 +143,10 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
 | 
			
		||||
                                    MB_PORT_TASK_AFFINITY);
 | 
			
		||||
    if (xErr != pdTRUE)
 | 
			
		||||
    {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP master task creation failure.");
 | 
			
		||||
        ESP_LOGE(TAG, "TCP master task creation failure.");
 | 
			
		||||
        (void)vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "TCP master stack initialized.");
 | 
			
		||||
        ESP_LOGI(TAG, "TCP master stack initialized.");
 | 
			
		||||
        bOkay = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -153,9 +154,30 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
 | 
			
		||||
    return bOkay;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MbSlaveInfo_t* vMBTCPPortMasterFindSlaveInfo(UCHAR ucSlaveAddr)
 | 
			
		||||
{
 | 
			
		||||
    int xIndex;
 | 
			
		||||
    BOOL xFound = false;
 | 
			
		||||
    for (xIndex = 0; xIndex < xMbPortConfig.usMbSlaveInfoCount; xIndex++) {
 | 
			
		||||
        if (xMbPortConfig.pxMbSlaveInfo[xIndex]->ucSlaveAddr == ucSlaveAddr) {
 | 
			
		||||
            xMbPortConfig.pxMbSlaveCurrInfo = xMbPortConfig.pxMbSlaveInfo[xIndex];
 | 
			
		||||
            xFound = TRUE;
 | 
			
		||||
            xMbPortConfig.ucCurSlaveIndex = xIndex;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (!xFound) {
 | 
			
		||||
        xMbPortConfig.pxMbSlaveCurrInfo = NULL;
 | 
			
		||||
        ESP_LOGE(TAG, "Slave info for short address %d not found.", ucSlaveAddr);
 | 
			
		||||
    }
 | 
			
		||||
    return xMbPortConfig.pxMbSlaveCurrInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static MbSlaveInfo_t* vMBTCPPortMasterGetCurrInfo(void)
 | 
			
		||||
{
 | 
			
		||||
    return xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.ucCurSlaveIndex - 1];
 | 
			
		||||
    if (!xMbPortConfig.pxMbSlaveCurrInfo) {
 | 
			
		||||
        ESP_LOGE(TAG, "Incorrect current slave info.");
 | 
			
		||||
    }
 | 
			
		||||
    return xMbPortConfig.pxMbSlaveCurrInfo;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Start Modbus event state machine
 | 
			
		||||
@@ -166,10 +188,10 @@ static void vMBTCPPortMasterStartPoll(void)
 | 
			
		||||
        EventBits_t xFlags = xEventGroupSetBits(xMasterEventHandle,
 | 
			
		||||
                                                (EventBits_t)xMasterEvent);
 | 
			
		||||
        if (!(xFlags & xMasterEvent)) {
 | 
			
		||||
            ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start TCP stack.");
 | 
			
		||||
            ESP_LOGE(TAG, "Fail to start TCP stack.");
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start polling. Incorrect event handle...");
 | 
			
		||||
        ESP_LOGE(TAG, "Fail to start polling. Incorrect event handle...");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -181,10 +203,10 @@ static void vMBTCPPortMasterStopPoll(void)
 | 
			
		||||
        EventBits_t xFlags = xEventGroupClearBits(xMasterEventHandle,
 | 
			
		||||
                                                (EventBits_t)xMasterEvent);
 | 
			
		||||
        if (!(xFlags & xMasterEvent)) {
 | 
			
		||||
            ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling.");
 | 
			
		||||
            ESP_LOGE(TAG, "Fail to stop polling.");
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling. Incorrect event handle...");
 | 
			
		||||
        ESP_LOGE(TAG, "Fail to stop polling. Incorrect event handle...");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -215,11 +237,11 @@ static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    if (pxInfo->xSockId == -1) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Wrong socket info or disconnected socket: %d, skip.", pxInfo->xSockId);
 | 
			
		||||
        ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d, skip.", pxInfo->xSockId);
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
 | 
			
		||||
        ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Shutdown failed sock %d, errno=%d", pxInfo->xSockId, errno);
 | 
			
		||||
        ESP_LOGV(TAG, "Shutdown failed sock %d, errno=%d", pxInfo->xSockId, errno);
 | 
			
		||||
    }
 | 
			
		||||
    close(pxInfo->xSockId);
 | 
			
		||||
    pxInfo->xSockId = -1;
 | 
			
		||||
@@ -289,12 +311,12 @@ static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t* pxInfo, UCHAR* pucDstBuf, USHOR
 | 
			
		||||
                continue;
 | 
			
		||||
            } else if (errno == ENOTCONN) {
 | 
			
		||||
                // Socket connection closed
 | 
			
		||||
                ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) connection closed.",
 | 
			
		||||
                ESP_LOGE(TAG, "Socket(#%d)(%s) connection closed.",
 | 
			
		||||
                                            pxInfo->xSockId, pxInfo->pcIpAddr);
 | 
			
		||||
                return ERR_CONN;
 | 
			
		||||
            } else {
 | 
			
		||||
                // Other error occurred during receiving
 | 
			
		||||
                ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) receive error, length=%d, errno=%d",
 | 
			
		||||
                ESP_LOGE(TAG, "Socket(#%d)(%s) receive error, length=%d, errno=%d",
 | 
			
		||||
                                            pxInfo->xSockId, pxInfo->pcIpAddr, xLength, errno);
 | 
			
		||||
                return -1;
 | 
			
		||||
            }
 | 
			
		||||
@@ -325,7 +347,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
            pxInfo->xRcvErr = xRet;
 | 
			
		||||
            return xRet;
 | 
			
		||||
        } else if (xRet != MB_TCP_UID) {
 | 
			
		||||
            ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s), Fail to read modbus header. ret=%d",
 | 
			
		||||
            ESP_LOGD(TAG, "Socket (#%d)(%s), Fail to read modbus header. ret=%d",
 | 
			
		||||
                                                                pxInfo->xSockId, pxInfo->pcIpAddr, xRet);
 | 
			
		||||
            pxInfo->xRcvErr = ERR_VAL;
 | 
			
		||||
            return ERR_VAL;
 | 
			
		||||
@@ -339,7 +361,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
            return xRet;
 | 
			
		||||
        } else if (xRet != xLength) {
 | 
			
		||||
            // Received incorrect or fragmented packet.
 | 
			
		||||
            ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) incorrect packet, length=%d, TID=0x%02x, errno=%d(%s)",
 | 
			
		||||
            ESP_LOGD(TAG, "Socket(#%d)(%s) incorrect packet, length=%d, TID=0x%02x, errno=%d(%s)",
 | 
			
		||||
                                               pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
 | 
			
		||||
                                               usTidRcv, errno, strerror(errno));
 | 
			
		||||
            pxInfo->xRcvErr = ERR_VAL;
 | 
			
		||||
@@ -349,13 +371,13 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
 | 
			
		||||
        // Check transaction identifier field in the incoming packet.
 | 
			
		||||
        if ((pxInfo->usTidCnt - 1) != usTidRcv) {
 | 
			
		||||
            ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s), incorrect TID(0x%02x)!=(0x%02x) received, discard data.",
 | 
			
		||||
            ESP_LOGD(TAG, "Socket (#%d)(%s), incorrect TID(0x%02x)!=(0x%02x) received, discard data.",
 | 
			
		||||
                                                pxInfo->xSockId, pxInfo->pcIpAddr, usTidRcv, (pxInfo->usTidCnt - 1));
 | 
			
		||||
            pxInfo->xRcvErr = ERR_BUF;
 | 
			
		||||
            return ERR_BUF;
 | 
			
		||||
        }
 | 
			
		||||
        pxInfo->usRcvPos += xRet + MB_TCP_UID;
 | 
			
		||||
        ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) get data, length=%d, TID=0x%02x, errno=%d(%s)",
 | 
			
		||||
        ESP_LOGD(TAG, "Socket(#%d)(%s) get data, length=%d, TID=0x%02x, errno=%d(%s)",
 | 
			
		||||
                                           pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
 | 
			
		||||
                                           usTidRcv, errno, strerror(errno));
 | 
			
		||||
        pxInfo->xRcvErr = ERR_OK;
 | 
			
		||||
@@ -372,7 +394,7 @@ static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
    // Set non blocking attribute for socket
 | 
			
		||||
    ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
 | 
			
		||||
    if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), fcntl() call error=%d",
 | 
			
		||||
        ESP_LOGE(TAG, "Socket(#%d)(%s), fcntl() call error=%d",
 | 
			
		||||
                                              pxInfo->xSockId, pxInfo->pcIpAddr, errno);
 | 
			
		||||
        return ERR_WOULDBLOCK;
 | 
			
		||||
    }
 | 
			
		||||
@@ -405,12 +427,12 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
 | 
			
		||||
            if (errno == EINPROGRESS) {
 | 
			
		||||
                xErr = ERR_INPROGRESS;
 | 
			
		||||
            } else {
 | 
			
		||||
                ESP_LOGV(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
 | 
			
		||||
                ESP_LOGV(TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
 | 
			
		||||
                                                    pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
 | 
			
		||||
                xErr = ERR_CONN;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (xErr == 0) {
 | 
			
		||||
            ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
 | 
			
		||||
            ESP_LOGV(TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
 | 
			
		||||
                                        pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
 | 
			
		||||
            return ERR_INPROGRESS;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -419,11 +441,11 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
 | 
			
		||||
            // Check socket error
 | 
			
		||||
            xErr = getsockopt(pxInfo->xSockId, SOL_SOCKET, SO_ERROR, (void*)&xOptErr, (socklen_t*)&ulOptLen);
 | 
			
		||||
            if (xOptErr != 0) {
 | 
			
		||||
                ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), sock error occurred (%d).",
 | 
			
		||||
                ESP_LOGD(TAG, "Socket(#%d)(%s), sock error occurred (%d).",
 | 
			
		||||
                                            pxInfo->xSockId, pxInfo->pcIpAddr, xOptErr);
 | 
			
		||||
                return ERR_CONN;
 | 
			
		||||
            }
 | 
			
		||||
            ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), is alive.",
 | 
			
		||||
            ESP_LOGV(TAG, "Socket(#%d)(%s), is alive.",
 | 
			
		||||
                                        pxInfo->xSockId, pxInfo->pcIpAddr);
 | 
			
		||||
            return ERR_OK;
 | 
			
		||||
        }
 | 
			
		||||
@@ -453,7 +475,7 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
 | 
			
		||||
    int xRet = getaddrinfo(pcHostStr, NULL, &xHint, &pxAddrList);
 | 
			
		||||
 | 
			
		||||
    if (xRet != 0) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect host name or IP: %s", pcHostStr);
 | 
			
		||||
        ESP_LOGE(TAG, "Incorrect host name or IP: %s", pcHostStr);
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    if (pxAddrList->ai_family == AF_INET) {
 | 
			
		||||
@@ -471,20 +493,24 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
 | 
			
		||||
    if (pxHostAddr) {
 | 
			
		||||
        *pxHostAddr = xTargetAddr;
 | 
			
		||||
    }
 | 
			
		||||
    ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Host[IP]: \"%s\"[%s]", pxAddrList->ai_canonname, pcStr);
 | 
			
		||||
    ESP_LOGI(TAG, "Host[IP]: \"%s\"[%s]", pxAddrList->ai_canonname, pcStr);
 | 
			
		||||
    freeaddrinfo(pxAddrList);
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr)
 | 
			
		||||
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress)
 | 
			
		||||
{
 | 
			
		||||
    BOOL xRes = FALSE;
 | 
			
		||||
    MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
 | 
			
		||||
    MB_PORT_CHECK(xMbPortConfig.xConnectQueue != NULL, FALSE, "Wrong slave IP address to add.");
 | 
			
		||||
    if (pcIpStr) {
 | 
			
		||||
    if (pcIpStr && (usIndex != 0xFF)) {
 | 
			
		||||
        xRes = xMBTCPPortMasterCheckHost(pcIpStr, NULL);
 | 
			
		||||
    }
 | 
			
		||||
    if (xRes || !pcIpStr) {
 | 
			
		||||
        BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (const void*)&pcIpStr, 100);
 | 
			
		||||
        xSlaveAddrInfo.pcIPAddr = pcIpStr;
 | 
			
		||||
        xSlaveAddrInfo.usIndex = usIndex;
 | 
			
		||||
        xSlaveAddrInfo.ucSlaveAddr = ucSlaveAddress;
 | 
			
		||||
        BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, 100);
 | 
			
		||||
        MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "FAIL to add slave IP address: [%s].", pcIpStr);
 | 
			
		||||
    }
 | 
			
		||||
    return xRes;
 | 
			
		||||
@@ -522,7 +548,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
    int xRet = getaddrinfo(pxInfo->pcIpAddr, pcStr, &xHint, &pxAddrList);
 | 
			
		||||
    free(pcStr);
 | 
			
		||||
    if (xRet != 0) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Cannot resolve host: %s", pxInfo->pcIpAddr);
 | 
			
		||||
        ESP_LOGE(TAG, "Cannot resolve host: %s", pxInfo->pcIpAddr);
 | 
			
		||||
        return ERR_CONN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -545,12 +571,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
        if (pxInfo->xSockId <= 0) {
 | 
			
		||||
            pxInfo->xSockId = socket(pxCurAddr->ai_family, pxCurAddr->ai_socktype, pxCurAddr->ai_protocol);
 | 
			
		||||
            if (pxInfo->xSockId < 0) {
 | 
			
		||||
                ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Unable to create socket: #%d, errno %d", pxInfo->xSockId, errno);
 | 
			
		||||
                ESP_LOGE(TAG, "Unable to create socket: #%d, errno %d", pxInfo->xSockId, errno);
 | 
			
		||||
                xErr = ERR_IF;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s) created.", pxInfo->xSockId, cStr);
 | 
			
		||||
            ESP_LOGV(TAG, "Socket (#%d)(%s) created.", pxInfo->xSockId, cStr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Set non blocking attribute for socket
 | 
			
		||||
@@ -561,7 +587,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
        xErr = connect(pxInfo->xSockId, (struct sockaddr*)pxCurAddr->ai_addr, pxCurAddr->ai_addrlen);
 | 
			
		||||
        if ((xErr < 0) && (errno == EINPROGRESS || errno == EALREADY)) {
 | 
			
		||||
            // The unblocking connect is pending (check status later) or already connected
 | 
			
		||||
            ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) connection is pending, errno %d (%s).",
 | 
			
		||||
            ESP_LOGV(TAG, "Socket(#%d)(%s) connection is pending, errno %d (%s).",
 | 
			
		||||
                                        pxInfo->xSockId, cStr, errno, strerror(errno));
 | 
			
		||||
 | 
			
		||||
            // Set keep alive flag in socket options
 | 
			
		||||
@@ -574,12 +600,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
 | 
			
		||||
            continue;
 | 
			
		||||
        } else if (xErr != ERR_OK) {
 | 
			
		||||
            // Other error occurred during connection
 | 
			
		||||
            ESP_LOGV(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
 | 
			
		||||
            ESP_LOGV(TAG, MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
 | 
			
		||||
                                                pxInfo->xIndex, pxInfo->xSockId, cStr, xErr, errno, strerror(errno));
 | 
			
		||||
            xMBTCPPortMasterCloseConnection(pxInfo);
 | 
			
		||||
            xErr = ERR_CONN;
 | 
			
		||||
        } else {
 | 
			
		||||
            ESP_LOGI(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", successfully connected."),
 | 
			
		||||
            ESP_LOGI(TAG, MB_SLAVE_FMT(", successfully connected."),
 | 
			
		||||
                                                  pxInfo->xIndex, pxInfo->xSockId, cStr);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
@@ -621,7 +647,7 @@ static int xMBTCPPortMasterCheckConnState(fd_set* pxFdSet)
 | 
			
		||||
            xErr = xMBTCPPortMasterCheckAlive(pxInfo, 0);
 | 
			
		||||
            if ((xErr < 0) && (((xTime - pxInfo->xRecvTimeStamp) > MB_TCP_RECONNECT_TIMEOUT) ||
 | 
			
		||||
                                ((xTime - pxInfo->xSendTimeStamp) > MB_TCP_RECONNECT_TIMEOUT))) {
 | 
			
		||||
                ESP_LOGI(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%ju][%ju]."),
 | 
			
		||||
                ESP_LOGI(TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%ju][%ju]."),
 | 
			
		||||
                                                            pxInfo->xIndex,
 | 
			
		||||
                                                            pxInfo->xSockId,
 | 
			
		||||
                                                            pxInfo->pcIpAddr,
 | 
			
		||||
@@ -643,9 +669,9 @@ static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMas
 | 
			
		||||
 | 
			
		||||
static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
{
 | 
			
		||||
    CHAR* pcAddrStr = NULL;
 | 
			
		||||
    MbSlaveInfo_t* pxInfo;
 | 
			
		||||
    MbSlaveInfo_t* pxCurrInfo;
 | 
			
		||||
 | 
			
		||||
    fd_set xConnSet;
 | 
			
		||||
    fd_set xReadSet;
 | 
			
		||||
    int xMaxSd = 0;
 | 
			
		||||
@@ -655,51 +681,53 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
 | 
			
		||||
    // Register each slave in the connection info structure
 | 
			
		||||
    while (1) {
 | 
			
		||||
        BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&pcAddrStr, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
 | 
			
		||||
        xMBTCPPortMasterCheckShutdown();
 | 
			
		||||
        MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
 | 
			
		||||
        BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
 | 
			
		||||
	    xMBTCPPortMasterCheckShutdown();
 | 
			
		||||
        if (xStatus != pdTRUE) {
 | 
			
		||||
            ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to register slave IP.");
 | 
			
		||||
            ESP_LOGE(TAG, "Fail to register slave IP.");
 | 
			
		||||
        } else {
 | 
			
		||||
            if (pcAddrStr == NULL && xMbPortConfig.usMbSlaveInfoCount) {
 | 
			
		||||
            if (xSlaveAddrInfo.pcIPAddr == NULL && xMbPortConfig.usMbSlaveInfoCount && xSlaveAddrInfo.usIndex == 0xFF) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            if (xMbPortConfig.usMbSlaveInfoCount > MB_TCP_PORT_MAX_CONN) {
 | 
			
		||||
                ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Exceeds maximum connections limit=%d.", MB_TCP_PORT_MAX_CONN);
 | 
			
		||||
                ESP_LOGE(TAG, "Exceeds maximum connections limit=%d.", MB_TCP_PORT_MAX_CONN);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            pxInfo = calloc(1, sizeof(MbSlaveInfo_t));
 | 
			
		||||
            if (!pxInfo) {
 | 
			
		||||
                ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Slave(#%d), info structure allocation fail.",
 | 
			
		||||
                ESP_LOGE(TAG, "Slave(#%d), info structure allocation fail.",
 | 
			
		||||
                                                    xMbPortConfig.usMbSlaveInfoCount);
 | 
			
		||||
                free(pxInfo);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            pxInfo->pucRcvBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
 | 
			
		||||
            if (!pxInfo->pucRcvBuf) {
 | 
			
		||||
                ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Slave(#%d), receive buffer allocation fail.",
 | 
			
		||||
                ESP_LOGE(TAG, "Slave(#%d), receive buffer allocation fail.",
 | 
			
		||||
                                                    xMbPortConfig.usMbSlaveInfoCount);
 | 
			
		||||
                free(pxInfo->pucRcvBuf);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            pxInfo->usRcvPos = 0;
 | 
			
		||||
            pxInfo->pcIpAddr = pcAddrStr;
 | 
			
		||||
            pxInfo->pcIpAddr = xSlaveAddrInfo.pcIPAddr;
 | 
			
		||||
            pxInfo->xSockId = -1;
 | 
			
		||||
            pxInfo->xError = -1;
 | 
			
		||||
            pxInfo->xRecvTimeStamp = xMBTCPGetTimeStamp();
 | 
			
		||||
            pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
 | 
			
		||||
            pxInfo->xMbProto = MB_PROTO_TCP;
 | 
			
		||||
            pxInfo->xIndex = xMbPortConfig.usMbSlaveInfoCount;
 | 
			
		||||
            pxInfo->ucSlaveAddr = xSlaveAddrInfo.ucSlaveAddr;
 | 
			
		||||
            pxInfo->xIndex = xSlaveAddrInfo.usIndex;
 | 
			
		||||
            pxInfo->usTidCnt = (USHORT)(xMbPortConfig.usMbSlaveInfoCount << 8U);
 | 
			
		||||
            // Register slave
 | 
			
		||||
            xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.usMbSlaveInfoCount++] = pxInfo;
 | 
			
		||||
            ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Add slave IP: %s", pcAddrStr);
 | 
			
		||||
            ESP_LOGI(TAG, "Add slave IP: %s", xSlaveAddrInfo.pcIPAddr);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Main connection cycle
 | 
			
		||||
    while (1)
 | 
			
		||||
    {
 | 
			
		||||
        ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connecting to slaves...");
 | 
			
		||||
        ESP_LOGI(TAG, "Connecting to slaves...");
 | 
			
		||||
        xTime = xMBTCPGetTimeStamp();
 | 
			
		||||
        usSlaveConnCnt = 0;
 | 
			
		||||
        CHAR ucDot = '.';
 | 
			
		||||
@@ -712,7 +740,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
                pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
 | 
			
		||||
                // if slave descriptor is NULL then it is end of list or connection closed.
 | 
			
		||||
                if (!pxInfo) {
 | 
			
		||||
                    ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Index: %d is not initialized, skip.", ucCnt);
 | 
			
		||||
                    ESP_LOGV(TAG, "Index: %d is not initialized, skip.", ucCnt);
 | 
			
		||||
                    if (xMbPortConfig.usMbSlaveInfoCount) {
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
@@ -727,12 +755,12 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
                        // In case of connection errors remove the socket from set
 | 
			
		||||
                        if (FD_ISSET(pxInfo->xSockId, &xConnSet)) {
 | 
			
		||||
                            FD_CLR(pxInfo->xSockId, &xConnSet);
 | 
			
		||||
                            ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" connect failed, error = %d."),
 | 
			
		||||
                            ESP_LOGE(TAG, MB_SLAVE_FMT(" connect failed, error = %d."),
 | 
			
		||||
                                                                            pxInfo->xIndex, pxInfo->xSockId,
 | 
			
		||||
                                                                            (char*)pxInfo->pcIpAddr, xErr);
 | 
			
		||||
                                if (usSlaveConnCnt) {
 | 
			
		||||
                                    usSlaveConnCnt--;
 | 
			
		||||
                                }
 | 
			
		||||
                            if (usSlaveConnCnt) {
 | 
			
		||||
                                usSlaveConnCnt--;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    case ERR_OK:
 | 
			
		||||
@@ -741,7 +769,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
                            FD_SET(pxInfo->xSockId, &xConnSet);
 | 
			
		||||
                            usSlaveConnCnt++;
 | 
			
		||||
                            xMaxSd = (pxInfo->xSockId > xMaxSd) ? pxInfo->xSockId : xMaxSd;
 | 
			
		||||
                            ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", connected %d slave(s), error = %d."),
 | 
			
		||||
                            ESP_LOGD(TAG, MB_SLAVE_FMT(", connected %d slave(s), error = %d."),
 | 
			
		||||
                                                                pxInfo->xIndex, pxInfo->xSockId,
 | 
			
		||||
                                                                pxInfo->pcIpAddr,
 | 
			
		||||
                                                                usSlaveConnCnt, xErr);
 | 
			
		||||
@@ -751,7 +779,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
                    default:
 | 
			
		||||
                        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", unexpected error = %d."),
 | 
			
		||||
                        ESP_LOGE(TAG, MB_SLAVE_FMT(", unexpected error = %d."),
 | 
			
		||||
                                                            pxInfo->xIndex,
 | 
			
		||||
                                                            pxInfo->xSockId,
 | 
			
		||||
                                                            pxInfo->pcIpAddr, xErr);
 | 
			
		||||
@@ -763,7 +791,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
                xMBTCPPortMasterCheckShutdown();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
 | 
			
		||||
        ESP_LOGI(TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
 | 
			
		||||
 | 
			
		||||
        vMBTCPPortMasterStartPoll(); // Send event to start stack
 | 
			
		||||
 | 
			
		||||
@@ -774,26 +802,26 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
            xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
 | 
			
		||||
            // Synchronize state machine with send packet event
 | 
			
		||||
            if (xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_SENT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS))) {
 | 
			
		||||
                ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "FSM Synchronized with sent event.");
 | 
			
		||||
                ESP_LOGD(TAG, "FSM Synchronized with sent event.");
 | 
			
		||||
            }
 | 
			
		||||
            // Get slave info for the current slave.
 | 
			
		||||
            pxCurrInfo = vMBTCPPortMasterGetCurrInfo();
 | 
			
		||||
            if (!pxCurrInfo) {
 | 
			
		||||
                ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect connection options for slave index: %d.",
 | 
			
		||||
                ESP_LOGE(TAG, "Incorrect connection options for slave index: %d.",
 | 
			
		||||
                                            xMbPortConfig.ucCurSlaveIndex);
 | 
			
		||||
                vMBTCPPortMasterStopPoll();
 | 
			
		||||
                xMBTCPPortMasterCheckShutdown();
 | 
			
		||||
                break; // incorrect slave descriptor, reconnect.
 | 
			
		||||
            }
 | 
			
		||||
            xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
 | 
			
		||||
            ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Set select timeout, left time: %ju ms.",
 | 
			
		||||
            ESP_LOGD(TAG, "Set select timeout, left time: %ju ms.",
 | 
			
		||||
                                        xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
 | 
			
		||||
            // Wait respond from current slave during respond timeout
 | 
			
		||||
            int xRes = vMBTCPPortMasterRxCheck(pxCurrInfo->xSockId, &xReadSet, xTime);
 | 
			
		||||
            if (xRes == ERR_TIMEOUT) {
 | 
			
		||||
                // No respond from current slave, process timeout.
 | 
			
		||||
                // Need to drop response later if it is received after timeout.
 | 
			
		||||
                ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Select timeout, left time: %ju ms.",
 | 
			
		||||
                ESP_LOGD(TAG, "Select timeout, left time: %ju ms.",
 | 
			
		||||
                                                    xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
 | 
			
		||||
                xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
 | 
			
		||||
                // Wait completion of last transaction
 | 
			
		||||
@@ -802,7 +830,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
                continue;
 | 
			
		||||
            } else if (xRes < 0) {
 | 
			
		||||
                // Select error (slave connection or r/w failure).
 | 
			
		||||
                ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", socket select error. Slave disconnected?"),
 | 
			
		||||
                ESP_LOGD(TAG, MB_SLAVE_FMT(", socket select error. Slave disconnected?"),
 | 
			
		||||
                            pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
 | 
			
		||||
                xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
 | 
			
		||||
                // Wait completion of last transaction
 | 
			
		||||
@@ -816,30 +844,30 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
            } else {
 | 
			
		||||
                // Check to make sure that active slave data is ready
 | 
			
		||||
                if (FD_ISSET(pxCurrInfo->xSockId, &xReadSet)) {
 | 
			
		||||
                    xErr = ERR_BUF;
 | 
			
		||||
                    for (int retry = 0; (xErr == ERR_BUF) && (retry < MB_TCP_READ_BUF_RETRY_CNT); retry++) {
 | 
			
		||||
                        xErr = vMBTCPPortMasterReadPacket(pxCurrInfo);
 | 
			
		||||
                    int xRet = ERR_BUF;
 | 
			
		||||
                    for (int retry = 0; (xRet == ERR_BUF) && (retry < MB_TCP_READ_BUF_RETRY_CNT); retry++) {
 | 
			
		||||
                        xRet = vMBTCPPortMasterReadPacket(pxCurrInfo);
 | 
			
		||||
                        // The error ERR_BUF means received response to previous request
 | 
			
		||||
                        // (due to timeout) with the same socket ID and incorrect TID,
 | 
			
		||||
                        // then ignore it and try to get next response buffer.
 | 
			
		||||
                    }
 | 
			
		||||
                    if (xErr > 0) {
 | 
			
		||||
                    if (xRet > 0) {
 | 
			
		||||
                        // Response received correctly, send an event to stack
 | 
			
		||||
                        xMBTCPPortMasterFsmSetError(EV_ERROR_INIT, EV_MASTER_FRAME_RECEIVED);
 | 
			
		||||
                        ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame received."),
 | 
			
		||||
                        ESP_LOGD(TAG, MB_SLAVE_FMT(", frame received."),
 | 
			
		||||
                                    pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
 | 
			
		||||
                    } else if ((xErr == ERR_TIMEOUT) || (xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo) == 0)) {
 | 
			
		||||
                    } else if ((xRet == ERR_TIMEOUT) || (xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo) == 0)) {
 | 
			
		||||
                        // Timeout occurred when receiving frame, process respond timeout
 | 
			
		||||
                        ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame read timeout."),
 | 
			
		||||
                        ESP_LOGD(TAG, MB_SLAVE_FMT(", frame read timeout."),
 | 
			
		||||
                                    pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
 | 
			
		||||
                    } else if (xErr == ERR_BUF) {
 | 
			
		||||
                    } else if (xRet == ERR_BUF) {
 | 
			
		||||
                        // After retries a response with incorrect TID received, process failure.
 | 
			
		||||
                        xMBTCPPortMasterFsmSetError(EV_ERROR_RECEIVE_DATA, EV_MASTER_ERROR_PROCESS);
 | 
			
		||||
                        ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame error."),
 | 
			
		||||
                        ESP_LOGD(TAG, MB_SLAVE_FMT(", frame error."),
 | 
			
		||||
                                    pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
 | 
			
		||||
                    } else {
 | 
			
		||||
                        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", critical error=%d."),
 | 
			
		||||
                                    pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xErr);
 | 
			
		||||
                        ESP_LOGE(TAG, MB_SLAVE_FMT(", critical error=%d."),
 | 
			
		||||
                                    pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xRet);
 | 
			
		||||
                        // Stop polling process
 | 
			
		||||
                        vMBTCPPortMasterStopPoll();
 | 
			
		||||
                        xMBTCPPortMasterCheckShutdown();
 | 
			
		||||
@@ -848,14 +876,14 @@ static void vMBTCPPortMasterTask(void *pvParameters)
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
 | 
			
		||||
                    ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Slave #%d, data processing left time %ju [ms].", pxCurrInfo->xIndex, xTime);
 | 
			
		||||
                    ESP_LOGD(TAG, "Slave #%d, data processing left time %ju [ms].", pxCurrInfo->xIndex, xTime);
 | 
			
		||||
                    // Wait completion of Modbus frame processing before start of new transaction.
 | 
			
		||||
                    if (xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime))) {
 | 
			
		||||
                        ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", data processing completed."),
 | 
			
		||||
                        ESP_LOGD(TAG, MB_SLAVE_FMT(", data processing completed."),
 | 
			
		||||
                                pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
 | 
			
		||||
                    }
 | 
			
		||||
                    xTime = xMBTCPGetTimeStamp() - pxCurrInfo->xSendTimeStamp;
 | 
			
		||||
                    ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", processing time[us] = %ju."),
 | 
			
		||||
                    ESP_LOGD(TAG, MB_SLAVE_FMT(", processing time[us] = %ju."),
 | 
			
		||||
                                                    pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -892,7 +920,7 @@ vMBMasterTCPPortClose(void)
 | 
			
		||||
    xShutdownSemaphore = xSemaphoreCreateBinary();
 | 
			
		||||
    // if no semaphore (alloc issues) or couldn't acquire it, just delete the task
 | 
			
		||||
    if (xShutdownSemaphore == NULL || xSemaphoreTake(xShutdownSemaphore, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)) != pdTRUE) {
 | 
			
		||||
        ESP_LOGW(MB_TCP_MASTER_PORT_TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
 | 
			
		||||
        ESP_LOGW(TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
 | 
			
		||||
        vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
 | 
			
		||||
    }
 | 
			
		||||
    if (xShutdownSemaphore) {
 | 
			
		||||
@@ -930,13 +958,13 @@ int xMBMasterTCPPortWritePoll(MbSlaveInfo_t* pxInfo, const UCHAR * pucMBTCPFrame
 | 
			
		||||
    int xRes = (int)xMBTCPPortMasterCheckAlive(pxInfo, xTimeout);
 | 
			
		||||
    if ((xRes < 0) && (xRes != ERR_INPROGRESS))
 | 
			
		||||
    {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
 | 
			
		||||
        ESP_LOGE(TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
 | 
			
		||||
                                    pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
 | 
			
		||||
        return xRes;
 | 
			
		||||
    }
 | 
			
		||||
    xRes = send(pxInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
 | 
			
		||||
    if (xRes < 0) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
 | 
			
		||||
        ESP_LOGE(TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
 | 
			
		||||
                                        pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
 | 
			
		||||
    }
 | 
			
		||||
    return xRes;
 | 
			
		||||
@@ -946,36 +974,41 @@ BOOL
 | 
			
		||||
xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
 | 
			
		||||
{
 | 
			
		||||
    BOOL bFrameSent = FALSE;
 | 
			
		||||
    xMbPortConfig.ucCurSlaveIndex = ucMBMasterGetDestAddress();
 | 
			
		||||
    MbSlaveInfo_t* pxInfo = vMBTCPPortMasterGetCurrInfo();
 | 
			
		||||
    USHORT ucCurSlaveIndex = ucMBMasterGetDestAddress();
 | 
			
		||||
    MbSlaveInfo_t* pxInfo = vMBTCPPortMasterFindSlaveInfo(ucCurSlaveIndex);
 | 
			
		||||
 | 
			
		||||
    // If socket active then send data
 | 
			
		||||
    if (pxInfo->xSockId > -1) {
 | 
			
		||||
        // Apply TID field to the frame before send
 | 
			
		||||
        pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
 | 
			
		||||
        pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
 | 
			
		||||
        int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
 | 
			
		||||
        if (xRes < 0) {
 | 
			
		||||
            ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),
 | 
			
		||||
                                           pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
 | 
			
		||||
            bFrameSent = FALSE;
 | 
			
		||||
            pxInfo->xError = xRes;
 | 
			
		||||
        } else {
 | 
			
		||||
            bFrameSent = TRUE;
 | 
			
		||||
            ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data successful: TID=0x%02x, %d (bytes), errno %d"),
 | 
			
		||||
                                                pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usTidCnt, xRes, errno);
 | 
			
		||||
            pxInfo->xError = 0;
 | 
			
		||||
            pxInfo->usRcvPos = 0;
 | 
			
		||||
            if (pxInfo->usTidCnt < (USHRT_MAX - 1)) {
 | 
			
		||||
                pxInfo->usTidCnt++;
 | 
			
		||||
            } else {
 | 
			
		||||
                pxInfo->usTidCnt = (USHORT)(pxInfo->xIndex << 8U);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send to died slave, error = %d"),
 | 
			
		||||
    // If the slave is correct and active then send data
 | 
			
		||||
    // otherwise treat slave as died and skip
 | 
			
		||||
    if (pxInfo != NULL) {
 | 
			
		||||
        if (pxInfo->xSockId < 0) {
 | 
			
		||||
            ESP_LOGD(TAG, MB_SLAVE_FMT(", send to died slave, error = %d"),
 | 
			
		||||
                                                  pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->xError);
 | 
			
		||||
        } else {
 | 
			
		||||
            // Apply TID field to the frame before send
 | 
			
		||||
            pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
 | 
			
		||||
            pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
 | 
			
		||||
            int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
 | 
			
		||||
            if (xRes < 0) {
 | 
			
		||||
                ESP_LOGE(TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),
 | 
			
		||||
                                            pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
 | 
			
		||||
                bFrameSent = FALSE;
 | 
			
		||||
                pxInfo->xError = xRes;
 | 
			
		||||
            } else {
 | 
			
		||||
                bFrameSent = TRUE;
 | 
			
		||||
                ESP_LOGD(TAG, MB_SLAVE_FMT(", send data successful: TID=0x%02x, %d (bytes), errno %d"),
 | 
			
		||||
                                                    pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usTidCnt, xRes, errno);
 | 
			
		||||
                pxInfo->xError = 0;
 | 
			
		||||
                pxInfo->usRcvPos = 0;
 | 
			
		||||
                if (pxInfo->usTidCnt < (USHRT_MAX - 1)) {
 | 
			
		||||
                    pxInfo->usTidCnt++;
 | 
			
		||||
                } else {
 | 
			
		||||
                    pxInfo->usTidCnt = (USHORT)(pxInfo->xIndex << 8U);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGD(TAG, "Send data to died slave, address = %d", ucCurSlaveIndex);
 | 
			
		||||
    }
 | 
			
		||||
    vMBMasterPortTimersRespondTimeoutEnable();
 | 
			
		||||
    xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
 | 
			
		||||
 
 | 
			
		||||
@@ -74,6 +74,7 @@ typedef struct {
 | 
			
		||||
    int xError;                 /*!< Socket error */
 | 
			
		||||
    int xRcvErr;                /*!< Socket receive error */
 | 
			
		||||
    const char* pcIpAddr;       /*!< TCP/UDP IP address */
 | 
			
		||||
    UCHAR ucSlaveAddr;          /*!< Slave short address */
 | 
			
		||||
    UCHAR* pucRcvBuf;           /*!< Receive buffer pointer */
 | 
			
		||||
    USHORT usRcvPos;            /*!< Receive buffer position */
 | 
			
		||||
    int pcPort;                 /*!< TCP/UDP port number */
 | 
			
		||||
@@ -84,28 +85,37 @@ typedef struct {
 | 
			
		||||
} MbSlaveInfo_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    TaskHandle_t  xMbTcpTaskHandle; /*!< Master TCP/UDP handling task handle */
 | 
			
		||||
    QueueHandle_t xConnectQueue;    /*!< Master connection queue */
 | 
			
		||||
    USHORT usPort;                  /*!< Master TCP/UDP port number */
 | 
			
		||||
    USHORT usMbSlaveInfoCount;      /*!< Master count of connected slaves */
 | 
			
		||||
    USHORT ucCurSlaveIndex;         /*!< Master current processing slave index */
 | 
			
		||||
    eMBPortIpVer eMbIpVer;          /*!< Master IP version */
 | 
			
		||||
    eMBPortProto eMbProto;          /*!< Master protocol type */
 | 
			
		||||
    void* pvNetIface;               /*!< Master netif interface pointer */
 | 
			
		||||
    MbSlaveInfo_t** pxMbSlaveInfo;  /*!< Master information structure for each connected slave */
 | 
			
		||||
    TaskHandle_t  xMbTcpTaskHandle;     /*!< Master TCP/UDP handling task handle */
 | 
			
		||||
    QueueHandle_t xConnectQueue;        /*!< Master connection queue */
 | 
			
		||||
    USHORT usPort;                      /*!< Master TCP/UDP port number */
 | 
			
		||||
    USHORT usMbSlaveInfoCount;          /*!< Master count of connected slaves */
 | 
			
		||||
    USHORT ucCurSlaveIndex;             /*!< Master current processing slave index */
 | 
			
		||||
    eMBPortIpVer eMbIpVer;              /*!< Master IP version */
 | 
			
		||||
    eMBPortProto eMbProto;              /*!< Master protocol type */
 | 
			
		||||
    void* pvNetIface;                   /*!< Master netif interface pointer */
 | 
			
		||||
    MbSlaveInfo_t** pxMbSlaveInfo;      /*!< Master information structure for each connected slave */
 | 
			
		||||
    MbSlaveInfo_t* pxMbSlaveCurrInfo;   /*!< Master current slave information */
 | 
			
		||||
} MbPortConfig_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    USHORT usIndex;                     /*!< index of the address info */
 | 
			
		||||
    const char* pcIPAddr;               /*!< represents the IP address of the slave */
 | 
			
		||||
    UCHAR ucSlaveAddr;                  /*!< slave unit ID (UID) field for MBAP frame  */
 | 
			
		||||
} MbSlaveAddrInfo_t;
 | 
			
		||||
 | 
			
		||||
/* ----------------------- Function prototypes ------------------------------*/
 | 
			
		||||
 | 
			
		||||
// The functions below are used by Modbus controller interface to configure Modbus port.
 | 
			
		||||
/**
 | 
			
		||||
 * Registers slave IP address
 | 
			
		||||
 *
 | 
			
		||||
 * @param usIndex index of element in the configuration
 | 
			
		||||
 * @param pcIpStr IP address to register
 | 
			
		||||
 * @param ucSlaveAddress slave element index
 | 
			
		||||
 *
 | 
			
		||||
 * @return TRUE if address registered successfully, else FALSE
 | 
			
		||||
 */
 | 
			
		||||
BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr);
 | 
			
		||||
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Keeps FSM event handle and mask then wait for Master stack to start
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@
 | 
			
		||||
 | 
			
		||||
// Shared pointer to interface structure
 | 
			
		||||
static mb_slave_interface_t* mbs_interface_ptr = NULL;
 | 
			
		||||
static const char *TAG = "MB_CONTROLLER_SLAVE";
 | 
			
		||||
 | 
			
		||||
// Modbus task function
 | 
			
		||||
static void modbus_tcp_slave_task(void *pvParameters)
 | 
			
		||||
 
 | 
			
		||||
@@ -68,13 +68,13 @@
 | 
			
		||||
/* ----------------------- Defines  -----------------------------------------*/
 | 
			
		||||
#define MB_TCP_DISCONNECT_TIMEOUT       ( CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000000 ) // disconnect timeout in uS
 | 
			
		||||
#define MB_TCP_RESP_TIMEOUT_MS          ( MB_MASTER_TIMEOUT_MS_RESPOND - 2 ) // slave response time limit
 | 
			
		||||
#define MB_TCP_SLAVE_PORT_TAG           "MB_TCP_SLAVE_PORT"
 | 
			
		||||
#define MB_TCP_NET_LISTEN_BACKLOG       ( SOMAXCONN )
 | 
			
		||||
 | 
			
		||||
/* ----------------------- Prototypes ---------------------------------------*/
 | 
			
		||||
void vMBPortEventClose( void );
 | 
			
		||||
 | 
			
		||||
/* ----------------------- Static variables ---------------------------------*/
 | 
			
		||||
static const char *TAG = "MB_TCP_SLAVE_PORT";
 | 
			
		||||
static int xListenSock = -1;
 | 
			
		||||
static MbSlavePortConfig_t xConfig = { 0 };
 | 
			
		||||
 | 
			
		||||
@@ -136,14 +136,14 @@ xMBTCPPortInit( USHORT usTCPPort )
 | 
			
		||||
 | 
			
		||||
    xConfig.pxMbClientInfo = calloc(MB_TCP_PORT_MAX_CONN + 1, sizeof(MbClientInfo_t*));
 | 
			
		||||
    if (!xConfig.pxMbClientInfo) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "TCP client info allocation failure.");
 | 
			
		||||
        ESP_LOGE(TAG, "TCP client info allocation failure.");
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xConfig.pxMbClientInfo[idx] = NULL, idx++);
 | 
			
		||||
 | 
			
		||||
    xConfig.xRespQueueHandle = xMBTCPPortRespQueueCreate();
 | 
			
		||||
    if (!xConfig.xRespQueueHandle) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Response queue allocation failure.");
 | 
			
		||||
        ESP_LOGE(TAG, "Response queue allocation failure.");
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -164,10 +164,10 @@ xMBTCPPortInit( USHORT usTCPPort )
 | 
			
		||||
    vTaskSuspend(xConfig.xMbTcpTaskHandle);
 | 
			
		||||
    if (xErr != pdTRUE)
 | 
			
		||||
    {
 | 
			
		||||
        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Server task creation failure.");
 | 
			
		||||
        ESP_LOGE(TAG, "Server task creation failure.");
 | 
			
		||||
        vTaskDelete(xConfig.xMbTcpTaskHandle);
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Protocol stack initialized.");
 | 
			
		||||
        ESP_LOGI(TAG, "Protocol stack initialized.");
 | 
			
		||||
        bOkay = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
    return bOkay;
 | 
			
		||||
@@ -202,7 +202,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
 | 
			
		||||
    // Accept new socket connection if not active
 | 
			
		||||
    xSockId = accept(xListenSockId, (struct sockaddr *)&xSrcAddr, &xSize);
 | 
			
		||||
    if (xSockId < 0) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Unable to accept connection: errno=%d", errno);
 | 
			
		||||
        ESP_LOGE(TAG, "Unable to accept connection: errno=%d", errno);
 | 
			
		||||
        close(xSockId);
 | 
			
		||||
    } else {
 | 
			
		||||
        // Get the sender's ip address as string
 | 
			
		||||
@@ -214,7 +214,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
 | 
			
		||||
            inet6_ntoa_r(((struct sockaddr_in6 *)&xSrcAddr)->sin6_addr, cAddrStr, sizeof(cAddrStr) - 1);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), accept client connection from address: %s", xSockId, cAddrStr);
 | 
			
		||||
        ESP_LOGI(TAG, "Socket (#%d), accept client connection from address: %s", xSockId, cAddrStr);
 | 
			
		||||
        pcStr = calloc(1, strlen(cAddrStr) + 1);
 | 
			
		||||
        if (pcStr && pcIPAddr) {
 | 
			
		||||
            memcpy(pcStr, cAddrStr, strlen(cAddrStr));
 | 
			
		||||
@@ -230,11 +230,11 @@ static BOOL xMBTCPPortCloseConnection(MbClientInfo_t* pxInfo)
 | 
			
		||||
    MB_PORT_CHECK(pxInfo, FALSE, "Client info is NULL.");
 | 
			
		||||
 | 
			
		||||
    if (pxInfo->xSockId == -1) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Wrong socket info or disconnected socket: %d.", pxInfo->xSockId);
 | 
			
		||||
        ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d.", pxInfo->xSockId);
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
    if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
 | 
			
		||||
        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), shutdown failed: errno %d", pxInfo->xSockId, errno);
 | 
			
		||||
        ESP_LOGE(TAG, "Socket (#%d), shutdown failed: errno %d", pxInfo->xSockId, errno);
 | 
			
		||||
    }
 | 
			
		||||
    close(pxInfo->xSockId);
 | 
			
		||||
    pxInfo->xSockId = -1;
 | 
			
		||||
@@ -271,7 +271,7 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
 | 
			
		||||
            } else if (xRet == 0) {
 | 
			
		||||
                // timeout occurred
 | 
			
		||||
                if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) {
 | 
			
		||||
                    ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d) Read timeout.", pxClientInfo->xSockId);
 | 
			
		||||
                    ESP_LOGD(TAG, "Socket (#%d) Read timeout.", pxClientInfo->xSockId);
 | 
			
		||||
                    xRet = ERR_TIMEOUT;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
@@ -286,12 +286,12 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
 | 
			
		||||
                                      pxClientInfo->usTCPFrameBytesLeft, MSG_DONTWAIT);
 | 
			
		||||
                if (xLength < 0) {
 | 
			
		||||
                    // If an error occurred during receiving
 | 
			
		||||
                    ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Receive failed: length=%d, errno=%d", xLength, errno);
 | 
			
		||||
                    ESP_LOGE(TAG, "Receive failed: length=%d, errno=%d", xLength, errno);
 | 
			
		||||
                    xRet = (err_t)xLength;
 | 
			
		||||
                    break;
 | 
			
		||||
                } else if (xLength == 0) {
 | 
			
		||||
                    // Socket connection closed
 | 
			
		||||
                    ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), connection closed.",
 | 
			
		||||
                    ESP_LOGD(TAG, "Socket (#%d)(%s), connection closed.",
 | 
			
		||||
                                                        pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
 | 
			
		||||
                    xRet = ERR_CLSD;
 | 
			
		||||
                    break;
 | 
			
		||||
@@ -309,14 +309,14 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
 | 
			
		||||
                            pxClientInfo->usTCPFrameBytesLeft = xLength + MB_TCP_UID - pxClientInfo->usTCPBufPos;
 | 
			
		||||
                        } else if (pxClientInfo->usTCPBufPos == (MB_TCP_UID + xLength)) {
 | 
			
		||||
#if MB_TCP_DEBUG
 | 
			
		||||
                            prvvMBTCPLogFrame(MB_TCP_SLAVE_PORT_TAG, (UCHAR*)&pxClientInfo->pucTCPBuf[0], pxClientInfo->usTCPBufPos);
 | 
			
		||||
                            prvvMBTCPLogFrame(TAG, (UCHAR*)&pxClientInfo->pucTCPBuf[0], pxClientInfo->usTCPBufPos);
 | 
			
		||||
#endif
 | 
			
		||||
                            // Copy TID field from incoming packet
 | 
			
		||||
                            pxClientInfo->usTidCnt = MB_TCP_GET_FIELD(pxClientInfo->pucTCPBuf, MB_TCP_TID);
 | 
			
		||||
                            xRet = pxClientInfo->usTCPBufPos;
 | 
			
		||||
                            break;
 | 
			
		||||
                        } else if ((pxClientInfo->usTCPBufPos + xLength) >= MB_TCP_BUF_SIZE) {
 | 
			
		||||
                            ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Incorrect buffer received (%u) bytes.", xLength);
 | 
			
		||||
                            ESP_LOGE(TAG, "Incorrect buffer received (%u) bytes.", xLength);
 | 
			
		||||
                            // This should not happen. We can't deal with such a client and
 | 
			
		||||
                            // drop the connection for security reasons.
 | 
			
		||||
                            xRet = ERR_BUF;
 | 
			
		||||
@@ -401,7 +401,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
 | 
			
		||||
        {
 | 
			
		||||
            if (listen(xListenSockFd, MB_TCP_NET_LISTEN_BACKLOG) != 0)
 | 
			
		||||
            {
 | 
			
		||||
                ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Error occurred during listen: errno=%d", errno);
 | 
			
		||||
                ESP_LOGE(TAG, "Error occurred during listen: errno=%d", errno);
 | 
			
		||||
                close(xListenSockFd);
 | 
			
		||||
                xListenSockFd = -1;
 | 
			
		||||
                continue;
 | 
			
		||||
@@ -409,7 +409,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
 | 
			
		||||
        }
 | 
			
		||||
        // Bind was successful
 | 
			
		||||
        pcStr = (pxCurAddr->ai_canonname == NULL) ? (CHAR*)"\0" : pxCurAddr->ai_canonname;
 | 
			
		||||
        ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), listener %s on port: %d, errno=%d",
 | 
			
		||||
        ESP_LOGI(TAG, "Socket (#%d), listener %s on port: %d, errno=%d",
 | 
			
		||||
                                            xListenSockFd, pcStr, xConfig.usPort, errno);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
@@ -475,11 +475,11 @@ static void vMBTCPPortServerTask(void *pvParameters)
 | 
			
		||||
            xErr = select(xMaxSd + 1 , &xReadSet , NULL , NULL , NULL);
 | 
			
		||||
            if ((xErr < 0) && (errno != EINTR)) {
 | 
			
		||||
                // error occurred during wait for read
 | 
			
		||||
                ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() errno = %d.", errno);
 | 
			
		||||
                ESP_LOGE(TAG, "select() errno = %d.", errno);
 | 
			
		||||
                continue;
 | 
			
		||||
            } else if (xErr == 0) {
 | 
			
		||||
                // If timeout happened, something is wrong
 | 
			
		||||
                ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() timeout, errno = %d.", errno);
 | 
			
		||||
                ESP_LOGE(TAG, "select() timeout, errno = %d.", errno);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If something happened on the master socket, then its an incoming connection.
 | 
			
		||||
@@ -495,21 +495,21 @@ static void vMBTCPPortServerTask(void *pvParameters)
 | 
			
		||||
                // if request for new connection but no space left
 | 
			
		||||
                if (pxClientInfo != NULL) {
 | 
			
		||||
                    if (xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] == NULL) {
 | 
			
		||||
                        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to accept connection %d, only %d connections supported.", i + 1, MB_TCP_PORT_MAX_CONN);
 | 
			
		||||
                        ESP_LOGE(TAG, "Fail to accept connection %d, only %d connections supported.", i + 1, MB_TCP_PORT_MAX_CONN);
 | 
			
		||||
                    }
 | 
			
		||||
                    xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] = pxClientInfo; // set last connection info
 | 
			
		||||
                } else {
 | 
			
		||||
                    // allocate memory for new client info
 | 
			
		||||
                    pxClientInfo = calloc(1, sizeof(MbClientInfo_t));
 | 
			
		||||
                    if (!pxClientInfo) {
 | 
			
		||||
                        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client info allocation fail.");
 | 
			
		||||
                        ESP_LOGE(TAG, "Client info allocation fail.");
 | 
			
		||||
                        vMBTCPPortFreeClientInfo(pxClientInfo);
 | 
			
		||||
                        pxClientInfo = NULL;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        // Accept new client connection
 | 
			
		||||
                        pxClientInfo->xSockId = xMBTCPPortAcceptConnection(xListenSock, &pcClientIp);
 | 
			
		||||
                        if (pxClientInfo->xSockId < 0) {
 | 
			
		||||
                            ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to accept connection for client %d.", (xConfig.usClientCount - 1));
 | 
			
		||||
                            ESP_LOGE(TAG, "Fail to accept connection for client %d.", (xConfig.usClientCount - 1));
 | 
			
		||||
                            // Accept connection fail, then free client info and continue polling.
 | 
			
		||||
                            vMBTCPPortFreeClientInfo(pxClientInfo);
 | 
			
		||||
                            pxClientInfo = NULL;
 | 
			
		||||
@@ -517,7 +517,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
 | 
			
		||||
                        }
 | 
			
		||||
                        pxClientInfo->pucTCPBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
 | 
			
		||||
                        if (!pxClientInfo->pucTCPBuf) {
 | 
			
		||||
                            ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to allocate buffer for client %d.", (xConfig.usClientCount - 1));
 | 
			
		||||
                            ESP_LOGE(TAG, "Fail to allocate buffer for client %d.", (xConfig.usClientCount - 1));
 | 
			
		||||
                            vMBTCPPortFreeClientInfo(pxClientInfo);
 | 
			
		||||
                            pxClientInfo = NULL;
 | 
			
		||||
                            continue;
 | 
			
		||||
@@ -551,17 +551,17 @@ static void vMBTCPPortServerTask(void *pvParameters)
 | 
			
		||||
                                switch(xErr)
 | 
			
		||||
                                {
 | 
			
		||||
                                    case ERR_TIMEOUT:
 | 
			
		||||
                                        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %d, close active connection.",
 | 
			
		||||
                                        ESP_LOGE(TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %d, close active connection.",
 | 
			
		||||
                                                                            pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
 | 
			
		||||
                                                                            (int)(xTimeStamp - pxClientInfo->xRecvTimeStamp));
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case ERR_CLSD:
 | 
			
		||||
                                        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), connection closed by peer.",
 | 
			
		||||
                                        ESP_LOGE(TAG, "Socket (#%d)(%s), connection closed by peer.",
 | 
			
		||||
                                                                            pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
 | 
			
		||||
                                        break;
 | 
			
		||||
                                    case ERR_BUF:
 | 
			
		||||
                                    default:
 | 
			
		||||
                                        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), read data error: %d",
 | 
			
		||||
                                        ESP_LOGE(TAG, "Socket (#%d)(%s), read data error: %d",
 | 
			
		||||
                                                                            pxClientInfo->xSockId, pxClientInfo->pcIpAddr, xErr);
 | 
			
		||||
                                        break;
 | 
			
		||||
                                }
 | 
			
		||||
@@ -586,26 +586,26 @@ static void vMBTCPPortServerTask(void *pvParameters)
 | 
			
		||||
                                // Complete frame received, inform state machine to process frame
 | 
			
		||||
                                xMBPortEventPost(EV_FRAME_RECEIVED);
 | 
			
		||||
 | 
			
		||||
                                ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), get packet TID=0x%X, %d bytes.",
 | 
			
		||||
                                ESP_LOGD(TAG, "Socket (#%d)(%s), get packet TID=0x%X, %d bytes.",
 | 
			
		||||
                                                                    pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
 | 
			
		||||
                                                                    pxClientInfo->usTidCnt, xErr);
 | 
			
		||||
 | 
			
		||||
                                // Wait while response is not processed by stack by timeout
 | 
			
		||||
                                UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
 | 
			
		||||
                                if (pucSentBuffer == NULL) {
 | 
			
		||||
                                    ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Response time exceeds configured %d [ms], ignore packet.",
 | 
			
		||||
                                    ESP_LOGE(TAG, "Response time exceeds configured %d [ms], ignore packet.",
 | 
			
		||||
                                                                        MB_TCP_RESP_TIMEOUT_MS);
 | 
			
		||||
                                } else  {
 | 
			
		||||
                                    USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID);
 | 
			
		||||
                                    if (usSentTid != pxClientInfo->usTidCnt) {
 | 
			
		||||
                                        ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Sent TID(%x) != Recv TID(%x), ignore packet.",
 | 
			
		||||
                                        ESP_LOGE(TAG, "Sent TID(%x) != Recv TID(%x), ignore packet.",
 | 
			
		||||
                                                                            usSentTid, pxClientInfo->usTidCnt);
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
 | 
			
		||||
                                // Get time stamp of last data update
 | 
			
		||||
                                pxClientInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
 | 
			
		||||
                                ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Client %d, Socket(#%d), processing time = %d (us).",
 | 
			
		||||
                                ESP_LOGD(TAG, "Client %d, Socket(#%d), processing time = %d (us).",
 | 
			
		||||
                                                            pxClientInfo->xIndex, pxClientInfo->xSockId,
 | 
			
		||||
                                                            (int)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp));
 | 
			
		||||
                            }
 | 
			
		||||
@@ -614,7 +614,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
 | 
			
		||||
                                // client is not ready to be read
 | 
			
		||||
                                int64_t xTime = xMBTCPGetTimeStamp() - pxClientInfo->xRecvTimeStamp;
 | 
			
		||||
                                if (xTime > MB_TCP_DISCONNECT_TIMEOUT) {
 | 
			
		||||
                                    ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client %d, Socket(#%d) do not answer for %d (us). Drop connection...",
 | 
			
		||||
                                    ESP_LOGE(TAG, "Client %d, Socket(#%d) do not answer for %d (us). Drop connection...",
 | 
			
		||||
                                                                    pxClientInfo->xIndex, pxClientInfo->xSockId, (int)(xTime));
 | 
			
		||||
                                    xMBTCPPortCloseConnection(pxClientInfo);
 | 
			
		||||
 | 
			
		||||
@@ -623,7 +623,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
 | 
			
		||||
                                    xConfig.pxMbClientInfo[i] = NULL;
 | 
			
		||||
                                }
 | 
			
		||||
                            } else {
 | 
			
		||||
                                ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client %d is disconnected.", i);
 | 
			
		||||
                                ESP_LOGE(TAG, "Client %d is disconnected.", i);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } // if ((pxClientInfo != NULL)
 | 
			
		||||
@@ -693,7 +693,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
 | 
			
		||||
        // Check if socket writable
 | 
			
		||||
        xErr = select(xConfig.pxCurClientInfo->xSockId + 1, NULL, &xWriteSet, &xErrorSet, &xTimeVal);
 | 
			
		||||
        if ((xErr == -1) || FD_ISSET(xConfig.pxCurClientInfo->xSockId, &xErrorSet)) {
 | 
			
		||||
            ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket(#%d) , send select() error = %d.",
 | 
			
		||||
            ESP_LOGE(TAG, "Socket(#%d) , send select() error = %d.",
 | 
			
		||||
                    xConfig.pxCurClientInfo->xSockId, errno);
 | 
			
		||||
            return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
@@ -705,7 +705,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
 | 
			
		||||
        // Write message into socket and disable Nagle's algorithm
 | 
			
		||||
        xErr = send(xConfig.pxCurClientInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
 | 
			
		||||
        if (xErr < 0) {
 | 
			
		||||
            ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket(#%d), fail to send data, errno = %d",
 | 
			
		||||
            ESP_LOGE(TAG, "Socket(#%d), fail to send data, errno = %d",
 | 
			
		||||
                    xConfig.pxCurClientInfo->xSockId, errno);
 | 
			
		||||
            xConfig.pxCurClientInfo->xError = xErr;
 | 
			
		||||
        } else {
 | 
			
		||||
@@ -713,7 +713,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
 | 
			
		||||
            vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Port is not active. Release lock.");
 | 
			
		||||
        ESP_LOGD(TAG, "Port is not active. Release lock.");
 | 
			
		||||
        vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
 | 
			
		||||
    }
 | 
			
		||||
    return bFrameSent;
 | 
			
		||||
 
 | 
			
		||||
@@ -38,14 +38,6 @@
 | 
			
		||||
#define POLL_TIMEOUT_MS                 (1)
 | 
			
		||||
#define POLL_TIMEOUT_TICS               (POLL_TIMEOUT_MS / portTICK_RATE_MS)
 | 
			
		||||
 | 
			
		||||
#define MASTER_TAG "MASTER_TEST"
 | 
			
		||||
 | 
			
		||||
#define MASTER_CHECK(a, ret_val, str, ...) \
 | 
			
		||||
    if (!(a)) { \
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
 | 
			
		||||
        return (ret_val); \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
// The macro to get offset for parameter in the appropriate structure
 | 
			
		||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
 | 
			
		||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
 | 
			
		||||
@@ -57,6 +49,8 @@
 | 
			
		||||
// Options can be used as bit masks or parameter limits
 | 
			
		||||
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
 | 
			
		||||
 | 
			
		||||
static const char *TAG = "MASTER_TEST";
 | 
			
		||||
 | 
			
		||||
// Enumeration of modbus device addresses accessed by master device
 | 
			
		||||
enum {
 | 
			
		||||
    MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
 | 
			
		||||
@@ -135,7 +129,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
 | 
			
		||||
               break;
 | 
			
		||||
       }
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
 | 
			
		||||
        ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
 | 
			
		||||
        assert(instance_ptr != NULL);
 | 
			
		||||
    }
 | 
			
		||||
    return instance_ptr;
 | 
			
		||||
@@ -149,7 +143,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
    bool alarm_state = false;
 | 
			
		||||
    const mb_parameter_descriptor_t* param_descriptor = NULL;
 | 
			
		||||
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Start modbus test...");
 | 
			
		||||
    ESP_LOGI(TAG, "Start modbus test...");
 | 
			
		||||
 | 
			
		||||
    for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
 | 
			
		||||
        // Read all found characteristics from slave(s)
 | 
			
		||||
@@ -169,7 +163,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                    err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
 | 
			
		||||
                                                                            (uint8_t*)temp_data_ptr, &type);
 | 
			
		||||
                    if (err == ESP_OK) {
 | 
			
		||||
                        ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
 | 
			
		||||
                        ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
 | 
			
		||||
                                                 param_descriptor->cid,
 | 
			
		||||
                                                 (char*)param_descriptor->param_key,
 | 
			
		||||
                                                 (char*)param_descriptor->param_units,
 | 
			
		||||
@@ -181,13 +175,13 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                            err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
 | 
			
		||||
                                                              (uint8_t*)temp_data_ptr, &type);
 | 
			
		||||
                            if (err == ESP_OK) {
 | 
			
		||||
                                ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
 | 
			
		||||
                                ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
 | 
			
		||||
                                                            param_descriptor->cid,
 | 
			
		||||
                                                            (char*)param_descriptor->param_key,
 | 
			
		||||
                                                            (char*)param_descriptor->param_units,
 | 
			
		||||
                                                            *(uint32_t*)temp_data_ptr);
 | 
			
		||||
                            } else {
 | 
			
		||||
                                ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
 | 
			
		||||
                                ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
 | 
			
		||||
                                                        param_descriptor->cid,
 | 
			
		||||
                                                        (char*)param_descriptor->param_key,
 | 
			
		||||
                                                        (int)err,
 | 
			
		||||
@@ -195,7 +189,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
 | 
			
		||||
                        ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
 | 
			
		||||
                                                param_descriptor->cid,
 | 
			
		||||
                                                (char*)param_descriptor->param_key,
 | 
			
		||||
                                                (int)err,
 | 
			
		||||
@@ -208,7 +202,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                        *(float*)temp_data_ptr = value;
 | 
			
		||||
                        if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
 | 
			
		||||
                            (param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
 | 
			
		||||
                            ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
 | 
			
		||||
                            ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
 | 
			
		||||
                                            param_descriptor->cid,
 | 
			
		||||
                                            (char*)param_descriptor->param_key,
 | 
			
		||||
                                            (char*)param_descriptor->param_units,
 | 
			
		||||
@@ -222,7 +216,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            uint16_t state = *(uint16_t*)temp_data_ptr;
 | 
			
		||||
                            const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
 | 
			
		||||
                            ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
 | 
			
		||||
                            ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
 | 
			
		||||
                                            param_descriptor->cid,
 | 
			
		||||
                                            (char*)param_descriptor->param_key,
 | 
			
		||||
                                            (char*)param_descriptor->param_units,
 | 
			
		||||
@@ -234,7 +228,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    } else {
 | 
			
		||||
                        ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
 | 
			
		||||
                        ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
 | 
			
		||||
                                            param_descriptor->cid,
 | 
			
		||||
                                            (char*)param_descriptor->param_key,
 | 
			
		||||
                                            (int)err,
 | 
			
		||||
@@ -248,13 +242,13 @@ static void master_operation_func(void *arg)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (alarm_state) {
 | 
			
		||||
        ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
 | 
			
		||||
        ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
 | 
			
		||||
                                        param_descriptor->cid);
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
 | 
			
		||||
        ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
 | 
			
		||||
                                        MASTER_MAX_RETRY);
 | 
			
		||||
    }
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Destroy master...");
 | 
			
		||||
    ESP_LOGI(TAG, "Destroy master...");
 | 
			
		||||
    ESP_ERROR_CHECK(mbc_master_destroy());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -275,13 +269,13 @@ static esp_err_t master_init(void)
 | 
			
		||||
    void* master_handler = NULL;
 | 
			
		||||
 | 
			
		||||
    esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
 | 
			
		||||
    MASTER_CHECK((master_handler != NULL), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
 | 
			
		||||
                                "mb controller initialization fail.");
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
 | 
			
		||||
                            "mb controller initialization fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)err);
 | 
			
		||||
    err = mbc_master_setup((void*)&comm);
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
 | 
			
		||||
                            "mb controller setup fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
@@ -290,23 +284,23 @@ static esp_err_t master_init(void)
 | 
			
		||||
                              CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
 | 
			
		||||
 | 
			
		||||
    err = mbc_master_start();
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
 | 
			
		||||
                            "mb controller start fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
 | 
			
		||||
            "mb serial set pin failure, uart_set_pin() returned (0x%x).", (uint32_t)err);
 | 
			
		||||
    // Set driver mode to Half Duplex
 | 
			
		||||
    err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
 | 
			
		||||
            "mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
    vTaskDelay(5);
 | 
			
		||||
    err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
 | 
			
		||||
                                "mb controller set descriptor fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)err);
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
 | 
			
		||||
    ESP_LOGI(TAG, "Modbus master stack initialized...");
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@
 | 
			
		||||
                                                | MB_EVENT_COILS_WR)
 | 
			
		||||
#define MB_READ_WRITE_MASK                  (MB_READ_MASK | MB_WRITE_MASK)
 | 
			
		||||
 | 
			
		||||
static const char *SLAVE_TAG = "SLAVE_TEST";
 | 
			
		||||
static const char *TAG = "SLAVE_TEST";
 | 
			
		||||
 | 
			
		||||
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +92,7 @@ void app_main(void)
 | 
			
		||||
    mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
 | 
			
		||||
 | 
			
		||||
    // Set UART log level
 | 
			
		||||
    esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
 | 
			
		||||
    esp_log_level_set(TAG, ESP_LOG_INFO);
 | 
			
		||||
    void* mbc_slave_handler = NULL;
 | 
			
		||||
 | 
			
		||||
    ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller
 | 
			
		||||
@@ -166,8 +166,8 @@ void app_main(void)
 | 
			
		||||
    // Set UART driver mode to Half Duplex
 | 
			
		||||
    ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
 | 
			
		||||
 | 
			
		||||
    ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
 | 
			
		||||
    ESP_LOGI(SLAVE_TAG, "Start modbus test...");
 | 
			
		||||
    ESP_LOGI(TAG, "Modbus slave stack initialized.");
 | 
			
		||||
    ESP_LOGI(TAG, "Start modbus test...");
 | 
			
		||||
 | 
			
		||||
    // The cycle below will be terminated when parameter holdingRegParams.dataChan0
 | 
			
		||||
    // incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
 | 
			
		||||
@@ -180,7 +180,7 @@ void app_main(void)
 | 
			
		||||
        if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
 | 
			
		||||
            // Get parameter information from parameter queue
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                    rw_str,
 | 
			
		||||
                    (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                    (uint32_t)reg_info.mb_offset,
 | 
			
		||||
@@ -198,7 +198,7 @@ void app_main(void)
 | 
			
		||||
            }
 | 
			
		||||
        } else if (event & MB_EVENT_INPUT_REG_RD) {
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                    (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                    (uint32_t)reg_info.mb_offset,
 | 
			
		||||
                    (uint32_t)reg_info.type,
 | 
			
		||||
@@ -206,7 +206,7 @@ void app_main(void)
 | 
			
		||||
                    (uint32_t)reg_info.size);
 | 
			
		||||
        } else if (event & MB_EVENT_DISCRETE_RD) {
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                                (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                                (uint32_t)reg_info.mb_offset,
 | 
			
		||||
                                (uint32_t)reg_info.type,
 | 
			
		||||
@@ -214,7 +214,7 @@ void app_main(void)
 | 
			
		||||
                                (uint32_t)reg_info.size);
 | 
			
		||||
        } else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                                rw_str,
 | 
			
		||||
                                (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                                (uint32_t)reg_info.mb_offset,
 | 
			
		||||
@@ -225,7 +225,7 @@ void app_main(void)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Destroy of Modbus controller on alarm
 | 
			
		||||
    ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
 | 
			
		||||
    ESP_LOGI(TAG,"Modbus controller destroyed.");
 | 
			
		||||
    vTaskDelay(100);
 | 
			
		||||
    ESP_ERROR_CHECK(mbc_slave_destroy());
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,6 @@
 | 
			
		||||
# SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
 | 
			
		||||
# SPDX-License-Identifier: Apache-2.0
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
@@ -69,7 +72,7 @@ class DutTestThread(Thread):
 | 
			
		||||
        super(DutTestThread, self).__init__()
 | 
			
		||||
 | 
			
		||||
    def __enter__(self):
 | 
			
		||||
        logger.debug('Restart %s.' % self.tname)
 | 
			
		||||
        logger.debug('Restart %s.', self.tname)
 | 
			
		||||
        # Reset DUT first
 | 
			
		||||
        self.dut.reset()
 | 
			
		||||
        # Capture output from the DUT
 | 
			
		||||
@@ -80,7 +83,7 @@ class DutTestThread(Thread):
 | 
			
		||||
        """ The exit method of context manager
 | 
			
		||||
        """
 | 
			
		||||
        if exc_type is not None or exc_value is not None:
 | 
			
		||||
            logger.info('Thread %s rised an exception type: %s, value: %s' % (self.tname, str(exc_type), str(exc_value)))
 | 
			
		||||
            logger.info('Thread %s rised an exception type: %s, value: %s', self.tname, str(exc_type), str(exc_value))
 | 
			
		||||
 | 
			
		||||
    def run(self):
 | 
			
		||||
        """ The function implements thread functionality
 | 
			
		||||
@@ -95,7 +98,7 @@ class DutTestThread(Thread):
 | 
			
		||||
        # Check DUT exceptions
 | 
			
		||||
        dut_exceptions = self.dut.get_exceptions()
 | 
			
		||||
        if 'Guru Meditation Error:' in dut_exceptions:
 | 
			
		||||
            raise Exception('%s generated an exception: %s\n' % (str(self.dut), dut_exceptions))
 | 
			
		||||
            raise RuntimeError('%s generated an exception(s): %s\n' % (str(self.dut), dut_exceptions))
 | 
			
		||||
 | 
			
		||||
        # Mark thread has run to completion without any exceptions
 | 
			
		||||
        self.data = self.dut.stop_capture_raw_data(capture_id=self.dut.name)
 | 
			
		||||
@@ -106,15 +109,17 @@ class DutTestThread(Thread):
 | 
			
		||||
        message = r'.*Waiting IP([0-9]{1,2}) from stdin.*'
 | 
			
		||||
        # Read all data from previous restart to get prompt correctly
 | 
			
		||||
        self.dut.read()
 | 
			
		||||
        result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
 | 
			
		||||
        result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
 | 
			
		||||
        if int(result[0]) != index:
 | 
			
		||||
            raise Exception('Incorrect index of IP=%d for %s\n' % (int(result[0]), str(self.dut)))
 | 
			
		||||
        message = 'IP%s=%s' % (result[0], self.ip_addr)
 | 
			
		||||
        self.dut.write(message, '\r\n', False)
 | 
			
		||||
        logger.debug('Sent message for %s: %s' % (self.tname, message))
 | 
			
		||||
            raise RuntimeError('Incorrect index of IP=%s for %s\n' % (result[0], str(self.dut)))
 | 
			
		||||
        # Use the same slave IP address for all characteristics during the test
 | 
			
		||||
        self.dut.write('IP0=' + self.ip_addr, '\n', False)
 | 
			
		||||
        self.dut.write('IP1=' + self.ip_addr, '\n', False)
 | 
			
		||||
        self.dut.write('IP2=' + self.ip_addr, '\n', False)
 | 
			
		||||
        logger.debug('Set IP address=%s for %s', self.ip_addr, self.tname)
 | 
			
		||||
        message = r'.*IP\([0-9]+\) = \[([0-9a-zA-Z\.\:]+)\] set from stdin.*'
 | 
			
		||||
        result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
 | 
			
		||||
        logger.debug('Thread %s initialized with slave IP (%s).' % (self.tname, result[0]))
 | 
			
		||||
        result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
 | 
			
		||||
        logger.debug('Thread %s initialized with slave IP=%s.', self.tname, self.ip_addr)
 | 
			
		||||
 | 
			
		||||
    def test_start(self, timeout_value):
 | 
			
		||||
        """ The method to initialize and handle test stages
 | 
			
		||||
@@ -122,37 +127,37 @@ class DutTestThread(Thread):
 | 
			
		||||
        def handle_get_ip4(data):
 | 
			
		||||
            """ Handle get_ip v4
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[STACK_IPV4]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[STACK_IPV4]: %s', self.tname, str(data))
 | 
			
		||||
            self.test_stage = STACK_IPV4
 | 
			
		||||
 | 
			
		||||
        def handle_get_ip6(data):
 | 
			
		||||
            """ Handle get_ip v6
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[STACK_IPV6]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[STACK_IPV6]: %s', self.tname, str(data))
 | 
			
		||||
            self.test_stage = STACK_IPV6
 | 
			
		||||
 | 
			
		||||
        def handle_init(data):
 | 
			
		||||
            """ Handle init
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[STACK_INIT]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[STACK_INIT]: %s', self.tname, str(data))
 | 
			
		||||
            self.test_stage = STACK_INIT
 | 
			
		||||
 | 
			
		||||
        def handle_connect(data):
 | 
			
		||||
            """ Handle connect
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[STACK_CONNECT]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[STACK_CONNECT]: %s', self.tname, str(data))
 | 
			
		||||
            self.test_stage = STACK_CONNECT
 | 
			
		||||
 | 
			
		||||
        def handle_test_start(data):
 | 
			
		||||
            """ Handle connect
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[STACK_START]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[STACK_START]: %s', self.tname, str(data))
 | 
			
		||||
            self.test_stage = STACK_START
 | 
			
		||||
 | 
			
		||||
        def handle_par_ok(data):
 | 
			
		||||
            """ Handle parameter ok
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[READ_PAR_OK]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[READ_PAR_OK]: %s', self.tname, str(data))
 | 
			
		||||
            if self.test_stage >= STACK_START:
 | 
			
		||||
                self.param_ok_count += 1
 | 
			
		||||
            self.test_stage = STACK_PAR_OK
 | 
			
		||||
@@ -160,14 +165,14 @@ class DutTestThread(Thread):
 | 
			
		||||
        def handle_par_fail(data):
 | 
			
		||||
            """ Handle parameter fail
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[READ_PAR_FAIL]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[READ_PAR_FAIL]: %s', self.tname, str(data))
 | 
			
		||||
            self.param_fail_count += 1
 | 
			
		||||
            self.test_stage = STACK_PAR_FAIL
 | 
			
		||||
 | 
			
		||||
        def handle_destroy(data):
 | 
			
		||||
            """ Handle destroy
 | 
			
		||||
            """
 | 
			
		||||
            logger.debug('%s[DESTROY]: %s' % (self.tname, str(data)))
 | 
			
		||||
            logger.debug('%s[DESTROY]: %s', self.tname, str(data))
 | 
			
		||||
            self.test_stage = STACK_DESTROY
 | 
			
		||||
            self.test_finish = True
 | 
			
		||||
 | 
			
		||||
@@ -183,7 +188,7 @@ class DutTestThread(Thread):
 | 
			
		||||
                                    (re.compile(self.expected[STACK_DESTROY]), handle_destroy),
 | 
			
		||||
                                    timeout=timeout_value)
 | 
			
		||||
            except DUT.ExpectTimeout:
 | 
			
		||||
                logger.debug('%s, expect timeout on stage #%d (%s seconds)' % (self.tname, self.test_stage, timeout_value))
 | 
			
		||||
                logger.debug('%s, expect timeout on stage #%d (%s seconds)', self.tname, self.test_stage, timeout_value)
 | 
			
		||||
                self.test_finish = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -193,14 +198,14 @@ def test_check_mode(dut=None, mode_str=None, value=None):
 | 
			
		||||
    global logger
 | 
			
		||||
    try:
 | 
			
		||||
        opt = dut.app.get_sdkconfig()[mode_str]
 | 
			
		||||
        logger.debug('%s {%s} = %s.\n' % (str(dut), mode_str, opt))
 | 
			
		||||
        logger.debug('%s {%s} = %s.\n', str(dut), mode_str, opt)
 | 
			
		||||
        return value == opt
 | 
			
		||||
    except Exception:
 | 
			
		||||
        logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.' % (str(dut), mode_str))
 | 
			
		||||
        logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.', str(dut), mode_str)
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ttfw_idf.idf_example_test(env_tag='Example_Modbus_TCP')
 | 
			
		||||
@ttfw_idf.idf_example_test(env_tag='Example_Modbus_TCP', target=['esp32'])
 | 
			
		||||
def test_modbus_communication(env, comm_mode):
 | 
			
		||||
    global logger
 | 
			
		||||
 | 
			
		||||
@@ -235,7 +240,7 @@ def test_modbus_communication(env, comm_mode):
 | 
			
		||||
            master_name = TEST_MASTER_TCP
 | 
			
		||||
        else:
 | 
			
		||||
            logger.error('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
 | 
			
		||||
            raise Exception('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
 | 
			
		||||
            raise RuntimeError('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
 | 
			
		||||
        address = None
 | 
			
		||||
        if test_check_mode(dut_master, 'CONFIG_MB_SLAVE_IP_FROM_STDIN', 'y'):
 | 
			
		||||
            logger.info('ENV_TEST_INFO: Set slave IP address through STDIN.\n')
 | 
			
		||||
@@ -249,9 +254,9 @@ def test_modbus_communication(env, comm_mode):
 | 
			
		||||
            if address is not None:
 | 
			
		||||
                    print('Found IP slave address: %s' % address[0])
 | 
			
		||||
            else:
 | 
			
		||||
                raise Exception('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
 | 
			
		||||
                raise RuntimeError('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
 | 
			
		||||
        else:
 | 
			
		||||
            raise Exception('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
 | 
			
		||||
            raise RuntimeError('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
 | 
			
		||||
 | 
			
		||||
        # Create thread for each dut
 | 
			
		||||
        with DutTestThread(dut=dut_master, name=master_name, ip_addr=address[0], expect=pattern_dict_master) as dut_master_thread:
 | 
			
		||||
@@ -265,32 +270,32 @@ def test_modbus_communication(env, comm_mode):
 | 
			
		||||
                dut_slave_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
 | 
			
		||||
                dut_master_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
 | 
			
		||||
 | 
			
		||||
                if dut_slave_thread.isAlive():
 | 
			
		||||
                    logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
 | 
			
		||||
                                 (dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
 | 
			
		||||
                    raise Exception('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
 | 
			
		||||
                                    (dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
 | 
			
		||||
                if dut_slave_thread.is_alive():
 | 
			
		||||
                    logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
 | 
			
		||||
                                 dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
 | 
			
		||||
                    raise RuntimeError('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
 | 
			
		||||
                                       (dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
 | 
			
		||||
 | 
			
		||||
                if dut_master_thread.isAlive():
 | 
			
		||||
                    logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
 | 
			
		||||
                                 (dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
 | 
			
		||||
                    raise Exception('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
 | 
			
		||||
                                    (dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
 | 
			
		||||
                if dut_master_thread.is_alive():
 | 
			
		||||
                    logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
 | 
			
		||||
                                 dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
 | 
			
		||||
                    raise RuntimeError('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
 | 
			
		||||
                                       (dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
 | 
			
		||||
 | 
			
		||||
                logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n' %
 | 
			
		||||
                            (dut_master_thread.tname, dut_master_thread.param_fail_count,
 | 
			
		||||
                             dut_slave_thread.tname, dut_slave_thread.param_fail_count))
 | 
			
		||||
                logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n' %
 | 
			
		||||
                            (dut_master_thread.tname, dut_master_thread.param_ok_count,
 | 
			
		||||
                             dut_slave_thread.tname, dut_slave_thread.param_ok_count))
 | 
			
		||||
                logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n',
 | 
			
		||||
                            dut_master_thread.tname, dut_master_thread.param_fail_count,
 | 
			
		||||
                            dut_slave_thread.tname, dut_slave_thread.param_fail_count)
 | 
			
		||||
                logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n',
 | 
			
		||||
                            dut_master_thread.tname, dut_master_thread.param_ok_count,
 | 
			
		||||
                            dut_slave_thread.tname, dut_slave_thread.param_ok_count)
 | 
			
		||||
 | 
			
		||||
                if ((dut_master_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
 | 
			
		||||
                   (dut_slave_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
 | 
			
		||||
                   (dut_slave_thread.param_ok_count == 0) or
 | 
			
		||||
                   (dut_master_thread.param_ok_count == 0)):
 | 
			
		||||
                    raise Exception('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
 | 
			
		||||
                                    (dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
 | 
			
		||||
                                     dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
 | 
			
		||||
                    raise RuntimeError('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
 | 
			
		||||
                                       (dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
 | 
			
		||||
                                        dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
 | 
			
		||||
                logger.info('TEST_SUCCESS: The Modbus parameter test is completed successfully.\n')
 | 
			
		||||
 | 
			
		||||
    finally:
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,10 @@
 | 
			
		||||
// 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_system.h"
 | 
			
		||||
#include "esp_wifi.h"
 | 
			
		||||
@@ -44,14 +47,6 @@
 | 
			
		||||
#define POLL_TIMEOUT_TICS               (POLL_TIMEOUT_MS / portTICK_RATE_MS)
 | 
			
		||||
#define MB_MDNS_PORT                    (502)
 | 
			
		||||
 | 
			
		||||
#define MASTER_TAG "MASTER_TEST"
 | 
			
		||||
 | 
			
		||||
#define MASTER_CHECK(a, ret_val, str, ...) \
 | 
			
		||||
    if (!(a)) { \
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
 | 
			
		||||
        return (ret_val); \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
// The macro to get offset for parameter in the appropriate structure
 | 
			
		||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
 | 
			
		||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
 | 
			
		||||
@@ -76,12 +71,14 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp"
 | 
			
		||||
static const char *TAG = "MASTER_TEST";
 | 
			
		||||
 | 
			
		||||
// Enumeration of modbus device addresses accessed by master device
 | 
			
		||||
// Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
 | 
			
		||||
enum {
 | 
			
		||||
    MB_DEVICE_ADDR1 = 1, // Slave address 1
 | 
			
		||||
    MB_DEVICE_COUNT
 | 
			
		||||
    MB_DEVICE_ADDR2 = 200,
 | 
			
		||||
    MB_DEVICE_ADDR3 = 35
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Enumeration of all supported CIDs for device (used in parameter definition table)
 | 
			
		||||
@@ -114,11 +111,11 @@ const mb_parameter_descriptor_t device_parameters[] = {
 | 
			
		||||
            HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
 | 
			
		||||
    { CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
 | 
			
		||||
            INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
 | 
			
		||||
    { CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 2,
 | 
			
		||||
    { CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 2, 2,
 | 
			
		||||
            HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
 | 
			
		||||
    { CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 4, 2,
 | 
			
		||||
    { CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR2, MB_PARAM_INPUT, 4, 2,
 | 
			
		||||
            INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
 | 
			
		||||
    { CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2,
 | 
			
		||||
    { CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR3, MB_PARAM_HOLDING, 4, 2,
 | 
			
		||||
            HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
 | 
			
		||||
    { CID_RELAY_P1, STR("RelayP1"), STR("on/off"), MB_DEVICE_ADDR1, MB_PARAM_COIL, 0, 8,
 | 
			
		||||
            COIL_OFFSET(coils_port0), PARAM_TYPE_U16, 2, OPTS( BIT1, 0, 0 ), PAR_PERMS_READ_WRITE_TRIGGER },
 | 
			
		||||
@@ -127,20 +124,26 @@ const mb_parameter_descriptor_t device_parameters[] = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Calculate number of parameters in the table
 | 
			
		||||
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters[0]));
 | 
			
		||||
const uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
 | 
			
		||||
 | 
			
		||||
// This table represents slave IP addresses that correspond to the short address field of the slave in device_parameters structure
 | 
			
		||||
// Modbus TCP stack shall use these addresses to be able to connect and read parameters from slave
 | 
			
		||||
char* slave_ip_address_table[MB_DEVICE_COUNT] = {
 | 
			
		||||
char* slave_ip_address_table[] = {
 | 
			
		||||
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
 | 
			
		||||
    "FROM_STDIN",     // Address corresponds to MB_DEVICE_ADDR1 and set to predefined value by user
 | 
			
		||||
    NULL
 | 
			
		||||
    "FROM_STDIN",     // Corresponds to characteristic MB_DEVICE_ADDR2
 | 
			
		||||
    "FROM_STDIN",     // Corresponds to characteristic MB_DEVICE_ADDR3
 | 
			
		||||
    NULL              // End of table condition (must be included)
 | 
			
		||||
#elif CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
    NULL,
 | 
			
		||||
    NULL,
 | 
			
		||||
    NULL,
 | 
			
		||||
    NULL
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const size_t ip_table_sz = (size_t)(sizeof(slave_ip_address_table) / sizeof(slave_ip_address_table[0]));
 | 
			
		||||
 | 
			
		||||
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
 | 
			
		||||
 | 
			
		||||
// Scan IP address according to IPV settings
 | 
			
		||||
@@ -191,8 +194,8 @@ static int master_get_slave_ip_stdin(char** addr_table)
 | 
			
		||||
            fputc('\n', stdout);
 | 
			
		||||
            ip_str = master_scan_addr(&index, buf);
 | 
			
		||||
            if (ip_str != NULL) {
 | 
			
		||||
                ESP_LOGI(MASTER_TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
 | 
			
		||||
                if ((ip_cnt >= MB_DEVICE_COUNT) || (index != ip_cnt)) {
 | 
			
		||||
                ESP_LOGI(TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
 | 
			
		||||
                if ((ip_cnt >= ip_table_sz) || (index != ip_cnt)) {
 | 
			
		||||
                    addr_table[ip_cnt] = NULL;
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
@@ -204,10 +207,10 @@ static int master_get_slave_ip_stdin(char** addr_table)
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            if (addr_table[ip_cnt]) {
 | 
			
		||||
                ESP_LOGI(MASTER_TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
 | 
			
		||||
                ESP_LOGI(TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
 | 
			
		||||
                ip_cnt++;
 | 
			
		||||
            } else {
 | 
			
		||||
                ESP_LOGI(MASTER_TAG, "IP(%d) is not set in the table.", ip_cnt);
 | 
			
		||||
                ESP_LOGI(TAG, "IP(%d) is not set in the table.", ip_cnt);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -217,6 +220,16 @@ static int master_get_slave_ip_stdin(char** addr_table)
 | 
			
		||||
 | 
			
		||||
#elif CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
 | 
			
		||||
typedef struct slave_addr_entry_s {
 | 
			
		||||
    uint16_t index;
 | 
			
		||||
    char* ip_address;
 | 
			
		||||
    uint8_t slave_addr;
 | 
			
		||||
    void* p_data;
 | 
			
		||||
    LIST_ENTRY(slave_addr_entry_s) entries;
 | 
			
		||||
} slave_addr_entry_t;
 | 
			
		||||
 | 
			
		||||
LIST_HEAD(slave_addr_, slave_addr_entry_s) slave_addr_list = LIST_HEAD_INITIALIZER(slave_addr_list);
 | 
			
		||||
 | 
			
		||||
// convert MAC from binary format to string
 | 
			
		||||
static inline char* gen_mac_str(const uint8_t* mac, char* pref, char* mac_str)
 | 
			
		||||
{
 | 
			
		||||
@@ -240,7 +253,7 @@ static void master_start_mdns_service()
 | 
			
		||||
    ESP_ERROR_CHECK(mdns_init());
 | 
			
		||||
    // set mDNS hostname (required if you want to advertise services)
 | 
			
		||||
    ESP_ERROR_CHECK(mdns_hostname_set(hostname));
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "mdns hostname set to: [%s]", hostname);
 | 
			
		||||
    ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname);
 | 
			
		||||
 | 
			
		||||
    // set default mDNS instance name
 | 
			
		||||
    ESP_ERROR_CHECK(mdns_instance_name_set(MB_MDNS_INSTANCE("esp32_")));
 | 
			
		||||
@@ -281,15 +294,21 @@ static char* master_get_slave_ip_str(mdns_ip_addr_t* address, mb_tcp_addr_type_t
 | 
			
		||||
    return slave_ip_str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, char** resolved_ip,
 | 
			
		||||
static esp_err_t master_resolve_slave(uint8_t short_addr, mdns_result_t* result, char** resolved_ip,
 | 
			
		||||
                                        mb_tcp_addr_type_t addr_type)
 | 
			
		||||
{
 | 
			
		||||
    if (!name || !result) {
 | 
			
		||||
    if (!short_addr || !result || !resolved_ip) {
 | 
			
		||||
        return ESP_ERR_INVALID_ARG;
 | 
			
		||||
    }
 | 
			
		||||
    mdns_result_t* r = result;
 | 
			
		||||
    int t;
 | 
			
		||||
    char* slave_ip = NULL;
 | 
			
		||||
    char slave_name[22] = {0};
 | 
			
		||||
 | 
			
		||||
    if (sprintf(slave_name, "mb_slave_tcp_%02X", short_addr) < 0) {
 | 
			
		||||
        ESP_LOGE(TAG, "Fail to create instance name for index: %d", short_addr);
 | 
			
		||||
        abort();
 | 
			
		||||
    }
 | 
			
		||||
    for (; r ; r = r->next) {
 | 
			
		||||
        if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
 | 
			
		||||
            continue;
 | 
			
		||||
@@ -298,7 +317,7 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
 | 
			
		||||
        }
 | 
			
		||||
        // Check host name for Modbus short address and
 | 
			
		||||
        // append it into slave ip address table
 | 
			
		||||
        if ((strcmp(r->instance_name, name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
 | 
			
		||||
        if ((strcmp(r->instance_name, slave_name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
 | 
			
		||||
            printf("  PTR : %s\n", r->instance_name);
 | 
			
		||||
            if (r->txt_count) {
 | 
			
		||||
                printf("  TXT : [%u] ", r->txt_count);
 | 
			
		||||
@@ -309,92 +328,124 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
 | 
			
		||||
            }
 | 
			
		||||
            slave_ip = master_get_slave_ip_str(r->addr, addr_type);
 | 
			
		||||
            if (slave_ip) {
 | 
			
		||||
                ESP_LOGI(MASTER_TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
 | 
			
		||||
                ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
 | 
			
		||||
                *resolved_ip = slave_ip;
 | 
			
		||||
                return ESP_OK;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    *resolved_ip = NULL;
 | 
			
		||||
    ESP_LOGD(MASTER_TAG, "Fail to resolve slave: %s", name);
 | 
			
		||||
    ESP_LOGD(TAG, "Fail to resolve slave: %s", slave_name);
 | 
			
		||||
    return ESP_ERR_NOT_FOUND;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int master_create_slave_list(mdns_result_t* results, char** addr_table,
 | 
			
		||||
                                        mb_tcp_addr_type_t addr_type)
 | 
			
		||||
                                        int addr_table_size, mb_tcp_addr_type_t addr_type)
 | 
			
		||||
{
 | 
			
		||||
    if (!results) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    int i, addr, resolved = 0;
 | 
			
		||||
    int i, slave_addr, cid_resolve_cnt = 0;
 | 
			
		||||
    int ip_index = 0;
 | 
			
		||||
    const mb_parameter_descriptor_t* pdescr = &device_parameters[0];
 | 
			
		||||
    char** ip_table = addr_table;
 | 
			
		||||
    char slave_name[22] = {0};
 | 
			
		||||
    char* slave_ip = NULL;
 | 
			
		||||
    slave_addr_entry_t *it;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++) {
 | 
			
		||||
        addr = pdescr->mb_slave_addr;
 | 
			
		||||
        if (-1 == sprintf(slave_name, "mb_slave_tcp_%02X", addr)) {
 | 
			
		||||
            ESP_LOGI(MASTER_TAG, "Fail to create instance name for index: %d", addr);
 | 
			
		||||
            abort();
 | 
			
		||||
    for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++)
 | 
			
		||||
    {
 | 
			
		||||
        slave_addr = pdescr->mb_slave_addr;
 | 
			
		||||
 | 
			
		||||
        it = NULL;
 | 
			
		||||
        // Is the slave address already registered?
 | 
			
		||||
        LIST_FOREACH(it, &slave_addr_list, entries) {
 | 
			
		||||
            if (slave_addr == it->slave_addr) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!ip_table[addr - 1]) {
 | 
			
		||||
            esp_err_t err = master_resolve_slave(slave_name, results, &slave_ip, addr_type);
 | 
			
		||||
        if (!it) {
 | 
			
		||||
            // Resolve new slave IP address using its short address
 | 
			
		||||
            esp_err_t err = master_resolve_slave(slave_addr, results, &slave_ip, addr_type);
 | 
			
		||||
            if (err != ESP_OK) {
 | 
			
		||||
                ESP_LOGE(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, failed to resolve!",
 | 
			
		||||
                                        i, addr, slave_name);
 | 
			
		||||
                ESP_LOGE(TAG, "Index: %d, sl_addr: %d, failed to resolve!", i, slave_addr);
 | 
			
		||||
                // Set correspond index to NULL indicate host not resolved
 | 
			
		||||
                ip_table[addr - 1] = NULL;
 | 
			
		||||
                ip_table[ip_index] = NULL;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            ip_table[addr - 1] = slave_ip; //slave_name;
 | 
			
		||||
            ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, resolve to IP: [%s]",
 | 
			
		||||
                                    i, addr, slave_name, slave_ip);
 | 
			
		||||
            resolved++;
 | 
			
		||||
            // Register new slave address information
 | 
			
		||||
            slave_addr_entry_t* new_slave_entry = (slave_addr_entry_t*) heap_caps_malloc(sizeof(slave_addr_entry_t),
 | 
			
		||||
                                                       MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
 | 
			
		||||
            MB_RETURN_ON_FALSE((new_slave_entry != NULL), ESP_ERR_NO_MEM,
 | 
			
		||||
                                                 TAG, "Can not allocate memory for slave entry.");
 | 
			
		||||
            new_slave_entry->index = i;
 | 
			
		||||
            new_slave_entry->ip_address = slave_ip;
 | 
			
		||||
            new_slave_entry->slave_addr = slave_addr;
 | 
			
		||||
            new_slave_entry->p_data = NULL;
 | 
			
		||||
            LIST_INSERT_HEAD(&slave_addr_list, new_slave_entry, entries);
 | 
			
		||||
            ip_table[ip_index] = slave_ip;
 | 
			
		||||
            ESP_LOGI(TAG, "Index: %d, sl_addr: %d, resolved to IP: [%s]",
 | 
			
		||||
                                                i, slave_addr, slave_ip);
 | 
			
		||||
            cid_resolve_cnt++;
 | 
			
		||||
            if (ip_index < addr_table_size) {
 | 
			
		||||
                ip_index++;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, set to IP: [%s]",
 | 
			
		||||
                                    i, addr, slave_name, ip_table[addr - 1]);
 | 
			
		||||
            resolved++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return resolved;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void master_destroy_slave_list(char** table)
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; ((i < MB_DEVICE_COUNT) && table[i] != NULL); i++) {
 | 
			
		||||
        if (table[i]) {
 | 
			
		||||
            free(table[i]);
 | 
			
		||||
            table[i] = NULL;
 | 
			
		||||
            ip_table[ip_index] = it ? it->ip_address : ip_table[ip_index];
 | 
			
		||||
            ESP_LOGI(TAG, "Index: %d, sl_addr: %d, set to IP: [%s]",
 | 
			
		||||
                                    i, slave_addr, ip_table[ip_index]);
 | 
			
		||||
            cid_resolve_cnt++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ESP_LOGI(TAG, "Resolved %d cids, with %d IP addresses", cid_resolve_cnt, ip_index);
 | 
			
		||||
    return cid_resolve_cnt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int master_query_slave_service(const char * service_name, const char * proto,
 | 
			
		||||
                                        mb_tcp_addr_type_t addr_type)
 | 
			
		||||
{
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Query PTR: %s.%s.local", service_name, proto);
 | 
			
		||||
    ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
 | 
			
		||||
 | 
			
		||||
    mdns_result_t* results = NULL;
 | 
			
		||||
    int count = 0;
 | 
			
		||||
 | 
			
		||||
    esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
 | 
			
		||||
    if(err){
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Query Failed: %s", esp_err_to_name(err));
 | 
			
		||||
        ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
    if(!results){
 | 
			
		||||
        ESP_LOGW(MASTER_TAG, "No results found!");
 | 
			
		||||
        ESP_LOGW(TAG, "No results found!");
 | 
			
		||||
        return count;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    count = master_create_slave_list(results, slave_ip_address_table, addr_type);
 | 
			
		||||
    count = master_create_slave_list(results, slave_ip_address_table, ip_table_sz, addr_type);
 | 
			
		||||
 | 
			
		||||
    mdns_query_results_free(results);
 | 
			
		||||
    return count;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void master_destroy_slave_list(char** table, size_t ip_table_size)
 | 
			
		||||
{
 | 
			
		||||
#if CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
    slave_addr_entry_t *it;
 | 
			
		||||
    LIST_FOREACH(it, &slave_addr_list, entries) {
 | 
			
		||||
        LIST_REMOVE(it, entries);
 | 
			
		||||
        free(it);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    for (int i = 0; ((i < ip_table_size) && table[i] != NULL); i++) {
 | 
			
		||||
        if (table[i]) {
 | 
			
		||||
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
 | 
			
		||||
            free(table[i]);
 | 
			
		||||
            table[i] = "FROM_STDIN";
 | 
			
		||||
#elif CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
            table[i] = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The function to get pointer to parameter storage (instance) according to parameter description table
 | 
			
		||||
static void* master_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
 | 
			
		||||
{
 | 
			
		||||
@@ -420,7 +471,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
 | 
			
		||||
               break;
 | 
			
		||||
       }
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
 | 
			
		||||
        ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
 | 
			
		||||
        assert(instance_ptr != NULL);
 | 
			
		||||
    }
 | 
			
		||||
    return instance_ptr;
 | 
			
		||||
@@ -434,7 +485,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
    bool alarm_state = false;
 | 
			
		||||
    const mb_parameter_descriptor_t* param_descriptor = NULL;
 | 
			
		||||
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Start modbus test...");
 | 
			
		||||
    ESP_LOGI(TAG, "Start modbus test...");
 | 
			
		||||
 | 
			
		||||
    for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
 | 
			
		||||
        // Read all found characteristics from slave(s)
 | 
			
		||||
@@ -454,7 +505,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                    *(float*)temp_data_ptr = value;
 | 
			
		||||
                    if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
 | 
			
		||||
                        (param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
 | 
			
		||||
                        ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
 | 
			
		||||
                        ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
 | 
			
		||||
                                        param_descriptor->cid,
 | 
			
		||||
                                        (char*)param_descriptor->param_key,
 | 
			
		||||
                                        (char*)param_descriptor->param_units,
 | 
			
		||||
@@ -468,7 +519,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                    } else {
 | 
			
		||||
                        uint16_t state = *(uint16_t*)temp_data_ptr;
 | 
			
		||||
                        const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
 | 
			
		||||
                        ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
 | 
			
		||||
                        ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
 | 
			
		||||
                                        param_descriptor->cid,
 | 
			
		||||
                                        (char*)param_descriptor->param_key,
 | 
			
		||||
                                        (char*)param_descriptor->param_units,
 | 
			
		||||
@@ -480,7 +531,7 @@ static void master_operation_func(void *arg)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = %d (%s).",
 | 
			
		||||
                    ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = %d (%s).",
 | 
			
		||||
                                        param_descriptor->cid,
 | 
			
		||||
                                        (char*)param_descriptor->param_key,
 | 
			
		||||
                                        (int)err,
 | 
			
		||||
@@ -493,13 +544,13 @@ static void master_operation_func(void *arg)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (alarm_state) {
 | 
			
		||||
        ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
 | 
			
		||||
        ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
 | 
			
		||||
                                        param_descriptor->cid);
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
 | 
			
		||||
        ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
 | 
			
		||||
                                        MASTER_MAX_RETRY);
 | 
			
		||||
    }
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Destroy master...");
 | 
			
		||||
    ESP_LOGI(TAG, "Destroy master...");
 | 
			
		||||
    vTaskDelay(100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -510,15 +561,18 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
 | 
			
		||||
      ESP_ERROR_CHECK(nvs_flash_erase());
 | 
			
		||||
      result = nvs_flash_init();
 | 
			
		||||
    }
 | 
			
		||||
    MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "nvs_flash_init fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)result);
 | 
			
		||||
    result = esp_netif_init();
 | 
			
		||||
    MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "esp_netif_init fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)result);
 | 
			
		||||
    result = esp_event_loop_create_default();
 | 
			
		||||
    MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "esp_event_loop_create_default fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)result);
 | 
			
		||||
#if CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
@@ -529,12 +583,14 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
 | 
			
		||||
    // Read "Establishing Wi-Fi or Ethernet Connection" section in
 | 
			
		||||
    // examples/protocols/README.md for more information about this function.
 | 
			
		||||
    result = example_connect();
 | 
			
		||||
    MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "example_connect fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)result);
 | 
			
		||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
 | 
			
		||||
   result = esp_wifi_set_ps(WIFI_PS_NONE);
 | 
			
		||||
   MASTER_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
   MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                   TAG,
 | 
			
		||||
                                   "esp_wifi_set_ps fail, returns(0x%x).",
 | 
			
		||||
                                   (uint32_t)result);
 | 
			
		||||
#endif
 | 
			
		||||
@@ -544,17 +600,17 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
 | 
			
		||||
        res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
 | 
			
		||||
    }
 | 
			
		||||
    if (res < num_device_parameters) {
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
 | 
			
		||||
        ESP_LOGE(TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
 | 
			
		||||
        ESP_LOGE(TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
 | 
			
		||||
        return ESP_ERR_NOT_FOUND;
 | 
			
		||||
    }
 | 
			
		||||
    mdns_free();
 | 
			
		||||
#elif CONFIG_MB_SLAVE_IP_FROM_STDIN
 | 
			
		||||
    int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table);
 | 
			
		||||
    if (ip_cnt) {
 | 
			
		||||
        ESP_LOGI(MASTER_TAG, "Configured %d IP addresse(s).", ip_cnt);
 | 
			
		||||
        ESP_LOGI(TAG, "Configured %d IP addresse(s).", ip_cnt);
 | 
			
		||||
    } else {
 | 
			
		||||
        ESP_LOGE(MASTER_TAG, "Fail to get IP address from stdin. Continue.");
 | 
			
		||||
        ESP_LOGE(TAG, "Fail to get IP address from stdin. Continue.");
 | 
			
		||||
        return ESP_ERR_NOT_FOUND;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
@@ -564,23 +620,26 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
 | 
			
		||||
static esp_err_t destroy_services(void)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t err = ESP_OK;
 | 
			
		||||
#if CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
    master_destroy_slave_list(slave_ip_address_table);
 | 
			
		||||
#endif
 | 
			
		||||
    master_destroy_slave_list(slave_ip_address_table, ip_table_sz);
 | 
			
		||||
 | 
			
		||||
    err = example_disconnect();
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                   TAG,
 | 
			
		||||
                                   "example_disconnect fail, returns(0x%x).",
 | 
			
		||||
                                   (uint32_t)err);
 | 
			
		||||
    err = esp_event_loop_delete_default();
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                       TAG,
 | 
			
		||||
                                       "esp_event_loop_delete_default fail, returns(0x%x).",
 | 
			
		||||
                                       (uint32_t)err);
 | 
			
		||||
    err = esp_netif_deinit();
 | 
			
		||||
    MASTER_CHECK((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,
 | 
			
		||||
                                        TAG,
 | 
			
		||||
                                        "esp_netif_deinit fail, returns(0x%x).",
 | 
			
		||||
                                        (uint32_t)err);
 | 
			
		||||
    err = nvs_flash_deinit();
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "nvs_flash_deinit fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)err);
 | 
			
		||||
    return err;
 | 
			
		||||
@@ -592,25 +651,30 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
 | 
			
		||||
    void* master_handler = NULL;
 | 
			
		||||
 | 
			
		||||
    esp_err_t err = mbc_master_init_tcp(&master_handler);
 | 
			
		||||
    MASTER_CHECK((master_handler != NULL), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "mb controller initialization fail.");
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "mb controller initialization fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
    err = mbc_master_setup((void*)comm_info);
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "mb controller setup fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
    err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "mb controller set descriptor fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)err);
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
 | 
			
		||||
    ESP_LOGI(TAG, "Modbus master stack initialized...");
 | 
			
		||||
 | 
			
		||||
    err = mbc_master_start();
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "mb controller start fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)err);
 | 
			
		||||
    vTaskDelay(5);
 | 
			
		||||
@@ -620,10 +684,11 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
 | 
			
		||||
static esp_err_t master_destroy(void)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t err = mbc_master_destroy();
 | 
			
		||||
    MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "mbc_master_destroy fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)err);
 | 
			
		||||
    ESP_LOGI(MASTER_TAG, "Modbus master stack destroy...");
 | 
			
		||||
    ESP_LOGI(TAG, "Modbus master stack destroy...");
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ menu "Modbus Example Configuration"
 | 
			
		||||
 | 
			
		||||
    config MB_SLAVE_ADDR
 | 
			
		||||
        int "Modbus slave address"
 | 
			
		||||
        range 1 127
 | 
			
		||||
        range 1 255
 | 
			
		||||
        default 1
 | 
			
		||||
        help
 | 
			
		||||
            This is the Modbus slave address in the network.
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,6 @@
 | 
			
		||||
#include "esp_err.h"
 | 
			
		||||
#include "sdkconfig.h"
 | 
			
		||||
#include "esp_log.h"
 | 
			
		||||
 | 
			
		||||
#include "esp_system.h"
 | 
			
		||||
#include "esp_wifi.h"
 | 
			
		||||
#include "esp_event.h"
 | 
			
		||||
@@ -47,13 +46,7 @@
 | 
			
		||||
                                                | MB_EVENT_COILS_WR)
 | 
			
		||||
#define MB_READ_WRITE_MASK                  (MB_READ_MASK | MB_WRITE_MASK)
 | 
			
		||||
 | 
			
		||||
#define SLAVE_TAG "SLAVE_TEST"
 | 
			
		||||
 | 
			
		||||
#define SLAVE_CHECK(a, ret_val, str, ...) \
 | 
			
		||||
    if (!(a)) { \
 | 
			
		||||
        ESP_LOGE(SLAVE_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
 | 
			
		||||
        return (ret_val); \
 | 
			
		||||
    }
 | 
			
		||||
static const char *TAG = "SLAVE_TEST";
 | 
			
		||||
 | 
			
		||||
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
 | 
			
		||||
 | 
			
		||||
@@ -167,8 +160,8 @@ static void slave_operation_func(void *arg)
 | 
			
		||||
{
 | 
			
		||||
    mb_param_info_t reg_info; // keeps the Modbus registers access information
 | 
			
		||||
 | 
			
		||||
    ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
 | 
			
		||||
    ESP_LOGI(SLAVE_TAG, "Start modbus test...");
 | 
			
		||||
    ESP_LOGI(TAG, "Modbus slave stack initialized.");
 | 
			
		||||
    ESP_LOGI(TAG, "Start modbus test...");
 | 
			
		||||
    // The cycle below will be terminated when parameter holding_data0
 | 
			
		||||
    // incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
 | 
			
		||||
    for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
 | 
			
		||||
@@ -179,7 +172,7 @@ static void slave_operation_func(void *arg)
 | 
			
		||||
        if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
 | 
			
		||||
            // Get parameter information from parameter queue
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "HOLDING %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                    rw_str,
 | 
			
		||||
                    (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                    (uint32_t)reg_info.mb_offset,
 | 
			
		||||
@@ -197,7 +190,7 @@ static void slave_operation_func(void *arg)
 | 
			
		||||
            }
 | 
			
		||||
        } else if (event & MB_EVENT_INPUT_REG_RD) {
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "INPUT READ (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                    (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                    (uint32_t)reg_info.mb_offset,
 | 
			
		||||
                    (uint32_t)reg_info.type,
 | 
			
		||||
@@ -205,7 +198,7 @@ static void slave_operation_func(void *arg)
 | 
			
		||||
                    (uint32_t)reg_info.size);
 | 
			
		||||
        } else if (event & MB_EVENT_DISCRETE_RD) {
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "DISCRETE READ (%u us): ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                                (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                                (uint32_t)reg_info.mb_offset,
 | 
			
		||||
                                (uint32_t)reg_info.type,
 | 
			
		||||
@@ -213,7 +206,7 @@ static void slave_operation_func(void *arg)
 | 
			
		||||
                                (uint32_t)reg_info.size);
 | 
			
		||||
        } else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
 | 
			
		||||
            ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
 | 
			
		||||
            ESP_LOGI(SLAVE_TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
            ESP_LOGI(TAG, "COILS %s (%u us), ADDR:%u, TYPE:%u, INST_ADDR:0x%.4x, SIZE:%u",
 | 
			
		||||
                                rw_str,
 | 
			
		||||
                                (uint32_t)reg_info.time_stamp,
 | 
			
		||||
                                (uint32_t)reg_info.mb_offset,
 | 
			
		||||
@@ -224,7 +217,7 @@ static void slave_operation_func(void *arg)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Destroy of Modbus controller on alarm
 | 
			
		||||
    ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
 | 
			
		||||
    ESP_LOGI(TAG,"Modbus controller destroyed.");
 | 
			
		||||
    vTaskDelay(100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -235,15 +228,18 @@ static esp_err_t init_services(void)
 | 
			
		||||
      ESP_ERROR_CHECK(nvs_flash_erase());
 | 
			
		||||
      result = nvs_flash_init();
 | 
			
		||||
    }
 | 
			
		||||
    SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "nvs_flash_init fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)result);
 | 
			
		||||
    result = esp_netif_init();
 | 
			
		||||
    SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "esp_netif_init fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)result);
 | 
			
		||||
    result = esp_event_loop_create_default();
 | 
			
		||||
    SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                            TAG,
 | 
			
		||||
                            "esp_event_loop_create_default fail, returns(0x%x).",
 | 
			
		||||
                            (uint32_t)result);
 | 
			
		||||
#if CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
@@ -254,12 +250,14 @@ static esp_err_t init_services(void)
 | 
			
		||||
    // Read "Establishing Wi-Fi or Ethernet Connection" section in
 | 
			
		||||
    // examples/protocols/README.md for more information about this function.
 | 
			
		||||
    result = example_connect();
 | 
			
		||||
    SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "example_connect fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)result);
 | 
			
		||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
 | 
			
		||||
    result = esp_wifi_set_ps(WIFI_PS_NONE);
 | 
			
		||||
    SLAVE_CHECK((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                   TAG,
 | 
			
		||||
                                   "esp_wifi_set_ps fail, returns(0x%x).",
 | 
			
		||||
                                   (uint32_t)result);
 | 
			
		||||
#endif
 | 
			
		||||
@@ -271,19 +269,23 @@ static esp_err_t destroy_services(void)
 | 
			
		||||
    esp_err_t err = ESP_OK;
 | 
			
		||||
 | 
			
		||||
    err = example_disconnect();
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                   TAG,
 | 
			
		||||
                                   "example_disconnect fail, returns(0x%x).",
 | 
			
		||||
                                   (uint32_t)err);
 | 
			
		||||
    err = esp_event_loop_delete_default();
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                       TAG,
 | 
			
		||||
                                       "esp_event_loop_delete_default fail, returns(0x%x).",
 | 
			
		||||
                                       (uint32_t)err);
 | 
			
		||||
    err = esp_netif_deinit();
 | 
			
		||||
    SLAVE_CHECK((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,
 | 
			
		||||
                                        TAG,
 | 
			
		||||
                                        "esp_netif_deinit fail, returns(0x%x).",
 | 
			
		||||
                                        (uint32_t)err);
 | 
			
		||||
    err = nvs_flash_deinit();
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "nvs_flash_deinit fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)err);
 | 
			
		||||
#if CONFIG_MB_MDNS_IP_RESOLVER
 | 
			
		||||
@@ -301,7 +303,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
 | 
			
		||||
    // Initialization of Modbus controller
 | 
			
		||||
    esp_err_t err = mbc_slave_init_tcp(&slave_handler);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "mb controller initialization fail.");
 | 
			
		||||
 | 
			
		||||
    comm_info->ip_addr = NULL; // Bind to any address
 | 
			
		||||
@@ -309,7 +312,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
 | 
			
		||||
    // Setup communication parameters and start stack
 | 
			
		||||
    err = mbc_slave_setup((void*)comm_info);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                        TAG,
 | 
			
		||||
                                        "mbc_slave_setup fail, returns(0x%x).",
 | 
			
		||||
                                        (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
@@ -324,7 +328,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
    reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
 | 
			
		||||
    reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
 | 
			
		||||
    err = mbc_slave_set_descriptor(reg_area);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                    TAG,
 | 
			
		||||
                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
 | 
			
		||||
                                    (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
@@ -333,7 +338,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
    reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
 | 
			
		||||
    reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
 | 
			
		||||
    err = mbc_slave_set_descriptor(reg_area);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                    TAG,
 | 
			
		||||
                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
 | 
			
		||||
                                    (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
@@ -343,7 +349,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
    reg_area.address = (void*)&input_reg_params.input_data0;
 | 
			
		||||
    reg_area.size = sizeof(float) << 2;
 | 
			
		||||
    err = mbc_slave_set_descriptor(reg_area);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                        TAG,
 | 
			
		||||
                                        "mbc_slave_set_descriptor fail, returns(0x%x).",
 | 
			
		||||
                                        (uint32_t)err);
 | 
			
		||||
    reg_area.type = MB_PARAM_INPUT;
 | 
			
		||||
@@ -351,7 +358,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
    reg_area.address = (void*)&input_reg_params.input_data4;
 | 
			
		||||
    reg_area.size = sizeof(float) << 2;
 | 
			
		||||
    err = mbc_slave_set_descriptor(reg_area);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                        TAG,
 | 
			
		||||
                                        "mbc_slave_set_descriptor fail, returns(0x%x).",
 | 
			
		||||
                                        (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
@@ -361,7 +369,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
    reg_area.address = (void*)&coil_reg_params;
 | 
			
		||||
    reg_area.size = sizeof(coil_reg_params);
 | 
			
		||||
    err = mbc_slave_set_descriptor(reg_area);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                    TAG,
 | 
			
		||||
                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
 | 
			
		||||
                                    (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
@@ -371,7 +380,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
    reg_area.address = (void*)&discrete_reg_params;
 | 
			
		||||
    reg_area.size = sizeof(discrete_reg_params);
 | 
			
		||||
    err = mbc_slave_set_descriptor(reg_area);
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                    TAG,
 | 
			
		||||
                                    "mbc_slave_set_descriptor fail, returns(0x%x).",
 | 
			
		||||
                                    (uint32_t)err);
 | 
			
		||||
 | 
			
		||||
@@ -380,7 +390,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
 | 
			
		||||
    // Starts of modbus controller and stack
 | 
			
		||||
    err = mbc_slave_start();
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                        TAG,
 | 
			
		||||
                                        "mbc_slave_start fail, returns(0x%x).",
 | 
			
		||||
                                        (uint32_t)err);
 | 
			
		||||
    vTaskDelay(5);
 | 
			
		||||
@@ -390,7 +401,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
 | 
			
		||||
static esp_err_t slave_destroy(void)
 | 
			
		||||
{
 | 
			
		||||
    esp_err_t err = mbc_slave_destroy();
 | 
			
		||||
    SLAVE_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
    MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
 | 
			
		||||
                                TAG,
 | 
			
		||||
                                "mbc_slave_destroy fail, returns(0x%x).",
 | 
			
		||||
                                (uint32_t)err);
 | 
			
		||||
    return err;
 | 
			
		||||
@@ -405,7 +417,7 @@ void app_main(void)
 | 
			
		||||
    ESP_ERROR_CHECK(init_services());
 | 
			
		||||
 | 
			
		||||
    // Set UART log level
 | 
			
		||||
    esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
 | 
			
		||||
    esp_log_level_set(TAG, ESP_LOG_INFO);
 | 
			
		||||
 | 
			
		||||
    mb_communication_info_t comm_info = { 0 };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user