mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'bugfix/modbus_allow_address_gaps_in_master_data_dict' into 'master'
freemodbus: allow address gaps in master data dictionary (support of UID field in MBAP) See merge request espressif/esp-idf!12162
This commit is contained in:
commit
2cad565781
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -9,6 +9,8 @@
|
|||||||
#include "esp_modbus_master.h" // for public interface defines
|
#include "esp_modbus_master.h" // for public interface defines
|
||||||
#include "esp_modbus_callbacks.h" // for callback functions
|
#include "esp_modbus_callbacks.h" // for callback functions
|
||||||
|
|
||||||
|
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_MASTER";
|
||||||
|
|
||||||
// This file implements public API for Modbus master controller.
|
// This file implements public API for Modbus master controller.
|
||||||
// These functions are wrappers for interface functions of the controller
|
// These functions are wrappers for interface functions of the controller
|
||||||
static mb_master_interface_t* master_interface_ptr = NULL;
|
static mb_master_interface_t* master_interface_ptr = NULL;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -35,6 +35,7 @@ static uint8_t mb_slave_id[] = { MB_ID_BYTE0(MB_CONTROLLER_SLAVE_ID),
|
|||||||
|
|
||||||
// Common interface pointer for slave port
|
// Common interface pointer for slave port
|
||||||
static mb_slave_interface_t* slave_interface_ptr = NULL;
|
static mb_slave_interface_t* slave_interface_ptr = NULL;
|
||||||
|
static const char TAG[] __attribute__((unused)) = "MB_CONTROLLER_SLAVE";
|
||||||
|
|
||||||
// Searches the register in the area specified by type, returns descriptor if found, else NULL
|
// Searches the register in the area specified by type, returns descriptor if found, else NULL
|
||||||
static mb_descr_entry_t* mbc_slave_find_reg_descriptor(mb_param_type_t type, uint16_t addr, size_t regs)
|
static mb_descr_entry_t* mbc_slave_find_reg_descriptor(mb_param_type_t type, uint16_t addr, size_t regs)
|
||||||
@ -251,11 +252,11 @@ static esp_err_t mbc_slave_send_param_info(mb_event_group_t par_type, uint16_t m
|
|||||||
par_info.mb_offset = mb_offset;
|
par_info.mb_offset = mb_offset;
|
||||||
BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, &par_info, MB_PAR_INFO_TOUT);
|
BaseType_t status = xQueueSend(mbs_opts->mbs_notification_queue_handle, &par_info, MB_PAR_INFO_TOUT);
|
||||||
if (pdTRUE == status) {
|
if (pdTRUE == status) {
|
||||||
ESP_LOGD(MB_SLAVE_TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d",
|
ESP_LOGD(TAG, "Queue send parameter info (type, address, size): %d, 0x%.4x, %d",
|
||||||
par_type, (uint32_t)par_address, par_size);
|
par_type, (uint32_t)par_address, par_size);
|
||||||
error = ESP_OK;
|
error = ESP_OK;
|
||||||
} else if (errQUEUE_FULL == status) {
|
} else if (errQUEUE_FULL == status) {
|
||||||
ESP_LOGD(MB_SLAVE_TAG, "Parameter queue is overflowed.");
|
ESP_LOGD(TAG, "Parameter queue is overflowed.");
|
||||||
}
|
}
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
@ -268,7 +269,7 @@ static esp_err_t mbc_slave_send_param_access_notification(mb_event_group_t event
|
|||||||
esp_err_t err = ESP_FAIL;
|
esp_err_t err = ESP_FAIL;
|
||||||
mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, (EventBits_t)event);
|
mb_event_group_t bits = (mb_event_group_t)xEventGroupSetBits(mbs_opts->mbs_event_group, (EventBits_t)event);
|
||||||
if (bits & event) {
|
if (bits & event) {
|
||||||
ESP_LOGD(MB_SLAVE_TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event);
|
ESP_LOGD(TAG, "The MB_REG_CHANGE_EVENT = 0x%.2x is set.", (uint8_t)event);
|
||||||
err = ESP_OK;
|
err = ESP_OK;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -13,6 +13,24 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if __has_include("esp_check.h")
|
||||||
|
#include "esp_check.h"
|
||||||
|
|
||||||
|
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) ESP_RETURN_ON_FALSE(a, err_code, tag, format __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// if cannot include esp_check then use custom check macro
|
||||||
|
|
||||||
|
#define MB_RETURN_ON_FALSE(a, err_code, tag, format, ...) do { \
|
||||||
|
if (!(a)) { \
|
||||||
|
MB_LOGE(tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \
|
||||||
|
return err_code; \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MB_CONTROLLER_STACK_SIZE (CONFIG_FMB_CONTROLLER_STACK_SIZE) // Stack size for Modbus controller
|
#define MB_CONTROLLER_STACK_SIZE (CONFIG_FMB_CONTROLLER_STACK_SIZE) // Stack size for Modbus controller
|
||||||
#define MB_CONTROLLER_PRIORITY (CONFIG_FMB_PORT_TASK_PRIO - 1) // priority of MB controller task
|
#define MB_CONTROLLER_PRIORITY (CONFIG_FMB_PORT_TASK_PRIO - 1) // priority of MB controller task
|
||||||
|
|
||||||
|
@ -15,6 +15,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MB_MASTER_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MB_MASTER_ASSERT(con) do { \
|
||||||
|
if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Modbus descriptor table parameter type defines.
|
* \brief Modbus descriptor table parameter type defines.
|
||||||
*/
|
*/
|
||||||
|
@ -18,6 +18,12 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MB_SLAVE_CHECK(a, err_code, format, ...) MB_RETURN_ON_FALSE(a, err_code, TAG, format __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#define MB_SLAVE_ASSERT(con) do { \
|
||||||
|
if (!(con)) { ESP_LOGE(TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parameter access event information type
|
* @brief Parameter access event information type
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -7,6 +7,7 @@
|
|||||||
#ifndef _MB_CONTROLLER_MASTER_H
|
#ifndef _MB_CONTROLLER_MASTER_H
|
||||||
#define _MB_CONTROLLER_MASTER_H
|
#define _MB_CONTROLLER_MASTER_H
|
||||||
|
|
||||||
|
#include <sys/queue.h> // for list
|
||||||
#include "freertos/FreeRTOS.h" // for task creation and queue access
|
#include "freertos/FreeRTOS.h" // for task creation and queue access
|
||||||
#include "freertos/task.h" // for task api access
|
#include "freertos/task.h" // for task api access
|
||||||
#include "freertos/event_groups.h" // for event groups
|
#include "freertos/event_groups.h" // for event groups
|
||||||
@ -20,18 +21,6 @@
|
|||||||
|
|
||||||
/* ----------------------- Defines ------------------------------------------*/
|
/* ----------------------- Defines ------------------------------------------*/
|
||||||
|
|
||||||
#define MB_MASTER_TAG "MB_CONTROLLER_MASTER"
|
|
||||||
|
|
||||||
#define MB_MASTER_CHECK(a, ret_val, str, ...) \
|
|
||||||
if (!(a)) { \
|
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
|
||||||
return (ret_val); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MB_MASTER_ASSERT(con) do { \
|
|
||||||
if (!(con)) { ESP_LOGE(MB_MASTER_TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Request mode for parameter to use in data dictionary
|
* @brief Request mode for parameter to use in data dictionary
|
||||||
*/
|
*/
|
||||||
@ -51,6 +40,19 @@ typedef struct {
|
|||||||
uart_parity_t parity; /*!< Modbus UART parity settings */
|
uart_parity_t parity; /*!< Modbus UART parity settings */
|
||||||
} mb_master_comm_info_t;
|
} mb_master_comm_info_t;
|
||||||
|
|
||||||
|
#if MB_MASTER_TCP_ENABLED
|
||||||
|
/**
|
||||||
|
* @brief Modbus slave addr list item for the master
|
||||||
|
*/
|
||||||
|
typedef struct mb_slave_addr_entry_s{
|
||||||
|
uint16_t index; /*!< Index of the slave address */
|
||||||
|
const char* ip_address; /*!< IP address string of the slave */
|
||||||
|
uint8_t slave_addr; /*!< Short slave address */
|
||||||
|
void* p_data; /*!< pointer to data structure */
|
||||||
|
LIST_ENTRY(mb_slave_addr_entry_s) entries; /*!< The slave address entry */
|
||||||
|
} mb_slave_addr_entry_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Modbus controller handler structure
|
* @brief Modbus controller handler structure
|
||||||
*/
|
*/
|
||||||
@ -63,6 +65,10 @@ typedef struct {
|
|||||||
EventGroupHandle_t mbm_event_group; /*!< Modbus controller event group */
|
EventGroupHandle_t mbm_event_group; /*!< Modbus controller event group */
|
||||||
const mb_parameter_descriptor_t* mbm_param_descriptor_table; /*!< Modbus controller parameter description table */
|
const mb_parameter_descriptor_t* mbm_param_descriptor_table; /*!< Modbus controller parameter description table */
|
||||||
size_t mbm_param_descriptor_size; /*!< Modbus controller parameter description table size*/
|
size_t mbm_param_descriptor_size; /*!< Modbus controller parameter description table size*/
|
||||||
|
#if MB_MASTER_TCP_ENABLED
|
||||||
|
LIST_HEAD(mbm_slave_addr_info_, mb_slave_addr_entry_s) mbm_slave_list; /*!< Slave address information list */
|
||||||
|
uint16_t mbm_slave_list_count;
|
||||||
|
#endif
|
||||||
} mb_master_options_t;
|
} mb_master_options_t;
|
||||||
|
|
||||||
typedef esp_err_t (*iface_get_cid_info)(uint16_t, const mb_parameter_descriptor_t**); /*!< Interface get_cid_info method */
|
typedef esp_err_t (*iface_get_cid_info)(uint16_t, const mb_parameter_descriptor_t**); /*!< Interface get_cid_info method */
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -23,18 +23,6 @@
|
|||||||
#define MB_CONTROLLER_NOTIFY_QUEUE_SIZE (CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE) // Number of messages in parameter notification queue
|
#define MB_CONTROLLER_NOTIFY_QUEUE_SIZE (CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE) // Number of messages in parameter notification queue
|
||||||
#define MB_CONTROLLER_NOTIFY_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT)) // notification timeout
|
#define MB_CONTROLLER_NOTIFY_TIMEOUT (pdMS_TO_TICKS(CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT)) // notification timeout
|
||||||
|
|
||||||
#define MB_SLAVE_TAG "MB_CONTROLLER_SLAVE"
|
|
||||||
|
|
||||||
#define MB_SLAVE_CHECK(a, ret_val, str, ...) \
|
|
||||||
if (!(a)) { \
|
|
||||||
ESP_LOGE(MB_SLAVE_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
|
||||||
return (ret_val); \
|
|
||||||
}
|
|
||||||
|
|
||||||
#define MB_SLAVE_ASSERT(con) do { \
|
|
||||||
if (!(con)) { ESP_LOGE(MB_SLAVE_TAG, "assert errno:%d, errno_str: !(%s)", errno, strerror(errno)); assert(0 && #con); } \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Device communication parameters for master
|
* @brief Device communication parameters for master
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -31,6 +31,7 @@ extern BOOL xMBMasterPortSerialTxPoll(void);
|
|||||||
|
|
||||||
|
|
||||||
static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
|
static mb_master_interface_t* mbm_interface_ptr = NULL; //&default_interface_inst;
|
||||||
|
static const char *TAG = "MB_CONTROLLER_MASTER";
|
||||||
|
|
||||||
// Modbus event processing task
|
// Modbus event processing task
|
||||||
static void modbus_master_task(void *pvParameters)
|
static void modbus_master_task(void *pvParameters)
|
||||||
@ -229,7 +230,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
|
|||||||
(USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
|
(USHORT)mb_size, (LONG) MB_RESPONSE_TICS );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
|
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
|
||||||
__FUNCTION__, mb_command);
|
__FUNCTION__, mb_command);
|
||||||
mb_error = MB_MRE_NO_REG;
|
mb_error = MB_MRE_NO_REG;
|
||||||
break;
|
break;
|
||||||
@ -260,7 +261,7 @@ static esp_err_t mbc_serial_master_send_request(mb_param_request_t* request, voi
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ",
|
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ",
|
||||||
__FUNCTION__, mb_error);
|
__FUNCTION__, mb_error);
|
||||||
error = ESP_FAIL;
|
error = ESP_FAIL;
|
||||||
break;
|
break;
|
||||||
@ -315,12 +316,12 @@ static uint8_t mbc_serial_master_get_command(mb_param_type_t param_type, mb_para
|
|||||||
if (mode != MB_PARAM_WRITE) {
|
if (mode != MB_PARAM_WRITE) {
|
||||||
command = MB_FUNC_READ_DISCRETE_INPUTS;
|
command = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)",
|
ESP_LOGE(TAG, "%s: Incorrect mode (%u)",
|
||||||
__FUNCTION__, (uint8_t)mode);
|
__FUNCTION__, (uint8_t)mode);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)",
|
ESP_LOGE(TAG, "%s: Incorrect param type (%u)",
|
||||||
__FUNCTION__, param_type);
|
__FUNCTION__, param_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -392,16 +393,16 @@ static esp_err_t mbc_serial_master_get_parameter(uint16_t cid, char* name,
|
|||||||
// Send request to read characteristic data
|
// Send request to read characteristic data
|
||||||
error = mbc_serial_master_send_request(&request, value_ptr);
|
error = mbc_serial_master_send_request(&request, value_ptr);
|
||||||
if (error == ESP_OK) {
|
if (error == ESP_OK) {
|
||||||
ESP_LOGD(MB_MASTER_TAG, "%s: Good response for get cid(%u) = %s",
|
ESP_LOGD(TAG, "%s: Good response for get cid(%u) = %s",
|
||||||
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
|
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
|
||||||
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
}
|
}
|
||||||
// Set the type of parameter found in the table
|
// Set the type of parameter found in the table
|
||||||
*type = reg_info.param_type;
|
*type = reg_info.param_type;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
|
ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
|
||||||
__FUNCTION__, reg_info.cid);
|
__FUNCTION__, reg_info.cid);
|
||||||
error = ESP_ERR_INVALID_ARG;
|
error = ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -427,16 +428,16 @@ static esp_err_t mbc_serial_master_set_parameter(uint16_t cid, char* name,
|
|||||||
// Send request to write characteristic data
|
// Send request to write characteristic data
|
||||||
error = mbc_serial_master_send_request(&request, value_ptr);
|
error = mbc_serial_master_send_request(&request, value_ptr);
|
||||||
if (error == ESP_OK) {
|
if (error == ESP_OK) {
|
||||||
ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
|
ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
|
||||||
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, (int)reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
|
ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
|
||||||
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
}
|
}
|
||||||
// Set the type of parameter found in the table
|
// Set the type of parameter found in the table
|
||||||
*type = reg_info.param_type;
|
*type = reg_info.param_type;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
|
ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
|
||||||
__FUNCTION__, reg_info.cid);
|
__FUNCTION__, reg_info.cid);
|
||||||
error = ESP_ERR_INVALID_ARG;
|
error = ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
// Shared pointer to interface structure
|
// Shared pointer to interface structure
|
||||||
static mb_slave_interface_t* mbs_interface_ptr = NULL;
|
static mb_slave_interface_t* mbs_interface_ptr = NULL;
|
||||||
|
static const char *TAG = "MB_CONTROLLER_SLAVE";
|
||||||
|
|
||||||
// Modbus task function
|
// Modbus task function
|
||||||
static void modbus_slave_task(void *pvParameters)
|
static void modbus_slave_task(void *pvParameters)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -10,6 +10,7 @@
|
|||||||
#include <sys/time.h> // for calculation of time stamp in milliseconds
|
#include <sys/time.h> // for calculation of time stamp in milliseconds
|
||||||
#include "esp_log.h" // for log_write
|
#include "esp_log.h" // for log_write
|
||||||
#include <string.h> // for memcpy
|
#include <string.h> // for memcpy
|
||||||
|
#include <sys/queue.h> // for list
|
||||||
#include "freertos/FreeRTOS.h" // for task creation and queue access
|
#include "freertos/FreeRTOS.h" // for task creation and queue access
|
||||||
#include "freertos/task.h" // for task api access
|
#include "freertos/task.h" // for task api access
|
||||||
#include "freertos/event_groups.h" // for event groups
|
#include "freertos/event_groups.h" // for event groups
|
||||||
@ -33,6 +34,59 @@
|
|||||||
#define MB_TCP_CONNECTION_TOUT pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000)
|
#define MB_TCP_CONNECTION_TOUT pdMS_TO_TICKS(CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000)
|
||||||
|
|
||||||
static mb_master_interface_t* mbm_interface_ptr = NULL;
|
static mb_master_interface_t* mbm_interface_ptr = NULL;
|
||||||
|
static const char *TAG = "MB_CONTROLLER_MASTER";
|
||||||
|
|
||||||
|
// Searches the slave address in the address info list and returns address info if found, else NULL
|
||||||
|
static mb_slave_addr_entry_t* mbc_tcp_master_find_slave_addr(uint8_t slave_addr)
|
||||||
|
{
|
||||||
|
mb_slave_addr_entry_t* it;
|
||||||
|
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||||
|
|
||||||
|
if (LIST_EMPTY(&mbm_opts->mbm_slave_list)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
LIST_FOREACH(it, &mbm_opts->mbm_slave_list, entries) {
|
||||||
|
if (slave_addr == it->slave_addr) {
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static esp_err_t mbc_tcp_master_add_slave(uint16_t index, uint8_t slave_addr, const char* ip_addr)
|
||||||
|
{
|
||||||
|
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||||
|
// Initialize interface properties
|
||||||
|
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||||
|
|
||||||
|
mb_slave_addr_entry_t* new_slave_entry = (mb_slave_addr_entry_t*) heap_caps_malloc(sizeof(mb_slave_addr_entry_t),
|
||||||
|
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
|
MB_MASTER_CHECK((new_slave_entry != NULL), ESP_ERR_NO_MEM, "mb can not allocate memory for slave entry.");
|
||||||
|
new_slave_entry->index = index;
|
||||||
|
new_slave_entry->ip_address = ip_addr;
|
||||||
|
new_slave_entry->slave_addr = slave_addr;
|
||||||
|
new_slave_entry->p_data = NULL;
|
||||||
|
LIST_INSERT_HEAD(&mbm_opts->mbm_slave_list, new_slave_entry, entries);
|
||||||
|
MB_MASTER_CHECK((mbm_opts->mbm_slave_list_count < (MB_TCP_PORT_MAX_CONN - 1)),
|
||||||
|
ESP_ERR_INVALID_STATE, "mb max number of slaves < %d.", MB_TCP_PORT_MAX_CONN);
|
||||||
|
mbm_opts->mbm_slave_list_count++;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mbc_tcp_master_free_slave_list(void)
|
||||||
|
{
|
||||||
|
mb_slave_addr_entry_t* it;
|
||||||
|
MB_MASTER_ASSERT(mbm_interface_ptr != NULL);
|
||||||
|
|
||||||
|
// Initialize interface properties
|
||||||
|
mb_master_options_t* mbm_opts = &mbm_interface_ptr->opts;
|
||||||
|
|
||||||
|
LIST_FOREACH(it, &mbm_opts->mbm_slave_list, entries) {
|
||||||
|
LIST_REMOVE(it, entries);
|
||||||
|
mbm_opts->mbm_slave_list_count--;
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Modbus event processing task
|
// Modbus event processing task
|
||||||
static void modbus_tcp_master_task(void *pvParameters)
|
static void modbus_tcp_master_task(void *pvParameters)
|
||||||
@ -104,21 +158,21 @@ static esp_err_t mbc_tcp_master_start(void)
|
|||||||
vMBTCPPortMasterSetNetOpt(comm_info->ip_netif_ptr, ip_ver, proto);
|
vMBTCPPortMasterSetNetOpt(comm_info->ip_netif_ptr, ip_ver, proto);
|
||||||
vMBTCPPortMasterTaskStart();
|
vMBTCPPortMasterTaskStart();
|
||||||
|
|
||||||
// Add slave IP address for each slave to initialise connection
|
// Add slave IP address for each slave to initialize connection
|
||||||
for (int idx = 0; *comm_ip_table != NULL; idx++, comm_ip_table++)
|
mb_slave_addr_entry_t *p_slave_info;
|
||||||
{
|
|
||||||
result = (BOOL)xMBTCPPortMasterAddSlaveIp(*comm_ip_table);
|
LIST_FOREACH(p_slave_info, &mbm_opts->mbm_slave_list, entries) {
|
||||||
|
result = (BOOL)xMBTCPPortMasterAddSlaveIp(p_slave_info->index, p_slave_info->ip_address, p_slave_info->slave_addr);
|
||||||
MB_MASTER_CHECK(result, ESP_ERR_INVALID_STATE, "mb stack add slave IP failed: %s.", *comm_ip_table);
|
MB_MASTER_CHECK(result, ESP_ERR_INVALID_STATE, "mb stack add slave IP failed: %s.", *comm_ip_table);
|
||||||
}
|
}
|
||||||
// Init polling event handlers and wait before start polling
|
|
||||||
xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group, (EventBits_t)MB_EVENT_STACK_STARTED, 1);
|
// Add end of list condition
|
||||||
|
(void)xMBTCPPortMasterAddSlaveIp(0xFF, NULL, 0xFF);
|
||||||
|
|
||||||
status = eMBMasterEnable();
|
status = eMBMasterEnable();
|
||||||
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
MB_MASTER_CHECK((status == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||||
"mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);
|
"mb stack set slave ID failure, eMBMasterEnable() returned (0x%x).", (uint32_t)status);
|
||||||
|
|
||||||
// Send end of list condition to start connection phase
|
|
||||||
(void)xMBTCPPortMasterAddSlaveIp(NULL);
|
|
||||||
|
|
||||||
// Wait for connection done event
|
// Wait for connection done event
|
||||||
bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group,
|
bool start = (bool)xMBTCPPortMasterWaitEvent(mbm_opts->mbm_event_group,
|
||||||
@ -143,13 +197,14 @@ static esp_err_t mbc_tcp_master_destroy(void)
|
|||||||
mb_error = eMBMasterClose();
|
mb_error = eMBMasterClose();
|
||||||
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
MB_MASTER_CHECK((mb_error == MB_ENOERR), ESP_ERR_INVALID_STATE,
|
||||||
"mb stack close failure returned (0x%x).", (uint32_t)mb_error);
|
"mb stack close failure returned (0x%x).", (uint32_t)mb_error);
|
||||||
// Stop polling by clearing correspondent bit in the event group
|
// Stop polling by clearing correspondent bit in the event group
|
||||||
xEventGroupClearBits(mbm_opts->mbm_event_group,
|
xEventGroupClearBits(mbm_opts->mbm_event_group,
|
||||||
(EventBits_t)MB_EVENT_STACK_STARTED);
|
(EventBits_t)MB_EVENT_STACK_STARTED);
|
||||||
(void)vTaskDelete(mbm_opts->mbm_task_handle);
|
(void)vTaskDelete(mbm_opts->mbm_task_handle);
|
||||||
mbm_opts->mbm_task_handle = NULL;
|
mbm_opts->mbm_task_handle = NULL;
|
||||||
(void)vEventGroupDelete(mbm_opts->mbm_event_group);
|
(void)vEventGroupDelete(mbm_opts->mbm_event_group);
|
||||||
mbm_opts->mbm_event_group = NULL;
|
mbm_opts->mbm_event_group = NULL;
|
||||||
|
mbc_tcp_master_free_slave_list();
|
||||||
free(mbm_interface_ptr); // free the memory allocated for options
|
free(mbm_interface_ptr); // free the memory allocated for options
|
||||||
vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
|
vMBPortSetMode((UCHAR)MB_PORT_INACTIVE);
|
||||||
mbm_interface_ptr = NULL;
|
mbm_interface_ptr = NULL;
|
||||||
@ -169,15 +224,25 @@ static esp_err_t mbc_tcp_master_set_descriptor(const mb_parameter_descriptor_t*
|
|||||||
MB_MASTER_CHECK((comm_ip_table != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
|
MB_MASTER_CHECK((comm_ip_table != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
|
||||||
|
|
||||||
const mb_parameter_descriptor_t *reg_ptr = descriptor;
|
const mb_parameter_descriptor_t *reg_ptr = descriptor;
|
||||||
|
uint16_t slave_cnt = 0;
|
||||||
|
mb_slave_addr_entry_t* p_slave = NULL;
|
||||||
|
|
||||||
// Go through all items in the table to check all Modbus registers
|
// Go through all items in the table to check all Modbus registers
|
||||||
for (uint16_t counter = 0; counter < (num_elements); counter++, reg_ptr++)
|
for (int idx = 0; idx < (num_elements); idx++, reg_ptr++)
|
||||||
{
|
{
|
||||||
MB_MASTER_CHECK((comm_ip_table[reg_ptr->mb_slave_addr - 1] != NULL), ESP_ERR_INVALID_ARG, "mb ip table address is incorrect.");
|
|
||||||
// Below is the code to check consistency of the table format and required fields.
|
// Below is the code to check consistency of the table format and required fields.
|
||||||
MB_MASTER_CHECK((reg_ptr->cid == counter), ESP_ERR_INVALID_ARG, "cid: %d, mb descriptor cid field is incorrect.", reg_ptr->cid);
|
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, "cid: %d, mb descriptor param key is incorrect.", reg_ptr->cid);
|
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, "cid: %d, mb descriptor param size is incorrect.", reg_ptr->cid);
|
MB_MASTER_CHECK((reg_ptr->mb_size > 0), ESP_ERR_INVALID_ARG, "mb descriptor param size is incorrect.");
|
||||||
MB_MASTER_CHECK(((reg_ptr->mb_size << 1) >= reg_ptr->param_size), ESP_ERR_INVALID_ARG, "cid: %d, mb descriptor param size is incorrect.", reg_ptr->cid);
|
// Is the slave already in the list?
|
||||||
|
p_slave = mbc_tcp_master_find_slave_addr(reg_ptr->mb_slave_addr);
|
||||||
|
// Add it to slave list if not there.
|
||||||
|
if (!p_slave) {
|
||||||
|
// Is the IP address correctly defined for the slave?
|
||||||
|
MB_MASTER_CHECK((comm_ip_table[slave_cnt]), ESP_ERR_INVALID_STATE, "mb missing IP address for cid #%d.", reg_ptr->cid);
|
||||||
|
// Add slave to the list
|
||||||
|
MB_MASTER_ASSERT(mbc_tcp_master_add_slave(idx, reg_ptr->mb_slave_addr, comm_ip_table[slave_cnt++]) == ESP_OK);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mbm_opts->mbm_param_descriptor_table = descriptor;
|
mbm_opts->mbm_param_descriptor_table = descriptor;
|
||||||
mbm_opts->mbm_param_descriptor_size = num_elements;
|
mbm_opts->mbm_param_descriptor_size = num_elements;
|
||||||
@ -249,7 +314,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
|
|||||||
(USHORT)mb_size, (LONG) MB_RESPONSE_TIMEOUT );
|
(USHORT)mb_size, (LONG) MB_RESPONSE_TIMEOUT );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect function in request (%u) ",
|
ESP_LOGE(TAG, "%s: Incorrect function in request (%u) ",
|
||||||
__FUNCTION__, mb_command);
|
__FUNCTION__, mb_command);
|
||||||
mb_error = MB_MRE_NO_REG;
|
mb_error = MB_MRE_NO_REG;
|
||||||
break;
|
break;
|
||||||
@ -280,7 +345,7 @@ static esp_err_t mbc_tcp_master_send_request(mb_param_request_t* request, void*
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, mb_error);
|
ESP_LOGE(TAG, "%s: Incorrect return code (%x) ", __FUNCTION__, mb_error);
|
||||||
error = ESP_FAIL;
|
error = ESP_FAIL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -324,11 +389,11 @@ static uint8_t mbc_tcp_master_get_command(mb_param_type_t param_type, mb_param_m
|
|||||||
if (mode != MB_PARAM_WRITE) {
|
if (mode != MB_PARAM_WRITE) {
|
||||||
command = MB_FUNC_READ_DISCRETE_INPUTS;
|
command = MB_FUNC_READ_DISCRETE_INPUTS;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (uint8_t)mode);
|
ESP_LOGE(TAG, "%s: Incorrect mode (%u)", __FUNCTION__, (uint8_t)mode);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u)", __FUNCTION__, param_type);
|
ESP_LOGE(TAG, "%s: Incorrect param type (%u)", __FUNCTION__, param_type);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return command;
|
return command;
|
||||||
@ -359,7 +424,7 @@ static esp_err_t mbc_tcp_master_set_param_data(void* dest, void* src, mb_descr_t
|
|||||||
memcpy((void*)dest, (void*)src, (size_t)param_size);
|
memcpy((void*)dest, (void*)src, (size_t)param_size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: Incorrect param type (%u).",
|
ESP_LOGE(TAG, "%s: Incorrect param type (%u).",
|
||||||
__FUNCTION__, (uint16_t)param_type);
|
__FUNCTION__, (uint16_t)param_type);
|
||||||
err = ESP_ERR_NOT_SUPPORTED;
|
err = ESP_ERR_NOT_SUPPORTED;
|
||||||
break;
|
break;
|
||||||
@ -431,15 +496,15 @@ static esp_err_t mbc_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t*
|
|||||||
error = mbc_tcp_master_set_param_data((void*)value, (void*)pdata,
|
error = mbc_tcp_master_set_param_data((void*)value, (void*)pdata,
|
||||||
reg_info.param_type, reg_info.param_size);
|
reg_info.param_type, reg_info.param_size);
|
||||||
if (error != ESP_OK) {
|
if (error != ESP_OK) {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "fail to set parameter data.");
|
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||||
error = ESP_ERR_INVALID_STATE;
|
error = ESP_ERR_INVALID_STATE;
|
||||||
} else {
|
} else {
|
||||||
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__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to get cid(%u) = %s",
|
ESP_LOGD(TAG, "%s: Bad response to get cid(%u) = %s",
|
||||||
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
error = ESP_ERR_INVALID_RESPONSE;
|
error = ESP_ERR_INVALID_RESPONSE;
|
||||||
}
|
}
|
||||||
@ -447,7 +512,7 @@ static esp_err_t mbc_tcp_master_get_parameter(uint16_t cid, char* name, uint8_t*
|
|||||||
// Set the type of parameter found in the table
|
// Set the type of parameter found in the table
|
||||||
*type = reg_info.param_type;
|
*type = reg_info.param_type;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: The cid(%u) not found in the data dictionary.",
|
ESP_LOGE(TAG, "%s: The cid(%u) not found in the data dictionary.",
|
||||||
__FUNCTION__, reg_info.cid);
|
__FUNCTION__, reg_info.cid);
|
||||||
error = ESP_ERR_INVALID_ARG;
|
error = ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -476,24 +541,24 @@ static esp_err_t mbc_tcp_master_set_parameter(uint16_t cid, char* name, uint8_t*
|
|||||||
error = mbc_tcp_master_set_param_data((void*)pdata, (void*)value,
|
error = mbc_tcp_master_set_param_data((void*)pdata, (void*)value,
|
||||||
reg_info.param_type, reg_info.param_size);
|
reg_info.param_type, reg_info.param_size);
|
||||||
if (error != ESP_OK) {
|
if (error != ESP_OK) {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "fail to set parameter data.");
|
ESP_LOGE(TAG, "fail to set parameter data.");
|
||||||
free(pdata);
|
free(pdata);
|
||||||
return ESP_ERR_INVALID_STATE;
|
return ESP_ERR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
// Send request to write characteristic data
|
// Send request to write characteristic data
|
||||||
error = mbc_tcp_master_send_request(&request, pdata);
|
error = mbc_tcp_master_send_request(&request, pdata);
|
||||||
if (error == ESP_OK) {
|
if (error == ESP_OK) {
|
||||||
ESP_LOGD(MB_MASTER_TAG, "%s: Good response for set cid(%u) = %s",
|
ESP_LOGD(TAG, "%s: Good response for set cid(%u) = %s",
|
||||||
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, (unsigned)reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(MB_MASTER_TAG, "%s: Bad response to set cid(%u) = %s",
|
ESP_LOGD(TAG, "%s: Bad response to set cid(%u) = %s",
|
||||||
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
__FUNCTION__, reg_info.cid, (char*)esp_err_to_name(error));
|
||||||
}
|
}
|
||||||
free(pdata);
|
free(pdata);
|
||||||
// Set the type of parameter found in the table
|
// Set the type of parameter found in the table
|
||||||
*type = reg_info.param_type;
|
*type = reg_info.param_type;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_MASTER_TAG, "%s: The requested cid(%u) not found in the data dictionary.",
|
ESP_LOGE(TAG, "%s: The requested cid(%u) not found in the data dictionary.",
|
||||||
__FUNCTION__, reg_info.cid);
|
__FUNCTION__, reg_info.cid);
|
||||||
error = ESP_ERR_INVALID_ARG;
|
error = ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
@ -721,6 +786,9 @@ esp_err_t mbc_tcp_master_create(void** handler)
|
|||||||
}
|
}
|
||||||
MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
|
MB_MASTER_ASSERT(mbm_opts->mbm_task_handle != NULL); // The task is created but handle is incorrect
|
||||||
|
|
||||||
|
LIST_INIT(&mbm_opts->mbm_slave_list); // Init slave address list
|
||||||
|
mbm_opts->mbm_slave_list_count = 0;
|
||||||
|
|
||||||
// Initialize public interface methods of the interface
|
// Initialize public interface methods of the interface
|
||||||
mbm_interface_ptr->init = mbc_tcp_master_create;
|
mbm_interface_ptr->init = mbc_tcp_master_create;
|
||||||
mbm_interface_ptr->destroy = mbc_tcp_master_destroy;
|
mbm_interface_ptr->destroy = mbc_tcp_master_destroy;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
* SPDX-FileContributor: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* FreeModbus Libary: ESP32 TCP Port
|
* FreeModbus Libary: ESP32 TCP Port
|
||||||
@ -60,7 +60,6 @@
|
|||||||
#define MB_TCP_CONNECTION_TIMEOUT_MS ( 20 ) // Connection timeout in mS
|
#define MB_TCP_CONNECTION_TIMEOUT_MS ( 20 ) // Connection timeout in mS
|
||||||
#define MB_TCP_RECONNECT_TIMEOUT ( 5000000 ) // Connection timeout in uS
|
#define MB_TCP_RECONNECT_TIMEOUT ( 5000000 ) // Connection timeout in uS
|
||||||
|
|
||||||
#define MB_TCP_MASTER_PORT_TAG "MB_TCP_MASTER_PORT"
|
|
||||||
#define MB_EVENT_REQ_DONE_MASK ( EV_MASTER_PROCESS_SUCCESS | \
|
#define MB_EVENT_REQ_DONE_MASK ( EV_MASTER_PROCESS_SUCCESS | \
|
||||||
EV_MASTER_ERROR_RESPOND_TIMEOUT | \
|
EV_MASTER_ERROR_RESPOND_TIMEOUT | \
|
||||||
EV_MASTER_ERROR_RECEIVE_DATA | \
|
EV_MASTER_ERROR_RECEIVE_DATA | \
|
||||||
@ -78,6 +77,7 @@
|
|||||||
void vMBPortEventClose( void );
|
void vMBPortEventClose( void );
|
||||||
|
|
||||||
/* ----------------------- Static variables ---------------------------------*/
|
/* ----------------------- Static variables ---------------------------------*/
|
||||||
|
static const char *TAG = "MB_TCP_MASTER_PORT";
|
||||||
static MbPortConfig_t xMbPortConfig;
|
static MbPortConfig_t xMbPortConfig;
|
||||||
static EventGroupHandle_t xMasterEventHandle = NULL;
|
static EventGroupHandle_t xMasterEventHandle = NULL;
|
||||||
static SemaphoreHandle_t xShutdownSemaphore = NULL;
|
static SemaphoreHandle_t xShutdownSemaphore = NULL;
|
||||||
@ -108,7 +108,7 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
|
|||||||
|
|
||||||
xMbPortConfig.pxMbSlaveInfo = calloc(MB_TCP_PORT_MAX_CONN, sizeof(MbSlaveInfo_t*));
|
xMbPortConfig.pxMbSlaveInfo = calloc(MB_TCP_PORT_MAX_CONN, sizeof(MbSlaveInfo_t*));
|
||||||
if (!xMbPortConfig.pxMbSlaveInfo) {
|
if (!xMbPortConfig.pxMbSlaveInfo) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP slave info alloc failure.");
|
ESP_LOGE(TAG, "TCP slave info alloc failure.");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xMbPortConfig.pxMbSlaveInfo[idx] = NULL, idx++);
|
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xMbPortConfig.pxMbSlaveInfo[idx] = NULL, idx++);
|
||||||
@ -117,12 +117,13 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
|
|||||||
xMbPortConfig.usPort = usTCPPort;
|
xMbPortConfig.usPort = usTCPPort;
|
||||||
xMbPortConfig.usMbSlaveInfoCount = 0;
|
xMbPortConfig.usMbSlaveInfoCount = 0;
|
||||||
xMbPortConfig.ucCurSlaveIndex = 1;
|
xMbPortConfig.ucCurSlaveIndex = 1;
|
||||||
|
xMbPortConfig.pxMbSlaveCurrInfo = NULL;
|
||||||
|
|
||||||
xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(CHAR*));
|
xMbPortConfig.xConnectQueue = xQueueCreate(2, sizeof(MbSlaveAddrInfo_t));
|
||||||
if (xMbPortConfig.xConnectQueue == 0)
|
if (xMbPortConfig.xConnectQueue == 0)
|
||||||
{
|
{
|
||||||
// Queue was not created and must not be used.
|
// Queue was not created and must not be used.
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP master queue creation failure.");
|
ESP_LOGE(TAG, "TCP master queue creation failure.");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,10 +137,10 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
|
|||||||
MB_PORT_TASK_AFFINITY);
|
MB_PORT_TASK_AFFINITY);
|
||||||
if (xErr != pdTRUE)
|
if (xErr != pdTRUE)
|
||||||
{
|
{
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "TCP master task creation failure.");
|
ESP_LOGE(TAG, "TCP master task creation failure.");
|
||||||
(void)vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
|
(void)vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "TCP master stack initialized.");
|
ESP_LOGI(TAG, "TCP master stack initialized.");
|
||||||
bOkay = TRUE;
|
bOkay = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,9 +148,30 @@ xMBMasterTCPPortInit( USHORT usTCPPort )
|
|||||||
return bOkay;
|
return bOkay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MbSlaveInfo_t* vMBTCPPortMasterFindSlaveInfo(UCHAR ucSlaveAddr)
|
||||||
|
{
|
||||||
|
int xIndex;
|
||||||
|
BOOL xFound = false;
|
||||||
|
for (xIndex = 0; xIndex < xMbPortConfig.usMbSlaveInfoCount; xIndex++) {
|
||||||
|
if (xMbPortConfig.pxMbSlaveInfo[xIndex]->ucSlaveAddr == ucSlaveAddr) {
|
||||||
|
xMbPortConfig.pxMbSlaveCurrInfo = xMbPortConfig.pxMbSlaveInfo[xIndex];
|
||||||
|
xFound = TRUE;
|
||||||
|
xMbPortConfig.ucCurSlaveIndex = xIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!xFound) {
|
||||||
|
xMbPortConfig.pxMbSlaveCurrInfo = NULL;
|
||||||
|
ESP_LOGE(TAG, "Slave info for short address %d not found.", ucSlaveAddr);
|
||||||
|
}
|
||||||
|
return xMbPortConfig.pxMbSlaveCurrInfo;
|
||||||
|
}
|
||||||
|
|
||||||
static MbSlaveInfo_t* vMBTCPPortMasterGetCurrInfo(void)
|
static MbSlaveInfo_t* vMBTCPPortMasterGetCurrInfo(void)
|
||||||
{
|
{
|
||||||
return xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.ucCurSlaveIndex - 1];
|
if (!xMbPortConfig.pxMbSlaveCurrInfo) {
|
||||||
|
ESP_LOGE(TAG, "Incorrect current slave info.");
|
||||||
|
}
|
||||||
|
return xMbPortConfig.pxMbSlaveCurrInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start Modbus event state machine
|
// Start Modbus event state machine
|
||||||
@ -160,10 +182,10 @@ static void vMBTCPPortMasterStartPoll(void)
|
|||||||
EventBits_t xFlags = xEventGroupSetBits(xMasterEventHandle,
|
EventBits_t xFlags = xEventGroupSetBits(xMasterEventHandle,
|
||||||
(EventBits_t)xMasterEvent);
|
(EventBits_t)xMasterEvent);
|
||||||
if (!(xFlags & xMasterEvent)) {
|
if (!(xFlags & xMasterEvent)) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start TCP stack.");
|
ESP_LOGE(TAG, "Fail to start TCP stack.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to start polling. Incorrect event handle...");
|
ESP_LOGE(TAG, "Fail to start polling. Incorrect event handle...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,10 +197,10 @@ static void vMBTCPPortMasterStopPoll(void)
|
|||||||
EventBits_t xFlags = xEventGroupClearBits(xMasterEventHandle,
|
EventBits_t xFlags = xEventGroupClearBits(xMasterEventHandle,
|
||||||
(EventBits_t)xMasterEvent);
|
(EventBits_t)xMasterEvent);
|
||||||
if (!(xFlags & xMasterEvent)) {
|
if (!(xFlags & xMasterEvent)) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling.");
|
ESP_LOGE(TAG, "Fail to stop polling.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to stop polling. Incorrect event handle...");
|
ESP_LOGE(TAG, "Fail to stop polling. Incorrect event handle...");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,11 +231,11 @@ static BOOL xMBTCPPortMasterCloseConnection(MbSlaveInfo_t* pxInfo)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (pxInfo->xSockId == -1) {
|
if (pxInfo->xSockId == -1) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Wrong socket info or disconnected socket: %d, skip.", pxInfo->xSockId);
|
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d, skip.", pxInfo->xSockId);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
|
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Shutdown failed sock %d, errno=%d", pxInfo->xSockId, errno);
|
ESP_LOGV(TAG, "Shutdown failed sock %d, errno=%d", pxInfo->xSockId, errno);
|
||||||
}
|
}
|
||||||
close(pxInfo->xSockId);
|
close(pxInfo->xSockId);
|
||||||
pxInfo->xSockId = -1;
|
pxInfo->xSockId = -1;
|
||||||
@ -283,12 +305,12 @@ static int xMBTCPPortMasterGetBuf(MbSlaveInfo_t* pxInfo, UCHAR* pucDstBuf, USHOR
|
|||||||
continue;
|
continue;
|
||||||
} else if (errno == ENOTCONN) {
|
} else if (errno == ENOTCONN) {
|
||||||
// Socket connection closed
|
// Socket connection closed
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) connection closed.",
|
ESP_LOGE(TAG, "Socket(#%d)(%s) connection closed.",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr);
|
pxInfo->xSockId, pxInfo->pcIpAddr);
|
||||||
return ERR_CONN;
|
return ERR_CONN;
|
||||||
} else {
|
} else {
|
||||||
// Other error occurred during receiving
|
// Other error occurred during receiving
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) receive error, length=%d, errno=%d",
|
ESP_LOGE(TAG, "Socket(#%d)(%s) receive error, length=%d, errno=%d",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, xLength, errno);
|
pxInfo->xSockId, pxInfo->pcIpAddr, xLength, errno);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -319,7 +341,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
|
|||||||
pxInfo->xRcvErr = xRet;
|
pxInfo->xRcvErr = xRet;
|
||||||
return xRet;
|
return xRet;
|
||||||
} else if (xRet != MB_TCP_UID) {
|
} else if (xRet != MB_TCP_UID) {
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s), Fail to read modbus header. ret=%d",
|
ESP_LOGD(TAG, "Socket (#%d)(%s), Fail to read modbus header. ret=%d",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, xRet);
|
pxInfo->xSockId, pxInfo->pcIpAddr, xRet);
|
||||||
pxInfo->xRcvErr = ERR_VAL;
|
pxInfo->xRcvErr = ERR_VAL;
|
||||||
return ERR_VAL;
|
return ERR_VAL;
|
||||||
@ -333,7 +355,7 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
|
|||||||
return xRet;
|
return xRet;
|
||||||
} else if (xRet != xLength) {
|
} else if (xRet != xLength) {
|
||||||
// Received incorrect or fragmented packet.
|
// Received incorrect or fragmented packet.
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) incorrect packet, length=%d, TID=0x%02x, errno=%d(%s)",
|
ESP_LOGD(TAG, "Socket(#%d)(%s) incorrect packet, length=%d, TID=0x%02x, errno=%d(%s)",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
|
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
|
||||||
usTidRcv, errno, strerror(errno));
|
usTidRcv, errno, strerror(errno));
|
||||||
pxInfo->xRcvErr = ERR_VAL;
|
pxInfo->xRcvErr = ERR_VAL;
|
||||||
@ -343,13 +365,13 @@ static int vMBTCPPortMasterReadPacket(MbSlaveInfo_t* pxInfo)
|
|||||||
|
|
||||||
// Check transaction identifier field in the incoming packet.
|
// Check transaction identifier field in the incoming packet.
|
||||||
if ((pxInfo->usTidCnt - 1) != usTidRcv) {
|
if ((pxInfo->usTidCnt - 1) != usTidRcv) {
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s), incorrect TID(0x%02x)!=(0x%02x) received, discard data.",
|
ESP_LOGD(TAG, "Socket (#%d)(%s), incorrect TID(0x%02x)!=(0x%02x) received, discard data.",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, usTidRcv, (pxInfo->usTidCnt - 1));
|
pxInfo->xSockId, pxInfo->pcIpAddr, usTidRcv, (pxInfo->usTidCnt - 1));
|
||||||
pxInfo->xRcvErr = ERR_BUF;
|
pxInfo->xRcvErr = ERR_BUF;
|
||||||
return ERR_BUF;
|
return ERR_BUF;
|
||||||
}
|
}
|
||||||
pxInfo->usRcvPos += xRet + MB_TCP_UID;
|
pxInfo->usRcvPos += xRet + MB_TCP_UID;
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) get data, length=%d, TID=0x%02x, errno=%d(%s)",
|
ESP_LOGD(TAG, "Socket(#%d)(%s) get data, length=%d, TID=0x%02x, errno=%d(%s)",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
|
pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usRcvPos,
|
||||||
usTidRcv, errno, strerror(errno));
|
usTidRcv, errno, strerror(errno));
|
||||||
pxInfo->xRcvErr = ERR_OK;
|
pxInfo->xRcvErr = ERR_OK;
|
||||||
@ -366,7 +388,7 @@ static err_t xMBTCPPortMasterSetNonBlocking(MbSlaveInfo_t* pxInfo)
|
|||||||
// Set non blocking attribute for socket
|
// Set non blocking attribute for socket
|
||||||
ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
|
ULONG ulFlags = fcntl(pxInfo->xSockId, F_GETFL);
|
||||||
if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
|
if (fcntl(pxInfo->xSockId, F_SETFL, ulFlags | O_NONBLOCK) == -1) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), fcntl() call error=%d",
|
ESP_LOGE(TAG, "Socket(#%d)(%s), fcntl() call error=%d",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, errno);
|
pxInfo->xSockId, pxInfo->pcIpAddr, errno);
|
||||||
return ERR_WOULDBLOCK;
|
return ERR_WOULDBLOCK;
|
||||||
}
|
}
|
||||||
@ -399,12 +421,12 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
|
|||||||
if (errno == EINPROGRESS) {
|
if (errno == EINPROGRESS) {
|
||||||
xErr = ERR_INPROGRESS;
|
xErr = ERR_INPROGRESS;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
|
ESP_LOGV(TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
|
||||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
|
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
|
||||||
xErr = ERR_CONN;
|
xErr = ERR_CONN;
|
||||||
}
|
}
|
||||||
} else if (xErr == 0) {
|
} else if (xErr == 0) {
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
|
ESP_LOGV(TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
|
pxInfo->xSockId, pxInfo->pcIpAddr, xErr, errno);
|
||||||
return ERR_INPROGRESS;
|
return ERR_INPROGRESS;
|
||||||
} else {
|
} else {
|
||||||
@ -413,11 +435,11 @@ static err_t xMBTCPPortMasterCheckAlive(MbSlaveInfo_t* pxInfo, ULONG xTimeoutMs)
|
|||||||
// Check socket error
|
// Check socket error
|
||||||
xErr = getsockopt(pxInfo->xSockId, SOL_SOCKET, SO_ERROR, (void*)&xOptErr, (socklen_t*)&ulOptLen);
|
xErr = getsockopt(pxInfo->xSockId, SOL_SOCKET, SO_ERROR, (void*)&xOptErr, (socklen_t*)&ulOptLen);
|
||||||
if (xOptErr != 0) {
|
if (xOptErr != 0) {
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), sock error occurred (%d).",
|
ESP_LOGD(TAG, "Socket(#%d)(%s), sock error occurred (%d).",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr, xOptErr);
|
pxInfo->xSockId, pxInfo->pcIpAddr, xOptErr);
|
||||||
return ERR_CONN;
|
return ERR_CONN;
|
||||||
}
|
}
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s), is alive.",
|
ESP_LOGV(TAG, "Socket(#%d)(%s), is alive.",
|
||||||
pxInfo->xSockId, pxInfo->pcIpAddr);
|
pxInfo->xSockId, pxInfo->pcIpAddr);
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
@ -447,7 +469,7 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
|
|||||||
int xRet = getaddrinfo(pcHostStr, NULL, &xHint, &pxAddrList);
|
int xRet = getaddrinfo(pcHostStr, NULL, &xHint, &pxAddrList);
|
||||||
|
|
||||||
if (xRet != 0) {
|
if (xRet != 0) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect host name or IP: %s", pcHostStr);
|
ESP_LOGE(TAG, "Incorrect host name or IP: %s", pcHostStr);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (pxAddrList->ai_family == AF_INET) {
|
if (pxAddrList->ai_family == AF_INET) {
|
||||||
@ -465,20 +487,24 @@ static BOOL xMBTCPPortMasterCheckHost(const CHAR* pcHostStr, ip_addr_t* pxHostAd
|
|||||||
if (pxHostAddr) {
|
if (pxHostAddr) {
|
||||||
*pxHostAddr = xTargetAddr;
|
*pxHostAddr = xTargetAddr;
|
||||||
}
|
}
|
||||||
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Host[IP]: \"%s\"[%s]", pxAddrList->ai_canonname, pcStr);
|
ESP_LOGI(TAG, "Host[IP]: \"%s\"[%s]", pxAddrList->ai_canonname, pcStr);
|
||||||
freeaddrinfo(pxAddrList);
|
freeaddrinfo(pxAddrList);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr)
|
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress)
|
||||||
{
|
{
|
||||||
BOOL xRes = FALSE;
|
BOOL xRes = FALSE;
|
||||||
|
MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
|
||||||
MB_PORT_CHECK(xMbPortConfig.xConnectQueue != NULL, FALSE, "Wrong slave IP address to add.");
|
MB_PORT_CHECK(xMbPortConfig.xConnectQueue != NULL, FALSE, "Wrong slave IP address to add.");
|
||||||
if (pcIpStr) {
|
if (pcIpStr && (usIndex != 0xFF)) {
|
||||||
xRes = xMBTCPPortMasterCheckHost(pcIpStr, NULL);
|
xRes = xMBTCPPortMasterCheckHost(pcIpStr, NULL);
|
||||||
}
|
}
|
||||||
if (xRes || !pcIpStr) {
|
if (xRes || !pcIpStr) {
|
||||||
BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (const void*)&pcIpStr, 100);
|
xSlaveAddrInfo.pcIPAddr = pcIpStr;
|
||||||
|
xSlaveAddrInfo.usIndex = usIndex;
|
||||||
|
xSlaveAddrInfo.ucSlaveAddr = ucSlaveAddress;
|
||||||
|
BaseType_t xStatus = xQueueSend(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, 100);
|
||||||
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "FAIL to add slave IP address: [%s].", pcIpStr);
|
MB_PORT_CHECK((xStatus == pdTRUE), FALSE, "FAIL to add slave IP address: [%s].", pcIpStr);
|
||||||
}
|
}
|
||||||
return xRes;
|
return xRes;
|
||||||
@ -516,7 +542,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
|||||||
int xRet = getaddrinfo(pxInfo->pcIpAddr, pcStr, &xHint, &pxAddrList);
|
int xRet = getaddrinfo(pxInfo->pcIpAddr, pcStr, &xHint, &pxAddrList);
|
||||||
free(pcStr);
|
free(pcStr);
|
||||||
if (xRet != 0) {
|
if (xRet != 0) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Cannot resolve host: %s", pxInfo->pcIpAddr);
|
ESP_LOGE(TAG, "Cannot resolve host: %s", pxInfo->pcIpAddr);
|
||||||
return ERR_CONN;
|
return ERR_CONN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -539,12 +565,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
|||||||
if (pxInfo->xSockId <= 0) {
|
if (pxInfo->xSockId <= 0) {
|
||||||
pxInfo->xSockId = socket(pxCurAddr->ai_family, pxCurAddr->ai_socktype, pxCurAddr->ai_protocol);
|
pxInfo->xSockId = socket(pxCurAddr->ai_family, pxCurAddr->ai_socktype, pxCurAddr->ai_protocol);
|
||||||
if (pxInfo->xSockId < 0) {
|
if (pxInfo->xSockId < 0) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Unable to create socket: #%d, errno %d", pxInfo->xSockId, errno);
|
ESP_LOGE(TAG, "Unable to create socket: #%d, errno %d", pxInfo->xSockId, errno);
|
||||||
xErr = ERR_IF;
|
xErr = ERR_IF;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket (#%d)(%s) created.", pxInfo->xSockId, cStr);
|
ESP_LOGV(TAG, "Socket (#%d)(%s) created.", pxInfo->xSockId, cStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set non blocking attribute for socket
|
// Set non blocking attribute for socket
|
||||||
@ -555,7 +581,7 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
|||||||
xErr = connect(pxInfo->xSockId, (struct sockaddr*)pxCurAddr->ai_addr, pxCurAddr->ai_addrlen);
|
xErr = connect(pxInfo->xSockId, (struct sockaddr*)pxCurAddr->ai_addr, pxCurAddr->ai_addrlen);
|
||||||
if ((xErr < 0) && (errno == EINPROGRESS || errno == EALREADY)) {
|
if ((xErr < 0) && (errno == EINPROGRESS || errno == EALREADY)) {
|
||||||
// The unblocking connect is pending (check status later) or already connected
|
// The unblocking connect is pending (check status later) or already connected
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Socket(#%d)(%s) connection is pending, errno %d (%s).",
|
ESP_LOGV(TAG, "Socket(#%d)(%s) connection is pending, errno %d (%s).",
|
||||||
pxInfo->xSockId, cStr, errno, strerror(errno));
|
pxInfo->xSockId, cStr, errno, strerror(errno));
|
||||||
|
|
||||||
// Set keep alive flag in socket options
|
// Set keep alive flag in socket options
|
||||||
@ -568,12 +594,12 @@ static err_t xMBTCPPortMasterConnect(MbSlaveInfo_t* pxInfo)
|
|||||||
continue;
|
continue;
|
||||||
} else if (xErr != ERR_OK) {
|
} else if (xErr != ERR_OK) {
|
||||||
// Other error occurred during connection
|
// Other error occurred during connection
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
|
ESP_LOGV(TAG, MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
|
||||||
pxInfo->xIndex, pxInfo->xSockId, cStr, xErr, errno, strerror(errno));
|
pxInfo->xIndex, pxInfo->xSockId, cStr, xErr, errno, strerror(errno));
|
||||||
xMBTCPPortMasterCloseConnection(pxInfo);
|
xMBTCPPortMasterCloseConnection(pxInfo);
|
||||||
xErr = ERR_CONN;
|
xErr = ERR_CONN;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", successfully connected."),
|
ESP_LOGI(TAG, MB_SLAVE_FMT(", successfully connected."),
|
||||||
pxInfo->xIndex, pxInfo->xSockId, cStr);
|
pxInfo->xIndex, pxInfo->xSockId, cStr);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -615,7 +641,7 @@ static int xMBTCPPortMasterCheckConnState(fd_set* pxFdSet)
|
|||||||
xErr = xMBTCPPortMasterCheckAlive(pxInfo, 0);
|
xErr = xMBTCPPortMasterCheckAlive(pxInfo, 0);
|
||||||
if ((xErr < 0) && (((xTime - pxInfo->xRecvTimeStamp) > MB_TCP_RECONNECT_TIMEOUT) ||
|
if ((xErr < 0) && (((xTime - pxInfo->xRecvTimeStamp) > MB_TCP_RECONNECT_TIMEOUT) ||
|
||||||
((xTime - pxInfo->xSendTimeStamp) > MB_TCP_RECONNECT_TIMEOUT))) {
|
((xTime - pxInfo->xSendTimeStamp) > MB_TCP_RECONNECT_TIMEOUT))) {
|
||||||
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%ju][%ju]."),
|
ESP_LOGI(TAG, MB_SLAVE_FMT(", slave is down, off_time[r][w](us) = [%ju][%ju]."),
|
||||||
pxInfo->xIndex,
|
pxInfo->xIndex,
|
||||||
pxInfo->xSockId,
|
pxInfo->xSockId,
|
||||||
pxInfo->pcIpAddr,
|
pxInfo->pcIpAddr,
|
||||||
@ -637,9 +663,9 @@ static void xMBTCPPortMasterFsmSetError(eMBMasterErrorEventType xErrType, eMBMas
|
|||||||
|
|
||||||
static void vMBTCPPortMasterTask(void *pvParameters)
|
static void vMBTCPPortMasterTask(void *pvParameters)
|
||||||
{
|
{
|
||||||
CHAR* pcAddrStr = NULL;
|
|
||||||
MbSlaveInfo_t* pxInfo;
|
MbSlaveInfo_t* pxInfo;
|
||||||
MbSlaveInfo_t* pxCurrInfo;
|
MbSlaveInfo_t* pxCurrInfo;
|
||||||
|
|
||||||
fd_set xConnSet;
|
fd_set xConnSet;
|
||||||
fd_set xReadSet;
|
fd_set xReadSet;
|
||||||
int xMaxSd = 0;
|
int xMaxSd = 0;
|
||||||
@ -649,51 +675,53 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
|
|
||||||
// Register each slave in the connection info structure
|
// Register each slave in the connection info structure
|
||||||
while (1) {
|
while (1) {
|
||||||
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&pcAddrStr, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
|
MbSlaveAddrInfo_t xSlaveAddrInfo = { 0 };
|
||||||
|
BaseType_t xStatus = xQueueReceive(xMbPortConfig.xConnectQueue, (void*)&xSlaveAddrInfo, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
|
||||||
xMBTCPPortMasterCheckShutdown();
|
xMBTCPPortMasterCheckShutdown();
|
||||||
if (xStatus != pdTRUE) {
|
if (xStatus != pdTRUE) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Fail to register slave IP.");
|
ESP_LOGE(TAG, "Fail to register slave IP.");
|
||||||
} else {
|
} else {
|
||||||
if (pcAddrStr == NULL && xMbPortConfig.usMbSlaveInfoCount) {
|
if (xSlaveAddrInfo.pcIPAddr == NULL && xMbPortConfig.usMbSlaveInfoCount && xSlaveAddrInfo.usIndex == 0xFF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (xMbPortConfig.usMbSlaveInfoCount > MB_TCP_PORT_MAX_CONN) {
|
if (xMbPortConfig.usMbSlaveInfoCount > MB_TCP_PORT_MAX_CONN) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Exceeds maximum connections limit=%d.", MB_TCP_PORT_MAX_CONN);
|
ESP_LOGE(TAG, "Exceeds maximum connections limit=%d.", MB_TCP_PORT_MAX_CONN);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pxInfo = calloc(1, sizeof(MbSlaveInfo_t));
|
pxInfo = calloc(1, sizeof(MbSlaveInfo_t));
|
||||||
if (!pxInfo) {
|
if (!pxInfo) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Slave(#%d), info structure allocation fail.",
|
ESP_LOGE(TAG, "Slave(#%d), info structure allocation fail.",
|
||||||
xMbPortConfig.usMbSlaveInfoCount);
|
xMbPortConfig.usMbSlaveInfoCount);
|
||||||
free(pxInfo);
|
free(pxInfo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pxInfo->pucRcvBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
|
pxInfo->pucRcvBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
|
||||||
if (!pxInfo->pucRcvBuf) {
|
if (!pxInfo->pucRcvBuf) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Slave(#%d), receive buffer allocation fail.",
|
ESP_LOGE(TAG, "Slave(#%d), receive buffer allocation fail.",
|
||||||
xMbPortConfig.usMbSlaveInfoCount);
|
xMbPortConfig.usMbSlaveInfoCount);
|
||||||
free(pxInfo->pucRcvBuf);
|
free(pxInfo->pucRcvBuf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pxInfo->usRcvPos = 0;
|
pxInfo->usRcvPos = 0;
|
||||||
pxInfo->pcIpAddr = pcAddrStr;
|
pxInfo->pcIpAddr = xSlaveAddrInfo.pcIPAddr;
|
||||||
pxInfo->xSockId = -1;
|
pxInfo->xSockId = -1;
|
||||||
pxInfo->xError = -1;
|
pxInfo->xError = -1;
|
||||||
pxInfo->xRecvTimeStamp = xMBTCPGetTimeStamp();
|
pxInfo->xRecvTimeStamp = xMBTCPGetTimeStamp();
|
||||||
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
||||||
pxInfo->xMbProto = MB_PROTO_TCP;
|
pxInfo->xMbProto = MB_PROTO_TCP;
|
||||||
pxInfo->xIndex = xMbPortConfig.usMbSlaveInfoCount;
|
pxInfo->ucSlaveAddr = xSlaveAddrInfo.ucSlaveAddr;
|
||||||
|
pxInfo->xIndex = xSlaveAddrInfo.usIndex;
|
||||||
pxInfo->usTidCnt = (USHORT)(xMbPortConfig.usMbSlaveInfoCount << 8U);
|
pxInfo->usTidCnt = (USHORT)(xMbPortConfig.usMbSlaveInfoCount << 8U);
|
||||||
// Register slave
|
// Register slave
|
||||||
xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.usMbSlaveInfoCount++] = pxInfo;
|
xMbPortConfig.pxMbSlaveInfo[xMbPortConfig.usMbSlaveInfoCount++] = pxInfo;
|
||||||
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Add slave IP: %s", pcAddrStr);
|
ESP_LOGI(TAG, "Add slave IP: %s", xSlaveAddrInfo.pcIPAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main connection cycle
|
// Main connection cycle
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connecting to slaves...");
|
ESP_LOGI(TAG, "Connecting to slaves...");
|
||||||
xTime = xMBTCPGetTimeStamp();
|
xTime = xMBTCPGetTimeStamp();
|
||||||
usSlaveConnCnt = 0;
|
usSlaveConnCnt = 0;
|
||||||
CHAR ucDot = '.';
|
CHAR ucDot = '.';
|
||||||
@ -706,7 +734,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
|
pxInfo = xMbPortConfig.pxMbSlaveInfo[ucCnt];
|
||||||
// if slave descriptor is NULL then it is end of list or connection closed.
|
// if slave descriptor is NULL then it is end of list or connection closed.
|
||||||
if (!pxInfo) {
|
if (!pxInfo) {
|
||||||
ESP_LOGV(MB_TCP_MASTER_PORT_TAG, "Index: %d is not initialized, skip.", ucCnt);
|
ESP_LOGV(TAG, "Index: %d is not initialized, skip.", ucCnt);
|
||||||
if (xMbPortConfig.usMbSlaveInfoCount) {
|
if (xMbPortConfig.usMbSlaveInfoCount) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -721,7 +749,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
// In case of connection errors remove the socket from set
|
// In case of connection errors remove the socket from set
|
||||||
if (FD_ISSET(pxInfo->xSockId, &xConnSet)) {
|
if (FD_ISSET(pxInfo->xSockId, &xConnSet)) {
|
||||||
FD_CLR(pxInfo->xSockId, &xConnSet);
|
FD_CLR(pxInfo->xSockId, &xConnSet);
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(" connect failed, error = %d."),
|
ESP_LOGE(TAG, MB_SLAVE_FMT(" connect failed, error = %d."),
|
||||||
pxInfo->xIndex, pxInfo->xSockId,
|
pxInfo->xIndex, pxInfo->xSockId,
|
||||||
(char*)pxInfo->pcIpAddr, xErr);
|
(char*)pxInfo->pcIpAddr, xErr);
|
||||||
if (usSlaveConnCnt) {
|
if (usSlaveConnCnt) {
|
||||||
@ -735,7 +763,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
FD_SET(pxInfo->xSockId, &xConnSet);
|
FD_SET(pxInfo->xSockId, &xConnSet);
|
||||||
usSlaveConnCnt++;
|
usSlaveConnCnt++;
|
||||||
xMaxSd = (pxInfo->xSockId > xMaxSd) ? pxInfo->xSockId : xMaxSd;
|
xMaxSd = (pxInfo->xSockId > xMaxSd) ? pxInfo->xSockId : xMaxSd;
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", connected %d slave(s), error = %d."),
|
ESP_LOGD(TAG, MB_SLAVE_FMT(", connected %d slave(s), error = %d."),
|
||||||
pxInfo->xIndex, pxInfo->xSockId,
|
pxInfo->xIndex, pxInfo->xSockId,
|
||||||
pxInfo->pcIpAddr,
|
pxInfo->pcIpAddr,
|
||||||
usSlaveConnCnt, xErr);
|
usSlaveConnCnt, xErr);
|
||||||
@ -745,7 +773,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", unexpected error = %d."),
|
ESP_LOGE(TAG, MB_SLAVE_FMT(", unexpected error = %d."),
|
||||||
pxInfo->xIndex,
|
pxInfo->xIndex,
|
||||||
pxInfo->xSockId,
|
pxInfo->xSockId,
|
||||||
pxInfo->pcIpAddr, xErr);
|
pxInfo->pcIpAddr, xErr);
|
||||||
@ -757,7 +785,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
xMBTCPPortMasterCheckShutdown();
|
xMBTCPPortMasterCheckShutdown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ESP_LOGI(MB_TCP_MASTER_PORT_TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
|
ESP_LOGI(TAG, "Connected %d slaves, start polling...", usSlaveConnCnt);
|
||||||
|
|
||||||
vMBTCPPortMasterStartPoll(); // Send event to start stack
|
vMBTCPPortMasterStartPoll(); // Send event to start stack
|
||||||
|
|
||||||
@ -768,26 +796,26 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
|
xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_TRANSMIT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS));
|
||||||
// Synchronize state machine with send packet event
|
// Synchronize state machine with send packet event
|
||||||
if (xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_SENT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS))) {
|
if (xMBMasterPortFsmWaitConfirmation(EV_MASTER_FRAME_SENT, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS))) {
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "FSM Synchronized with sent event.");
|
ESP_LOGD(TAG, "FSM Synchronized with sent event.");
|
||||||
}
|
}
|
||||||
// Get slave info for the current slave.
|
// Get slave info for the current slave.
|
||||||
pxCurrInfo = vMBTCPPortMasterGetCurrInfo();
|
pxCurrInfo = vMBTCPPortMasterGetCurrInfo();
|
||||||
if (!pxCurrInfo) {
|
if (!pxCurrInfo) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, "Incorrect connection options for slave index: %d.",
|
ESP_LOGE(TAG, "Incorrect connection options for slave index: %d.",
|
||||||
xMbPortConfig.ucCurSlaveIndex);
|
xMbPortConfig.ucCurSlaveIndex);
|
||||||
vMBTCPPortMasterStopPoll();
|
vMBTCPPortMasterStopPoll();
|
||||||
xMBTCPPortMasterCheckShutdown();
|
xMBTCPPortMasterCheckShutdown();
|
||||||
break; // incorrect slave descriptor, reconnect.
|
break; // incorrect slave descriptor, reconnect.
|
||||||
}
|
}
|
||||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Set select timeout, left time: %ju ms.",
|
ESP_LOGD(TAG, "Set select timeout, left time: %ju ms.",
|
||||||
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
||||||
// Wait respond from current slave during respond timeout
|
// Wait respond from current slave during respond timeout
|
||||||
int xRes = vMBTCPPortMasterRxCheck(pxCurrInfo->xSockId, &xReadSet, xTime);
|
int xRes = vMBTCPPortMasterRxCheck(pxCurrInfo->xSockId, &xReadSet, xTime);
|
||||||
if (xRes == ERR_TIMEOUT) {
|
if (xRes == ERR_TIMEOUT) {
|
||||||
// No respond from current slave, process timeout.
|
// No respond from current slave, process timeout.
|
||||||
// Need to drop response later if it is received after timeout.
|
// Need to drop response later if it is received after timeout.
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Select timeout, left time: %ju ms.",
|
ESP_LOGD(TAG, "Select timeout, left time: %ju ms.",
|
||||||
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo));
|
||||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||||
// Wait completion of last transaction
|
// Wait completion of last transaction
|
||||||
@ -796,7 +824,7 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
continue;
|
continue;
|
||||||
} else if (xRes < 0) {
|
} else if (xRes < 0) {
|
||||||
// Select error (slave connection or r/w failure).
|
// Select error (slave connection or r/w failure).
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", socket select error. Slave disconnected?"),
|
ESP_LOGD(TAG, MB_SLAVE_FMT(", socket select error. Slave disconnected?"),
|
||||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||||
// Wait completion of last transaction
|
// Wait completion of last transaction
|
||||||
@ -820,19 +848,19 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
if (xRet > 0) {
|
if (xRet > 0) {
|
||||||
// Response received correctly, send an event to stack
|
// Response received correctly, send an event to stack
|
||||||
xMBTCPPortMasterFsmSetError(EV_ERROR_INIT, EV_MASTER_FRAME_RECEIVED);
|
xMBTCPPortMasterFsmSetError(EV_ERROR_INIT, EV_MASTER_FRAME_RECEIVED);
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame received."),
|
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame received."),
|
||||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||||
} else if ((xRet == ERR_TIMEOUT) || (xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo) == 0)) {
|
} else if ((xRet == ERR_TIMEOUT) || (xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo) == 0)) {
|
||||||
// Timeout occurred when receiving frame, process respond timeout
|
// Timeout occurred when receiving frame, process respond timeout
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame read timeout."),
|
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame read timeout."),
|
||||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||||
} else if (xRet == ERR_BUF) {
|
} else if (xRet == ERR_BUF) {
|
||||||
// After retries a response with incorrect TID received, process failure.
|
// After retries a response with incorrect TID received, process failure.
|
||||||
xMBTCPPortMasterFsmSetError(EV_ERROR_RECEIVE_DATA, EV_MASTER_ERROR_PROCESS);
|
xMBTCPPortMasterFsmSetError(EV_ERROR_RECEIVE_DATA, EV_MASTER_ERROR_PROCESS);
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", frame error."),
|
ESP_LOGD(TAG, MB_SLAVE_FMT(", frame error."),
|
||||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", critical error=%d."),
|
ESP_LOGE(TAG, MB_SLAVE_FMT(", critical error=%d."),
|
||||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xRet);
|
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xRet);
|
||||||
// Stop polling process
|
// Stop polling process
|
||||||
vMBTCPPortMasterStopPoll();
|
vMBTCPPortMasterStopPoll();
|
||||||
@ -842,14 +870,14 @@ static void vMBTCPPortMasterTask(void *pvParameters)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
xTime = xMBTCPPortMasterGetRespTimeLeft(pxCurrInfo);
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, "Slave #%d, data processing left time %ju [ms].", pxCurrInfo->xIndex, xTime);
|
ESP_LOGD(TAG, "Slave #%d, data processing left time %ju [ms].", pxCurrInfo->xIndex, xTime);
|
||||||
// Wait completion of Modbus frame processing before start of new transaction.
|
// Wait completion of Modbus frame processing before start of new transaction.
|
||||||
if (xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime))) {
|
if (xMBMasterPortFsmWaitConfirmation(MB_EVENT_REQ_DONE_MASK, pdMS_TO_TICKS(xTime))) {
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", data processing completed."),
|
ESP_LOGD(TAG, MB_SLAVE_FMT(", data processing completed."),
|
||||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr);
|
||||||
}
|
}
|
||||||
xTime = xMBTCPGetTimeStamp() - pxCurrInfo->xSendTimeStamp;
|
xTime = xMBTCPGetTimeStamp() - pxCurrInfo->xSendTimeStamp;
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", processing time[us] = %ju."),
|
ESP_LOGD(TAG, MB_SLAVE_FMT(", processing time[us] = %ju."),
|
||||||
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
|
pxCurrInfo->xIndex, pxCurrInfo->xSockId, pxCurrInfo->pcIpAddr, xTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -886,7 +914,7 @@ vMBMasterTCPPortClose(void)
|
|||||||
xShutdownSemaphore = xSemaphoreCreateBinary();
|
xShutdownSemaphore = xSemaphoreCreateBinary();
|
||||||
// if no semaphore (alloc issues) or couldn't acquire it, just delete the task
|
// if no semaphore (alloc issues) or couldn't acquire it, just delete the task
|
||||||
if (xShutdownSemaphore == NULL || xSemaphoreTake(xShutdownSemaphore, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)) != pdTRUE) {
|
if (xShutdownSemaphore == NULL || xSemaphoreTake(xShutdownSemaphore, pdMS_TO_TICKS(MB_EVENT_WAIT_TOUT_MS)) != pdTRUE) {
|
||||||
ESP_LOGW(MB_TCP_MASTER_PORT_TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
|
ESP_LOGW(TAG, "Modbus port task couldn't exit gracefully within timeout -> abruptly deleting the task.");
|
||||||
vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
|
vTaskDelete(xMbPortConfig.xMbTcpTaskHandle);
|
||||||
}
|
}
|
||||||
if (xShutdownSemaphore) {
|
if (xShutdownSemaphore) {
|
||||||
@ -924,13 +952,13 @@ int xMBMasterTCPPortWritePoll(MbSlaveInfo_t* pxInfo, const UCHAR * pucMBTCPFrame
|
|||||||
int xRes = (int)xMBTCPPortMasterCheckAlive(pxInfo, xTimeout);
|
int xRes = (int)xMBTCPPortMasterCheckAlive(pxInfo, xTimeout);
|
||||||
if ((xRes < 0) && (xRes != ERR_INPROGRESS))
|
if ((xRes < 0) && (xRes != ERR_INPROGRESS))
|
||||||
{
|
{
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
|
ESP_LOGE(TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
|
||||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
||||||
return xRes;
|
return xRes;
|
||||||
}
|
}
|
||||||
xRes = send(pxInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
|
xRes = send(pxInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
|
||||||
if (xRes < 0) {
|
if (xRes < 0) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
|
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
|
||||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
||||||
}
|
}
|
||||||
return xRes;
|
return xRes;
|
||||||
@ -940,23 +968,28 @@ BOOL
|
|||||||
xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
||||||
{
|
{
|
||||||
BOOL bFrameSent = FALSE;
|
BOOL bFrameSent = FALSE;
|
||||||
xMbPortConfig.ucCurSlaveIndex = ucMBMasterGetDestAddress();
|
USHORT ucCurSlaveIndex = ucMBMasterGetDestAddress();
|
||||||
MbSlaveInfo_t* pxInfo = vMBTCPPortMasterGetCurrInfo();
|
MbSlaveInfo_t* pxInfo = vMBTCPPortMasterFindSlaveInfo(ucCurSlaveIndex);
|
||||||
|
|
||||||
// If socket active then send data
|
// If the slave is correct and active then send data
|
||||||
if (pxInfo->xSockId > -1) {
|
// otherwise treat slave as died and skip
|
||||||
|
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
|
// Apply TID field to the frame before send
|
||||||
pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
|
pucMBTCPFrame[MB_TCP_TID] = (UCHAR)(pxInfo->usTidCnt >> 8U);
|
||||||
pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
|
pucMBTCPFrame[MB_TCP_TID + 1] = (UCHAR)(pxInfo->usTidCnt & 0xFF);
|
||||||
int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
|
int xRes = xMBMasterTCPPortWritePoll(pxInfo, pucMBTCPFrame, usTCPLength, MB_TCP_SEND_TIMEOUT_MS);
|
||||||
if (xRes < 0) {
|
if (xRes < 0) {
|
||||||
ESP_LOGE(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),
|
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data failure, err(errno) = %d(%d)."),
|
||||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, xRes, errno);
|
||||||
bFrameSent = FALSE;
|
bFrameSent = FALSE;
|
||||||
pxInfo->xError = xRes;
|
pxInfo->xError = xRes;
|
||||||
} else {
|
} else {
|
||||||
bFrameSent = TRUE;
|
bFrameSent = TRUE;
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send data successful: TID=0x%02x, %d (bytes), errno %d"),
|
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->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->usTidCnt, xRes, errno);
|
||||||
pxInfo->xError = 0;
|
pxInfo->xError = 0;
|
||||||
pxInfo->usRcvPos = 0;
|
pxInfo->usRcvPos = 0;
|
||||||
@ -967,9 +1000,9 @@ xMBMasterTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
pxInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(MB_TCP_MASTER_PORT_TAG, MB_SLAVE_FMT(", send to died slave, error = %d"),
|
ESP_LOGD(TAG, "Send data to died slave, address = %d", ucCurSlaveIndex);
|
||||||
pxInfo->xIndex, pxInfo->xSockId, pxInfo->pcIpAddr, pxInfo->xError);
|
|
||||||
}
|
}
|
||||||
vMBMasterPortTimersRespondTimeoutEnable();
|
vMBMasterPortTimersRespondTimeoutEnable();
|
||||||
xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
|
xMBMasterPortEventPost(EV_MASTER_FRAME_SENT);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
* SPDX-FileContributor: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* FreeModbus Libary: ESP32 TCP Port
|
* FreeModbus Libary: ESP32 TCP Port
|
||||||
@ -67,6 +67,7 @@ typedef struct {
|
|||||||
int xError; /*!< Socket error */
|
int xError; /*!< Socket error */
|
||||||
int xRcvErr; /*!< Socket receive error */
|
int xRcvErr; /*!< Socket receive error */
|
||||||
const char* pcIpAddr; /*!< TCP/UDP IP address */
|
const char* pcIpAddr; /*!< TCP/UDP IP address */
|
||||||
|
UCHAR ucSlaveAddr; /*!< Slave short address */
|
||||||
UCHAR* pucRcvBuf; /*!< Receive buffer pointer */
|
UCHAR* pucRcvBuf; /*!< Receive buffer pointer */
|
||||||
USHORT usRcvPos; /*!< Receive buffer position */
|
USHORT usRcvPos; /*!< Receive buffer position */
|
||||||
int pcPort; /*!< TCP/UDP port number */
|
int pcPort; /*!< TCP/UDP port number */
|
||||||
@ -86,19 +87,28 @@ typedef struct {
|
|||||||
eMBPortProto eMbProto; /*!< Master protocol type */
|
eMBPortProto eMbProto; /*!< Master protocol type */
|
||||||
void* pvNetIface; /*!< Master netif interface pointer */
|
void* pvNetIface; /*!< Master netif interface pointer */
|
||||||
MbSlaveInfo_t** pxMbSlaveInfo; /*!< Master information structure for each connected slave */
|
MbSlaveInfo_t** pxMbSlaveInfo; /*!< Master information structure for each connected slave */
|
||||||
|
MbSlaveInfo_t* pxMbSlaveCurrInfo; /*!< Master current slave information */
|
||||||
} MbPortConfig_t;
|
} MbPortConfig_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
USHORT usIndex; /*!< index of the address info */
|
||||||
|
const char* pcIPAddr; /*!< represents the IP address of the slave */
|
||||||
|
UCHAR ucSlaveAddr; /*!< slave unit ID (UID) field for MBAP frame */
|
||||||
|
} MbSlaveAddrInfo_t;
|
||||||
|
|
||||||
/* ----------------------- Function prototypes ------------------------------*/
|
/* ----------------------- Function prototypes ------------------------------*/
|
||||||
|
|
||||||
// The functions below are used by Modbus controller interface to configure Modbus port.
|
// The functions below are used by Modbus controller interface to configure Modbus port.
|
||||||
/**
|
/**
|
||||||
* Registers slave IP address
|
* Registers slave IP address
|
||||||
*
|
*
|
||||||
|
* @param usIndex index of element in the configuration
|
||||||
* @param pcIpStr IP address to register
|
* @param pcIpStr IP address to register
|
||||||
|
* @param ucSlaveAddress slave element index
|
||||||
*
|
*
|
||||||
* @return TRUE if address registered successfully, else FALSE
|
* @return TRUE if address registered successfully, else FALSE
|
||||||
*/
|
*/
|
||||||
BOOL xMBTCPPortMasterAddSlaveIp(const CHAR* pcIpStr);
|
BOOL xMBTCPPortMasterAddSlaveIp(const USHORT usIndex, const CHAR* pcIpStr, UCHAR ucSlaveAddress);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keeps FSM event handle and mask then wait for Master stack to start
|
* Keeps FSM event handle and mask then wait for Master stack to start
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
// Shared pointer to interface structure
|
// Shared pointer to interface structure
|
||||||
static mb_slave_interface_t* mbs_interface_ptr = NULL;
|
static mb_slave_interface_t* mbs_interface_ptr = NULL;
|
||||||
|
static const char *TAG = "MB_CONTROLLER_SLAVE";
|
||||||
|
|
||||||
// Modbus task function
|
// Modbus task function
|
||||||
static void modbus_tcp_slave_task(void *pvParameters)
|
static void modbus_tcp_slave_task(void *pvParameters)
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
* SPDX-FileContributor: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileContributor: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
* FreeModbus Libary: ESP32 TCP Port
|
* FreeModbus Libary: ESP32 TCP Port
|
||||||
@ -62,13 +62,13 @@
|
|||||||
/* ----------------------- Defines -----------------------------------------*/
|
/* ----------------------- Defines -----------------------------------------*/
|
||||||
#define MB_TCP_DISCONNECT_TIMEOUT ( CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000000 ) // disconnect timeout in uS
|
#define MB_TCP_DISCONNECT_TIMEOUT ( CONFIG_FMB_TCP_CONNECTION_TOUT_SEC * 1000000 ) // disconnect timeout in uS
|
||||||
#define MB_TCP_RESP_TIMEOUT_MS ( MB_MASTER_TIMEOUT_MS_RESPOND - 2 ) // slave response time limit
|
#define MB_TCP_RESP_TIMEOUT_MS ( MB_MASTER_TIMEOUT_MS_RESPOND - 2 ) // slave response time limit
|
||||||
#define MB_TCP_SLAVE_PORT_TAG "MB_TCP_SLAVE_PORT"
|
|
||||||
#define MB_TCP_NET_LISTEN_BACKLOG ( SOMAXCONN )
|
#define MB_TCP_NET_LISTEN_BACKLOG ( SOMAXCONN )
|
||||||
|
|
||||||
/* ----------------------- Prototypes ---------------------------------------*/
|
/* ----------------------- Prototypes ---------------------------------------*/
|
||||||
void vMBPortEventClose( void );
|
void vMBPortEventClose( void );
|
||||||
|
|
||||||
/* ----------------------- Static variables ---------------------------------*/
|
/* ----------------------- Static variables ---------------------------------*/
|
||||||
|
static const char *TAG = "MB_TCP_SLAVE_PORT";
|
||||||
static int xListenSock = -1;
|
static int xListenSock = -1;
|
||||||
static SemaphoreHandle_t xShutdownSemaphore = NULL;
|
static SemaphoreHandle_t xShutdownSemaphore = NULL;
|
||||||
static MbSlavePortConfig_t xConfig = { 0 };
|
static MbSlavePortConfig_t xConfig = { 0 };
|
||||||
@ -131,14 +131,14 @@ xMBTCPPortInit( USHORT usTCPPort )
|
|||||||
|
|
||||||
xConfig.pxMbClientInfo = calloc(MB_TCP_PORT_MAX_CONN + 1, sizeof(MbClientInfo_t*));
|
xConfig.pxMbClientInfo = calloc(MB_TCP_PORT_MAX_CONN + 1, sizeof(MbClientInfo_t*));
|
||||||
if (!xConfig.pxMbClientInfo) {
|
if (!xConfig.pxMbClientInfo) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "TCP client info allocation failure.");
|
ESP_LOGE(TAG, "TCP client info allocation failure.");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xConfig.pxMbClientInfo[idx] = NULL, idx++);
|
for(int idx = 0; idx < MB_TCP_PORT_MAX_CONN; xConfig.pxMbClientInfo[idx] = NULL, idx++);
|
||||||
|
|
||||||
xConfig.xRespQueueHandle = xMBTCPPortRespQueueCreate();
|
xConfig.xRespQueueHandle = xMBTCPPortRespQueueCreate();
|
||||||
if (!xConfig.xRespQueueHandle) {
|
if (!xConfig.xRespQueueHandle) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Response queue allocation failure.");
|
ESP_LOGE(TAG, "Response queue allocation failure.");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,10 +159,10 @@ xMBTCPPortInit( USHORT usTCPPort )
|
|||||||
vTaskSuspend(xConfig.xMbTcpTaskHandle);
|
vTaskSuspend(xConfig.xMbTcpTaskHandle);
|
||||||
if (xErr != pdTRUE)
|
if (xErr != pdTRUE)
|
||||||
{
|
{
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Server task creation failure.");
|
ESP_LOGE(TAG, "Server task creation failure.");
|
||||||
vTaskDelete(xConfig.xMbTcpTaskHandle);
|
vTaskDelete(xConfig.xMbTcpTaskHandle);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Protocol stack initialized.");
|
ESP_LOGI(TAG, "Protocol stack initialized.");
|
||||||
bOkay = TRUE;
|
bOkay = TRUE;
|
||||||
}
|
}
|
||||||
return bOkay;
|
return bOkay;
|
||||||
@ -197,7 +197,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
|
|||||||
// Accept new socket connection if not active
|
// Accept new socket connection if not active
|
||||||
xSockId = accept(xListenSockId, (struct sockaddr *)&xSrcAddr, &xSize);
|
xSockId = accept(xListenSockId, (struct sockaddr *)&xSrcAddr, &xSize);
|
||||||
if (xSockId < 0) {
|
if (xSockId < 0) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Unable to accept connection: errno=%d", errno);
|
ESP_LOGE(TAG, "Unable to accept connection: errno=%d", errno);
|
||||||
close(xSockId);
|
close(xSockId);
|
||||||
} else {
|
} else {
|
||||||
// Get the sender's ip address as string
|
// Get the sender's ip address as string
|
||||||
@ -209,7 +209,7 @@ static int xMBTCPPortAcceptConnection(int xListenSockId, char** pcIPAddr)
|
|||||||
inet6_ntoa_r(((struct sockaddr_in6 *)&xSrcAddr)->sin6_addr, cAddrStr, sizeof(cAddrStr) - 1);
|
inet6_ntoa_r(((struct sockaddr_in6 *)&xSrcAddr)->sin6_addr, cAddrStr, sizeof(cAddrStr) - 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), accept client connection from address: %s", xSockId, cAddrStr);
|
ESP_LOGI(TAG, "Socket (#%d), accept client connection from address: %s", xSockId, cAddrStr);
|
||||||
pcStr = calloc(1, strlen(cAddrStr) + 1);
|
pcStr = calloc(1, strlen(cAddrStr) + 1);
|
||||||
if (pcStr && pcIPAddr) {
|
if (pcStr && pcIPAddr) {
|
||||||
memcpy(pcStr, cAddrStr, strlen(cAddrStr));
|
memcpy(pcStr, cAddrStr, strlen(cAddrStr));
|
||||||
@ -225,11 +225,11 @@ static BOOL xMBTCPPortCloseConnection(MbClientInfo_t* pxInfo)
|
|||||||
MB_PORT_CHECK(pxInfo, FALSE, "Client info is NULL.");
|
MB_PORT_CHECK(pxInfo, FALSE, "Client info is NULL.");
|
||||||
|
|
||||||
if (pxInfo->xSockId == -1) {
|
if (pxInfo->xSockId == -1) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Wrong socket info or disconnected socket: %d.", pxInfo->xSockId);
|
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d.", pxInfo->xSockId);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
|
if (shutdown(pxInfo->xSockId, SHUT_RDWR) == -1) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), shutdown failed: errno %d", pxInfo->xSockId, errno);
|
ESP_LOGE(TAG, "Socket (#%d), shutdown failed: errno %d", pxInfo->xSockId, errno);
|
||||||
}
|
}
|
||||||
close(pxInfo->xSockId);
|
close(pxInfo->xSockId);
|
||||||
pxInfo->xSockId = -1;
|
pxInfo->xSockId = -1;
|
||||||
@ -266,7 +266,7 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
|
|||||||
} else if (xRet == 0) {
|
} else if (xRet == 0) {
|
||||||
// timeout occurred
|
// timeout occurred
|
||||||
if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) {
|
if ((xStartTimeStamp + xTimeoutMs * 1000) > xMBTCPGetTimeStamp()) {
|
||||||
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d) Read timeout.", pxClientInfo->xSockId);
|
ESP_LOGD(TAG, "Socket (#%d) Read timeout.", pxClientInfo->xSockId);
|
||||||
xRet = ERR_TIMEOUT;
|
xRet = ERR_TIMEOUT;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -281,12 +281,12 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
|
|||||||
pxClientInfo->usTCPFrameBytesLeft, MSG_DONTWAIT);
|
pxClientInfo->usTCPFrameBytesLeft, MSG_DONTWAIT);
|
||||||
if (xLength < 0) {
|
if (xLength < 0) {
|
||||||
// If an error occurred during receiving
|
// If an error occurred during receiving
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Receive failed: length=%d, errno=%d", xLength, errno);
|
ESP_LOGE(TAG, "Receive failed: length=%d, errno=%d", xLength, errno);
|
||||||
xRet = (err_t)xLength;
|
xRet = (err_t)xLength;
|
||||||
break;
|
break;
|
||||||
} else if (xLength == 0) {
|
} else if (xLength == 0) {
|
||||||
// Socket connection closed
|
// Socket connection closed
|
||||||
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), connection closed.",
|
ESP_LOGD(TAG, "Socket (#%d)(%s), connection closed.",
|
||||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
||||||
xRet = ERR_CLSD;
|
xRet = ERR_CLSD;
|
||||||
break;
|
break;
|
||||||
@ -304,14 +304,14 @@ static int xMBTCPPortRxPoll(MbClientInfo_t* pxClientInfo, ULONG xTimeoutMs)
|
|||||||
pxClientInfo->usTCPFrameBytesLeft = xLength + MB_TCP_UID - pxClientInfo->usTCPBufPos;
|
pxClientInfo->usTCPFrameBytesLeft = xLength + MB_TCP_UID - pxClientInfo->usTCPBufPos;
|
||||||
} else if (pxClientInfo->usTCPBufPos == (MB_TCP_UID + xLength)) {
|
} else if (pxClientInfo->usTCPBufPos == (MB_TCP_UID + xLength)) {
|
||||||
#if MB_TCP_DEBUG
|
#if MB_TCP_DEBUG
|
||||||
prvvMBTCPLogFrame(MB_TCP_SLAVE_PORT_TAG, (UCHAR*)&pxClientInfo->pucTCPBuf[0], pxClientInfo->usTCPBufPos);
|
prvvMBTCPLogFrame(TAG, (UCHAR*)&pxClientInfo->pucTCPBuf[0], pxClientInfo->usTCPBufPos);
|
||||||
#endif
|
#endif
|
||||||
// Copy TID field from incoming packet
|
// Copy TID field from incoming packet
|
||||||
pxClientInfo->usTidCnt = MB_TCP_GET_FIELD(pxClientInfo->pucTCPBuf, MB_TCP_TID);
|
pxClientInfo->usTidCnt = MB_TCP_GET_FIELD(pxClientInfo->pucTCPBuf, MB_TCP_TID);
|
||||||
xRet = pxClientInfo->usTCPBufPos;
|
xRet = pxClientInfo->usTCPBufPos;
|
||||||
break;
|
break;
|
||||||
} else if ((pxClientInfo->usTCPBufPos + xLength) >= MB_TCP_BUF_SIZE) {
|
} else if ((pxClientInfo->usTCPBufPos + xLength) >= MB_TCP_BUF_SIZE) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Incorrect buffer received (%u) bytes.", xLength);
|
ESP_LOGE(TAG, "Incorrect buffer received (%u) bytes.", xLength);
|
||||||
// This should not happen. We can't deal with such a client and
|
// This should not happen. We can't deal with such a client and
|
||||||
// drop the connection for security reasons.
|
// drop the connection for security reasons.
|
||||||
xRet = ERR_BUF;
|
xRet = ERR_BUF;
|
||||||
@ -396,7 +396,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
|
|||||||
{
|
{
|
||||||
if (listen(xListenSockFd, MB_TCP_NET_LISTEN_BACKLOG) != 0)
|
if (listen(xListenSockFd, MB_TCP_NET_LISTEN_BACKLOG) != 0)
|
||||||
{
|
{
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Error occurred during listen: errno=%d", errno);
|
ESP_LOGE(TAG, "Error occurred during listen: errno=%d", errno);
|
||||||
close(xListenSockFd);
|
close(xListenSockFd);
|
||||||
xListenSockFd = -1;
|
xListenSockFd = -1;
|
||||||
continue;
|
continue;
|
||||||
@ -404,7 +404,7 @@ vMBTCPPortBindAddr(const CHAR* pcBindIp)
|
|||||||
}
|
}
|
||||||
// Bind was successful
|
// Bind was successful
|
||||||
pcStr = (pxCurAddr->ai_canonname == NULL) ? (CHAR*)"\0" : pxCurAddr->ai_canonname;
|
pcStr = (pxCurAddr->ai_canonname == NULL) ? (CHAR*)"\0" : pxCurAddr->ai_canonname;
|
||||||
ESP_LOGI(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d), listener %s on port: %d, errno=%d",
|
ESP_LOGI(TAG, "Socket (#%d), listener %s on port: %d, errno=%d",
|
||||||
xListenSockFd, pcStr, xConfig.usPort, errno);
|
xListenSockFd, pcStr, xConfig.usPort, errno);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -475,11 +475,11 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
}
|
}
|
||||||
// error occurred during wait for read
|
// error occurred during wait for read
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() errno = %d.", errno);
|
ESP_LOGE(TAG, "select() errno = %d.", errno);
|
||||||
continue;
|
continue;
|
||||||
} else if (xErr == 0) {
|
} else if (xErr == 0) {
|
||||||
// If timeout happened, something is wrong
|
// If timeout happened, something is wrong
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "select() timeout, errno = %d.", errno);
|
ESP_LOGE(TAG, "select() timeout, errno = %d.", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If something happened on the master socket, then its an incoming connection.
|
// If something happened on the master socket, then its an incoming connection.
|
||||||
@ -495,21 +495,21 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
// if request for new connection but no space left
|
// if request for new connection but no space left
|
||||||
if (pxClientInfo != NULL) {
|
if (pxClientInfo != NULL) {
|
||||||
if (xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] == NULL) {
|
if (xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] == NULL) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to accept connection %d, only %d connections supported.", i + 1, MB_TCP_PORT_MAX_CONN);
|
ESP_LOGE(TAG, "Fail to accept connection %d, only %d connections supported.", i + 1, MB_TCP_PORT_MAX_CONN);
|
||||||
}
|
}
|
||||||
xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] = pxClientInfo; // set last connection info
|
xConfig.pxMbClientInfo[MB_TCP_PORT_MAX_CONN] = pxClientInfo; // set last connection info
|
||||||
} else {
|
} else {
|
||||||
// allocate memory for new client info
|
// allocate memory for new client info
|
||||||
pxClientInfo = calloc(1, sizeof(MbClientInfo_t));
|
pxClientInfo = calloc(1, sizeof(MbClientInfo_t));
|
||||||
if (!pxClientInfo) {
|
if (!pxClientInfo) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client info allocation fail.");
|
ESP_LOGE(TAG, "Client info allocation fail.");
|
||||||
vMBTCPPortFreeClientInfo(pxClientInfo);
|
vMBTCPPortFreeClientInfo(pxClientInfo);
|
||||||
pxClientInfo = NULL;
|
pxClientInfo = NULL;
|
||||||
} else {
|
} else {
|
||||||
// Accept new client connection
|
// Accept new client connection
|
||||||
pxClientInfo->xSockId = xMBTCPPortAcceptConnection(xListenSock, &pcClientIp);
|
pxClientInfo->xSockId = xMBTCPPortAcceptConnection(xListenSock, &pcClientIp);
|
||||||
if (pxClientInfo->xSockId < 0) {
|
if (pxClientInfo->xSockId < 0) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to accept connection for client %d.", (xConfig.usClientCount - 1));
|
ESP_LOGE(TAG, "Fail to accept connection for client %d.", (xConfig.usClientCount - 1));
|
||||||
// Accept connection fail, then free client info and continue polling.
|
// Accept connection fail, then free client info and continue polling.
|
||||||
vMBTCPPortFreeClientInfo(pxClientInfo);
|
vMBTCPPortFreeClientInfo(pxClientInfo);
|
||||||
pxClientInfo = NULL;
|
pxClientInfo = NULL;
|
||||||
@ -517,7 +517,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
}
|
}
|
||||||
pxClientInfo->pucTCPBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
|
pxClientInfo->pucTCPBuf = calloc(MB_TCP_BUF_SIZE, sizeof(UCHAR));
|
||||||
if (!pxClientInfo->pucTCPBuf) {
|
if (!pxClientInfo->pucTCPBuf) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Fail to allocate buffer for client %d.", (xConfig.usClientCount - 1));
|
ESP_LOGE(TAG, "Fail to allocate buffer for client %d.", (xConfig.usClientCount - 1));
|
||||||
vMBTCPPortFreeClientInfo(pxClientInfo);
|
vMBTCPPortFreeClientInfo(pxClientInfo);
|
||||||
pxClientInfo = NULL;
|
pxClientInfo = NULL;
|
||||||
continue;
|
continue;
|
||||||
@ -551,17 +551,17 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
switch(xErr)
|
switch(xErr)
|
||||||
{
|
{
|
||||||
case ERR_TIMEOUT:
|
case ERR_TIMEOUT:
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %d, close active connection.",
|
ESP_LOGE(TAG, "Socket (#%d)(%s), data receive timeout, time[us]: %d, close active connection.",
|
||||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
||||||
(int)(xTimeStamp - pxClientInfo->xRecvTimeStamp));
|
(int)(xTimeStamp - pxClientInfo->xRecvTimeStamp));
|
||||||
break;
|
break;
|
||||||
case ERR_CLSD:
|
case ERR_CLSD:
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), connection closed by peer.",
|
ESP_LOGE(TAG, "Socket (#%d)(%s), connection closed by peer.",
|
||||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
pxClientInfo->xSockId, pxClientInfo->pcIpAddr);
|
||||||
break;
|
break;
|
||||||
case ERR_BUF:
|
case ERR_BUF:
|
||||||
default:
|
default:
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), read data error: %d",
|
ESP_LOGE(TAG, "Socket (#%d)(%s), read data error: %d",
|
||||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr, xErr);
|
pxClientInfo->xSockId, pxClientInfo->pcIpAddr, xErr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -586,26 +586,26 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
// Complete frame received, inform state machine to process frame
|
// Complete frame received, inform state machine to process frame
|
||||||
xMBPortEventPost(EV_FRAME_RECEIVED);
|
xMBPortEventPost(EV_FRAME_RECEIVED);
|
||||||
|
|
||||||
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Socket (#%d)(%s), get packet TID=0x%X, %d bytes.",
|
ESP_LOGD(TAG, "Socket (#%d)(%s), get packet TID=0x%X, %d bytes.",
|
||||||
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
pxClientInfo->xSockId, pxClientInfo->pcIpAddr,
|
||||||
pxClientInfo->usTidCnt, xErr);
|
pxClientInfo->usTidCnt, xErr);
|
||||||
|
|
||||||
// Wait while response is not processed by stack by timeout
|
// Wait while response is not processed by stack by timeout
|
||||||
UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
|
UCHAR* pucSentBuffer = vxMBTCPPortRespQueueRecv(xConfig.xRespQueueHandle);
|
||||||
if (pucSentBuffer == NULL) {
|
if (pucSentBuffer == NULL) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Response time exceeds configured %d [ms], ignore packet.",
|
ESP_LOGE(TAG, "Response time exceeds configured %d [ms], ignore packet.",
|
||||||
MB_TCP_RESP_TIMEOUT_MS);
|
MB_TCP_RESP_TIMEOUT_MS);
|
||||||
} else {
|
} else {
|
||||||
USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID);
|
USHORT usSentTid = MB_TCP_GET_FIELD(pucSentBuffer, MB_TCP_TID);
|
||||||
if (usSentTid != pxClientInfo->usTidCnt) {
|
if (usSentTid != pxClientInfo->usTidCnt) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Sent TID(%x) != Recv TID(%x), ignore packet.",
|
ESP_LOGE(TAG, "Sent TID(%x) != Recv TID(%x), ignore packet.",
|
||||||
usSentTid, pxClientInfo->usTidCnt);
|
usSentTid, pxClientInfo->usTidCnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get time stamp of last data update
|
// Get time stamp of last data update
|
||||||
pxClientInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
pxClientInfo->xSendTimeStamp = xMBTCPGetTimeStamp();
|
||||||
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Client %d, Socket(#%d), processing time = %d (us).",
|
ESP_LOGD(TAG, "Client %d, Socket(#%d), processing time = %d (us).",
|
||||||
pxClientInfo->xIndex, pxClientInfo->xSockId,
|
pxClientInfo->xIndex, pxClientInfo->xSockId,
|
||||||
(int)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp));
|
(int)(pxClientInfo->xSendTimeStamp - pxClientInfo->xRecvTimeStamp));
|
||||||
}
|
}
|
||||||
@ -614,7 +614,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
// client is not ready to be read
|
// client is not ready to be read
|
||||||
int64_t xTime = xMBTCPGetTimeStamp() - pxClientInfo->xRecvTimeStamp;
|
int64_t xTime = xMBTCPGetTimeStamp() - pxClientInfo->xRecvTimeStamp;
|
||||||
if (xTime > MB_TCP_DISCONNECT_TIMEOUT) {
|
if (xTime > MB_TCP_DISCONNECT_TIMEOUT) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client %d, Socket(#%d) do not answer for %d (us). Drop connection...",
|
ESP_LOGE(TAG, "Client %d, Socket(#%d) do not answer for %d (us). Drop connection...",
|
||||||
pxClientInfo->xIndex, pxClientInfo->xSockId, (int)(xTime));
|
pxClientInfo->xIndex, pxClientInfo->xSockId, (int)(xTime));
|
||||||
xMBTCPPortCloseConnection(pxClientInfo);
|
xMBTCPPortCloseConnection(pxClientInfo);
|
||||||
|
|
||||||
@ -623,7 +623,7 @@ static void vMBTCPPortServerTask(void *pvParameters)
|
|||||||
xConfig.pxMbClientInfo[i] = NULL;
|
xConfig.pxMbClientInfo[i] = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Client %d is disconnected.", i);
|
ESP_LOGE(TAG, "Client %d is disconnected.", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // if ((pxClientInfo != NULL)
|
} // if ((pxClientInfo != NULL)
|
||||||
@ -645,7 +645,7 @@ vMBTCPPortClose( )
|
|||||||
vTaskResume(xConfig.xMbTcpTaskHandle);
|
vTaskResume(xConfig.xMbTcpTaskHandle);
|
||||||
if (xShutdownSemaphore == NULL || // if no semaphore (alloc issues) or couldn't acquire it, just delete the task
|
if (xShutdownSemaphore == NULL || // if no semaphore (alloc issues) or couldn't acquire it, just delete the task
|
||||||
xSemaphoreTake(xShutdownSemaphore, 2*pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)) != pdTRUE) {
|
xSemaphoreTake(xShutdownSemaphore, 2*pdMS_TO_TICKS(CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND)) != pdTRUE) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Task couldn't exit gracefully within timeout -> abruptly deleting the task");
|
ESP_LOGE(TAG, "Task couldn't exit gracefully within timeout -> abruptly deleting the task");
|
||||||
vTaskDelete(xConfig.xMbTcpTaskHandle);
|
vTaskDelete(xConfig.xMbTcpTaskHandle);
|
||||||
}
|
}
|
||||||
if (xShutdownSemaphore) {
|
if (xShutdownSemaphore) {
|
||||||
@ -707,7 +707,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
|||||||
// Check if socket writable
|
// Check if socket writable
|
||||||
xErr = select(xConfig.pxCurClientInfo->xSockId + 1, NULL, &xWriteSet, &xErrorSet, &xTimeVal);
|
xErr = select(xConfig.pxCurClientInfo->xSockId + 1, NULL, &xWriteSet, &xErrorSet, &xTimeVal);
|
||||||
if ((xErr == -1) || FD_ISSET(xConfig.pxCurClientInfo->xSockId, &xErrorSet)) {
|
if ((xErr == -1) || FD_ISSET(xConfig.pxCurClientInfo->xSockId, &xErrorSet)) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket(#%d) , send select() error = %d.",
|
ESP_LOGE(TAG, "Socket(#%d) , send select() error = %d.",
|
||||||
xConfig.pxCurClientInfo->xSockId, errno);
|
xConfig.pxCurClientInfo->xSockId, errno);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -719,7 +719,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
|||||||
// Write message into socket and disable Nagle's algorithm
|
// Write message into socket and disable Nagle's algorithm
|
||||||
xErr = send(xConfig.pxCurClientInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
|
xErr = send(xConfig.pxCurClientInfo->xSockId, pucMBTCPFrame, usTCPLength, TCP_NODELAY);
|
||||||
if (xErr < 0) {
|
if (xErr < 0) {
|
||||||
ESP_LOGE(MB_TCP_SLAVE_PORT_TAG, "Socket(#%d), fail to send data, errno = %d",
|
ESP_LOGE(TAG, "Socket(#%d), fail to send data, errno = %d",
|
||||||
xConfig.pxCurClientInfo->xSockId, errno);
|
xConfig.pxCurClientInfo->xSockId, errno);
|
||||||
xConfig.pxCurClientInfo->xError = xErr;
|
xConfig.pxCurClientInfo->xError = xErr;
|
||||||
} else {
|
} else {
|
||||||
@ -727,7 +727,7 @@ xMBTCPPortSendResponse( UCHAR * pucMBTCPFrame, USHORT usTCPLength )
|
|||||||
vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
|
vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(MB_TCP_SLAVE_PORT_TAG, "Port is not active. Release lock.");
|
ESP_LOGD(TAG, "Port is not active. Release lock.");
|
||||||
vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
|
vxMBTCPPortRespQueueSend(xConfig.xRespQueueHandle, (void*)pucMBTCPFrame);
|
||||||
}
|
}
|
||||||
return bFrameSent;
|
return bFrameSent;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -30,14 +30,6 @@
|
|||||||
#define POLL_TIMEOUT_MS (1)
|
#define POLL_TIMEOUT_MS (1)
|
||||||
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
|
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
|
||||||
|
|
||||||
#define MASTER_TAG "MASTER_TEST"
|
|
||||||
|
|
||||||
#define MASTER_CHECK(a, ret_val, str, ...) \
|
|
||||||
if (!(a)) { \
|
|
||||||
ESP_LOGE(MASTER_TAG, "%s(%u): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
|
||||||
return (ret_val); \
|
|
||||||
}
|
|
||||||
|
|
||||||
// The macro to get offset for parameter in the appropriate structure
|
// The macro to get offset for parameter in the appropriate structure
|
||||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
||||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
||||||
@ -49,6 +41,8 @@
|
|||||||
// Options can be used as bit masks or parameter limits
|
// Options can be used as bit masks or parameter limits
|
||||||
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
|
#define OPTS(min_val, max_val, step_val) { .opt1 = min_val, .opt2 = max_val, .opt3 = step_val }
|
||||||
|
|
||||||
|
static const char *TAG = "MASTER_TEST";
|
||||||
|
|
||||||
// Enumeration of modbus device addresses accessed by master device
|
// Enumeration of modbus device addresses accessed by master device
|
||||||
enum {
|
enum {
|
||||||
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
|
MB_DEVICE_ADDR1 = 1 // Only one slave device used for the test (add other slave addresses here)
|
||||||
@ -127,7 +121,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
|
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
|
||||||
assert(instance_ptr != NULL);
|
assert(instance_ptr != NULL);
|
||||||
}
|
}
|
||||||
return instance_ptr;
|
return instance_ptr;
|
||||||
@ -141,7 +135,7 @@ static void master_operation_func(void *arg)
|
|||||||
bool alarm_state = false;
|
bool alarm_state = false;
|
||||||
const mb_parameter_descriptor_t* param_descriptor = NULL;
|
const mb_parameter_descriptor_t* param_descriptor = NULL;
|
||||||
|
|
||||||
ESP_LOGI(MASTER_TAG, "Start modbus test...");
|
ESP_LOGI(TAG, "Start modbus test...");
|
||||||
|
|
||||||
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
||||||
// Read all found characteristics from slave(s)
|
// Read all found characteristics from slave(s)
|
||||||
@ -161,7 +155,7 @@ static void master_operation_func(void *arg)
|
|||||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||||
(uint8_t*)temp_data_ptr, &type);
|
(uint8_t*)temp_data_ptr, &type);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
@ -173,13 +167,13 @@ static void master_operation_func(void *arg)
|
|||||||
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
|
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
|
||||||
(uint8_t*)temp_data_ptr, &type);
|
(uint8_t*)temp_data_ptr, &type);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
*(uint32_t*)temp_data_ptr);
|
*(uint32_t*)temp_data_ptr);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
|
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(int)err,
|
(int)err,
|
||||||
@ -187,7 +181,7 @@ static void master_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(int)err,
|
(int)err,
|
||||||
@ -200,7 +194,7 @@ static void master_operation_func(void *arg)
|
|||||||
*(float*)temp_data_ptr = value;
|
*(float*)temp_data_ptr = value;
|
||||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
@ -214,7 +208,7 @@ static void master_operation_func(void *arg)
|
|||||||
} else {
|
} else {
|
||||||
uint16_t state = *(uint16_t*)temp_data_ptr;
|
uint16_t state = *(uint16_t*)temp_data_ptr;
|
||||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
@ -226,7 +220,7 @@ static void master_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(int)err,
|
(int)err,
|
||||||
@ -240,13 +234,13 @@ static void master_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (alarm_state) {
|
if (alarm_state) {
|
||||||
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
|
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
|
||||||
param_descriptor->cid);
|
param_descriptor->cid);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
|
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
|
||||||
MASTER_MAX_RETRY);
|
MASTER_MAX_RETRY);
|
||||||
}
|
}
|
||||||
ESP_LOGI(MASTER_TAG, "Destroy master...");
|
ESP_LOGI(TAG, "Destroy master...");
|
||||||
ESP_ERROR_CHECK(mbc_master_destroy());
|
ESP_ERROR_CHECK(mbc_master_destroy());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,13 +261,13 @@ static esp_err_t master_init(void)
|
|||||||
void* master_handler = NULL;
|
void* master_handler = NULL;
|
||||||
|
|
||||||
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
|
esp_err_t err = mbc_master_init(MB_PORT_SERIAL_MASTER, &master_handler);
|
||||||
MASTER_CHECK((master_handler != NULL), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb controller initialization fail.");
|
"mb controller initialization fail.");
|
||||||
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb controller initialization fail, returns(0x%x).",
|
"mb controller initialization fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
err = mbc_master_setup((void*)&comm);
|
err = mbc_master_setup((void*)&comm);
|
||||||
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb controller setup fail, returns(0x%x).",
|
"mb controller setup fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
@ -282,23 +276,23 @@ static esp_err_t master_init(void)
|
|||||||
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
|
CONFIG_MB_UART_RTS, UART_PIN_NO_CHANGE);
|
||||||
|
|
||||||
err = mbc_master_start();
|
err = mbc_master_start();
|
||||||
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb controller start fail, returns(0x%x).",
|
"mb controller start fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (uint32_t)err);
|
"mb serial set pin failure, uart_set_pin() returned (0x%x).", (uint32_t)err);
|
||||||
// Set driver mode to Half Duplex
|
// Set driver mode to Half Duplex
|
||||||
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
|
err = uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX);
|
||||||
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err);
|
"mb serial set mode failure, uart_set_mode() returned (0x%x).", (uint32_t)err);
|
||||||
|
|
||||||
vTaskDelay(5);
|
vTaskDelay(5);
|
||||||
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
|
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
|
||||||
MASTER_CHECK((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE, TAG,
|
||||||
"mb controller set descriptor fail, returns(0x%x).",
|
"mb controller set descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
|
ESP_LOGI(TAG, "Modbus master stack initialized...");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -42,7 +42,7 @@
|
|||||||
| MB_EVENT_COILS_WR)
|
| MB_EVENT_COILS_WR)
|
||||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||||
|
|
||||||
static const char *SLAVE_TAG = "SLAVE_TEST";
|
static const char *TAG = "SLAVE_TEST";
|
||||||
|
|
||||||
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ void app_main(void)
|
|||||||
mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
|
mb_register_area_descriptor_t reg_area; // Modbus register area descriptor structure
|
||||||
|
|
||||||
// Set UART log level
|
// Set UART log level
|
||||||
esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
|
esp_log_level_set(TAG, ESP_LOG_INFO);
|
||||||
void* mbc_slave_handler = NULL;
|
void* mbc_slave_handler = NULL;
|
||||||
|
|
||||||
ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller
|
ESP_ERROR_CHECK(mbc_slave_init(MB_PORT_SERIAL_SLAVE, &mbc_slave_handler)); // Initialization of Modbus controller
|
||||||
@ -168,8 +168,8 @@ void app_main(void)
|
|||||||
// Set UART driver mode to Half Duplex
|
// Set UART driver mode to Half Duplex
|
||||||
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
|
ESP_ERROR_CHECK(uart_set_mode(MB_PORT_NUM, UART_MODE_RS485_HALF_DUPLEX));
|
||||||
|
|
||||||
ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
|
ESP_LOGI(TAG, "Modbus slave stack initialized.");
|
||||||
ESP_LOGI(SLAVE_TAG, "Start modbus test...");
|
ESP_LOGI(TAG, "Start modbus test...");
|
||||||
|
|
||||||
// The cycle below will be terminated when parameter holdingRegParams.dataChan0
|
// The cycle below will be terminated when parameter holdingRegParams.dataChan0
|
||||||
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
|
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
|
||||||
@ -182,7 +182,7 @@ void app_main(void)
|
|||||||
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||||
// Get parameter information from parameter queue
|
// Get parameter information from parameter queue
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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,
|
rw_str,
|
||||||
(uint32_t)reg_info.time_stamp,
|
(uint32_t)reg_info.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
@ -200,7 +200,7 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
(uint32_t)reg_info.type,
|
(uint32_t)reg_info.type,
|
||||||
@ -208,7 +208,7 @@ void app_main(void)
|
|||||||
(uint32_t)reg_info.size);
|
(uint32_t)reg_info.size);
|
||||||
} else if (event & MB_EVENT_DISCRETE_RD) {
|
} else if (event & MB_EVENT_DISCRETE_RD) {
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
(uint32_t)reg_info.type,
|
(uint32_t)reg_info.type,
|
||||||
@ -216,7 +216,7 @@ void app_main(void)
|
|||||||
(uint32_t)reg_info.size);
|
(uint32_t)reg_info.size);
|
||||||
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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,
|
rw_str,
|
||||||
(uint32_t)reg_info.time_stamp,
|
(uint32_t)reg_info.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
@ -227,7 +227,7 @@ void app_main(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Destroy of Modbus controller on alarm
|
// Destroy of Modbus controller on alarm
|
||||||
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
|
ESP_LOGI(TAG,"Modbus controller destroyed.");
|
||||||
vTaskDelay(100);
|
vTaskDelay(100);
|
||||||
ESP_ERROR_CHECK(mbc_slave_destroy());
|
ESP_ERROR_CHECK(mbc_slave_destroy());
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
# SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
@ -72,7 +72,7 @@ class DutTestThread(Thread):
|
|||||||
super(DutTestThread, self).__init__()
|
super(DutTestThread, self).__init__()
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
logger.debug('Restart %s.' % self.tname)
|
logger.debug('Restart %s.', self.tname)
|
||||||
# Reset DUT first
|
# Reset DUT first
|
||||||
self.dut.reset()
|
self.dut.reset()
|
||||||
# Capture output from the DUT
|
# Capture output from the DUT
|
||||||
@ -83,7 +83,7 @@ class DutTestThread(Thread):
|
|||||||
""" The exit method of context manager
|
""" The exit method of context manager
|
||||||
"""
|
"""
|
||||||
if exc_type is not None or exc_value is not None:
|
if exc_type is not None or exc_value is not None:
|
||||||
logger.info('Thread %s rised an exception type: %s, value: %s' % (self.tname, str(exc_type), str(exc_value)))
|
logger.info('Thread %s rised an exception type: %s, value: %s', self.tname, str(exc_type), str(exc_value))
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
""" The function implements thread functionality
|
""" The function implements thread functionality
|
||||||
@ -98,7 +98,7 @@ class DutTestThread(Thread):
|
|||||||
# Check DUT exceptions
|
# Check DUT exceptions
|
||||||
dut_exceptions = self.dut.get_exceptions()
|
dut_exceptions = self.dut.get_exceptions()
|
||||||
if 'Guru Meditation Error:' in dut_exceptions:
|
if 'Guru Meditation Error:' in dut_exceptions:
|
||||||
raise Exception('%s generated an exception: %s\n' % (str(self.dut), dut_exceptions))
|
raise RuntimeError('%s generated an exception(s): %s\n' % (str(self.dut), dut_exceptions))
|
||||||
|
|
||||||
# Mark thread has run to completion without any exceptions
|
# Mark thread has run to completion without any exceptions
|
||||||
self.data = self.dut.stop_capture_raw_data(capture_id=self.dut.name)
|
self.data = self.dut.stop_capture_raw_data(capture_id=self.dut.name)
|
||||||
@ -109,15 +109,17 @@ class DutTestThread(Thread):
|
|||||||
message = r'.*Waiting IP([0-9]{1,2}) from stdin.*'
|
message = r'.*Waiting IP([0-9]{1,2}) from stdin.*'
|
||||||
# Read all data from previous restart to get prompt correctly
|
# Read all data from previous restart to get prompt correctly
|
||||||
self.dut.read()
|
self.dut.read()
|
||||||
result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
|
result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
|
||||||
if int(result[0]) != index:
|
if int(result[0]) != index:
|
||||||
raise Exception('Incorrect index of IP=%d for %s\n' % (int(result[0]), str(self.dut)))
|
raise RuntimeError('Incorrect index of IP=%s for %s\n' % (result[0], str(self.dut)))
|
||||||
message = 'IP%s=%s' % (result[0], self.ip_addr)
|
# Use the same slave IP address for all characteristics during the test
|
||||||
self.dut.write(message, '\r\n', False)
|
self.dut.write('IP0=' + self.ip_addr, '\n', False)
|
||||||
logger.debug('Sent message for %s: %s' % (self.tname, message))
|
self.dut.write('IP1=' + self.ip_addr, '\n', False)
|
||||||
|
self.dut.write('IP2=' + self.ip_addr, '\n', False)
|
||||||
|
logger.debug('Set IP address=%s for %s', self.ip_addr, self.tname)
|
||||||
message = r'.*IP\([0-9]+\) = \[([0-9a-zA-Z\.\:]+)\] set from stdin.*'
|
message = r'.*IP\([0-9]+\) = \[([0-9a-zA-Z\.\:]+)\] set from stdin.*'
|
||||||
result = self.dut.expect(re.compile(message), TEST_EXPECT_STR_TIMEOUT)
|
result = self.dut.expect(re.compile(message), timeout=TEST_EXPECT_STR_TIMEOUT)
|
||||||
logger.debug('Thread %s initialized with slave IP (%s).' % (self.tname, result[0]))
|
logger.debug('Thread %s initialized with slave IP=%s.', self.tname, self.ip_addr)
|
||||||
|
|
||||||
def test_start(self, timeout_value):
|
def test_start(self, timeout_value):
|
||||||
""" The method to initialize and handle test stages
|
""" The method to initialize and handle test stages
|
||||||
@ -125,37 +127,37 @@ class DutTestThread(Thread):
|
|||||||
def handle_get_ip4(data):
|
def handle_get_ip4(data):
|
||||||
""" Handle get_ip v4
|
""" Handle get_ip v4
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[STACK_IPV4]: %s' % (self.tname, str(data)))
|
logger.debug('%s[STACK_IPV4]: %s', self.tname, str(data))
|
||||||
self.test_stage = STACK_IPV4
|
self.test_stage = STACK_IPV4
|
||||||
|
|
||||||
def handle_get_ip6(data):
|
def handle_get_ip6(data):
|
||||||
""" Handle get_ip v6
|
""" Handle get_ip v6
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[STACK_IPV6]: %s' % (self.tname, str(data)))
|
logger.debug('%s[STACK_IPV6]: %s', self.tname, str(data))
|
||||||
self.test_stage = STACK_IPV6
|
self.test_stage = STACK_IPV6
|
||||||
|
|
||||||
def handle_init(data):
|
def handle_init(data):
|
||||||
""" Handle init
|
""" Handle init
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[STACK_INIT]: %s' % (self.tname, str(data)))
|
logger.debug('%s[STACK_INIT]: %s', self.tname, str(data))
|
||||||
self.test_stage = STACK_INIT
|
self.test_stage = STACK_INIT
|
||||||
|
|
||||||
def handle_connect(data):
|
def handle_connect(data):
|
||||||
""" Handle connect
|
""" Handle connect
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[STACK_CONNECT]: %s' % (self.tname, str(data)))
|
logger.debug('%s[STACK_CONNECT]: %s', self.tname, str(data))
|
||||||
self.test_stage = STACK_CONNECT
|
self.test_stage = STACK_CONNECT
|
||||||
|
|
||||||
def handle_test_start(data):
|
def handle_test_start(data):
|
||||||
""" Handle connect
|
""" Handle connect
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[STACK_START]: %s' % (self.tname, str(data)))
|
logger.debug('%s[STACK_START]: %s', self.tname, str(data))
|
||||||
self.test_stage = STACK_START
|
self.test_stage = STACK_START
|
||||||
|
|
||||||
def handle_par_ok(data):
|
def handle_par_ok(data):
|
||||||
""" Handle parameter ok
|
""" Handle parameter ok
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[READ_PAR_OK]: %s' % (self.tname, str(data)))
|
logger.debug('%s[READ_PAR_OK]: %s', self.tname, str(data))
|
||||||
if self.test_stage >= STACK_START:
|
if self.test_stage >= STACK_START:
|
||||||
self.param_ok_count += 1
|
self.param_ok_count += 1
|
||||||
self.test_stage = STACK_PAR_OK
|
self.test_stage = STACK_PAR_OK
|
||||||
@ -163,14 +165,14 @@ class DutTestThread(Thread):
|
|||||||
def handle_par_fail(data):
|
def handle_par_fail(data):
|
||||||
""" Handle parameter fail
|
""" Handle parameter fail
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[READ_PAR_FAIL]: %s' % (self.tname, str(data)))
|
logger.debug('%s[READ_PAR_FAIL]: %s', self.tname, str(data))
|
||||||
self.param_fail_count += 1
|
self.param_fail_count += 1
|
||||||
self.test_stage = STACK_PAR_FAIL
|
self.test_stage = STACK_PAR_FAIL
|
||||||
|
|
||||||
def handle_destroy(data):
|
def handle_destroy(data):
|
||||||
""" Handle destroy
|
""" Handle destroy
|
||||||
"""
|
"""
|
||||||
logger.debug('%s[DESTROY]: %s' % (self.tname, str(data)))
|
logger.debug('%s[DESTROY]: %s', self.tname, str(data))
|
||||||
self.test_stage = STACK_DESTROY
|
self.test_stage = STACK_DESTROY
|
||||||
self.test_finish = True
|
self.test_finish = True
|
||||||
|
|
||||||
@ -186,7 +188,7 @@ class DutTestThread(Thread):
|
|||||||
(re.compile(self.expected[STACK_DESTROY]), handle_destroy),
|
(re.compile(self.expected[STACK_DESTROY]), handle_destroy),
|
||||||
timeout=timeout_value)
|
timeout=timeout_value)
|
||||||
except DUT.ExpectTimeout:
|
except DUT.ExpectTimeout:
|
||||||
logger.debug('%s, expect timeout on stage #%d (%s seconds)' % (self.tname, self.test_stage, timeout_value))
|
logger.debug('%s, expect timeout on stage #%d (%s seconds)', self.tname, self.test_stage, timeout_value)
|
||||||
self.test_finish = True
|
self.test_finish = True
|
||||||
|
|
||||||
|
|
||||||
@ -196,10 +198,10 @@ def test_check_mode(dut=None, mode_str=None, value=None):
|
|||||||
global logger
|
global logger
|
||||||
try:
|
try:
|
||||||
opt = dut.app.get_sdkconfig()[mode_str]
|
opt = dut.app.get_sdkconfig()[mode_str]
|
||||||
logger.debug('%s {%s} = %s.\n' % (str(dut), mode_str, opt))
|
logger.debug('%s {%s} = %s.\n', str(dut), mode_str, opt)
|
||||||
return value == opt
|
return value == opt
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.' % (str(dut), mode_str))
|
logger.error('ENV_TEST_FAILURE: %s: Cannot find option %s in sdkconfig.', str(dut), mode_str)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -238,7 +240,7 @@ def test_modbus_communication(env, comm_mode):
|
|||||||
master_name = TEST_MASTER_TCP
|
master_name = TEST_MASTER_TCP
|
||||||
else:
|
else:
|
||||||
logger.error('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
|
logger.error('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
|
||||||
raise Exception('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
|
raise RuntimeError('ENV_TEST_FAILURE: IP resolver mode do not match in the master and slave implementation.\n')
|
||||||
address = None
|
address = None
|
||||||
if test_check_mode(dut_master, 'CONFIG_MB_SLAVE_IP_FROM_STDIN', 'y'):
|
if test_check_mode(dut_master, 'CONFIG_MB_SLAVE_IP_FROM_STDIN', 'y'):
|
||||||
logger.info('ENV_TEST_INFO: Set slave IP address through STDIN.\n')
|
logger.info('ENV_TEST_INFO: Set slave IP address through STDIN.\n')
|
||||||
@ -252,9 +254,9 @@ def test_modbus_communication(env, comm_mode):
|
|||||||
if address is not None:
|
if address is not None:
|
||||||
print('Found IP slave address: %s' % address[0])
|
print('Found IP slave address: %s' % address[0])
|
||||||
else:
|
else:
|
||||||
raise Exception('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
|
raise RuntimeError('ENV_TEST_FAILURE: Slave IP address is not found in the output. Check network settings.\n')
|
||||||
else:
|
else:
|
||||||
raise Exception('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
|
raise RuntimeError('ENV_TEST_FAILURE: Slave IP resolver is not configured correctly.\n')
|
||||||
|
|
||||||
# Create thread for each dut
|
# Create thread for each dut
|
||||||
with DutTestThread(dut=dut_master, name=master_name, ip_addr=address[0], expect=pattern_dict_master) as dut_master_thread:
|
with DutTestThread(dut=dut_master, name=master_name, ip_addr=address[0], expect=pattern_dict_master) as dut_master_thread:
|
||||||
@ -268,30 +270,30 @@ def test_modbus_communication(env, comm_mode):
|
|||||||
dut_slave_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
|
dut_slave_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
|
||||||
dut_master_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
|
dut_master_thread.join(timeout=TEST_THREAD_JOIN_TIMEOUT)
|
||||||
|
|
||||||
if dut_slave_thread.isAlive():
|
if dut_slave_thread.is_alive():
|
||||||
logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
|
logger.error('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
|
||||||
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
|
dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
|
||||||
raise Exception('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
|
raise RuntimeError('ENV_TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
|
||||||
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
|
(dut_slave_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
|
||||||
|
|
||||||
if dut_master_thread.isAlive():
|
if dut_master_thread.is_alive():
|
||||||
logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
|
logger.error('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n',
|
||||||
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
|
dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT)
|
||||||
raise Exception('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
|
raise RuntimeError('TEST_FAILURE: The thread %s is not completed successfully after %d seconds.\n' %
|
||||||
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
|
(dut_master_thread.tname, TEST_THREAD_JOIN_TIMEOUT))
|
||||||
|
|
||||||
logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n' %
|
logger.info('TEST_INFO: %s error count = %d, %s error count = %d.\n',
|
||||||
(dut_master_thread.tname, dut_master_thread.param_fail_count,
|
dut_master_thread.tname, dut_master_thread.param_fail_count,
|
||||||
dut_slave_thread.tname, dut_slave_thread.param_fail_count))
|
dut_slave_thread.tname, dut_slave_thread.param_fail_count)
|
||||||
logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n' %
|
logger.info('TEST_INFO: %s ok count = %d, %s ok count = %d.\n',
|
||||||
(dut_master_thread.tname, dut_master_thread.param_ok_count,
|
dut_master_thread.tname, dut_master_thread.param_ok_count,
|
||||||
dut_slave_thread.tname, dut_slave_thread.param_ok_count))
|
dut_slave_thread.tname, dut_slave_thread.param_ok_count)
|
||||||
|
|
||||||
if ((dut_master_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
|
if ((dut_master_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
|
||||||
(dut_slave_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
|
(dut_slave_thread.param_fail_count > TEST_READ_MAX_ERR_COUNT) or
|
||||||
(dut_slave_thread.param_ok_count == 0) or
|
(dut_slave_thread.param_ok_count == 0) or
|
||||||
(dut_master_thread.param_ok_count == 0)):
|
(dut_master_thread.param_ok_count == 0)):
|
||||||
raise Exception('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
|
raise RuntimeError('TEST_FAILURE: %s parameter read error(ok) count = %d(%d), %s parameter read error(ok) count = %d(%d).\n' %
|
||||||
(dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
|
(dut_master_thread.tname, dut_master_thread.param_fail_count, dut_master_thread.param_ok_count,
|
||||||
dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
|
dut_slave_thread.tname, dut_slave_thread.param_fail_count, dut_slave_thread.param_ok_count))
|
||||||
logger.info('TEST_SUCCESS: The Modbus parameter test is completed successfully.\n')
|
logger.info('TEST_SUCCESS: The Modbus parameter test is completed successfully.\n')
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// FreeModbus Master Example ESP32
|
// FreeModbus Master Example ESP32
|
||||||
|
|
||||||
#include "string.h"
|
#include <string.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_check.h"
|
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
@ -39,8 +39,6 @@
|
|||||||
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
|
#define POLL_TIMEOUT_TICS (POLL_TIMEOUT_MS / portTICK_RATE_MS)
|
||||||
#define MB_MDNS_PORT (502)
|
#define MB_MDNS_PORT (502)
|
||||||
|
|
||||||
#define MASTER_TAG "MASTER_TEST"
|
|
||||||
|
|
||||||
// The macro to get offset for parameter in the appropriate structure
|
// The macro to get offset for parameter in the appropriate structure
|
||||||
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
#define HOLD_OFFSET(field) ((uint16_t)(offsetof(holding_reg_params_t, field) + 1))
|
||||||
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
#define INPUT_OFFSET(field) ((uint16_t)(offsetof(input_reg_params_t, field) + 1))
|
||||||
@ -65,12 +63,14 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp"
|
#define MB_MDNS_INSTANCE(pref) pref"mb_master_tcp"
|
||||||
|
static const char *TAG = "MASTER_TEST";
|
||||||
|
|
||||||
// Enumeration of modbus device addresses accessed by master device
|
// Enumeration of modbus device addresses accessed by master device
|
||||||
// Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
|
// Each address in the table is a index of TCP slave ip address in mb_communication_info_t::tcp_ip_addr table
|
||||||
enum {
|
enum {
|
||||||
MB_DEVICE_ADDR1 = 1, // Slave address 1
|
MB_DEVICE_ADDR1 = 1, // Slave address 1
|
||||||
MB_DEVICE_COUNT
|
MB_DEVICE_ADDR2 = 200,
|
||||||
|
MB_DEVICE_ADDR3 = 35
|
||||||
};
|
};
|
||||||
|
|
||||||
// Enumeration of all supported CIDs for device (used in parameter definition table)
|
// Enumeration of all supported CIDs for device (used in parameter definition table)
|
||||||
@ -104,11 +104,11 @@ const mb_parameter_descriptor_t device_parameters[] = {
|
|||||||
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
HOLD_OFFSET(holding_data0), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||||
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
|
{ CID_INP_DATA_1, STR("Temperature_1"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 2, 2,
|
||||||
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
INPUT_OFFSET(input_data1), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||||
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 2, 2,
|
{ CID_HOLD_DATA_1, STR("Humidity_2"), STR("%rH"), MB_DEVICE_ADDR2, MB_PARAM_HOLDING, 2, 2,
|
||||||
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
HOLD_OFFSET(holding_data1), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||||
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR1, MB_PARAM_INPUT, 4, 2,
|
{ CID_INP_DATA_2, STR("Temperature_2"), STR("C"), MB_DEVICE_ADDR2, MB_PARAM_INPUT, 4, 2,
|
||||||
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
INPUT_OFFSET(input_data2), PARAM_TYPE_FLOAT, 4, OPTS( -40, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||||
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 4, 2,
|
{ CID_HOLD_DATA_2, STR("Humidity_3"), STR("%rH"), MB_DEVICE_ADDR3, MB_PARAM_HOLDING, 4, 2,
|
||||||
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
HOLD_OFFSET(holding_data2), PARAM_TYPE_FLOAT, 4, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||||
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 8, 100,
|
{ CID_HOLD_TEST_REG, STR("Test_regs"), STR("__"), MB_DEVICE_ADDR1, MB_PARAM_HOLDING, 8, 100,
|
||||||
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 200, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
HOLD_OFFSET(test_regs), PARAM_TYPE_ASCII, 200, OPTS( 0, 100, 1 ), PAR_PERMS_READ_WRITE_TRIGGER },
|
||||||
@ -119,20 +119,26 @@ const mb_parameter_descriptor_t device_parameters[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Calculate number of parameters in the table
|
// Calculate number of parameters in the table
|
||||||
const uint16_t num_device_parameters = (sizeof(device_parameters)/sizeof(device_parameters[0]));
|
const uint16_t num_device_parameters = (sizeof(device_parameters) / sizeof(device_parameters[0]));
|
||||||
|
|
||||||
// This table represents slave IP addresses that correspond to the short address field of the slave in device_parameters structure
|
// This table represents slave IP addresses that correspond to the short address field of the slave in device_parameters structure
|
||||||
// Modbus TCP stack shall use these addresses to be able to connect and read parameters from slave
|
// Modbus TCP stack shall use these addresses to be able to connect and read parameters from slave
|
||||||
char* slave_ip_address_table[MB_DEVICE_COUNT] = {
|
char* slave_ip_address_table[] = {
|
||||||
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
|
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
|
||||||
"FROM_STDIN", // Address corresponds to MB_DEVICE_ADDR1 and set to predefined value by user
|
"FROM_STDIN", // Address corresponds to MB_DEVICE_ADDR1 and set to predefined value by user
|
||||||
NULL
|
"FROM_STDIN", // Corresponds to characteristic MB_DEVICE_ADDR2
|
||||||
|
"FROM_STDIN", // Corresponds to characteristic MB_DEVICE_ADDR3
|
||||||
|
NULL // End of table condition (must be included)
|
||||||
#elif CONFIG_MB_MDNS_IP_RESOLVER
|
#elif CONFIG_MB_MDNS_IP_RESOLVER
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const size_t ip_table_sz = (size_t)(sizeof(slave_ip_address_table) / sizeof(slave_ip_address_table[0]));
|
||||||
|
|
||||||
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
|
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
|
||||||
|
|
||||||
// Scan IP address according to IPV settings
|
// Scan IP address according to IPV settings
|
||||||
@ -183,8 +189,8 @@ static int master_get_slave_ip_stdin(char** addr_table)
|
|||||||
fputc('\n', stdout);
|
fputc('\n', stdout);
|
||||||
ip_str = master_scan_addr(&index, buf);
|
ip_str = master_scan_addr(&index, buf);
|
||||||
if (ip_str != NULL) {
|
if (ip_str != NULL) {
|
||||||
ESP_LOGI(MASTER_TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
|
ESP_LOGI(TAG, "IP(%d) = [%s] set from stdin.", ip_cnt, ip_str);
|
||||||
if ((ip_cnt >= MB_DEVICE_COUNT) || (index != ip_cnt)) {
|
if ((ip_cnt >= ip_table_sz) || (index != ip_cnt)) {
|
||||||
addr_table[ip_cnt] = NULL;
|
addr_table[ip_cnt] = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -196,10 +202,10 @@ static int master_get_slave_ip_stdin(char** addr_table)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (addr_table[ip_cnt]) {
|
if (addr_table[ip_cnt]) {
|
||||||
ESP_LOGI(MASTER_TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
|
ESP_LOGI(TAG, "Leave IP(%d) = [%s] set manually.", ip_cnt, addr_table[ip_cnt]);
|
||||||
ip_cnt++;
|
ip_cnt++;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(MASTER_TAG, "IP(%d) is not set in the table.", ip_cnt);
|
ESP_LOGI(TAG, "IP(%d) is not set in the table.", ip_cnt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +215,16 @@ static int master_get_slave_ip_stdin(char** addr_table)
|
|||||||
|
|
||||||
#elif CONFIG_MB_MDNS_IP_RESOLVER
|
#elif CONFIG_MB_MDNS_IP_RESOLVER
|
||||||
|
|
||||||
|
typedef struct slave_addr_entry_s {
|
||||||
|
uint16_t index;
|
||||||
|
char* ip_address;
|
||||||
|
uint8_t slave_addr;
|
||||||
|
void* p_data;
|
||||||
|
LIST_ENTRY(slave_addr_entry_s) entries;
|
||||||
|
} slave_addr_entry_t;
|
||||||
|
|
||||||
|
LIST_HEAD(slave_addr_, slave_addr_entry_s) slave_addr_list = LIST_HEAD_INITIALIZER(slave_addr_list);
|
||||||
|
|
||||||
// convert MAC from binary format to string
|
// convert MAC from binary format to string
|
||||||
static inline char* gen_mac_str(const uint8_t* mac, char* pref, char* mac_str)
|
static inline char* gen_mac_str(const uint8_t* mac, char* pref, char* mac_str)
|
||||||
{
|
{
|
||||||
@ -232,7 +248,7 @@ static void master_start_mdns_service()
|
|||||||
ESP_ERROR_CHECK(mdns_init());
|
ESP_ERROR_CHECK(mdns_init());
|
||||||
// set mDNS hostname (required if you want to advertise services)
|
// set mDNS hostname (required if you want to advertise services)
|
||||||
ESP_ERROR_CHECK(mdns_hostname_set(hostname));
|
ESP_ERROR_CHECK(mdns_hostname_set(hostname));
|
||||||
ESP_LOGI(MASTER_TAG, "mdns hostname set to: [%s]", hostname);
|
ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname);
|
||||||
|
|
||||||
// set default mDNS instance name
|
// set default mDNS instance name
|
||||||
ESP_ERROR_CHECK(mdns_instance_name_set(MB_MDNS_INSTANCE("esp32_")));
|
ESP_ERROR_CHECK(mdns_instance_name_set(MB_MDNS_INSTANCE("esp32_")));
|
||||||
@ -273,15 +289,21 @@ static char* master_get_slave_ip_str(mdns_ip_addr_t* address, mb_tcp_addr_type_t
|
|||||||
return slave_ip_str;
|
return slave_ip_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, char** resolved_ip,
|
static esp_err_t master_resolve_slave(uint8_t short_addr, mdns_result_t* result, char** resolved_ip,
|
||||||
mb_tcp_addr_type_t addr_type)
|
mb_tcp_addr_type_t addr_type)
|
||||||
{
|
{
|
||||||
if (!name || !result) {
|
if (!short_addr || !result || !resolved_ip) {
|
||||||
return ESP_ERR_INVALID_ARG;
|
return ESP_ERR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
mdns_result_t* r = result;
|
mdns_result_t* r = result;
|
||||||
int t;
|
int t;
|
||||||
char* slave_ip = NULL;
|
char* slave_ip = NULL;
|
||||||
|
char slave_name[22] = {0};
|
||||||
|
|
||||||
|
if (sprintf(slave_name, "mb_slave_tcp_%02X", short_addr) < 0) {
|
||||||
|
ESP_LOGE(TAG, "Fail to create instance name for index: %d", short_addr);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
for (; r ; r = r->next) {
|
for (; r ; r = r->next) {
|
||||||
if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
|
if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
|
||||||
continue;
|
continue;
|
||||||
@ -290,7 +312,7 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
|
|||||||
}
|
}
|
||||||
// Check host name for Modbus short address and
|
// Check host name for Modbus short address and
|
||||||
// append it into slave ip address table
|
// append it into slave ip address table
|
||||||
if ((strcmp(r->instance_name, name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
|
if ((strcmp(r->instance_name, slave_name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
|
||||||
printf(" PTR : %s\n", r->instance_name);
|
printf(" PTR : %s\n", r->instance_name);
|
||||||
if (r->txt_count) {
|
if (r->txt_count) {
|
||||||
printf(" TXT : [%u] ", r->txt_count);
|
printf(" TXT : [%u] ", r->txt_count);
|
||||||
@ -301,92 +323,124 @@ static esp_err_t master_resolve_slave(const char* name, mdns_result_t* result, c
|
|||||||
}
|
}
|
||||||
slave_ip = master_get_slave_ip_str(r->addr, addr_type);
|
slave_ip = master_get_slave_ip_str(r->addr, addr_type);
|
||||||
if (slave_ip) {
|
if (slave_ip) {
|
||||||
ESP_LOGI(MASTER_TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
|
ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
|
||||||
*resolved_ip = slave_ip;
|
*resolved_ip = slave_ip;
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*resolved_ip = NULL;
|
*resolved_ip = NULL;
|
||||||
ESP_LOGD(MASTER_TAG, "Fail to resolve slave: %s", name);
|
ESP_LOGD(TAG, "Fail to resolve slave: %s", slave_name);
|
||||||
return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int master_create_slave_list(mdns_result_t* results, char** addr_table,
|
static int master_create_slave_list(mdns_result_t* results, char** addr_table,
|
||||||
mb_tcp_addr_type_t addr_type)
|
int addr_table_size, mb_tcp_addr_type_t addr_type)
|
||||||
{
|
{
|
||||||
if (!results) {
|
if (!results) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int i, addr, resolved = 0;
|
int i, slave_addr, cid_resolve_cnt = 0;
|
||||||
|
int ip_index = 0;
|
||||||
const mb_parameter_descriptor_t* pdescr = &device_parameters[0];
|
const mb_parameter_descriptor_t* pdescr = &device_parameters[0];
|
||||||
char** ip_table = addr_table;
|
char** ip_table = addr_table;
|
||||||
char slave_name[22] = {0};
|
|
||||||
char* slave_ip = NULL;
|
char* slave_ip = NULL;
|
||||||
|
slave_addr_entry_t *it;
|
||||||
|
|
||||||
for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++) {
|
for (i = 0; (i < num_device_parameters && pdescr); i++, pdescr++)
|
||||||
addr = pdescr->mb_slave_addr;
|
{
|
||||||
if (-1 == sprintf(slave_name, "mb_slave_tcp_%02X", addr)) {
|
slave_addr = pdescr->mb_slave_addr;
|
||||||
ESP_LOGI(MASTER_TAG, "Fail to create instance name for index: %d", addr);
|
|
||||||
abort();
|
it = NULL;
|
||||||
|
// Is the slave address already registered?
|
||||||
|
LIST_FOREACH(it, &slave_addr_list, entries) {
|
||||||
|
if (slave_addr == it->slave_addr) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (!ip_table[addr - 1]) {
|
}
|
||||||
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) {
|
if (err != ESP_OK) {
|
||||||
ESP_LOGE(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, failed to resolve!",
|
ESP_LOGE(TAG, "Index: %d, sl_addr: %d, failed to resolve!", i, slave_addr);
|
||||||
i, addr, slave_name);
|
|
||||||
// Set correspond index to NULL indicate host not resolved
|
// Set correspond index to NULL indicate host not resolved
|
||||||
ip_table[addr - 1] = NULL;
|
ip_table[ip_index] = NULL;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ip_table[addr - 1] = slave_ip; //slave_name;
|
// Register new slave address information
|
||||||
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, resolve to IP: [%s]",
|
slave_addr_entry_t* new_slave_entry = (slave_addr_entry_t*) heap_caps_malloc(sizeof(slave_addr_entry_t),
|
||||||
i, addr, slave_name, slave_ip);
|
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
resolved++;
|
MB_RETURN_ON_FALSE((new_slave_entry != NULL), ESP_ERR_NO_MEM,
|
||||||
|
TAG, "Can not allocate memory for slave entry.");
|
||||||
|
new_slave_entry->index = i;
|
||||||
|
new_slave_entry->ip_address = slave_ip;
|
||||||
|
new_slave_entry->slave_addr = slave_addr;
|
||||||
|
new_slave_entry->p_data = NULL;
|
||||||
|
LIST_INSERT_HEAD(&slave_addr_list, new_slave_entry, entries);
|
||||||
|
ip_table[ip_index] = slave_ip;
|
||||||
|
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, resolved to IP: [%s]",
|
||||||
|
i, slave_addr, slave_ip);
|
||||||
|
cid_resolve_cnt++;
|
||||||
|
if (ip_index < addr_table_size) {
|
||||||
|
ip_index++;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGI(MASTER_TAG, "Index: %d, sl_addr: %d, name:%s, set to IP: [%s]",
|
ip_table[ip_index] = it ? it->ip_address : ip_table[ip_index];
|
||||||
i, addr, slave_name, ip_table[addr - 1]);
|
ESP_LOGI(TAG, "Index: %d, sl_addr: %d, set to IP: [%s]",
|
||||||
resolved++;
|
i, slave_addr, ip_table[ip_index]);
|
||||||
}
|
cid_resolve_cnt++;
|
||||||
}
|
|
||||||
return resolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void master_destroy_slave_list(char** table)
|
|
||||||
{
|
|
||||||
for (int i = 0; ((i < MB_DEVICE_COUNT) && table[i] != NULL); i++) {
|
|
||||||
if (table[i]) {
|
|
||||||
free(table[i]);
|
|
||||||
table[i] = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ESP_LOGI(TAG, "Resolved %d cids, with %d IP addresses", cid_resolve_cnt, ip_index);
|
||||||
|
return cid_resolve_cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int master_query_slave_service(const char * service_name, const char * proto,
|
static int master_query_slave_service(const char * service_name, const char * proto,
|
||||||
mb_tcp_addr_type_t addr_type)
|
mb_tcp_addr_type_t addr_type)
|
||||||
{
|
{
|
||||||
ESP_LOGI(MASTER_TAG, "Query PTR: %s.%s.local", service_name, proto);
|
ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);
|
||||||
|
|
||||||
mdns_result_t* results = NULL;
|
mdns_result_t* results = NULL;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
|
esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20, &results);
|
||||||
if(err){
|
if(err){
|
||||||
ESP_LOGE(MASTER_TAG, "Query Failed: %s", esp_err_to_name(err));
|
ESP_LOGE(TAG, "Query Failed: %s", esp_err_to_name(err));
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
if(!results){
|
if(!results){
|
||||||
ESP_LOGW(MASTER_TAG, "No results found!");
|
ESP_LOGW(TAG, "No results found!");
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
count = master_create_slave_list(results, slave_ip_address_table, addr_type);
|
count = master_create_slave_list(results, slave_ip_address_table, ip_table_sz, addr_type);
|
||||||
|
|
||||||
mdns_query_results_free(results);
|
mdns_query_results_free(results);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void master_destroy_slave_list(char** table, size_t ip_table_size)
|
||||||
|
{
|
||||||
|
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||||
|
slave_addr_entry_t *it;
|
||||||
|
LIST_FOREACH(it, &slave_addr_list, entries) {
|
||||||
|
LIST_REMOVE(it, entries);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (int i = 0; ((i < ip_table_size) && table[i] != NULL); i++) {
|
||||||
|
if (table[i]) {
|
||||||
|
#if CONFIG_MB_SLAVE_IP_FROM_STDIN
|
||||||
|
free(table[i]);
|
||||||
|
table[i] = "FROM_STDIN";
|
||||||
|
#elif CONFIG_MB_MDNS_IP_RESOLVER
|
||||||
|
table[i] = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The function to get pointer to parameter storage (instance) according to parameter description table
|
// The function to get pointer to parameter storage (instance) according to parameter description table
|
||||||
static void* master_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
|
static void* master_get_param_data(const mb_parameter_descriptor_t* param_descriptor)
|
||||||
{
|
{
|
||||||
@ -412,7 +466,7 @@ static void* master_get_param_data(const mb_parameter_descriptor_t* param_descri
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
|
ESP_LOGE(TAG, "Wrong parameter offset for CID #%d", param_descriptor->cid);
|
||||||
assert(instance_ptr != NULL);
|
assert(instance_ptr != NULL);
|
||||||
}
|
}
|
||||||
return instance_ptr;
|
return instance_ptr;
|
||||||
@ -426,7 +480,7 @@ static void master_operation_func(void *arg)
|
|||||||
bool alarm_state = false;
|
bool alarm_state = false;
|
||||||
const mb_parameter_descriptor_t* param_descriptor = NULL;
|
const mb_parameter_descriptor_t* param_descriptor = NULL;
|
||||||
|
|
||||||
ESP_LOGI(MASTER_TAG, "Start modbus test...");
|
ESP_LOGI(TAG, "Start modbus test...");
|
||||||
|
|
||||||
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
for(uint16_t retry = 0; retry <= MASTER_MAX_RETRY && (!alarm_state); retry++) {
|
||||||
// Read all found characteristics from slave(s)
|
// Read all found characteristics from slave(s)
|
||||||
@ -446,7 +500,7 @@ static void master_operation_func(void *arg)
|
|||||||
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
err = mbc_master_get_parameter(cid, (char*)param_descriptor->param_key,
|
||||||
(uint8_t*)temp_data_ptr, &type);
|
(uint8_t*)temp_data_ptr, &type);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x) read successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
@ -458,13 +512,13 @@ static void master_operation_func(void *arg)
|
|||||||
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
|
err = mbc_master_set_parameter(cid, (char*)param_descriptor->param_key,
|
||||||
(uint8_t*)temp_data_ptr, &type);
|
(uint8_t*)temp_data_ptr, &type);
|
||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = (0x%08x), write successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
*(uint32_t*)temp_data_ptr);
|
*(uint32_t*)temp_data_ptr);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
|
ESP_LOGE(TAG, "Characteristic #%d (%s) write fail, err = 0x%x (%s).",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(int)err,
|
(int)err,
|
||||||
@ -472,7 +526,7 @@ static void master_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(int)err,
|
(int)err,
|
||||||
@ -485,7 +539,7 @@ static void master_operation_func(void *arg)
|
|||||||
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
if ((param_descriptor->mb_param_type == MB_PARAM_HOLDING) ||
|
||||||
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
(param_descriptor->mb_param_type == MB_PARAM_INPUT)) {
|
||||||
value = *(float*)temp_data_ptr;
|
value = *(float*)temp_data_ptr;
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %f (0x%x) read successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
@ -499,7 +553,7 @@ static void master_operation_func(void *arg)
|
|||||||
} else {
|
} else {
|
||||||
uint8_t state = *(uint8_t*)temp_data_ptr;
|
uint8_t state = *(uint8_t*)temp_data_ptr;
|
||||||
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
const char* rw_str = (state & param_descriptor->param_opts.opt1) ? "ON" : "OFF";
|
||||||
ESP_LOGI(MASTER_TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
|
ESP_LOGI(TAG, "Characteristic #%d %s (%s) value = %s (0x%x) read successful.",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(char*)param_descriptor->param_units,
|
(char*)param_descriptor->param_units,
|
||||||
@ -511,7 +565,7 @@ static void master_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
ESP_LOGE(TAG, "Characteristic #%d (%s) read fail, err = 0x%x (%s).",
|
||||||
param_descriptor->cid,
|
param_descriptor->cid,
|
||||||
(char*)param_descriptor->param_key,
|
(char*)param_descriptor->param_key,
|
||||||
(int)err,
|
(int)err,
|
||||||
@ -525,13 +579,13 @@ static void master_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (alarm_state) {
|
if (alarm_state) {
|
||||||
ESP_LOGI(MASTER_TAG, "Alarm triggered by cid #%d.",
|
ESP_LOGI(TAG, "Alarm triggered by cid #%d.",
|
||||||
param_descriptor->cid);
|
param_descriptor->cid);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Alarm is not triggered after %d retries.",
|
ESP_LOGE(TAG, "Alarm is not triggered after %d retries.",
|
||||||
MASTER_MAX_RETRY);
|
MASTER_MAX_RETRY);
|
||||||
}
|
}
|
||||||
ESP_LOGI(MASTER_TAG, "Destroy master...");
|
ESP_LOGI(TAG, "Destroy master...");
|
||||||
vTaskDelay(100);
|
vTaskDelay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,18 +596,18 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
|||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
result = nvs_flash_init();
|
result = nvs_flash_init();
|
||||||
}
|
}
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"nvs_flash_init fail, returns(0x%x).",
|
"nvs_flash_init fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
result = esp_netif_init();
|
result = esp_netif_init();
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"esp_netif_init fail, returns(0x%x).",
|
"esp_netif_init fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
result = esp_event_loop_create_default();
|
result = esp_event_loop_create_default();
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"esp_event_loop_create_default fail, returns(0x%x).",
|
"esp_event_loop_create_default fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||||
@ -564,14 +618,14 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
|||||||
// Read "Establishing Wi-Fi or Ethernet Connection" section in
|
// Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||||
// examples/protocols/README.md for more information about this function.
|
// examples/protocols/README.md for more information about this function.
|
||||||
result = example_connect();
|
result = example_connect();
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"example_connect fail, returns(0x%x).",
|
"example_connect fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||||
result = esp_wifi_set_ps(WIFI_PS_NONE);
|
result = esp_wifi_set_ps(WIFI_PS_NONE);
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"esp_wifi_set_ps fail, returns(0x%x).",
|
"esp_wifi_set_ps fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
#endif
|
#endif
|
||||||
@ -581,17 +635,17 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
|||||||
res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
|
res = master_query_slave_service("_modbus", "_tcp", ip_addr_type);
|
||||||
}
|
}
|
||||||
if (res < num_device_parameters) {
|
if (res < num_device_parameters) {
|
||||||
ESP_LOGE(MASTER_TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
|
ESP_LOGE(TAG, "Could not resolve one or more slave IP addresses, resolved: %d out of %d.", res, num_device_parameters );
|
||||||
ESP_LOGE(MASTER_TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
|
ESP_LOGE(TAG, "Make sure you configured all slaves according to device parameter table and they alive in the network.");
|
||||||
return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
mdns_free();
|
mdns_free();
|
||||||
#elif CONFIG_MB_SLAVE_IP_FROM_STDIN
|
#elif CONFIG_MB_SLAVE_IP_FROM_STDIN
|
||||||
int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table);
|
int ip_cnt = master_get_slave_ip_stdin(slave_ip_address_table);
|
||||||
if (ip_cnt) {
|
if (ip_cnt) {
|
||||||
ESP_LOGI(MASTER_TAG, "Configured %d IP addresse(s).", ip_cnt);
|
ESP_LOGI(TAG, "Configured %d IP addresse(s).", ip_cnt);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(MASTER_TAG, "Fail to get IP address from stdin. Continue.");
|
ESP_LOGE(TAG, "Fail to get IP address from stdin. Continue.");
|
||||||
return ESP_ERR_NOT_FOUND;
|
return ESP_ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -601,27 +655,26 @@ static esp_err_t init_services(mb_tcp_addr_type_t ip_addr_type)
|
|||||||
static esp_err_t destroy_services(void)
|
static esp_err_t destroy_services(void)
|
||||||
{
|
{
|
||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
master_destroy_slave_list(slave_ip_address_table, ip_table_sz);
|
||||||
master_destroy_slave_list(slave_ip_address_table);
|
|
||||||
#endif
|
|
||||||
err = example_disconnect();
|
err = example_disconnect();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"example_disconnect fail, returns(0x%x).",
|
"example_disconnect fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
err = esp_event_loop_delete_default();
|
err = esp_event_loop_delete_default();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"esp_event_loop_delete_default fail, returns(0x%x).",
|
"esp_event_loop_delete_default fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
err = esp_netif_deinit();
|
err = esp_netif_deinit();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"esp_netif_deinit fail, returns(0x%x).",
|
"esp_netif_deinit fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
err = nvs_flash_deinit();
|
err = nvs_flash_deinit();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"nvs_flash_deinit fail, returns(0x%x).",
|
"nvs_flash_deinit fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
return err;
|
return err;
|
||||||
@ -633,30 +686,30 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
|
|||||||
void* master_handler = NULL;
|
void* master_handler = NULL;
|
||||||
|
|
||||||
esp_err_t err = mbc_master_init_tcp(&master_handler);
|
esp_err_t err = mbc_master_init_tcp(&master_handler);
|
||||||
ESP_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((master_handler != NULL), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"mb controller initialization fail.");
|
"mb controller initialization fail.");
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"mb controller initialization fail, returns(0x%x).",
|
"mb controller initialization fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
err = mbc_master_setup((void*)comm_info);
|
err = mbc_master_setup((void*)comm_info);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"mb controller setup fail, returns(0x%x).",
|
"mb controller setup fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
|
err = mbc_master_set_descriptor(&device_parameters[0], num_device_parameters);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"mb controller set descriptor fail, returns(0x%x).",
|
"mb controller set descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
ESP_LOGI(MASTER_TAG, "Modbus master stack initialized...");
|
ESP_LOGI(TAG, "Modbus master stack initialized...");
|
||||||
|
|
||||||
err = mbc_master_start();
|
err = mbc_master_start();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"mb controller start fail, returns(0x%x).",
|
"mb controller start fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
vTaskDelay(5);
|
vTaskDelay(5);
|
||||||
@ -666,11 +719,11 @@ static esp_err_t master_init(mb_communication_info_t* comm_info)
|
|||||||
static esp_err_t master_destroy(void)
|
static esp_err_t master_destroy(void)
|
||||||
{
|
{
|
||||||
esp_err_t err = mbc_master_destroy();
|
esp_err_t err = mbc_master_destroy();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
MASTER_TAG,
|
TAG,
|
||||||
"mbc_master_destroy fail, returns(0x%x).",
|
"mbc_master_destroy fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
ESP_LOGI(MASTER_TAG, "Modbus master stack destroy...");
|
ESP_LOGI(TAG, "Modbus master stack destroy...");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ menu "Modbus Example Configuration"
|
|||||||
|
|
||||||
config MB_SLAVE_ADDR
|
config MB_SLAVE_ADDR
|
||||||
int "Modbus slave address"
|
int "Modbus slave address"
|
||||||
range 1 127
|
range 1 255
|
||||||
default 1
|
default 1
|
||||||
help
|
help
|
||||||
This is the Modbus slave address in the network.
|
This is the Modbus slave address in the network.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* SPDX-FileCopyrightText: 2016-2021 Espressif Systems (Shanghai) CO LTD
|
* SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -10,7 +10,6 @@
|
|||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_check.h"
|
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "esp_wifi.h"
|
#include "esp_wifi.h"
|
||||||
#include "esp_event.h"
|
#include "esp_event.h"
|
||||||
@ -49,7 +48,7 @@
|
|||||||
| MB_EVENT_COILS_WR)
|
| MB_EVENT_COILS_WR)
|
||||||
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
#define MB_READ_WRITE_MASK (MB_READ_MASK | MB_WRITE_MASK)
|
||||||
|
|
||||||
#define SLAVE_TAG "SLAVE_TEST"
|
static const char *TAG = "SLAVE_TEST";
|
||||||
|
|
||||||
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
|
static portMUX_TYPE param_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||||
|
|
||||||
@ -163,8 +162,8 @@ static void slave_operation_func(void *arg)
|
|||||||
{
|
{
|
||||||
mb_param_info_t reg_info; // keeps the Modbus registers access information
|
mb_param_info_t reg_info; // keeps the Modbus registers access information
|
||||||
|
|
||||||
ESP_LOGI(SLAVE_TAG, "Modbus slave stack initialized.");
|
ESP_LOGI(TAG, "Modbus slave stack initialized.");
|
||||||
ESP_LOGI(SLAVE_TAG, "Start modbus test...");
|
ESP_LOGI(TAG, "Start modbus test...");
|
||||||
// The cycle below will be terminated when parameter holding_data0
|
// The cycle below will be terminated when parameter holding_data0
|
||||||
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
|
// incremented each access cycle reaches the CHAN_DATA_MAX_VAL value.
|
||||||
for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
|
for(;holding_reg_params.holding_data0 < MB_CHAN_DATA_MAX_VAL;) {
|
||||||
@ -175,7 +174,7 @@ static void slave_operation_func(void *arg)
|
|||||||
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
if(event & (MB_EVENT_HOLDING_REG_WR | MB_EVENT_HOLDING_REG_RD)) {
|
||||||
// Get parameter information from parameter queue
|
// Get parameter information from parameter queue
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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,
|
rw_str,
|
||||||
(uint32_t)reg_info.time_stamp,
|
(uint32_t)reg_info.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
@ -193,7 +192,7 @@ static void slave_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
} else if (event & MB_EVENT_INPUT_REG_RD) {
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
(uint32_t)reg_info.type,
|
(uint32_t)reg_info.type,
|
||||||
@ -201,7 +200,7 @@ static void slave_operation_func(void *arg)
|
|||||||
(uint32_t)reg_info.size);
|
(uint32_t)reg_info.size);
|
||||||
} else if (event & MB_EVENT_DISCRETE_RD) {
|
} else if (event & MB_EVENT_DISCRETE_RD) {
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
(uint32_t)reg_info.type,
|
(uint32_t)reg_info.type,
|
||||||
@ -209,7 +208,7 @@ static void slave_operation_func(void *arg)
|
|||||||
(uint32_t)reg_info.size);
|
(uint32_t)reg_info.size);
|
||||||
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
} else if (event & (MB_EVENT_COILS_RD | MB_EVENT_COILS_WR)) {
|
||||||
ESP_ERROR_CHECK(mbc_slave_get_param_info(®_info, MB_PAR_INFO_GET_TOUT));
|
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,
|
rw_str,
|
||||||
(uint32_t)reg_info.time_stamp,
|
(uint32_t)reg_info.time_stamp,
|
||||||
(uint32_t)reg_info.mb_offset,
|
(uint32_t)reg_info.mb_offset,
|
||||||
@ -220,7 +219,7 @@ static void slave_operation_func(void *arg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Destroy of Modbus controller on alarm
|
// Destroy of Modbus controller on alarm
|
||||||
ESP_LOGI(SLAVE_TAG,"Modbus controller destroyed.");
|
ESP_LOGI(TAG,"Modbus controller destroyed.");
|
||||||
vTaskDelay(100);
|
vTaskDelay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,18 +230,18 @@ static esp_err_t init_services(void)
|
|||||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||||
result = nvs_flash_init();
|
result = nvs_flash_init();
|
||||||
}
|
}
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"nvs_flash_init fail, returns(0x%x).",
|
"nvs_flash_init fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
result = esp_netif_init();
|
result = esp_netif_init();
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"esp_netif_init fail, returns(0x%x).",
|
"esp_netif_init fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
result = esp_event_loop_create_default();
|
result = esp_event_loop_create_default();
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"esp_event_loop_create_default fail, returns(0x%x).",
|
"esp_event_loop_create_default fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||||
@ -253,14 +252,14 @@ static esp_err_t init_services(void)
|
|||||||
// Read "Establishing Wi-Fi or Ethernet Connection" section in
|
// Read "Establishing Wi-Fi or Ethernet Connection" section in
|
||||||
// examples/protocols/README.md for more information about this function.
|
// examples/protocols/README.md for more information about this function.
|
||||||
result = example_connect();
|
result = example_connect();
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"example_connect fail, returns(0x%x).",
|
"example_connect fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
#if CONFIG_EXAMPLE_CONNECT_WIFI
|
||||||
result = esp_wifi_set_ps(WIFI_PS_NONE);
|
result = esp_wifi_set_ps(WIFI_PS_NONE);
|
||||||
ESP_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((result == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"esp_wifi_set_ps fail, returns(0x%x).",
|
"esp_wifi_set_ps fail, returns(0x%x).",
|
||||||
(uint32_t)result);
|
(uint32_t)result);
|
||||||
#endif
|
#endif
|
||||||
@ -272,23 +271,23 @@ static esp_err_t destroy_services(void)
|
|||||||
esp_err_t err = ESP_OK;
|
esp_err_t err = ESP_OK;
|
||||||
|
|
||||||
err = example_disconnect();
|
err = example_disconnect();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"example_disconnect fail, returns(0x%x).",
|
"example_disconnect fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
err = esp_event_loop_delete_default();
|
err = esp_event_loop_delete_default();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"esp_event_loop_delete_default fail, returns(0x%x).",
|
"esp_event_loop_delete_default fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
err = esp_netif_deinit();
|
err = esp_netif_deinit();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK || err == ESP_ERR_NOT_SUPPORTED), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"esp_netif_deinit fail, returns(0x%x).",
|
"esp_netif_deinit fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
err = nvs_flash_deinit();
|
err = nvs_flash_deinit();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"nvs_flash_deinit fail, returns(0x%x).",
|
"nvs_flash_deinit fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
#if CONFIG_MB_MDNS_IP_RESOLVER
|
#if CONFIG_MB_MDNS_IP_RESOLVER
|
||||||
@ -306,8 +305,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
|
|
||||||
// Initialization of Modbus controller
|
// Initialization of Modbus controller
|
||||||
esp_err_t err = mbc_slave_init_tcp(&slave_handler);
|
esp_err_t err = mbc_slave_init_tcp(&slave_handler);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK && slave_handler != NULL), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mb controller initialization fail.");
|
"mb controller initialization fail.");
|
||||||
|
|
||||||
comm_info->ip_addr = NULL; // Bind to any address
|
comm_info->ip_addr = NULL; // Bind to any address
|
||||||
@ -315,8 +314,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
|
|
||||||
// Setup communication parameters and start stack
|
// Setup communication parameters and start stack
|
||||||
err = mbc_slave_setup((void*)comm_info);
|
err = mbc_slave_setup((void*)comm_info);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_setup fail, returns(0x%x).",
|
"mbc_slave_setup fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
@ -331,8 +330,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
|
reg_area.address = (void*)&holding_reg_params.holding_data0; // Set pointer to storage instance
|
||||||
reg_area.size = (MB_REG_HOLDING_START_AREA1 - MB_REG_HOLDING_START_AREA0) << 1; // Set the size of register storage instance
|
reg_area.size = (MB_REG_HOLDING_START_AREA1 - MB_REG_HOLDING_START_AREA0) << 1; // Set the size of register storage instance
|
||||||
err = mbc_slave_set_descriptor(reg_area);
|
err = mbc_slave_set_descriptor(reg_area);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
@ -341,8 +340,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
|
reg_area.address = (void*)&holding_reg_params.holding_data4; // Set pointer to storage instance
|
||||||
reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
|
reg_area.size = sizeof(float) << 2; // Set the size of register storage instance
|
||||||
err = mbc_slave_set_descriptor(reg_area);
|
err = mbc_slave_set_descriptor(reg_area);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
@ -352,8 +351,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
reg_area.address = (void*)&input_reg_params.input_data0;
|
reg_area.address = (void*)&input_reg_params.input_data0;
|
||||||
reg_area.size = sizeof(float) << 2;
|
reg_area.size = sizeof(float) << 2;
|
||||||
err = mbc_slave_set_descriptor(reg_area);
|
err = mbc_slave_set_descriptor(reg_area);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
reg_area.type = MB_PARAM_INPUT;
|
reg_area.type = MB_PARAM_INPUT;
|
||||||
@ -361,8 +360,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
reg_area.address = (void*)&input_reg_params.input_data4;
|
reg_area.address = (void*)&input_reg_params.input_data4;
|
||||||
reg_area.size = sizeof(float) << 2;
|
reg_area.size = sizeof(float) << 2;
|
||||||
err = mbc_slave_set_descriptor(reg_area);
|
err = mbc_slave_set_descriptor(reg_area);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
@ -372,8 +371,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
reg_area.address = (void*)&coil_reg_params;
|
reg_area.address = (void*)&coil_reg_params;
|
||||||
reg_area.size = sizeof(coil_reg_params);
|
reg_area.size = sizeof(coil_reg_params);
|
||||||
err = mbc_slave_set_descriptor(reg_area);
|
err = mbc_slave_set_descriptor(reg_area);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
@ -383,8 +382,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
reg_area.address = (void*)&discrete_reg_params;
|
reg_area.address = (void*)&discrete_reg_params;
|
||||||
reg_area.size = sizeof(discrete_reg_params);
|
reg_area.size = sizeof(discrete_reg_params);
|
||||||
err = mbc_slave_set_descriptor(reg_area);
|
err = mbc_slave_set_descriptor(reg_area);
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
"mbc_slave_set_descriptor fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
|
|
||||||
@ -393,8 +392,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
|
|
||||||
// Starts of modbus controller and stack
|
// Starts of modbus controller and stack
|
||||||
err = mbc_slave_start();
|
err = mbc_slave_start();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_start fail, returns(0x%x).",
|
"mbc_slave_start fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
vTaskDelay(5);
|
vTaskDelay(5);
|
||||||
@ -404,8 +403,8 @@ static esp_err_t slave_init(mb_communication_info_t* comm_info)
|
|||||||
static esp_err_t slave_destroy(void)
|
static esp_err_t slave_destroy(void)
|
||||||
{
|
{
|
||||||
esp_err_t err = mbc_slave_destroy();
|
esp_err_t err = mbc_slave_destroy();
|
||||||
ESP_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
MB_RETURN_ON_FALSE((err == ESP_OK), ESP_ERR_INVALID_STATE,
|
||||||
SLAVE_TAG,
|
TAG,
|
||||||
"mbc_slave_destroy fail, returns(0x%x).",
|
"mbc_slave_destroy fail, returns(0x%x).",
|
||||||
(uint32_t)err);
|
(uint32_t)err);
|
||||||
return err;
|
return err;
|
||||||
@ -420,7 +419,7 @@ void app_main(void)
|
|||||||
ESP_ERROR_CHECK(init_services());
|
ESP_ERROR_CHECK(init_services());
|
||||||
|
|
||||||
// Set UART log level
|
// Set UART log level
|
||||||
esp_log_level_set(SLAVE_TAG, ESP_LOG_INFO);
|
esp_log_level_set(TAG, ESP_LOG_INFO);
|
||||||
|
|
||||||
mb_communication_info_t comm_info = { 0 };
|
mb_communication_info_t comm_info = { 0 };
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user