feature modbus tcp master slave v2

This commit is contained in:
Alex Lisitsyn committed 2024-09-02 03:12:36 +08:00
1 parent d4345f8cd7
commit 2e2be467f6
109 files changed
+4454 -2319

No files matched your search

@@ -278,7 +278,7 @@ static esp_err_t mbc_slave_send_param_info(void *ctx, mb_event_group_t par_type,
par_info.mb_offset = mb_offset;
BaseType_t status = xQueueSend(mbs_opts->notification_queue_handle, &par_info, MB_PAR_INFO_TOUT);
if (pdTRUE == status) {
ESP_LOGD(TAG, "Queue send parameter info (type, address, size): %d, 0x%" PRIu32 ", %d",
ESP_LOGD(TAG, "Queue send parameter info (type, address, size): %d, 0x%" PRIx32 ", %d",
(int)par_type, (uint32_t)par_address, (int)par_size);
error = ESP_OK;
} else if (errQUEUE_FULL == status) {
@@ -405,7 +405,7 @@ esp_err_t mbc_master_set_parameter_with(void *ctx, uint16_t cid, uint8_t uid, ui
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_holding_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs, mb_reg_mode_enum_t mode);
mb_err_enum_t mbc_reg_holding_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs, mb_reg_mode_enum_t mode) __attribute__ ((weak));
/**
* @brief Input register read/write callback function
@@ -419,7 +419,7 @@ mb_err_enum_t mbc_reg_holding_master_cb(mb_base_t *inst, uint8_t *reg_buffer, ui
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_input_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs);
mb_err_enum_t mbc_reg_input_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs) __attribute__ ((weak));
/**
* @brief Discrete register read/write callback function
@@ -433,7 +433,7 @@ mb_err_enum_t mbc_reg_input_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_discrete_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_discrete);
mb_err_enum_t mbc_reg_discrete_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_discrete) __attribute__ ((weak));
/**
* @brief Coil register read/write callback function
@@ -448,7 +448,7 @@ mb_err_enum_t mbc_reg_discrete_master_cb(mb_base_t *inst, uint8_t *reg_buffer, u
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_coils_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_coils, mb_reg_mode_enum_t mode);
mb_err_enum_t mbc_reg_coils_master_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_coils, mb_reg_mode_enum_t mode) __attribute__ ((weak));
/**
* @brief The helper function to set data of parameters according to its type
@@ -163,18 +163,6 @@ esp_err_t mbc_slave_start(void *ctx);
*/
esp_err_t mbc_slave_stop(void *ctx);
/**
* @brief Set Modbus communication parameters for the controller
*
* @param[in] ctx context pointer of the initialized modbus interface
* @param comm_info Communication parameters structure.
*
* @return
* - ESP_OK Success
* - ESP_ERR_INVALID_ARG Incorrect parameter data
*/
esp_err_t mbc_slave_setup(void *ctx, void *comm_info);
/**
* @brief Wait for specific event on parameter change.
*
@@ -226,7 +214,7 @@ esp_err_t mbc_slave_set_descriptor(void *ctx, mb_register_area_descriptor_t desc
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_holding_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs, mb_reg_mode_enum_t mode);
mb_err_enum_t mbc_reg_holding_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs, mb_reg_mode_enum_t mode) __attribute__ ((weak));
/**
* @brief Input register read/write callback function
@@ -240,7 +228,7 @@ mb_err_enum_t mbc_reg_holding_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uin
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_input_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs);
mb_err_enum_t mbc_reg_input_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_regs) __attribute__ ((weak));
/**
* @brief Discrete register read/write callback function
@@ -254,7 +242,7 @@ mb_err_enum_t mbc_reg_input_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint1
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_discrete_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_discrete);
mb_err_enum_t mbc_reg_discrete_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_discrete) __attribute__ ((weak));
/**
* @brief Coil register read/write callback function
@@ -269,7 +257,7 @@ mb_err_enum_t mbc_reg_discrete_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, ui
* - MB_ENOERR: Read write is successful
* - MB_ENOREG: The argument is incorrect
*/
mb_err_enum_t mbc_reg_coils_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_coils, mb_reg_mode_enum_t mode);
mb_err_enum_t mbc_reg_coils_slave_cb(mb_base_t *inst, uint8_t *reg_buffer, uint16_t address, uint16_t n_coils, mb_reg_mode_enum_t mode) __attribute__ ((weak));
#ifdef __cplusplus
}
-1
View File
@@ -71,7 +71,6 @@ typedef struct
iface_check_event_fp check_event; /*!< Interface method check_event */
iface_get_param_info_fp get_param_info; /*!< Interface method get_param_info */
iface_mbs_set_descriptor_fp set_descriptor; /*!< Interface method set_descriptor */
} mbs_controller_iface_t;
#ifdef __cplusplus
@@ -114,6 +114,7 @@ static esp_err_t mbc_serial_master_delete(void *ctx)
ESP_ERR_INVALID_STATE, TAG, "mb stack stop failure.");
}
mbm_iface->is_active = false;
vTaskDelete(mbm_opts->task_handle);
mbm_opts->task_handle = NULL;
vEventGroupDelete(mbm_opts->event_group_handle);
@@ -160,9 +161,8 @@ static esp_err_t mbc_serial_master_send_request(void *ctx, mb_param_request_t *r
mb_err_enum_t mb_error = MB_EBUSY;
esp_err_t error = ESP_FAIL;
if (mb_port_evt_res_take(mbm_controller_iface->mb_base->port_obj, pdMS_TO_TICKS(MB_MAX_RESP_DELAY_MS)))
if (mb_port_event_res_take(mbm_controller_iface->mb_base->port_obj, pdMS_TO_TICKS(MB_MAX_RESP_DELAY_MS)))
{
uint8_t mb_slave_addr = request->slave_addr;
uint8_t mb_command = request->command;
uint16_t mb_offset = request->reg_start;
@@ -172,7 +172,7 @@ static esp_err_t mbc_serial_master_send_request(void *ctx, mb_param_request_t *r
mbm_opts->reg_buffer_ptr = (uint8_t *)data_ptr;
mbm_opts->reg_buffer_size = mb_size;
mb_port_evt_res_release(mbm_controller_iface->mb_base->port_obj);
mb_port_event_res_release(mbm_controller_iface->mb_base->port_obj);
// Calls appropriate request function to send request and waits response
switch (mb_command)
@@ -133,6 +133,7 @@ static esp_err_t mbc_serial_slave_delete(void *ctx)
}
}
mbs_iface->is_active = false;
vTaskDelete(mbs_opts->task_handle);
vEventGroupDelete(mbs_opts->event_group_handle);
vQueueDelete(mbs_opts->notification_queue_handle);
+9 -8
View File
@@ -24,7 +24,7 @@
#include "port_tcp_common.h"
#include "port_tcp_master.h"
#include "mb_common.h" // for mb types definition
#include "mb_common.h" // for mb types definition
#include "mb_config.h"
#include "mb_proto.h"
#include "mb_port_types.h"
@@ -63,8 +63,7 @@ static void mbc_tcp_master_conn_done_cb(void *ctx)
{
mb_master_options_t *mbm_opts = MB_MASTER_GET_OPTS(ctx);
ESP_LOGI(TAG, "Modbus controller interface callback.");
ESP_LOGI(TAG, "mb controller connection done.");
EventBits_t flag = xEventGroupSetBits(mbm_opts->event_group_handle,
(EventBits_t)MB_EVENT_STACK_CONNECTED);
MB_RETURN_ON_FALSE((flag & MB_EVENT_STACK_CONNECTED),
@@ -171,7 +170,7 @@ static esp_err_t mbc_tcp_master_send_request(void *ctx, mb_param_request_t *requ
mb_err_enum_t mb_error = MB_EBUSY;
esp_err_t error = ESP_FAIL;
if (mb_port_evt_res_take(mbm_controller_iface->mb_base->port_obj, pdMS_TO_TICKS(MB_MAX_RESP_DELAY_MS))) {
if (mb_port_event_res_take(mbm_controller_iface->mb_base->port_obj, pdMS_TO_TICKS(MB_MAX_RESP_DELAY_MS))) {
uint8_t mb_slave_addr = request->slave_addr;
uint8_t mb_command = request->command;
uint16_t mb_offset = request->reg_start;
@@ -181,7 +180,7 @@ static esp_err_t mbc_tcp_master_send_request(void *ctx, mb_param_request_t *requ
mbm_opts->reg_buffer_ptr = (uint8_t *)data_ptr;
mbm_opts->reg_buffer_size = mb_size;
mb_port_evt_res_release(mbm_controller_iface->mb_base->port_obj);
mb_port_event_res_release(mbm_controller_iface->mb_base->port_obj);
// Calls appropriate request function to send request and waits response
switch(mb_command) {
@@ -561,7 +560,7 @@ static esp_err_t mbc_tcp_master_set_parameter_with(void *ctx, uint16_t cid, uint
"mb can not send request for cid #%d with uid=%d.",
(unsigned)reg_info.cid, (int)uid);
if (request.slave_addr != MB_SLAVE_ADDR_PLACEHOLDER) {
ESP_LOGW(TAG, "%s: override uid %d = %d for cid(%u)",
ESP_LOGD(TAG, "%s: override uid %d = %d for cid(%u)",
__FUNCTION__, (int)request.slave_addr, (int)uid, (unsigned)reg_info.cid);
}
request.slave_addr = uid; // override the UID
@@ -613,10 +612,12 @@ static esp_err_t mbc_tcp_master_delete(void *ctx)
pdFALSE,
pdMS_TO_TICKS(mbm_opts->comm_opts.tcp_opts.response_tout_ms));
if (mbm_iface->is_active || (status & MB_EVENT_STACK_STARTED)) {
ESP_LOGW(TAG, "mb stack is active, try to disable.");
ESP_LOGD(TAG, "mb stack is active, try to disable.");
MB_RETURN_ON_FALSE((mbc_tcp_master_stop(ctx) == ESP_OK),
ESP_ERR_INVALID_STATE, TAG, "mb stack stop failure.");
}
mbm_iface->is_active = false;
vTaskDelete(mbm_opts->task_handle);
mbm_opts->task_handle = NULL;
vEventGroupDelete(mbm_opts->event_group_handle);
@@ -704,7 +705,7 @@ esp_err_t mbc_tcp_master_create(mb_communication_info_t *config, void **ctx)
// Check communication options
mb_tcp_opts_t tcp_opts = (mb_tcp_opts_t)config->tcp_opts;
MB_RETURN_ON_FALSE((tcp_opts.ip_addr_table), ESP_ERR_INVALID_ARG, TAG, "mb ip table address is incorrect.");
MB_RETURN_ON_FALSE(((tcp_opts.mode == MB_TCP) || (tcp_opts.mode == MB_UDP)),
MB_RETURN_ON_FALSE((tcp_opts.mode == MB_TCP),
ESP_ERR_INVALID_ARG, TAG, "mb transport protocol is incorrect.");
MB_RETURN_ON_FALSE(((tcp_opts.addr_type == MB_IPV6) || (tcp_opts.addr_type == MB_IPV4)),
ESP_ERR_INVALID_ARG, TAG, "mb ip address type is incorrect.");
+1
View File
@@ -127,6 +127,7 @@ static esp_err_t mbc_tcp_slave_delete(void *ctx)
ESP_ERR_INVALID_STATE, TAG, "mb stack stop failure.");
}
mbs_iface->is_active = false;
vTaskDelete(mbs_opts->task_handle);
vEventGroupDelete(mbs_opts->event_group_handle);
vQueueDelete(mbs_opts->notification_queue_handle);
@@ -82,7 +82,7 @@ mb_err_enum_t mbm_rq_read_coils(mb_base_t *inst, uint8_t snd_addr, uint16_t coil
if (snd_addr > MB_ADDRESS_MAX) {
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout)) {
if (!mb_port_event_res_take(inst->port_obj, tout)) {
return MB_EBUSY;
}
inst->get_send_buf(inst, &mb_frame_ptr);
@@ -98,8 +98,8 @@ mb_err_enum_t mbm_rq_read_coils(mb_base_t *inst, uint8_t snd_addr, uint16_t coil
inst->set_send_len(inst, MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_read_coils(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -182,7 +182,7 @@ mb_err_enum_t mbm_rq_write_coil(mb_base_t *inst, uint8_t snd_addr, uint16_t coil
if ((coil_data != 0xFF00) && (coil_data != 0x0000)) {
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout)) {
if (!mb_port_event_res_take(inst->port_obj, tout)) {
return MB_EBUSY;
}
inst->get_send_buf(inst, &mb_frame_ptr);
@@ -199,8 +199,8 @@ mb_err_enum_t mbm_rq_write_coil(mb_base_t *inst, uint8_t snd_addr, uint16_t coil
inst->set_send_len(inst, (MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_SIZE));
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_write_coil(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -249,7 +249,7 @@ mb_err_enum_t mbm_rq_write_multi_coils(mb_base_t *inst, uint8_t snd_addr, uint16
if (coil_num > MB_PDU_REQ_WRITE_MUL_COILCNT_MAX) {
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout)) {
if (!mb_port_event_res_take(inst->port_obj, tout)) {
return MB_EBUSY;
}
inst->get_send_buf(inst, &mb_frame_ptr);
@@ -278,8 +278,8 @@ mb_err_enum_t mbm_rq_write_multi_coils(mb_base_t *inst, uint8_t snd_addr, uint16
inst->set_send_len(inst, (MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + byte_cnt));
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_write_multi_coils(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -332,4 +332,4 @@ mb_exception_t mbm_fn_write_multi_coils(mb_base_t *inst, uint8_t *frame_ptr, uin
}
#endif // #if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
#endif // #if MB_MASTER_RTU_ENABLED > 0 || MB_MASTER_ASCII_ENABLED > 0
#endif // #if MB_MASTER_RTU_ENABLED || MB_MASTER_ASCII_ENABLED || MB_MASTER_TCP_ENABLED
@@ -64,7 +64,7 @@ mb_err_enum_t mbm_rq_read_discrete_inputs(mb_base_t *inst, uint8_t snd_addr, uin
if (!inst || (snd_addr > MB_ADDRESS_MAX)) {
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout)) {
if (!mb_port_event_res_take(inst->port_obj, tout)) {
return MB_EBUSY;
}
inst->get_send_buf(inst, &mb_frame_ptr);
@@ -80,8 +80,8 @@ mb_err_enum_t mbm_rq_read_discrete_inputs(mb_base_t *inst, uint8_t snd_addr, uin
inst->set_send_len(inst, MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_read_discrete_inputs(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -94,7 +94,7 @@ mb_err_enum_t mbm_rq_write_holding_reg(mb_base_t *inst, uint8_t snd_addr, uint16
{
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout))
if (!mb_port_event_res_take(inst->port_obj, tout))
{
return MB_EBUSY;
}
@@ -111,8 +111,8 @@ mb_err_enum_t mbm_rq_write_holding_reg(mb_base_t *inst, uint8_t snd_addr, uint16
inst->set_send_len(inst, MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_write_holding_reg(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -170,7 +170,7 @@ mb_err_enum_t mbm_rq_write_multi_holding_reg(mb_base_t *inst, uint8_t snd_addr,
{
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout))
if (!mb_port_event_res_take(inst->port_obj, tout))
{
return MB_EBUSY;
}
@@ -198,8 +198,8 @@ mb_err_enum_t mbm_rq_write_multi_holding_reg(mb_base_t *inst, uint8_t snd_addr,
inst->set_send_len(inst, (MB_PDU_SIZE_MIN + MB_PDU_REQ_WRITE_MUL_SIZE_MIN + 2 * reg_num));
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_write_multi_holding_reg(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -272,7 +272,7 @@ mb_err_enum_t mbm_rq_read_holding_reg(mb_base_t *inst, uint8_t snd_addr, uint16_
{
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout))
if (!mb_port_event_res_take(inst->port_obj, tout))
{
return MB_EBUSY;
}
@@ -289,8 +289,8 @@ mb_err_enum_t mbm_rq_read_holding_reg(mb_base_t *inst, uint8_t snd_addr, uint16_
inst->set_send_len(inst, (MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE));
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_read_holding_reg(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -376,7 +376,7 @@ mb_err_enum_t mbm_rq_rw_multi_holding_reg(mb_base_t *inst, uint8_t snd_addr, uin
{
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout))
if (!mb_port_event_res_take(inst->port_obj, tout))
{
return MB_EBUSY;
}
@@ -408,8 +408,8 @@ mb_err_enum_t mbm_rq_rw_multi_holding_reg(mb_base_t *inst, uint8_t snd_addr, uin
inst->set_send_len(inst, (MB_PDU_SIZE_MIN + MB_PDU_REQ_READWRITE_SIZE_MIN + 2 * wr_reg_num));
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START));
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_rw_multi_holding_regs(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
@@ -67,7 +67,7 @@ mb_err_enum_t mbm_rq_read_inp_reg(mb_base_t *inst, uint8_t snd_addr, uint16_t re
if (!inst || (snd_addr > MB_ADDRESS_MAX)) {
return MB_EINVAL;
}
if (!mb_port_evt_res_take(inst->port_obj, tout)) {
if (!mb_port_event_res_take(inst->port_obj, tout)) {
return MB_EBUSY;
}
inst->get_send_buf(inst, &mb_frame_ptr);
@@ -83,8 +83,8 @@ mb_err_enum_t mbm_rq_read_inp_reg(mb_base_t *inst, uint8_t snd_addr, uint16_t re
inst->set_send_len(inst, MB_PDU_SIZE_MIN + MB_PDU_REQ_READ_SIZE);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_evt_wait_req_finish(inst->port_obj);
(void)mb_port_event_post(inst->port_obj, EVENT(EV_FRAME_TRANSMIT | EV_TRANS_START) );
return mb_port_event_wait_req_finish(inst->port_obj);
}
mb_exception_t mbm_fn_read_inp_reg(mb_base_t *inst, uint8_t *frame_ptr, uint16_t *len_buf)
+35 -18
View File
@@ -55,36 +55,53 @@ extern "C" {
(void)log_tag; \
if (!(a)) { \
ESP_LOGE(log_tag, "%s(%d): " format, __FUNCTION__, __LINE__ __VA_OPT__(,) __VA_ARGS__); \
ret = (err_code); \
ret = (err_code); \
goto goto_tag; \
} \
} while (0)
#endif
#define MB_CAT_BUF_SIZE (100)
#define MB_STR_CAT(pref, message) (__extension__( \
{ \
char buf##__FUNCTION__##__LINE__[MB_CAT_BUF_SIZE]; \
strncpy(&(buf##__FUNCTION__##__LINE__)[0], pref, (MB_CAT_BUF_SIZE - 1)); \
strncat((buf##__FUNCTION__##__LINE__), message, (MB_CAT_BUF_SIZE - 1)); \
(&((buf##__FUNCTION__##__LINE__)[0])); \
} \
))
#define MB_OBJ_FMT "%p"
#define MB_OBJ_PTR(inst) (__extension__( \
{ \
assert(inst); \
(((obj_descr_t*)(inst))->parent); \
} \
#define MB_GET_OBJ_CTX(pinst, type, base) (__extension__( \
{ \
assert(pinst); \
((type *)__containerof(pinst, type, base)); \
} \
))
#define MB_BASE2PORT(inst) (__extension__( \
{ \
assert(inst); \
(((mb_base_t *)inst)->port_obj); \
} \
#define MB_OBJ(pinst) (__extension__( \
{ \
assert(pinst); \
((typeof(pinst))(pinst)); \
} \
))
#define CAT_BUF_SIZE (100)
#define MB_STR_CAT(pref, message) (__extension__( \
{ \
static char string_buf[CAT_BUF_SIZE]; \
strncpy(string_buf, pref, (CAT_BUF_SIZE - 1)); \
strncat(string_buf, message, (CAT_BUF_SIZE - 1)); \
} \
#define MB_OBJ_PARENT(pinst) (__extension__( \
{ \
assert(pinst); \
(((obj_descr_t*)(pinst))->parent); \
} \
))
#define MB_BASE2PORT(pinst) (__extension__( \
{ \
assert(pinst); \
assert(((mb_base_t *)pinst)->port_obj); \
(((mb_base_t *)pinst)->port_obj); \
} \
))
typedef struct mb_base_t mb_base_t;
+24 -19
View File
@@ -5,6 +5,7 @@
*/
#pragma once
#include "stdatomic.h"
#include "mb_config.h"
#include "mb_types.h"
@@ -12,6 +13,8 @@
extern "C" {
#endif
#define MB_ATTR_WEAK __attribute__ ((weak))
typedef enum _mb_comm_mode mb_mode_type_t;
#if (CONFIG_FMB_COMM_MODE_ASCII_EN || CONFIG_FMB_COMM_MODE_RTU_EN)
@@ -60,42 +63,44 @@ struct _port_tcp_opts {
mb_addr_type_t addr_type; /*!< Modbus address type */
void *ip_addr_table; /*!< Modbus address or table for connection */
void *ip_netif_ptr; /*!< Modbus network interface */
bool start_disconnected; /*!< do not wait connection to all nodes before polling */
char *dns_name; /*!< Modbus node DNS name */
bool start_disconnected; /*!< (Master only option) do not wait for connection to all nodes before polling */
};
typedef struct _port_tcp_opts mb_tcp_opts_t;
// The common object descriptor struture (common for mb, transport, port objects)
struct _obj_descr {
char *parent_name;
char *obj_name;
void *parent;
uint32_t inst_index;
bool is_master;
char *parent_name; /*!< Name of the parent (base) object */
char *obj_name; /*!< Name of the object */
void *parent; /*!< Pointer to the parent (base) object */
uint32_t inst_index; /*!< The consicutive index of the object instance */
bool is_master; /*!< The current object is master or slave (false) */
};
typedef struct _obj_descr obj_descr_t;
typedef enum _mb_sock_state {
MB_SOCK_STATE_UNDEF = 0x0000,
MB_SOCK_STATE_CLOSED,
MB_SOCK_STATE_READY,
MB_SOCK_STATE_OPENED,
MB_SOCK_STATE_RESOLVED,
MB_SOCK_STATE_CONNECTING,
MB_SOCK_STATE_CONNECTED
MB_SOCK_STATE_UNDEF = 0x0000, /*!< Default init state */
MB_SOCK_STATE_CLOSED, /*!< Node is closed */
MB_SOCK_STATE_READY, /*!< Node is ready for communication */
MB_SOCK_STATE_OPENED, /*!< Node is opened */
MB_SOCK_STATE_RESOLVED, /*!< Node address is resolved */
MB_SOCK_STATE_CONNECTING, /*!< Node connection is in progress */
MB_SOCK_STATE_CONNECTED, /*!< Node is connected */
MB_SOCK_STATE_ACCEPTED /*!< Slave node accepted the connection */
} mb_sock_state_t;
typedef struct _uid_info {
uint16_t index; /*!< index of the address info */
int fd; /*!< slave global FD for VFS (reserved) */
char *node_name_str; /*!< node name string (host name of slave to resolve) */
char *ip_addr_str; /*!< represents the IP address of the slave */
int fd; /*!< node global FD for VFS (reserved) */
char *node_name_str; /*!< node name string (host name of node to resolve) */
char *ip_addr_str; /*!< represents the IP address of the node */
mb_addr_type_t addr_type; /*!< type of IP address */
uint16_t uid; /*!< slave unit ID (UID) field for MBAP frame */
uint16_t port; /*!< slave port number */
uint16_t uid; /*!< node unit ID (UID) field for MBAP frame */
uint16_t port; /*!< node port number */
mb_comm_mode_t proto; /*!< protocol type */
mb_sock_state_t state; /*!< slave state */
_Atomic mb_sock_state_t state; /*!< node state */
void *inst; /*!< pointer to linked instance */
} mb_uid_info_t;
+1 -1
View File
@@ -33,7 +33,7 @@ typedef enum _mb_commands_enum
MB_FUNC_DIAG_GET_COM_EVENT_CNT = ( 11 ),
MB_FUNC_DIAG_GET_COM_EVENT_LOG = ( 12 ),
MB_FUNC_OTHER_REPORT_SLAVEID = ( 17 ),
MB_FUNC_ERROR = ( 128u ),
MB_FUNC_ERROR = ( 128U ),
} mb_commands_t;
/* ----------------------- Type definitions ---------------------------------*/
+1 -1
View File
@@ -133,7 +133,7 @@ typedef enum
MB_TMODE_T35, /*!< Master receive frame T3.5 timeout. */
MB_TMODE_RESPOND_TIMEOUT, /*!< Master wait respond for slave. */
MB_TMODE_CONVERT_DELAY /*!< Master sent broadcast , then delay sometime.*/
} mb_tmr_mode_enum_t;
} mb_timer_mode_enum_t;
#ifdef __cplusplus
}
+74 -65
View File
@@ -175,7 +175,7 @@ mb_err_enum_t mbm_ascii_create(mb_serial_opts_t *ser_opts, void **in_out_obj)
mbm_obj->cur_state = STATE_DISABLED;
transp_obj->get_tx_frm(transp_obj, (uint8_t **)&mbm_obj->snd_frame);
transp_obj->get_rx_frm(transp_obj, (uint8_t **)&mbm_obj->rcv_frame);
mbm_obj->base.port_obj = transp_obj->port_obj; // binding of the modbus object with port objet
mbm_obj->base.port_obj = transp_obj->port_obj; // binding of the modbus object with port object
mbm_obj->base.transp_obj = transp_obj;
*in_out_obj = (void *)&(mbm_obj->base);
ESP_LOGD(TAG, "created object %s", mbm_obj->base.descr.parent_name);
@@ -253,10 +253,10 @@ error:
mb_err_enum_t mbm_delete(mb_base_t *inst)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
mb_err_enum_t status = MB_ENOERR;
if (mbm_obj->cur_state == STATE_DISABLED) {
if (mbm_obj->base.transp_obj->frm_delete) {
if (MB_OBJ(mbm_obj->base.transp_obj)->frm_delete) {
// call destructor of the transport object
mbm_obj->base.transp_obj->frm_delete(inst->transp_obj);
}
@@ -275,13 +275,13 @@ mb_err_enum_t mbm_delete(mb_base_t *inst)
mb_err_enum_t mbm_enable(mb_base_t *inst)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
mb_err_enum_t status = MB_ENOERR;
CRITICAL_SECTION(inst->lock)
{
if (mbm_obj->cur_state == STATE_DISABLED) {
/* Activate the protocol stack. */
mbm_obj->base.transp_obj->frm_start(mbm_obj->base.transp_obj);
MB_OBJ(mbm_obj->base.transp_obj)->frm_start(mbm_obj->base.transp_obj);
mbm_obj->cur_state = STATE_ENABLED;
status = MB_ENOERR;
} else {
@@ -294,11 +294,11 @@ mb_err_enum_t mbm_enable(mb_base_t *inst)
mb_err_enum_t mbm_disable(mb_base_t *inst)
{
mb_err_enum_t status = MB_ENOERR;
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
CRITICAL_SECTION(inst->lock)
{
if (mbm_obj->cur_state == STATE_ENABLED) {
mbm_obj->base.transp_obj->frm_stop(mbm_obj->base.transp_obj);
MB_OBJ(mbm_obj->base.transp_obj)->frm_stop(mbm_obj->base.transp_obj);
mbm_obj->cur_state = STATE_DISABLED;
status = MB_ENOERR;
} else if (mbm_obj->cur_state == STATE_DISABLED) {
@@ -312,20 +312,20 @@ mb_err_enum_t mbm_disable(mb_base_t *inst)
static void mbm_get_pdu_send_buf(mb_base_t *inst, uint8_t **pbuf)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_obj->base.transp_obj->get_tx_frm(mbm_obj->base.transp_obj, pbuf);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
MB_OBJ(mbm_obj->base.transp_obj)->get_tx_frm(mbm_obj->base.transp_obj, pbuf);
}
__attribute__((unused))
static void mbm_get_pdu_recv_buf(mb_base_t *inst, uint8_t **pbuf)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_obj->base.transp_obj->get_rx_frm(mbm_obj->base.transp_obj, pbuf);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
MB_OBJ(mbm_obj->base.transp_obj)->get_rx_frm(mbm_obj->base.transp_obj, pbuf);
}
static void mbm_set_pdu_send_length(mb_base_t *inst, uint16_t length)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
CRITICAL_SECTION(inst->lock)
{
mbm_obj->pdu_snd_len = length;
@@ -334,13 +334,13 @@ static void mbm_set_pdu_send_length(mb_base_t *inst, uint16_t length)
static uint16_t mbm_get_pdu_send_length(mb_base_t *inst)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
return mbm_obj->pdu_snd_len;
}
static void mbm_set_dest_addr(mb_base_t *inst, uint8_t dest_addr)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
CRITICAL_SECTION(inst->lock)
{
mbm_obj->master_dst_addr = dest_addr;
@@ -349,37 +349,37 @@ static void mbm_set_dest_addr(mb_base_t *inst, uint8_t dest_addr)
static uint8_t mbm_get_dest_addr(mb_base_t *inst)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
return mbm_obj->master_dst_addr;
}
void mbm_error_cb_respond_timeout(mb_base_t *inst, uint8_t dest_addr, const uint8_t *pdu_data, uint16_t pdu_length)
{
mb_port_evt_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_ERROR_RESPOND_TIMEOUT);
ESP_LOG_BUFFER_HEX_LEVEL(__func__, (void *)pdu_data, pdu_length, ESP_LOG_WARN);
mb_port_event_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_ERROR_RESPOND_TIMEOUT);
ESP_LOG_BUFFER_HEX_LEVEL(__func__, (void *)pdu_data, pdu_length, ESP_LOG_DEBUG);
}
void mbm_error_cb_receive_data(mb_base_t *inst, uint8_t dest_addr, const uint8_t *pdu_data, uint16_t pdu_length)
{
mb_port_evt_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_ERROR_RECEIVE_DATA);
mb_port_event_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_ERROR_RECEIVE_DATA);
ESP_LOG_BUFFER_HEX_LEVEL(__func__, (void *)pdu_data, pdu_length, ESP_LOG_DEBUG);
}
void mbm_error_cb_execute_function(mb_base_t *inst, uint8_t dest_address, const uint8_t *pdu_data, uint16_t pdu_length)
{
mb_port_evt_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_ERROR_EXECUTE_FUNCTION);
mb_port_event_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_ERROR_EXECUTE_FUNCTION);
ESP_LOG_BUFFER_HEX_LEVEL(__func__, (void *)pdu_data, pdu_length, ESP_LOG_DEBUG);
}
void mbm_error_cb_request_success(mb_base_t *inst, uint8_t dest_address, const uint8_t *pdu_data, uint16_t pdu_length)
{
mb_port_evt_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_PROCESS_SUCCESS);
mb_port_event_set_resp_flag(MB_BASE2PORT(inst), EV_MASTER_PROCESS_SUCCESS);
ESP_LOG_BUFFER_HEX_LEVEL(__func__, (void *)pdu_data, pdu_length, ESP_LOG_DEBUG);
}
mb_err_enum_t mbm_poll(mb_base_t *inst)
{
mbm_object_t *mbm_obj = __containerof(inst, mbm_object_t, base);
mbm_object_t *mbm_obj = MB_GET_OBJ_CTX(inst, mbm_object_t, base);;
uint16_t length;
mb_exception_t exception;
@@ -394,69 +394,78 @@ mb_err_enum_t mbm_poll(mb_base_t *inst)
/* Check if there is a event available. If not return control to caller.
* Otherwise we will handle the event. */
if (mb_port_evt_get(mbm_obj->base.port_obj, &event)) {
if (mb_port_event_get(MB_OBJ(mbm_obj->base.port_obj), &event)) {
switch (event.event) {
case EV_READY:
ESP_LOGW(TAG, MB_OBJ_FMT":EV_READY", MB_OBJ_PTR(inst));
mb_port_evt_res_release(inst->port_obj);
ESP_LOGD(TAG, MB_OBJ_FMT":EV_READY", MB_OBJ_PARENT(inst));
mb_port_event_res_release(MB_OBJ(inst->port_obj));
break;
case EV_FRAME_TRANSMIT:
mbm_get_pdu_send_buf(inst, &mbm_obj->snd_frame);
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":MB_TRANSMIT"), (void *)mbm_obj->snd_frame, mbm_obj->pdu_snd_len, ESP_LOG_WARN);
status = inst->transp_obj->frm_send(inst->transp_obj, mbm_obj->master_dst_addr, mbm_obj->snd_frame, mbm_obj->pdu_snd_len);
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":MB_TRANSMIT"),
(void *)mbm_obj->snd_frame, mbm_obj->pdu_snd_len, ESP_LOG_DEBUG);
status = MB_OBJ(inst->transp_obj)->frm_send(inst->transp_obj, mbm_obj->master_dst_addr,
mbm_obj->snd_frame, mbm_obj->pdu_snd_len);
if (status != MB_ENOERR) {
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_RECEIVE_DATA);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_ERROR_PROCESS));
ESP_LOGE(TAG, MB_OBJ_FMT", frame send error. %d", MB_OBJ_PTR(inst), (int)status);
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_RECEIVE_DATA);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_ERROR_PROCESS));
ESP_LOGE(TAG, MB_OBJ_FMT", frame send error. %d", MB_OBJ_PARENT(inst), (int)status);
}
// Initialize modbus transaction
mbm_obj->curr_trans_id = event.trans_id;
break;
case EV_FRAME_SENT:
ESP_LOGD(TAG, MB_OBJ_FMT":EV_MASTER_FRAME_SENT", MB_OBJ_PTR(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_FRAME_SENT", MB_OBJ_PARENT(inst));
break;
case EV_FRAME_RECEIVED:
ESP_LOGD(TAG, MB_OBJ_FMT":EV_FRAME_RECEIVED", MB_OBJ_PARENT(inst));
mbm_obj->pdu_rcv_len = event.length;
status = inst->transp_obj->frm_rcv(inst->transp_obj, &mbm_obj->rcv_addr, &mbm_obj->rcv_frame, &mbm_obj->pdu_rcv_len);
status = MB_OBJ(inst->transp_obj)->frm_rcv(inst->transp_obj, &mbm_obj->rcv_addr,
&mbm_obj->rcv_frame, &mbm_obj->pdu_rcv_len);
MB_RETURN_ON_FALSE(mbm_obj->snd_frame, MB_EILLSTATE, TAG, "Send buffer initialization fail.");
if (event.trans_id == mbm_obj->curr_trans_id) {
// Check if the frame is for us. If not ,send an error process event.
if ((status == MB_ENOERR) && ((mbm_obj->rcv_addr == mbm_obj->master_dst_addr)
if ((status == MB_ENOERR) && ((mbm_obj->rcv_addr == mbm_obj->master_dst_addr)
|| (mbm_obj->rcv_addr == MB_TCP_PSEUDO_ADDRESS))) {
if ((mbm_obj->rcv_frame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR) == (mbm_obj->snd_frame[MB_PDU_FUNC_OFF])) {
ESP_LOGD(TAG, MB_OBJ_FMT", frame data received successfully, (%d).", MB_OBJ_PTR(inst), (int)status);
ESP_LOGD(TAG, MB_OBJ_FMT", frame data received successfully, (%d).", MB_OBJ_PARENT(inst), (int)status);
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":MB_RECV"), (void *)mbm_obj->rcv_frame,
(uint16_t)mbm_obj->pdu_rcv_len, ESP_LOG_WARN);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_EXECUTE));
(uint16_t)mbm_obj->pdu_rcv_len, ESP_LOG_DEBUG);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_EXECUTE));
} else {
ESP_LOGE(TAG, MB_OBJ_FMT", drop incorrect frame, receive_func(%u) != send_func(%u)",
MB_OBJ_PTR(inst), (mbm_obj->rcv_frame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR),
MB_OBJ_PARENT(inst), (mbm_obj->rcv_frame[MB_PDU_FUNC_OFF] & ~MB_FUNC_ERROR),
mbm_obj->snd_frame[MB_PDU_FUNC_OFF]);
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_RECEIVE_DATA);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_ERROR_PROCESS));
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_RECEIVE_DATA);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_ERROR_PROCESS));
}
} else {
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_RECEIVE_DATA);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_ERROR_PROCESS));
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_RECEIVE_DATA);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_ERROR_PROCESS));
ESP_LOGD(TAG, MB_OBJ_FMT", packet data receive failed (addr=%u)(%u).",
MB_OBJ_PTR(inst), (unsigned)mbm_obj->rcv_addr, (unsigned)status);
MB_OBJ_PARENT(inst), (unsigned)mbm_obj->rcv_addr, (unsigned)status);
}
} else {
// Ignore the `EV_FRAME_RECEIVED` event because the respond timeout occurred
// and this is likely respond to previous transaction
ESP_LOGE(TAG, MB_OBJ_FMT", drop data received outside of transaction.", MB_OBJ_PTR(inst));
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_RESPOND_TIMEOUT);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_ERROR_PROCESS));
ESP_LOGE(TAG, MB_OBJ_FMT", drop data received outside of transaction.", MB_OBJ_PARENT(inst));
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_RESPOND_TIMEOUT);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_ERROR_PROCESS));
}
break;
case EV_EXECUTE:
if (event.trans_id == mbm_obj->curr_trans_id) {
MB_RETURN_ON_FALSE(mbm_obj->rcv_frame, MB_EILLSTATE, TAG, MB_OBJ_FMT", receive buffer initialization fail.", MB_OBJ_PTR(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_EXECUTE", MB_OBJ_PTR(inst));
if (MB_OBJ(inst->transp_obj)->frm_is_bcast(inst->transp_obj)
&& ((mbm_obj->cur_mode == MB_RTU) || (mbm_obj->cur_mode == MB_ASCII))) {
mbm_obj->rcv_frame = mbm_obj->snd_frame;
}
MB_RETURN_ON_FALSE(mbm_obj->rcv_frame, MB_EILLSTATE, TAG,
MB_OBJ_FMT", receive buffer initialization fail.", MB_OBJ_PARENT(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_EXECUTE", MB_OBJ_PARENT(inst));
mbm_obj->func_code = mbm_obj->rcv_frame[MB_PDU_FUNC_OFF];
exception = MB_EX_ILLEGAL_FUNCTION;
/* If receive frame has exception. The receive function code highest bit is 1.*/
@@ -472,7 +481,7 @@ mb_err_enum_t mbm_poll(mb_base_t *inst)
/* If master request is broadcast,
* the master need execute function for all slave.
*/
if (inst->transp_obj->frm_is_bcast(inst->transp_obj)) {
if (MB_OBJ(inst->transp_obj)->frm_is_bcast(inst->transp_obj)) {
length = mbm_obj->pdu_snd_len;
for (int j = 1; j <= MB_MASTER_TOTAL_SLAVE_NUM; j++) {
mbm_set_dest_addr(inst, j);
@@ -487,28 +496,28 @@ mb_err_enum_t mbm_poll(mb_base_t *inst)
}
/* If master has exception, will send error process event. Otherwise the master is idle.*/
if (exception != MB_EX_NONE) {
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_EXECUTE_FUNCTION);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_ERROR_PROCESS));
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_EXECUTE_FUNCTION);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_ERROR_PROCESS));
} else {
error_type = mb_port_evt_get_err_type(inst->port_obj);
error_type = mb_port_event_get_err_type(MB_OBJ(inst->port_obj));
if (error_type == EV_ERROR_INIT) {
ESP_LOGD(TAG, MB_OBJ_FMT", set event EV_ERROR_OK", MB_OBJ_PTR(inst));
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_OK);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_ERROR_PROCESS));
ESP_LOGD(TAG, MB_OBJ_FMT", set event EV_ERROR_OK", MB_OBJ_PARENT(inst));
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_OK);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_ERROR_PROCESS));
}
}
} else {
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_EXECUTE_FUNCTION);
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_ERROR_PROCESS));
ESP_LOGE(TAG, MB_OBJ_FMT", execution is expired.", MB_OBJ_PTR(inst));
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_EXECUTE_FUNCTION);
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_ERROR_PROCESS));
ESP_LOGE(TAG, MB_OBJ_FMT", execution is expired.", MB_OBJ_PARENT(inst));
}
break;
case EV_ERROR_PROCESS:
ESP_LOGW(TAG, MB_OBJ_FMT":EV_ERROR_PROCESS", MB_OBJ_PTR(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_ERROR_PROCESS", MB_OBJ_PARENT(inst));
// stop timer and execute specified error process callback function.
mb_port_tmr_disable(inst->port_obj);
error_type = mb_port_evt_get_err_type(inst->port_obj);
mb_port_timer_disable(MB_OBJ(inst->port_obj));
error_type = mb_port_event_get_err_type(MB_OBJ(inst->port_obj));
mbm_get_pdu_send_buf(inst, &mbm_obj->snd_frame);
switch (error_type)
{
@@ -529,23 +538,23 @@ mb_err_enum_t mbm_poll(mb_base_t *inst)
mbm_obj->snd_frame, mbm_obj->pdu_snd_len);
break;
default:
ESP_LOGE(TAG, MB_OBJ_FMT", incorrect error type = %d.", MB_OBJ_PTR(inst), (int)error_type);
ESP_LOGE(TAG, MB_OBJ_FMT", incorrect error type = %d.", MB_OBJ_PARENT(inst), (int)error_type);
break;
}
mb_port_evt_set_err_type(inst->port_obj, EV_ERROR_INIT);
mb_port_event_set_err_type(MB_OBJ(inst->port_obj), EV_ERROR_INIT);
uint64_t time_div_us = mbm_obj->curr_trans_id ? (event.get_ts - mbm_obj->curr_trans_id) : 0;
mbm_obj->curr_trans_id = 0;
ESP_LOGW(TAG, MB_OBJ_FMT", transaction processing time(us) = %" PRId64, MB_OBJ_PTR(inst), time_div_us);
mb_port_evt_res_release(inst->port_obj);
ESP_LOGD(TAG, MB_OBJ_FMT", transaction processing time(us) = %" PRId64, MB_OBJ_PARENT(inst), time_div_us);
mb_port_event_res_release(MB_OBJ(inst->port_obj));
break;
default:
ESP_LOGE(TAG, MB_OBJ_FMT", unexpected event triggered 0x%02x.", MB_OBJ_PTR(inst), (int)event.event);
ESP_LOGE(TAG, MB_OBJ_FMT", unexpected event triggered 0x%02x.", MB_OBJ_PARENT(inst), (int)event.event);
break;
}
} else {
// Something went wrong and task unblocked but there are no any correct events set
ESP_LOGE(TAG, MB_OBJ_FMT", unexpected event triggered 0x%02x.", MB_OBJ_PTR(inst), (int)event.event);
ESP_LOGE(TAG, MB_OBJ_FMT", unexpected event triggered 0x%02x.", MB_OBJ_PARENT(inst), (int)event.event);
status = MB_EILLSTATE;
}
return status;
+27 -28
View File
@@ -225,12 +225,12 @@ error:
mb_err_enum_t mbs_delete(mb_base_t *inst)
{
mbs_object_t *mbs_obj = __containerof(inst, mbs_object_t, base);
mbs_object_t *mbs_obj = MB_GET_OBJ_CTX(inst, mbs_object_t, base);
mb_err_enum_t status = MB_ENOERR;
if (mbs_obj->cur_state == STATE_DISABLED) {
if (mbs_obj->base.transp_obj->frm_delete) {
if (MB_OBJ(mbs_obj->base.transp_obj)->frm_delete) {
// call destructor of the transport object
mbs_obj->base.transp_obj->frm_delete(inst->transp_obj);
MB_OBJ(mbs_obj->base.transp_obj)->frm_delete(inst->transp_obj);
}
// delete the modbus instance
free(mbs_obj->base.descr.parent_name);
@@ -247,12 +247,12 @@ mb_err_enum_t mbs_delete(mb_base_t *inst)
mb_err_enum_t mbs_enable(mb_base_t *inst)
{
mbs_object_t *mbs_obj = __containerof(inst, mbs_object_t, base);
mbs_object_t *mbs_obj = MB_GET_OBJ_CTX(inst, mbs_object_t, base);
mb_err_enum_t status = MB_ENOERR;
CRITICAL_SECTION(inst->lock) {
if (mbs_obj->cur_state == STATE_DISABLED) {
/* Activate the protocol stack. */
mbs_obj->base.transp_obj->frm_start(mbs_obj->base.transp_obj);
MB_OBJ(mbs_obj->base.transp_obj)->frm_start(mbs_obj->base.transp_obj);
mbs_obj->cur_state = STATE_ENABLED;
status = MB_ENOERR;
} else {
@@ -269,10 +269,10 @@ mb_err_enum_t mbs_enable(mb_base_t *inst)
mb_err_enum_t mbs_disable(mb_base_t *inst)
{
mb_err_enum_t status = MB_ENOERR;
mbs_object_t *mbs_obj = __containerof(inst, mbs_object_t, base);
mbs_object_t *mbs_obj = MB_GET_OBJ_CTX(inst, mbs_object_t, base);;
CRITICAL_SECTION(inst->lock) {
if (mbs_obj->cur_state == STATE_ENABLED) {
mbs_obj->base.transp_obj->frm_stop(mbs_obj->base.transp_obj);
MB_OBJ(mbs_obj->base.transp_obj)->frm_stop(mbs_obj->base.transp_obj);
mbs_obj->cur_state = STATE_DISABLED;
status = MB_ENOERR;
} else if (mbs_obj->cur_state == STATE_DISABLED) {
@@ -286,7 +286,7 @@ mb_err_enum_t mbs_disable(mb_base_t *inst)
mb_err_enum_t mbs_poll(mb_base_t *inst)
{
mbs_object_t *mbs_obj = __containerof(inst, mbs_object_t, base);
mbs_object_t *mbs_obj = MB_GET_OBJ_CTX(inst, mbs_object_t, base);;
mb_exception_t exception;
mb_err_enum_t status = MB_ENOERR;
@@ -298,45 +298,44 @@ mb_err_enum_t mbs_poll(mb_base_t *inst)
}
/* Check if there is a event available. If not, return control to caller. Otherwise we will handle the event. */
if (mb_port_evt_get(mbs_obj->base.port_obj, &event)) {
if (mb_port_event_get(MB_OBJ(mbs_obj->base.port_obj), &event)) {
switch(event.event) {
case EV_READY:
ESP_LOGW(TAG, MB_OBJ_FMT":EV_READY", MB_OBJ_PTR(inst));
mb_port_evt_res_release(inst->port_obj);
ESP_LOGD(TAG, MB_OBJ_FMT":EV_READY", MB_OBJ_PARENT(inst));
mb_port_event_res_release(MB_OBJ(inst->port_obj));
break;
case EV_FRAME_RECEIVED:
ESP_LOGD(TAG, MB_OBJ_FMT":EV_FRAME_RECEIVED", MB_OBJ_PTR(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_FRAME_RECEIVED", MB_OBJ_PARENT(inst));
mbs_obj->length = event.length;
status = inst->transp_obj->frm_rcv(inst->transp_obj, &mbs_obj->rcv_addr, &mbs_obj->frame, &mbs_obj->length);
status = MB_OBJ(inst->transp_obj)->frm_rcv(inst->transp_obj, &mbs_obj->rcv_addr, &mbs_obj->frame, &mbs_obj->length);
// Check if the frame is for us. If not ,send an error process event.
if (status == MB_ENOERR) {
// Check if the frame is for us. If not ignore the frame.
if((mbs_obj->rcv_addr == mbs_obj->mb_address) || (mbs_obj->rcv_addr == MB_ADDRESS_BROADCAST)
|| (mbs_obj->rcv_addr == MB_TCP_PSEUDO_ADDRESS)) {
mbs_obj->curr_trans_id = event.get_ts;
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_EXECUTE | EV_TRANS_START));
(void)mb_port_event_post(MB_OBJ(inst->port_obj), EVENT(EV_EXECUTE | EV_TRANS_START));
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":MB_RECV"), &mbs_obj->frame[MB_PDU_FUNC_OFF],
(uint16_t)mbs_obj->length, ESP_LOG_WARN);
(uint16_t)mbs_obj->length, ESP_LOG_DEBUG);
}
}
break;
case EV_EXECUTE:
MB_RETURN_ON_FALSE(mbs_obj->frame, MB_EILLSTATE, TAG, "receive buffer fail.");
ESP_LOGD(TAG, MB_OBJ_FMT":EV_EXECUTE", MB_OBJ_PTR(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_EXECUTE", MB_OBJ_PARENT(inst));
mbs_obj->func_code = mbs_obj->frame[MB_PDU_FUNC_OFF];
exception = MB_EX_ILLEGAL_FUNCTION;
// If receive frame has exception. The receive function code highest bit is 1.
for (int i = 0; (i < MB_FUNC_HANDLERS_MAX); i++) {
// No more function handlers registered. Abort.
if (mbs_obj->func_handlers[i].func_code == 0) {
ESP_LOGD(TAG, MB_OBJ_FMT": function (0x%x), handler is not found.", MB_OBJ_PARENT(inst), (int)mbs_obj->func_code);
break;
}
if ((mbs_obj->func_handlers[i].func_code) == mbs_obj->func_code) {
if (mbs_obj->func_code == 0x04) {
ESP_LOGW(TAG, "Read input registers");
}
ESP_LOGD(TAG, MB_OBJ_FMT": function (0x%x), start handler.", MB_OBJ_PARENT(inst), (int)mbs_obj->func_code);
exception = mbs_obj->func_handlers[i].handler(inst, mbs_obj->frame, &mbs_obj->length);
break;
}
@@ -350,34 +349,34 @@ mb_err_enum_t mbs_poll(mb_base_t *inst)
mbs_obj->frame[mbs_obj->length++] = exception;
}
if ((mbs_obj->cur_mode == MB_ASCII) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS) {
mb_port_tmr_delay(inst->port_obj, MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS);
mb_port_timer_delay(MB_OBJ(inst->port_obj), MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS);
}
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":MB_SEND"), (void *)mbs_obj->frame, mbs_obj->length, ESP_LOG_WARN);
status = inst->transp_obj->frm_send(inst->transp_obj, mbs_obj->rcv_addr, mbs_obj->frame, mbs_obj->length);
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":MB_SEND"), (void *)mbs_obj->frame, mbs_obj->length, ESP_LOG_DEBUG);
status = MB_OBJ(inst->transp_obj)->frm_send(inst->transp_obj, mbs_obj->rcv_addr, mbs_obj->frame, mbs_obj->length);
if (status != MB_ENOERR) {
ESP_LOGE(TAG, MB_OBJ_FMT":frame send error. %d", MB_OBJ_PTR(inst), (int)status);
ESP_LOGE(TAG, MB_OBJ_FMT":frame send error. %d", MB_OBJ_PARENT(inst), (int)status);
}
}
break;
case EV_FRAME_TRANSMIT:
ESP_LOGD(TAG, MB_OBJ_FMT":EV_FRAME_TRANSMIT", MB_OBJ_PTR(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_FRAME_TRANSMIT", MB_OBJ_PARENT(inst));
break;
case EV_FRAME_SENT:
ESP_LOGD(TAG, MB_OBJ_FMT":EV_MASTER_FRAME_SENT", MB_OBJ_PTR(inst));
ESP_LOGD(TAG, MB_OBJ_FMT":EV_MASTER_FRAME_SENT", MB_OBJ_PARENT(inst));
uint64_t time_div_us = mbs_obj->curr_trans_id ? (event.get_ts - mbs_obj->curr_trans_id) : 0;
mbs_obj->curr_trans_id = 0;
ESP_LOGW(TAG, MB_OBJ_FMT", transaction processing time(us) = %" PRId64, MB_OBJ_PTR(inst), time_div_us);
ESP_LOGD(TAG, MB_OBJ_FMT", transaction processing time(us) = %" PRId64, MB_OBJ_PARENT(inst), time_div_us);
break;
default:
ESP_LOGD(TAG, MB_OBJ_FMT": Unexpected event triggered 0x%02x.", MB_OBJ_PTR(inst), (int)event.event);
ESP_LOGD(TAG, MB_OBJ_FMT": Unexpected event triggered 0x%02x.", MB_OBJ_PARENT(inst), (int)event.event);
break;
}
} else {
// Something went wrong and task unblocked but there are no any correct events set
ESP_LOGD(TAG, MB_OBJ_FMT": Unexpected event triggered 0x%02x, timeout?", MB_OBJ_PTR(inst), (int)event.event);
ESP_LOGD(TAG, MB_OBJ_FMT": Unexpected event triggered 0x%02x, timeout?", MB_OBJ_PARENT(inst), (int)event.event);
status = MB_EILLSTATE;
}
return status;
+278
View File
@@ -0,0 +1,278 @@
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdatomic.h>
#include "sys/queue.h"
#include "esp_heap_caps.h"
#include "esp_log.h"
#include "mb_transaction.h"
static const char *TAG = "mb_transaction";
/**
* @brief transaction list item
*/
typedef struct transaction_item {
uint8_t *buffer;
uint16_t len;
int node_id;
int msg_id;
void *pnode;
transaction_tick_t tick;
_Atomic pending_state_t state;
STAILQ_ENTRY(transaction_item) next;
} transaction_item_t;
STAILQ_HEAD(transaction_list_t, transaction_item);
struct transaction_t {
_lock_t lock;
uint64_t size;
struct transaction_list_t *list;
};
transaction_handle_t transaction_init(void)
{
transaction_handle_t transaction = calloc(1, sizeof(struct transaction_t));
ESP_MEM_CHECK(TAG, transaction, return NULL);
transaction->list = calloc(1, sizeof(struct transaction_list_t));
ESP_MEM_CHECK(TAG, transaction->list, {free(transaction); return NULL;});
transaction->size = 0;
CRITICAL_SECTION_INIT(transaction->lock);
STAILQ_INIT(transaction->list);
return transaction;
}
transaction_item_handle_t transaction_enqueue(transaction_handle_t transaction, transaction_message_handle_t message, transaction_tick_t tick)
{
transaction_item_handle_t item = calloc(1, sizeof(transaction_item_t));
ESP_MEM_CHECK(TAG, item, {
return NULL;
});
CRITICAL_SECTION_LOCK(transaction->lock);
item->tick = tick;
item->node_id = message->node_id;
item->pnode = message->pnode;
item->msg_id = message->msg_id;
item->len = message->len;
item->state = QUEUED;
if (!message->buffer) {
item->buffer = heap_caps_malloc(message->len, TRANSACTION_MEMORY);
memcpy(item->buffer, message->buffer, message->len);
} else {
item->buffer = message->buffer;
}
ESP_MEM_CHECK(TAG, item->buffer, {
free(item);
CRITICAL_SECTION_UNLOCK(transaction->lock);
return NULL;
});
STAILQ_INSERT_TAIL(transaction->list, item, next);
transaction->size += item->len;
CRITICAL_SECTION_UNLOCK(transaction->lock);
ESP_LOGD(TAG, "ENQUEUE msgid=%x, len=%d, size=%"PRIu64, message->msg_id, message->len, transaction_get_size(transaction));
return item;
}
transaction_item_handle_t transaction_get(transaction_handle_t transaction, int msg_id)
{
transaction_item_handle_t item;
CRITICAL_SECTION_LOCK(transaction->lock);
STAILQ_FOREACH(item, transaction->list, next) {
if (item->msg_id == msg_id) {
CRITICAL_SECTION_UNLOCK(transaction->lock);
return item;
}
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
return NULL;
}
transaction_item_handle_t transaction_get_first(transaction_handle_t transaction)
{
transaction_item_handle_t item;
if (STAILQ_EMPTY(transaction->list)) {
return NULL;
}
item = STAILQ_FIRST(transaction->list);
if (item)
{
return item;
}
return NULL;
}
transaction_item_handle_t transaction_dequeue(transaction_handle_t transaction, pending_state_t state, transaction_tick_t *tick)
{
transaction_item_handle_t item;
CRITICAL_SECTION_LOCK(transaction->lock);
STAILQ_FOREACH(item, transaction->list, next) {
if (atomic_load(&(item->state)) == state) {
if (tick) {
*tick = item->tick;
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
return item;
}
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
return NULL;
}
esp_err_t transaction_delete_item(transaction_handle_t transaction, transaction_item_handle_t item_to_delete)
{
transaction_item_handle_t item;
CRITICAL_SECTION_LOCK(transaction->lock);
STAILQ_FOREACH(item, transaction->list, next) {
if (item == item_to_delete) {
STAILQ_REMOVE(transaction->list, item, transaction_item, next);
transaction->size -= item->len;
free(item->buffer);
free(item);
CRITICAL_SECTION_UNLOCK(transaction->lock);
return ESP_OK;
}
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
return ESP_FAIL;
}
uint8_t *transaction_item_get_data(transaction_item_handle_t item, size_t *len, uint16_t *msg_id, int *node_id)
{
if (item) {
if (len) {
*len = item->len;
}
if (msg_id) {
*msg_id = item->msg_id;
}
if (node_id) {
*node_id = item->node_id;
}
return (uint8_t *)item->buffer;
}
return NULL;
}
esp_err_t transaction_delete(transaction_handle_t transaction, int msg_id)
{
transaction_item_handle_t item, tmp;
CRITICAL_SECTION_LOCK(transaction->lock);
STAILQ_FOREACH_SAFE(item, transaction->list, next, tmp) {
if (item->msg_id == msg_id) {
STAILQ_REMOVE(transaction->list, item, transaction_item, next);
transaction->size -= item->len;
free(item->buffer);
free(item);
CRITICAL_SECTION_UNLOCK(transaction->lock);
ESP_LOGD(TAG, "DELETED msgid=%x, remain size=%"PRIu64, msg_id, transaction_get_size(transaction));
return ESP_OK;
}
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
return ESP_FAIL;
}
esp_err_t transaction_set_state(transaction_handle_t transaction, int msg_id, pending_state_t state)
{
transaction_item_handle_t item = transaction_get(transaction, msg_id);
if (item) {
atomic_store(&(item->state), state);
return ESP_OK;
}
return ESP_FAIL;
}
pending_state_t transaction_item_get_state(transaction_item_handle_t item)
{
if (item) {
return atomic_load(&(item->state));
}
return INIT;
}
esp_err_t transaction_item_set_state(transaction_item_handle_t item, pending_state_t state)
{
if (item) {
atomic_store(&(item->state), state);
return ESP_OK;
}
return ESP_FAIL;
}
esp_err_t transaction_set_tick(transaction_handle_t transaction, int msg_id, transaction_tick_t tick)
{
transaction_item_handle_t item = transaction_get(transaction, msg_id);
if (item) {
item->tick = tick;
return ESP_OK;
}
return ESP_FAIL;
}
int transaction_delete_single_expired(transaction_handle_t transaction, transaction_tick_t current_tick, transaction_tick_t timeout)
{
int msg_id = -1;
transaction_item_handle_t item;
CRITICAL_SECTION_LOCK(transaction->lock);
STAILQ_FOREACH(item, transaction->list, next) {
if (current_tick - item->tick > timeout) {
STAILQ_REMOVE(transaction->list, item, transaction_item, next);
free(item->buffer);
transaction->size -= item->len;
msg_id = item->msg_id;
free(item);
CRITICAL_SECTION_UNLOCK(transaction->lock);
return msg_id;
}
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
return msg_id;
}
int transaction_delete_expired(transaction_handle_t transaction, transaction_tick_t current_tick, transaction_tick_t timeout)
{
int deleted_items = 0;
transaction_item_handle_t item, tmp;
CRITICAL_SECTION_LOCK(transaction->lock);
STAILQ_FOREACH_SAFE(item, transaction->list, next, tmp) {
if (current_tick - item->tick > timeout) {
STAILQ_REMOVE(transaction->list, item, transaction_item, next);
free(item->buffer);
transaction->size -= item->len;
free(item);
deleted_items ++;
}
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
return deleted_items;
}
uint64_t transaction_get_size(transaction_handle_t transaction)
{
return transaction->size;
}
void transaction_delete_all_items(transaction_handle_t transaction)
{
transaction_item_handle_t item, tmp;
CRITICAL_SECTION_LOCK(transaction->lock);
STAILQ_FOREACH_SAFE(item, transaction->list, next, tmp) {
STAILQ_REMOVE(transaction->list, item, transaction_item, next);
transaction->size -= item->len;
free(item->buffer);
free(item);
}
CRITICAL_SECTION_UNLOCK(transaction->lock);
}
void transaction_destroy(transaction_handle_t transaction)
{
transaction_delete_all_items(transaction);
CRITICAL_SECTION_CLOSE(transaction->lock);
free(transaction->list);
free(transaction);
}
+76
View File
@@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"
#include "port_common.h"
#ifdef __cplusplus
extern "C" {
#endif
#define TRANSACTION_MEMORY MALLOC_CAP_DEFAULT
#define ESP_MEM_CHECK(TAG, a, action) if (!(a)) { \
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Memory exhausted"); \
action; \
}
struct transaction_item;
typedef struct transaction_t *transaction_handle_t;
typedef struct transaction_item *transaction_item_handle_t;
typedef struct transaction_message {
uint8_t *buffer;
uint16_t len;
int msg_id;
int node_id;
void *pnode;
} transaction_message_t;
typedef struct transaction_message *transaction_message_handle_t;
typedef long long transaction_tick_t;
typedef enum pending_state {
INIT,
QUEUED,
ACKNOWLEDGED,
CONFIRMED,
REPLIED,
RECEIVED,
TRANSMITTED,
EXPIRED
} pending_state_t;
transaction_handle_t transaction_init(void);
transaction_item_handle_t transaction_enqueue(transaction_handle_t transaction, transaction_message_handle_t message, transaction_tick_t tick);
transaction_item_handle_t transaction_dequeue(transaction_handle_t transaction, pending_state_t pending, transaction_tick_t *tick);
transaction_item_handle_t transaction_get(transaction_handle_t transaction, int msg_id);
transaction_item_handle_t transaction_get_first(transaction_handle_t transaction);
uint8_t *transaction_item_get_data(transaction_item_handle_t item, size_t *len, uint16_t *msg_id, int *node_id);
esp_err_t transaction_delete(transaction_handle_t transaction, int msg_id);
esp_err_t transaction_delete_item(transaction_handle_t transaction, transaction_item_handle_t item);
int transaction_delete_expired(transaction_handle_t transaction, transaction_tick_t current_tick, transaction_tick_t timeout);
/**
* @brief Deletes single expired message returning it's message id
*
* @return msg id of the deleted message, -1 if no expired message in the transaction
*/
int transaction_delete_single_expired(transaction_handle_t transaction, transaction_tick_t current_tick, transaction_tick_t timeout);
esp_err_t transaction_set_state(transaction_handle_t transaction, int msg_id, pending_state_t pending);
pending_state_t transaction_item_get_state(transaction_item_handle_t item);
esp_err_t transaction_item_set_state(transaction_item_handle_t item, pending_state_t state);
esp_err_t transaction_set_tick(transaction_handle_t transaction, int msg_id, transaction_tick_t tick);
uint64_t transaction_get_size(transaction_handle_t transaction);
void transaction_destroy(transaction_handle_t transaction);
void transaction_delete_all_items(transaction_handle_t transaction);
#ifdef __cplusplus
}
#endif
+45 -21
View File
@@ -65,6 +65,29 @@ void unlock_obj(_lock_t *plock);
spinlock_initialize(&lock); \
} while (0)
#define CRITICAL_STORE(LOCK, PTR, VAL) \
__extension__ \
({ \
__auto_type __atomic_ptr = (PTR); \
__typeof__ ((void)0, *__atomic_ptr) __atomic_tmp = (VAL); \
_lock_acquire((_lock_t *)&LOCK); \
*__atomic_ptr = __atomic_tmp; \
_lock_release((_lock_t *)&LOCK); \
(__atomic_tmp); \
})
#define CRITICAL_LOAD(LOCK, PTR) \
__extension__ \
({ \
__auto_type __atomic_ptr = (PTR); \
__typeof__ ((void)0, *__atomic_ptr) __atomic_tmp; \
_lock_acquire((_lock_t *)&LOCK); \
__atomic_tmp = (*__atomic_ptr); \
_lock_release((_lock_t *)&LOCK); \
(__atomic_tmp); \
})
#define SPIN_LOCK_ENTER(lock) \
do \
{ \
@@ -160,29 +183,30 @@ struct mb_port_base_t
};
// Port event functions
mb_err_enum_t mb_port_evt_create(mb_port_base_t *port_obj);
bool mb_port_evt_post(mb_port_base_t *inst, mb_event_t event);
bool mb_port_evt_get(mb_port_base_t *inst, mb_event_t *event);
bool mb_port_evt_res_take(mb_port_base_t *inst, uint32_t timeout);
void mb_port_evt_res_release(mb_port_base_t *inst);
void mb_port_evt_set_resp_flag(mb_port_base_t *inst, mb_event_enum_t event_mask);
void mb_port_evt_set_err_type(mb_port_base_t *inst, mb_err_event_t event);
mb_err_event_t mb_port_evt_get_err_type(mb_port_base_t *inst);
void mb_port_evt_delete(mb_port_base_t *inst);
mb_err_enum_t mb_port_evt_wait_req_finish(mb_port_base_t *inst);
mb_err_enum_t mb_port_event_create(mb_port_base_t *port_obj);
bool mb_port_event_post(mb_port_base_t *inst, mb_event_t event);
bool mb_port_event_get(mb_port_base_t *inst, mb_event_t *event);
bool mb_port_event_res_take(mb_port_base_t *inst, uint32_t timeout);
void mb_port_event_res_release(mb_port_base_t *inst);
void mb_port_event_set_resp_flag(mb_port_base_t *inst, mb_event_enum_t event_mask);
void mb_port_event_set_err_type(mb_port_base_t *inst, mb_err_event_t event);
mb_err_event_t mb_port_event_get_err_type(mb_port_base_t *inst);
void mb_port_event_delete(mb_port_base_t *inst);
mb_err_enum_t mb_port_event_wait_req_finish(mb_port_base_t *inst);
uint64_t mb_port_get_trans_id(mb_port_base_t *inst);
// Port timer functions
mb_err_enum_t mb_port_tmr_create(mb_port_base_t *inst, uint16_t t35_timer_ticks);
void mb_port_tmr_disable(mb_port_base_t *inst);
void mb_port_tmr_enable(mb_port_base_t *inst);
void mb_port_tmr_respond_timeout_enable(mb_port_base_t *inst);
void mb_port_tmr_convert_delay_enable(mb_port_base_t *inst);
void mb_port_set_cur_tmr_mode(mb_port_base_t *inst, mb_tmr_mode_enum_t tmr_mode);
mb_tmr_mode_enum_t mb_port_get_cur_tmr_mode(mb_port_base_t *inst);
void mb_port_tmr_set_response_time(mb_port_base_t *inst, uint32_t resp_time_ms);
uint32_t mb_port_tmr_get_response_time_ms(mb_port_base_t *inst);
void mb_port_tmr_delay(mb_port_base_t *inst, uint16_t timeout_ms);
void mb_port_tmr_delete(mb_port_base_t *inst);
mb_err_enum_t mb_port_timer_create(mb_port_base_t *inst, uint16_t t35_timer_ticks);
void mb_port_timer_disable(mb_port_base_t *inst);
void mb_port_timer_enable(mb_port_base_t *inst);
void mb_port_timer_respond_timeout_enable(mb_port_base_t *inst);
void mb_port_timer_convert_delay_enable(mb_port_base_t *inst);
void mb_port_set_cur_timer_mode(mb_port_base_t *inst, mb_timer_mode_enum_t tmr_mode);
mb_timer_mode_enum_t mb_port_get_cur_timer_mode(mb_port_base_t *inst);
void mb_port_timer_set_response_time(mb_port_base_t *inst, uint32_t resp_time_ms);
uint32_t mb_port_timer_get_response_time_ms(mb_port_base_t *inst);
void mb_port_timer_delay(mb_port_base_t *inst, uint16_t timeout_ms);
void mb_port_timer_delete(mb_port_base_t *inst);
// Common functions to track instance descriptors
void mb_port_set_inst_counter(uint32_t inst_counter);
+15 -14
View File
@@ -18,14 +18,14 @@ static const char *TAG = "mb_port.event";
struct mb_port_event_t
{
volatile mb_err_event_t curr_err_type;
_Atomic mb_err_event_t curr_err_type;
SemaphoreHandle_t resource_hdl;
EventGroupHandle_t event_group_hdl;
QueueHandle_t event_hdl;
uint64_t curr_trans_id;
_Atomic uint64_t curr_trans_id;
};
mb_err_enum_t mb_port_evt_create(mb_port_base_t *inst)
mb_err_enum_t mb_port_event_create(mb_port_base_t *inst)
{
mb_port_event_t *pevent = NULL;
mb_err_enum_t ret = MB_EILLSTATE;
@@ -42,7 +42,7 @@ mb_err_enum_t mb_port_evt_create(mb_port_base_t *inst)
MB_GOTO_ON_FALSE((pevent->event_hdl), MB_EILLSTATE, error, TAG, "%s, event queue create error.", inst->descr.parent_name);
vQueueAddToRegistry(pevent->event_hdl, TAG);
inst->event_obj = pevent;
pevent->curr_err_type = EV_ERROR_INIT;
atomic_init(&pevent->curr_err_type, EV_ERROR_INIT);
ESP_LOGD(TAG, "initialized object @%p", pevent);
return MB_ENOERR;
@@ -64,12 +64,12 @@ error:
return ret;
}
inline void mb_port_evt_set_err_type(mb_port_base_t *inst, mb_err_event_t event)
inline void mb_port_event_set_err_type(mb_port_base_t *inst, mb_err_event_t event)
{
atomic_store(&(inst->event_obj->curr_err_type), event);
}
inline mb_err_event_t mb_port_evt_get_err_type(mb_port_base_t *inst)
inline mb_err_event_t mb_port_event_get_err_type(mb_port_base_t *inst)
{
return atomic_load(&inst->event_obj->curr_err_type);
}
@@ -79,7 +79,7 @@ uint64_t mb_port_get_trans_id(mb_port_base_t *inst)
return atomic_load(&(inst->event_obj->curr_trans_id));
}
bool mb_port_evt_post(mb_port_base_t *inst, mb_event_t event)
bool mb_port_event_post(mb_port_base_t *inst, mb_event_t event)
{
if (!inst || !inst->event_obj || !inst->event_obj->event_hdl) {
ESP_LOGE(TAG, "Wrong event handle %d %p %s.", (int)(event.event), inst, inst->descr.parent_name);
@@ -116,6 +116,7 @@ bool mb_port_evt_post(mb_port_base_t *inst, mb_event_t event)
} else {
result = xQueueSend(inst->event_obj->event_hdl, (const void*)&temp_event, MB_EVENT_QUEUE_TIMEOUT_MAX);
if (result != pdTRUE) {
xQueueReset(inst->event_obj->event_hdl);
ESP_LOGE(TAG, "%s, post message failure.", inst->descr.parent_name);
return false;
}
@@ -123,7 +124,7 @@ bool mb_port_evt_post(mb_port_base_t *inst, mb_event_t event)
return true;
}
bool mb_port_evt_get(mb_port_base_t *inst, mb_event_t *pevent)
bool mb_port_event_get(mb_port_base_t *inst, mb_event_t *pevent)
{
assert(inst->event_obj->event_hdl);
bool event_happened = false;
@@ -138,15 +139,15 @@ bool mb_port_evt_get(mb_port_base_t *inst, mb_event_t *pevent)
return event_happened;
}
bool mb_port_evt_res_take(mb_port_base_t *inst, uint32_t timeout)
bool mb_port_event_res_take(mb_port_base_t *inst, uint32_t timeout)
{
BaseType_t status = pdTRUE;
status = xSemaphoreTake(inst->event_obj->resource_hdl, timeout);
ESP_LOGW(TAG, "%s, mb take resource, (%" PRIu32 " ticks).", inst->descr.parent_name, timeout);
ESP_LOGD(TAG, "%s, mb take resource, (%" PRIu32 " ticks).", inst->descr.parent_name, timeout);
return status;
}
void mb_port_evt_res_release(mb_port_base_t *inst)
void mb_port_event_res_release(mb_port_base_t *inst)
{
BaseType_t status = pdFALSE;
status = xSemaphoreGive(inst->event_obj->resource_hdl);
@@ -155,12 +156,12 @@ void mb_port_evt_res_release(mb_port_base_t *inst)
}
}
void mb_port_evt_set_resp_flag(mb_port_base_t *inst, mb_event_enum_t event_mask)
void mb_port_event_set_resp_flag(mb_port_base_t *inst, mb_event_enum_t event_mask)
{
(void)xEventGroupSetBits(inst->event_obj->event_group_hdl, event_mask);
}
mb_err_enum_t mb_port_evt_wait_req_finish(mb_port_base_t *inst)
mb_err_enum_t mb_port_event_wait_req_finish(mb_port_base_t *inst)
{
mb_err_enum_t err_status = MB_ENOERR;
mb_event_enum_t rcv_event;
@@ -192,7 +193,7 @@ mb_err_enum_t mb_port_evt_wait_req_finish(mb_port_base_t *inst)
return err_status;
}
void mb_port_evt_delete(mb_port_base_t *inst)
void mb_port_event_delete(mb_port_base_t *inst)
{
if (inst->event_obj->resource_hdl) {
vSemaphoreDelete(inst->event_obj->resource_hdl);
+17 -9
View File
@@ -11,7 +11,7 @@
#include "port_common.h"
/* ----------------------- Variables ----------------------------------------*/
static uint32_t inst_counter = 0;
static _Atomic uint32_t inst_counter = 0;
/* ----------------------- Start implementation -----------------------------*/
int lock_obj(_lock_t *plock)
@@ -58,6 +58,7 @@ QueueHandle_t queue_create(int queue_size)
void queue_delete(QueueHandle_t queue)
{
queue_flush(queue);
vQueueDelete(queue);
}
@@ -65,7 +66,7 @@ esp_err_t queue_push(QueueHandle_t queue, void *pbuf, size_t len, frame_entry_t
{
frame_entry_t frame_info = {0};
if (!queue || !pbuf || (len <= 0)) {
if (!queue) { // || !pbuf || (len <= 0)
return -1;
}
@@ -73,12 +74,16 @@ esp_err_t queue_push(QueueHandle_t queue, void *pbuf, size_t len, frame_entry_t
frame_info = *pframe;
}
frame_info.pbuf = calloc(1, len + 1);
if (!frame_info.pbuf) {
return ESP_ERR_NO_MEM;
if (pbuf && (len > 0)) {
if (!frame_info.pbuf) {
frame_info.pbuf = calloc(1, len);
}
if (!frame_info.pbuf) {
return ESP_ERR_NO_MEM;
}
frame_info.len = len;
memcpy(frame_info.pbuf, pbuf, len);
}
frame_info.len = len;
memcpy(frame_info.pbuf, pbuf, len);
// try send to queue and check if the queue is full
if (xQueueSend(queue, &frame_info, portMAX_DELAY) != pdTRUE) {
@@ -100,10 +105,13 @@ ssize_t queue_pop(QueueHandle_t queue, void *pbuf, size_t len, frame_entry_t *pf
if (len > frame_info.len) {
len = frame_info.len;
}
// if the input buffer pointer is defined copy the data and free
// if the input buffer pointer is defined copy the data and free queued buffer,
// otherwise just return the frame entry
if (frame_info.pbuf && pbuf) {
memcpy(pbuf, frame_info.pbuf, len);
free(frame_info.pbuf);
if (!pframe) {
free(frame_info.pbuf); // must free the buffer manually!
}
}
} else {
goto err;
+38 -44
View File
@@ -5,6 +5,7 @@
*/
/*----------------------- Platform includes --------------------------------*/
#include <stdatomic.h>
#include "esp_idf_version.h"
#include "esp_attr.h"
@@ -25,19 +26,19 @@
/* ----------------------- Defines ----------------------------------------*/
struct mb_port_timer_t
{
spinlock_t spin_lock;
//spinlock_t spin_lock;
esp_timer_handle_t timer_handle;
uint16_t t35_ticks;
uint32_t response_time_ms;
bool timer_state;
uint16_t timer_mode;
_Atomic uint32_t response_time_ms;
_Atomic bool timer_state;
_Atomic uint16_t timer_mode;
};
/* ----------------------- Static variables ---------------------------------*/
static const char *TAG = "mb_port.timer";
/* ----------------------- Start implementation -----------------------------*/
mb_tmr_mode_enum_t mb_port_get_cur_tmr_mode(mb_port_base_t *inst);
mb_timer_mode_enum_t mb_port_get_cur_timer_mode(mb_port_base_t *inst);
static void IRAM_ATTR timer_alarm_cb(void *param)
{
@@ -45,11 +46,11 @@ static void IRAM_ATTR timer_alarm_cb(void *param)
if (inst->cb.tmr_expired && inst->arg) {
inst->cb.tmr_expired(inst->arg); // Timer expired callback function
}
inst->timer_obj->timer_state = true;
ESP_EARLY_LOGD(TAG, "timer mode: (%d) triggered", mb_port_get_cur_tmr_mode(inst));
atomic_store(&(inst->timer_obj->timer_state), true);
ESP_EARLY_LOGD(TAG, "timer mode: (%d) triggered", mb_port_get_cur_timer_mode(inst));
}
mb_err_enum_t mb_port_tmr_create(mb_port_base_t *inst, uint16_t t35_timer_ticks)
mb_err_enum_t mb_port_timer_create(mb_port_base_t *inst, uint16_t t35_timer_ticks)
{
MB_RETURN_ON_FALSE((t35_timer_ticks > 0), MB_EILLSTATE, TAG,
"modbus timeout discreet is incorrect.");
@@ -58,10 +59,11 @@ mb_err_enum_t mb_port_tmr_create(mb_port_base_t *inst, uint16_t t35_timer_ticks)
mb_err_enum_t ret = MB_EILLSTATE;
inst->timer_obj = (mb_port_timer_t *)calloc(1, sizeof(mb_port_timer_t));
MB_GOTO_ON_FALSE((inst && inst->timer_obj), MB_EILLSTATE, error, TAG, "mb timer allocation error.");
SPIN_LOCK_INIT(inst->timer_obj->spin_lock);
inst->timer_obj->timer_handle = NULL;
atomic_init(&(inst->timer_obj->timer_mode), MB_TMODE_T35);
atomic_init(&(inst->timer_obj->timer_state), false);
// Set default response time according to kconfig
inst->timer_obj->response_time_ms = MB_MASTER_TIMEOUT_MS_RESPOND;
atomic_init(&(inst->timer_obj->response_time_ms), MB_MASTER_TIMEOUT_MS_RESPOND);
// Save timer reload value for Modbus T35 period
inst->timer_obj->t35_ticks = t35_timer_ticks;
esp_timer_create_args_t timer_conf = {
@@ -90,7 +92,7 @@ error:
return ret;
}
void mb_port_tmr_delete(mb_port_base_t *inst)
void mb_port_timer_delete(mb_port_base_t *inst)
{
// Delete active timer
if (inst->timer_obj)
@@ -105,72 +107,66 @@ void mb_port_tmr_delete(mb_port_base_t *inst)
}
}
void mb_port_tmr_us(mb_port_base_t *inst, uint64_t timeout_us)
void mb_port_timer_us(mb_port_base_t *inst, uint64_t timeout_us)
{
MB_RETURN_ON_FALSE((inst && inst->timer_obj->timer_handle), ;, TAG, "timer is not initialized.");
MB_RETURN_ON_FALSE((timeout_us > 0), ;, TAG,
"%s, incorrect tick value for timer = (%" PRId64 ").", inst->descr.parent_name, timeout_us);
esp_timer_stop(inst->timer_obj->timer_handle);
esp_timer_start_once(inst->timer_obj->timer_handle, timeout_us);
SPIN_LOCK_ENTER(inst->timer_obj->spin_lock);
inst->timer_obj->timer_state = false;
SPIN_LOCK_EXIT(inst->timer_obj->spin_lock);
atomic_store(&(inst->timer_obj->timer_state), false);
}
inline void mb_port_set_cur_tmr_mode(mb_port_base_t *inst, mb_tmr_mode_enum_t tmr_mode)
inline void mb_port_set_cur_timer_mode(mb_port_base_t *inst, mb_timer_mode_enum_t tmr_mode)
{
SPIN_LOCK_ENTER(inst->timer_obj->spin_lock);
inst->timer_obj->timer_mode = tmr_mode;
SPIN_LOCK_EXIT(inst->timer_obj->spin_lock);
atomic_store(&(inst->timer_obj->timer_mode), tmr_mode);
}
inline mb_tmr_mode_enum_t mb_port_get_cur_tmr_mode(mb_port_base_t *inst)
inline mb_timer_mode_enum_t mb_port_get_cur_timer_mode(mb_port_base_t *inst)
{
return inst->timer_obj->timer_mode;
return atomic_load(&(inst->timer_obj->timer_mode));
}
void mb_port_tmr_enable(mb_port_base_t *inst)
void mb_port_timer_enable(mb_port_base_t *inst)
{
uint64_t tout_us = (inst->timer_obj->t35_ticks * MB_TIMER_TICK_TIME_US);
// Set current timer mode, don't change it.
mb_port_set_cur_tmr_mode(inst, MB_TMODE_T35);
mb_port_set_cur_timer_mode(inst, MB_TMODE_T35);
// Set timer alarm
mb_port_tmr_us(inst, tout_us);
ESP_LOGW(TAG, "%s, start timer (%" PRIu64 ").", inst->descr.parent_name, tout_us);
mb_port_timer_us(inst, tout_us);
ESP_LOGD(TAG, "%s, start timer (%" PRIu64 ").", inst->descr.parent_name, tout_us);
}
void mb_port_tmr_convert_delay_enable(mb_port_base_t *inst)
void mb_port_timer_convert_delay_enable(mb_port_base_t *inst)
{
// Covert time in milliseconds into ticks
uint64_t tout_us = (MB_MASTER_DELAY_MS_CONVERT * 1000);
// Set current timer mode
mb_port_set_cur_tmr_mode(inst, MB_TMODE_CONVERT_DELAY);
mb_port_set_cur_timer_mode(inst, MB_TMODE_CONVERT_DELAY);
ESP_LOGD(TAG, "%s, convert delay enable.", inst->descr.parent_name);
mb_port_tmr_us(inst, tout_us);
mb_port_timer_us(inst, tout_us);
}
void mb_port_tmr_respond_timeout_enable(mb_port_base_t *inst)
void mb_port_timer_respond_timeout_enable(mb_port_base_t *inst)
{
uint64_t tout_us = (inst->timer_obj->response_time_ms * 1000);
mb_port_set_cur_tmr_mode(inst, MB_TMODE_RESPOND_TIMEOUT);
ESP_LOGW(TAG, "%s, respond enable timeout (%d).",
inst->descr.parent_name, (int)inst->timer_obj->response_time_ms);
mb_port_tmr_us(inst, tout_us);
mb_port_set_cur_timer_mode(inst, MB_TMODE_RESPOND_TIMEOUT);
ESP_LOGD(TAG, "%s, respond enable timeout (%u).",
inst->descr.parent_name, (unsigned)mb_port_timer_get_response_time_ms(inst));
mb_port_timer_us(inst, tout_us);
}
void mb_port_tmr_delay(mb_port_base_t *inst, uint16_t timeout_ms)
void mb_port_timer_delay(mb_port_base_t *inst, uint16_t timeout_ms)
{
uint64_t tout_us = (timeout_ms * 1000);
mb_port_tmr_us(inst, tout_us);
mb_port_timer_us(inst, tout_us);
}
void mb_port_tmr_disable(mb_port_base_t *inst)
void mb_port_timer_disable(mb_port_base_t *inst)
{
// Disable timer alarm
esp_err_t err = esp_timer_stop(inst->timer_obj->timer_handle);
@@ -183,14 +179,12 @@ void mb_port_tmr_disable(mb_port_base_t *inst)
}
}
void mb_port_tmr_set_response_time(mb_port_base_t *inst, uint32_t resp_time_ms)
void mb_port_timer_set_response_time(mb_port_base_t *inst, uint32_t resp_time_ms)
{
SPIN_LOCK_ENTER(inst->timer_obj->spin_lock);
inst->timer_obj->response_time_ms = resp_time_ms;
SPIN_LOCK_EXIT(inst->timer_obj->spin_lock);
atomic_store(&(inst->timer_obj->response_time_ms), resp_time_ms);
}
uint32_t mb_port_tmr_get_response_time_ms(mb_port_base_t *inst)
uint32_t mb_port_timer_get_response_time_ms(mb_port_base_t *inst)
{
return inst->timer_obj->response_time_ms;
return atomic_load(&(inst->timer_obj->response_time_ms));
}
+15 -15
View File
@@ -117,7 +117,7 @@ void mb_port_ser_enable(mb_port_base_t *inst)
CRITICAL_SECTION (port_obj->base.lock) {
atomic_store(&(port_obj->enabled), true);
mb_port_ser_bus_sema_release(inst);
ESP_LOGW(TAG, "%s, resume port.", port_obj->base.descr.parent_name);
ESP_LOGD(TAG, "%s, resume port.", port_obj->base.descr.parent_name);
// Resume receiver task from known position
vTaskResume(port_obj->task_handle);
}
@@ -129,7 +129,7 @@ void mb_port_ser_disable(mb_port_base_t *inst)
CRITICAL_SECTION (port_obj->base.lock) {
// Suspend port task by itself
atomic_store(&(port_obj->enabled), false);
ESP_LOGW(TAG, "%s, suspend port.", port_obj->base.descr.parent_name);
ESP_LOGD(TAG, "%s, suspend port.", port_obj->base.descr.parent_name);
}
}
@@ -150,7 +150,7 @@ static void mb_port_ser_task(void *p_args)
ESP_LOGD(TAG, "%s, UART[%d] event:", port_obj->base.descr.parent_name, port_obj->ser_opts.port);
switch(event.type) {
case UART_DATA:
ESP_LOGW(TAG, "%s, data event, len: %d.", port_obj->base.descr.parent_name, (int)event.size);
ESP_LOGD(TAG, "%s, data event, len: %d.", port_obj->base.descr.parent_name, (int)event.size);
// This flag set in the event means that no more
// data received during configured timeout and UART TOUT feature is triggered
if (event.timeout_flag) {
@@ -162,12 +162,12 @@ static void mb_port_ser_task(void *p_args)
uart_get_buffered_data_len(port_obj->ser_opts.port, (unsigned int*)&event.size);
port_obj->recv_length = (event.size < MB_BUFFER_SIZE) ? event.size : MB_BUFFER_SIZE;
if (event.size <= MB_SER_PDU_SIZE_MIN) {
ESP_LOGW(TAG, "%s, drop short packet %d byte(s)", port_obj->base.descr.parent_name, (int)event.size);
ESP_LOGD(TAG, "%s, drop short packet %d byte(s)", port_obj->base.descr.parent_name, (int)event.size);
(void)mb_port_ser_rx_flush(&port_obj->base);
break;
}
// New frame is received, send an event to main FSM to read it into receiver buffer
mb_port_evt_post(&port_obj->base, EVENT(EV_FRAME_RECEIVED, port_obj->recv_length, NULL, 0));
mb_port_event_post(&port_obj->base, EVENT(EV_FRAME_RECEIVED, port_obj->recv_length, NULL, 0));
ESP_LOGD(TAG, "%s, frame %d bytes is ready.", port_obj->base.descr.parent_name, (int)port_obj->recv_length);
}
break;
@@ -187,12 +187,12 @@ static void mb_port_ser_task(void *p_args)
break;
//Event of UART parity check error
case UART_PARITY_ERR:
ESP_LOGW(TAG, "%s, uart parity error.", port_obj->base.descr.parent_name);
ESP_LOGD(TAG, "%s, uart parity error.", port_obj->base.descr.parent_name);
(void)mb_port_ser_rx_flush(&port_obj->base);
break;
//Event of UART frame error
case UART_FRAME_ERR:
ESP_LOGW(TAG, "%s, uart frame error.", port_obj->base.descr.parent_name);
ESP_LOGD(TAG, "%s, uart frame error.", port_obj->base.descr.parent_name);
(void)mb_port_ser_rx_flush(&port_obj->base);
break;
default:
@@ -293,21 +293,21 @@ bool mb_port_ser_recv_data(mb_port_base_t *inst, uint8_t **pp_ser_frame, uint16_
uint16_t counter = *p_ser_length ? *p_ser_length : port_obj->recv_length;
bool status = false;
status = mb_port_ser_bus_sema_take(inst, pdMS_TO_TICKS(mb_port_tmr_get_response_time_ms(inst)));
status = mb_port_ser_bus_sema_take(inst, pdMS_TO_TICKS(mb_port_timer_get_response_time_ms(inst)));
if (status && counter && *pp_ser_frame && atomic_load(&(port_obj->enabled))) {
// Read frame data from the ringbuffer of receiver
counter = uart_read_bytes(port_obj->ser_opts.port, (uint8_t *)*pp_ser_frame,
counter, MB_SERIAL_RX_TOUT_TICKS);
// Stop timer because the new data is received
mb_port_tmr_disable(inst);
mb_port_timer_disable(inst);
// Store the timestamp of received frame
port_obj->recv_time_stamp = esp_timer_get_time();
ESP_LOGW(TAG, "%s, received data: %d bytes.", inst->descr.parent_name, (int)counter);
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":PORT_RECV"), (void *)*pp_ser_frame, counter, ESP_LOG_WARN);
ESP_LOGD(TAG, "%s, received data: %d bytes.", inst->descr.parent_name, (int)counter);
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":PORT_RECV"), (void *)*pp_ser_frame, counter, ESP_LOG_DEBUG);
int64_t time_delta = (port_obj->recv_time_stamp > port_obj->send_time_stamp) ?
(port_obj->recv_time_stamp - port_obj->send_time_stamp) :
(port_obj->send_time_stamp - port_obj->recv_time_stamp);
ESP_LOGW(TAG, "%s, serial processing time[us] = %" PRId64, inst->descr.parent_name, time_delta);
ESP_LOGD(TAG, "%s, serial processing time[us] = %" PRId64, inst->descr.parent_name, time_delta);
status = true;
*p_ser_length = counter;
} else {
@@ -324,19 +324,19 @@ bool mb_port_ser_send_data(mb_port_base_t *inst, uint8_t *p_ser_frame, uint16_t
int count = 0;
mb_ser_port_t *port_obj = __containerof(inst, mb_ser_port_t, base);
res = mb_port_ser_bus_sema_take(inst, pdMS_TO_TICKS(mb_port_tmr_get_response_time_ms(inst)));
res = mb_port_ser_bus_sema_take(inst, pdMS_TO_TICKS(mb_port_timer_get_response_time_ms(inst)));
if (res && p_ser_frame && ser_length && atomic_load(&(port_obj->enabled))) {
// Flush buffer received from previous transaction
mb_port_ser_rx_flush(inst);
count = uart_write_bytes(port_obj->ser_opts.port, p_ser_frame, ser_length);
// Waits while UART sending the packet
esp_err_t status = uart_wait_tx_done(port_obj->ser_opts.port, MB_SERIAL_TX_TOUT_TICKS);
(void)mb_port_evt_post(inst, EVENT(EV_FRAME_SENT));
(void)mb_port_event_post(inst, EVENT(EV_FRAME_SENT));
ESP_LOGD(TAG, "%s, tx buffer sent: (%d) bytes.", inst->descr.parent_name, (int)count);
MB_RETURN_ON_FALSE((status == ESP_OK), false, TAG, "%s, mb serial sent buffer failure.",
inst->descr.parent_name);
ESP_LOG_BUFFER_HEX_LEVEL(MB_STR_CAT(inst->descr.parent_name, ":PORT_SEND"),
(void *)p_ser_frame, ser_length, ESP_LOG_WARN);
(void *)p_ser_frame, ser_length, ESP_LOG_DEBUG);
port_obj->send_time_stamp = esp_timer_get_time();
} else {
ESP_LOGE(TAG, "%s, send fail state:%d, %p, %u. ", inst->descr.parent_name, (int)port_obj->tx_state_en, p_ser_frame, (unsigned)ser_length);
+3 -3
View File
@@ -17,8 +17,8 @@ extern "C" {
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
#define MB_TCP_PORT_MAX_CONN (CONFIG_FMB_TCP_PORT_MAX_CONN)
#define MB_TCP_DEFAULT_PORT (502)
#define MB_FRAME_QUEUE_SZ (10)
#define MB_TCP_DEFAULT_PORT (CONFIG_FMB_TCP_PORT_DEFAULT)
#define MB_FRAME_QUEUE_SZ (20)
#define MB_TCP_CONNECTION_TIMEOUT_MS (20) // connection timeout in mS
#define MB_TCP_RECONNECT_TIMEOUT (5000000) // reconnection timeout in uS
@@ -30,7 +30,7 @@ extern "C" {
buffer[(field) + 1] = (uint8_t)((val) & 0xFF); \
}
#define MB_SLAVE_FMT(fmt) "slave #%d, socket(#%d)(%s)" fmt
#define MB_NODE_FMT(fmt) "node #%d, socket(#%d)(%s)" fmt
mb_err_enum_t mbm_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **port_obj);
void mbm_port_tcp_delete(mb_port_base_t *inst);
File diff suppressed because it is too large. Load diff
+141 -99
View File
@@ -31,21 +31,25 @@ extern "C" {
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
#define MB_PORT_DEFAULT (502)
#define INVALID_FD (-1)
#define MB_PORT_DEFAULT (CONFIG_FMB_TCP_PORT_DEFAULT)
#define UNDEF_FD (-1)
#define MB_EVENT_TOUT (300 / portTICK_PERIOD_MS)
#define MB_CONN_TICK_TIMEOUT (10 / portTICK_PERIOD_MS)
#define EVENT_HANDLER(handler_name) void handler_name(void *ctx, esp_event_base_t base, int32_t id, void *data)
typedef void (*mb_event_handler_fp)(void *ctx, esp_event_base_t base, int32_t id, void *data);
#define MB_EVENT_HANDLER(handler_name) void (handler_name)(void *ctx, esp_event_base_t base, int32_t id, void *data)
#define MB_TASK_STACK_SZ (CONFIG_FMB_PORT_TASK_STACK_SIZE)
#define MB_TASK_PRIO (CONFIG_FMB_PORT_TASK_PRIO)
#define MB_PORT_TASK_AFFINITY (CONFIG_FMB_PORT_TASK_AFFINITY)
#define MB_MAX_FDS (MB_TCP_PORT_MAX_CONN)
#define MB_RETRY_MAX (2)
#define MB_RECONNECT_TIME_MS (1000)
#define MB_RX_QUEUE_MAX_SIZE (CONFIG_FMB_QUEUE_LENGTH)
#define MB_TX_QUEUE_MAX_SIZE (CONFIG_FMB_QUEUE_LENGTH)
#define MB_EVENT_QUEUE_SZ (CONFIG_FMB_QUEUE_LENGTH * MB_TCP_PORT_MAX_CONN)
#define MB_TASK_STACK_SZ (CONFIG_FMB_PORT_TASK_STACK_SIZE)
#define MB_TASK_PRIO (CONFIG_FMB_PORT_TASK_PRIO)
#define MB_PORT_TASK_AFFINITY (CONFIG_FMB_PORT_TASK_AFFINITY)
#define MB_WAIT_DONE_MS (5000)
#define MB_SELECT_WAIT_MS (200)
#define MB_TCP_SEND_TIMEOUT_MS (500)
@@ -53,47 +57,86 @@ extern "C" {
#define MB_DRIVER_CONFIG_DEFAULT { \
.spin_lock = portMUX_INITIALIZER_UNLOCKED, \
.listen_sock_fd = UNDEF_FD, \
.retry_cnt = MB_RETRY_MAX, \
.mb_tcp_task_handle = NULL, \
.mb_slave_open_count = 0, \
.curr_slave_index = 0, \
.mb_node_open_count = 0, \
.curr_node_index = 0, \
.mb_proto = MB_TCP, \
.network_iface_ptr = NULL, \
.mb_slave_info = NULL, \
.mb_slave_curr_info = NULL, \
.dns_name = NULL, \
.mb_nodes = NULL, \
.mb_node_curr = NULL, \
.close_done_sema = NULL, \
.max_conn_sd = INVALID_FD, \
.slave_conn_count = 0, \
.event_fd = INVALID_FD, \
.max_conn_sd = UNDEF_FD, \
.node_conn_count = 0, \
.event_fd = UNDEF_FD, \
}
#define MB_EVENTFD_CONFIG() (esp_vfs_eventfd_config_t) { \
.max_fds = MB_TCP_PORT_MAX_CONN \
#define MB_EVENTFD_CONFIG() (esp_vfs_eventfd_config_t) { \
.max_fds = MB_TCP_PORT_MAX_CONN \
};
typedef struct _port_driver port_driver_t;
#define MB_CHECK_FD_RANGE(fd) ((fd < MB_TCP_PORT_MAX_CONN) && (fd >= 0))
#define GET_CONFIG_PTR(ctx) (__extension__( \
{ \
assert(ctx); \
((port_driver_t *)ctx); \
} \
#define MB_GET_DRV_PTR(ctx) (__extension__( \
{ \
assert(ctx); \
((port_driver_t *)ctx); \
} \
))
#define MB_EVENT_TBL_IT(event) {event, #event}
#define MB_EVENT_BASE(context) (__extension__( \
{ \
port_driver_t *pdrv_ctx = GET_CONFIG_PTR(context); \
(pdrv_ctx->loop_name) ? (esp_event_base_t)(pdrv_ctx->loop_name) : "UNK_BASE"; \
} \
#define MB_EVENT_BASE(context) (__extension__( \
{ \
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(context); \
(pdrv_ctx->loop_name) ? (esp_event_base_t)(pdrv_ctx->loop_name) : "UNK_BASE"; \
} \
))
#define MB_GET_SLAVE_STATE(pslave) (atomic_load(&((mb_slave_info_t *)pslave)->addr_info.state))
#define MB_ADD_FD(fd, max_fd, pfdset) do { \
if (fd) { \
(max_fd = (fd > max_fd) ? fd : max_fd); \
FD_SET(fd, pfdset); \
} \
} while(0)
#define MB_SET_SLAVE_STATE(pslave, slave_state) do { \
atomic_store(&(((mb_slave_info_t *)pslave)->addr_info.state), slave_state); \
// Macro for atomic operations
#define MB_ATOMIC_LOAD(ctx, addr) (__extension__( \
{ \
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx); \
(CRITICAL_LOAD(pdrv_ctx->lock, addr)); \
} \
))
#define MB_ATOMIC_STORE(ctx, addr, val) (__extension__( \
{ \
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx); \
CRITICAL_STORE(pdrv_ctx->lock, addr, val); \
} \
))
// Post event to event loop and unblocks the select through the eventfd to handle the event loop run,
// So, the eventfd value keeps last event and its fd.
#define DRIVER_SEND_EVENT(ctx, event, fd) (__extension__( \
{ \
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx); \
mb_event_info_t (event_info##__FUNCTION__##__LINE__); \
(event_info##__FUNCTION__##__LINE__).event_id = (int32_t)event; \
(event_info##__FUNCTION__##__LINE__).opt_fd = fd; \
((write_event((void *)pdrv_ctx, &(event_info##__FUNCTION__##__LINE__)) > 0) \
? ((event_info##__FUNCTION__##__LINE__)).event_id : UNDEF_FD); \
} \
))
#define MB_GET_NODE_STATE(pnode) (atomic_load(&((mb_node_info_t *)pnode)->addr_info.state))
#define MB_SET_NODE_STATE(pnode, node_state) do { \
atomic_store(&(((mb_node_info_t *)pnode)->addr_info.state), node_state); \
} while(0)
typedef enum _mb_driver_event {
@@ -103,7 +146,7 @@ typedef enum _mb_driver_event {
MB_EVENT_CONNECT = 0x0008,
MB_EVENT_SEND_DATA = 0x0010,
MB_EVENT_RECV_DATA = 0x0020,
MB_EVENT_RECONNECT = 0x0040,
MB_EVENT_ERROR = 0x0040,
MB_EVENT_CLOSE = 0x0080,
MB_EVENT_TIMEOUT = 0x0100
} mb_driver_event_t;
@@ -121,25 +164,13 @@ typedef union {
uint64_t val;
} mb_event_info_t;
// Post event to event loop and unblocks the select through the eventfd to handle the event loop run,
// So, the eventfd value keeps last event and its fd.
#define DRIVER_SEND_EVENT(ctx, event, fd) (__extension__( \
{ \
port_driver_t *pdrv_ctx = GET_CONFIG_PTR(ctx); \
static mb_event_info_t event_info; \
event_info.event_id = (int32_t)event; \
event_info.opt_fd = fd; \
(write_event((void *)pdrv_ctx, &event_info) > 0) ? event_info.event_id : -1; \
} \
))
typedef struct _mb_slave_info {
typedef struct _mb_node_info {
int index; /*!< slave information index */
int fd; /*!< slave global file descriptor */
int sock_id; /*!< socket ID of slave */
mb_uid_info_t addr_info; /*!< slave address info structure*/
int error; /*!< socket error */
int recv_err; /*!< socket receive error */
mb_uid_info_t addr_info; /*!< slave address info structure*/
QueueHandle_t rx_queue; /*!< receive response queue */
QueueHandle_t tx_queue; /*!< send request queue */
int64_t send_time; /*!< send request time stamp */
@@ -148,7 +179,7 @@ typedef struct _mb_slave_info {
uint16_t send_counter; /*!< number of packets sent to slave during one session */
uint16_t recv_counter; /*!< number of packets received from slave during one session */
bool is_blocking; /*!< slave blocking bit state saved */
} mb_slave_info_t;
} mb_node_info_t;
typedef enum _mb_sync_event {
MB_SYNC_EVENT_RECV_OK = 0x0001,
@@ -158,57 +189,56 @@ typedef enum _mb_sync_event {
} mb_sync_event_t;
typedef enum _mb_status_flags {
MB_FLAG_DISCONNECTED = 0x0001,
MB_FLAG_CONNECTED = 0x0002,
MB_FLAG_SUSPEND = 0x0004,
MB_FLAG_SHUTDOWN = 0x0008
MB_FLAG_BLANK = 0x0000,
MB_FLAG_TRANSACTION_DONE = 0x0001,
MB_FLAG_DISCONNECTED = 0x0002,
MB_FLAG_CONNECTED = 0x0004,
MB_FLAG_SUSPEND = 0x0008,
MB_FLAG_SHUTDOWN = 0x0010
} mb_status_flags_t;
typedef struct _driver_event_cbs {
void (*on_conn_done_cb)(void *);
void *arg;
void (*mb_sync_event_cb)(void *, mb_sync_event_t);
uint64_t (*mb_sync_event_cb)(void *, mb_sync_event_t);
void *port_arg;
} mb_driver_event_cb_t;
/**
* @brief Modbus slave addr list item for the master
*/
// typedef struct mb_uid_entry_s {
// void* pinst;
// mb_uid_info_t addr_info;
// LIST_ENTRY(mb_uid_entry_s) entries; /*!< The slave address entry */
// } mb_uid_entry_t;
/**
* @brief Modbus driver context parameters
*
*/
typedef struct _port_driver {
void *parent; /*!< Parent object */
portMUX_TYPE spin_lock; /*!< Driver spin lock */
_lock_t lock; /*!< Driver semaphore mutex */
bool is_registered; /*!< Driver is active flag */
TaskHandle_t mb_tcp_task_handle; /*!< Master TCP/UDP handling task handle */
mb_comm_mode_t mb_proto; /*!< Master protocol type */
void *network_iface_ptr; /*!< Master netif interface pointer */
mb_slave_info_t **mb_slave_info; /*!< Master information structure for each connected slave */
uint16_t mb_slave_open_count; /*!< Master count of connected slaves */
mb_slave_info_t *mb_slave_curr_info; /*!< Master current slave information */
uint16_t curr_slave_index; /*!< Master current processing slave index */
fd_set open_set; /*!< File descriptor set for opened slaves */
fd_set conn_set; /*!< File descriptor set for connected slaves */
EventGroupHandle_t status_flags_hdl; /*!< Status bits to control nodes states */
int max_conn_sd; /*!< Max file descriptor for connected slaves */
int slave_conn_count; /*!< Number of connected slaves */
SemaphoreHandle_t close_done_sema; /*!< Close and done semaphore */
void *parent; /*!< parent object pointer */
char *dns_name; /*!< DNS name of the object */
portMUX_TYPE spin_lock; /*!< spin lock */
_lock_t lock; /*!< semaphore mutex */
bool is_registered; /*!< driver is active flag */
int listen_sock_fd; /*!< listen socket fd */
int retry_cnt; /*!< retry counter for events */
mb_comm_mode_t mb_proto; /*!< current node protocol type */
uint16_t port; /*!< current node port number */
uint8_t uid; /*!< unit identifier of the node */
bool is_master; /*!< identify the type of instance (master, slave) */
void *network_iface_ptr; /*!< netif interface pointer */
mb_node_info_t **mb_nodes; /*!< information structures for each associated node */
uint16_t mb_node_open_count; /*!< count of associated nodes */
uint16_t node_conn_count; /*!< number of associated nodes */
mb_node_info_t *mb_node_curr; /*!< current slave information */
uint16_t curr_node_index; /*!< current processing slave index */
fd_set open_set; /*!< file descriptor set for opened nodes */
fd_set conn_set; /*!< file descriptor set for associated nodes */
int max_conn_sd; /*!< max file descriptor for associated nodes */
int event_fd; /*!< eventfd descriptor for modbus event tracking */
SemaphoreHandle_t close_done_sema; /*!< close and done semaphore */
EventGroupHandle_t status_flags_hdl; /*!< status bits to control nodes states */
TaskHandle_t mb_tcp_task_handle; /*!< TCP/UDP handling task handle */
esp_event_loop_handle_t event_loop_hdl; /*!< event loop handle */
char *loop_name; /*!< name for event loop used as base */
esp_event_handler_instance_t event_handler; /*!< event handler instance */
char *loop_name; /*!< name for event loop used as base */
mb_driver_event_cb_t event_cbs;
//LIST_HEAD(mb_uid_info_, mb_uid_entry_s) slave_list; /*!< Slave address information list */
uint16_t slave_list_count;
//LIST_HEAD(mb_uid_info_, mb_uid_entry_s) node_list; /*!< node address information list */
//uint16_t node_list_count;
} port_driver_t;
/**
@@ -221,7 +251,7 @@ typedef struct _port_driver {
* @return esp_err_t
* - ESP_OK on success
*/
esp_err_t mbm_drv_register(port_driver_t **config);
esp_err_t mb_drv_register(port_driver_t **config);
/**
* @brief Unregister modbus driver
@@ -230,7 +260,7 @@ esp_err_t mbm_drv_register(port_driver_t **config);
* @return esp_err_t
* - ESP_OK on success
*/
esp_err_t mbm_drv_unregister(void *ctx);
esp_err_t mb_drv_unregister(void *ctx);
/**
* @brief Start task of modbus driver
@@ -239,7 +269,7 @@ esp_err_t mbm_drv_unregister(void *ctx);
* @return esp_err_t
* - ESP_OK on success
*/
esp_err_t mbm_drv_start_task(void *ctx);
esp_err_t mb_drv_start_task(void *ctx);
/**
@@ -249,7 +279,7 @@ esp_err_t mbm_drv_start_task(void *ctx);
* @return esp_err_t
* - ESP_OK on success
*/
esp_err_t mbm_drv_stop_task(void *ctx);
esp_err_t mb_drv_stop_task(void *ctx);
/**
* @brief get slave information structure from its short slave address
@@ -257,37 +287,49 @@ esp_err_t mbm_drv_stop_task(void *ctx);
* This function must be called after initialization of ESP-MODBUS Interface
*
* @param uid - modbus slave address of the slave
* @return mb_slave_info_t
* @return mb_node_info_t
* - Address of slave info structure on success
* - NULL, if the slave is not found
*/
mb_slave_info_t *mbm_drv_get_slave_info_from_addr(void *ctx, uint8_t uid);
mb_node_info_t *mb_drv_get_node_info_from_addr(void *ctx, uint8_t uid);
int mbm_drv_open(void *ctx, mb_uid_info_t addr_info, int flags);
mb_node_info_t *mb_drv_get_node(void *ctx, int fd);
ssize_t mbm_drv_write(void *ctx, int fd, const void *data, size_t size);
mb_sock_state_t mb_drv_get_node_state(void *ctx, int fd);
ssize_t mbm_drv_read(void *ctx, int fd, void *data, size_t size);
int mb_drv_open(void *ctx, mb_uid_info_t addr_info, int flags);
int mbm_drv_close(void *ctx, int fd);
ssize_t mb_drv_write(void *ctx, int fd, const void *data, size_t size);
ssize_t mb_drv_read(void *ctx, int fd, void *data, size_t size);
int mb_drv_close(void *ctx, int fd);
int32_t write_event(void *ctx, mb_event_info_t *pevent);
const char *driver_event_to_name_r(mb_driver_event_t event);
void mbm_drv_set_cb(void *ctx, void *conn_cb, void *arg);
void mb_drv_set_cb(void *ctx, void *conn_cb, void *arg);
mb_status_flags_t mbm_drv_wait_status_flag(void *ctx, mb_status_flags_t mask, uint32_t tout_ms);
mb_status_flags_t mb_drv_wait_status_flag(void *ctx, mb_status_flags_t mask, TickType_t ticks);
EVENT_HANDLER(on_ready);
EVENT_HANDLER(on_open);
EVENT_HANDLER(on_connect);
EVENT_HANDLER(on_resolve);
EVENT_HANDLER(on_send_data);
EVENT_HANDLER(on_recv_data);
EVENT_HANDLER(on_reconnect);
EVENT_HANDLER(on_close);
EVENT_HANDLER(on_timeout);
esp_err_t mb_drv_register_handler(void *ctx, mb_driver_event_t event, mb_event_handler_fp fp);
esp_err_t mb_drv_unregister_handler(void *ctx, mb_driver_event_t event);
void mb_drv_check_suspend_shutdown(void *ctx);
void mb_drv_lock(void *ctx);
void mb_drv_unlock(void *ctx);
mb_node_info_t *mb_drv_get_next_node_from_set(void *ctx, int *pfd, fd_set *pfdset);
mb_status_flags_t mb_drv_set_status_flag(void *ctx, mb_status_flags_t mask);
mb_status_flags_t mb_drv_clear_status_flag(void *ctx, mb_status_flags_t mask);
err_t mb_drv_check_node_state(void *ctx, int fd);
#endif
+484 -51
View File
@@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
*/
#include <stdbool.h>
#include <string.h>
@@ -24,10 +24,81 @@ typedef struct
/* ----------------------- Static variables & functions ----------------------*/
static const char *TAG = "mb_port.tcp.master";
static void mbm_port_tcp_sync_event(void *inst, mb_sync_event_t sync_event);
static uint64_t mbm_port_tcp_sync_event(void *inst, mb_sync_event_t sync_event);
bool mbm_port_timer_expired(void *inst);
extern int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info);
static esp_err_t mbm_port_tcp_register_handlers(void *ctx)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
esp_err_t ret = ESP_ERR_INVALID_STATE;
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_READY, mbm_on_ready);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_READY);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_OPEN, mbm_on_open);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_OPEN);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_RESOLVE, mbm_on_resolve);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_RESOLVE);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_CONNECT, mbm_on_connect);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CONNECT);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_ERROR, mbm_on_error);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_ERROR);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_SEND_DATA, mbm_on_send_data);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_SEND_DATA);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_RECV_DATA, mbm_on_recv_data);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_RECV_DATA);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_CLOSE, mbm_on_close);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CLOSE);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_TIMEOUT, mbm_on_timeout);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_TIMEOUT);
return ESP_OK;
}
static esp_err_t mbm_port_tcp_unregister_handlers(void *ctx)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
esp_err_t ret = ESP_ERR_INVALID_STATE;
ESP_LOGD(TAG, "%p, event handler %p, unregister.", pdrv_ctx, pdrv_ctx->event_handler);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_READY);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_READY);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_OPEN);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_OPEN);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_RESOLVE);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_RESOLVE);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_CONNECT);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CONNECT);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_ERROR);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_ERROR);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_SEND_DATA);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_SEND_DATA);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_RECV_DATA);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_RECV_DATA);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_CLOSE);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CLOSE);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_TIMEOUT);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_TIMEOUT);
return ESP_OK;
}
mb_err_enum_t mbm_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **port_obj)
{
MB_RETURN_ON_FALSE((port_obj && tcp_opts), MB_EINVAL, TAG, "mb tcp port invalid arguments.");
@@ -41,13 +112,21 @@ mb_err_enum_t mbm_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **port
CRITICAL_SECTION_INIT(ptcp->base.lock);
ptcp->base.descr = ((mb_port_base_t *)*port_obj)->descr;
err = mbm_drv_register(&ptcp->pdriver);
err = mb_drv_register(&ptcp->pdriver);
MB_GOTO_ON_FALSE(((err == ESP_OK) && ptcp->pdriver), MB_EILLSTATE, error,
TAG, "mb tcp port driver registration failed.");
TAG, "mb tcp port driver registration failed, err = (%x).", (int)err);
ptcp->pdriver->parent = ptcp;
err = mbm_port_tcp_register_handlers(ptcp->pdriver);
MB_GOTO_ON_FALSE(((err == ESP_OK) && ptcp->pdriver), MB_EILLSTATE, error,
TAG, "mb tcp port driver event handlers registration failed, err = (%x).", (int)err);
ptcp->pdriver->network_iface_ptr = tcp_opts->ip_netif_ptr;
ptcp->pdriver->mb_proto = tcp_opts->mode;
ptcp->pdriver->port = tcp_opts->port;
ptcp->pdriver->uid = tcp_opts->uid;
ptcp->pdriver->is_master = true;
ptcp->pdriver->dns_name = tcp_opts->dns_name;
ptcp->pdriver->event_cbs.mb_sync_event_cb = mbm_port_tcp_sync_event;
ptcp->pdriver->event_cbs.port_arg = (void *)ptcp;
@@ -58,22 +137,21 @@ mb_err_enum_t mbm_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **port
char **paddr_table = tcp_opts->ip_addr_table;
MB_GOTO_ON_FALSE((paddr_table && *paddr_table), MB_EILLSTATE, error,
TAG, "mb tcp port driver registration failed.");
TAG, "mb tcp port nodes registration failed %p, %p.", paddr_table, *paddr_table);
mb_uid_info_t slave_address_info;
int fd = 0;
// Just for test now
while(*paddr_table) {
int res = port_scan_addr_string((char *)*paddr_table, &slave_address_info);
if (res > 0) {
ESP_LOGW(TAG, "Config: %s, IP: %s, port: %d, slave_addr: %d, ip_ver: %s",
ESP_LOGD(TAG, "Config: %s, IP: %s, port: %d, slave_addr: %d, ip_ver: %s",
(char *)*paddr_table, slave_address_info.ip_addr_str, slave_address_info.port,
slave_address_info.uid, (slave_address_info.addr_type == MB_IPV4 ? "IPV4" : "IPV6"));
fd = mbm_drv_open(ptcp->pdriver, slave_address_info, 0);
slave_address_info.uid, (slave_address_info.addr_type == MB_IPV4 ? "IPV4" : "IPV6"));
fd = mb_drv_open(ptcp->pdriver, slave_address_info, 0);
if (fd < 0) {
ESP_LOGE(TAG, "%p, unable to open slave: %s", ptcp->pdriver, slave_address_info.ip_addr_str);
} else {
ESP_LOGW(TAG, "%p, open slave: %d, %s:%d",
ESP_LOGD(TAG, "%p, open slave: %d, %s:%d",
ptcp->pdriver, fd, slave_address_info.ip_addr_str, slave_address_info.port);
}
} else {
@@ -81,14 +159,26 @@ mb_err_enum_t mbm_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **port
}
paddr_table++;
}
#ifdef MB_MDNS_IS_INCLUDED
err = port_start_mdns_service(&ptcp->pdriver->dns_name, true, tcp_opts->uid, ptcp->pdriver->network_iface_ptr);
MB_GOTO_ON_FALSE((err == ESP_OK), MB_EILLSTATE, error,
TAG, "mb tcp port mdns service init failure.");
#endif
*port_obj = &(ptcp->base);
ESP_LOGD(TAG, "created object @%p", ptcp);
return MB_ENOERR;
error:
#ifdef MB_MDNS_IS_INCLUDED
port_stop_mdns_service(&ptcp->pdriver->dns_name);
#endif
if (ptcp && ptcp->pdriver) {
(void)mbm_drv_unregister(ptcp->pdriver);
(void)mbm_port_tcp_unregister_handlers(ptcp->pdriver);
(void)mb_drv_unregister(ptcp->pdriver);
CRITICAL_SECTION_CLOSE(ptcp->base.lock);
// if the MDNS resolving is enabled, then free it
}
free(ptcp);
return ret;
@@ -97,7 +187,13 @@ error:
void mbm_port_tcp_delete(mb_port_base_t *inst)
{
mbm_tcp_port_t *port_obj = __containerof(inst, mbm_tcp_port_t, base);
esp_err_t err = mbm_drv_unregister(port_obj->pdriver);
esp_err_t err = MB_EILLSTATE;
err = mbm_port_tcp_unregister_handlers(port_obj->pdriver);
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG, "mb tcp port invalid arguments.");
#ifdef MB_MDNS_IS_INCLUDED
port_stop_mdns_service(&port_obj->pdriver->dns_name);
#endif
err = mb_drv_unregister(port_obj->pdriver);
if (err != ESP_OK) {
ESP_LOGE(TAG, "driver unregister fail, returns (0x%d).", (uint16_t)err);
}
@@ -108,51 +204,46 @@ void mbm_port_tcp_delete(mb_port_base_t *inst)
void mbm_port_tcp_enable(mb_port_base_t *inst)
{
mbm_tcp_port_t *port_obj = __containerof(inst, mbm_tcp_port_t, base);
//esp_err_t err = ESP_ERR_INVALID_STATE;
// if (!port_obj->pdriver->is_registered && !port_obj->pdriver) {
// err = mbm_drv_register(&port_obj->pdriver);
// MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG, "mb tcp port driver register failed.");
// }
(void)mbm_drv_start_task(port_obj->pdriver);
DRIVER_SEND_EVENT(port_obj->pdriver, MB_EVENT_RESOLVE, -1);
(void)mb_drv_start_task(port_obj->pdriver);
(void)mb_drv_clear_status_flag(port_obj->pdriver, MB_FLAG_DISCONNECTED);
DRIVER_SEND_EVENT(port_obj->pdriver, MB_EVENT_RESOLVE, UNDEF_FD);
}
void mbm_port_tcp_disable(mb_port_base_t *inst)
{
mbm_tcp_port_t *port_obj = __containerof(inst, mbm_tcp_port_t, base);
// Change the state of all slaves to close
DRIVER_SEND_EVENT(port_obj->pdriver, MB_EVENT_CLOSE, -1);
(void)mbm_drv_wait_status_flag(port_obj->pdriver, MB_FLAG_DISCONNECTED, MB_RECONNECT_TIME_MS);
//(void)mbm_drv_stop_task(port_obj->pdriver); // do not stop the task if we want to gracefully shutdown the task
DRIVER_SEND_EVENT(port_obj->pdriver, MB_EVENT_CLOSE, UNDEF_FD);
(void)mb_drv_wait_status_flag(port_obj->pdriver, MB_FLAG_DISCONNECTED, pdMS_TO_TICKS(MB_RECONNECT_TIME_MS));
}
bool mbm_port_tcp_recv_data(mb_port_base_t *inst, uint8_t **ppframe, uint16_t *plength)
{
mbm_tcp_port_t *port_obj = __containerof(inst, mbm_tcp_port_t, base);
mb_slave_info_t *pinfo = port_obj->pdriver->mb_slave_curr_info;
mb_node_info_t *pinfo = port_obj->pdriver->mb_node_curr;
MB_RETURN_ON_FALSE((pinfo), false, TAG, "incorrect current slave pointer.");
bool status = false;
size_t sz = mbm_drv_read(port_obj->pdriver, pinfo->fd, port_obj->ptemp_buf, MB_BUFFER_SIZE);
size_t sz = mb_drv_read(port_obj->pdriver, pinfo->fd, port_obj->ptemp_buf, MB_BUFFER_SIZE);
if (sz > MB_TCP_FUNC) {
uint16_t tid_counter = MB_TCP_MBAP_GET_FIELD(port_obj->ptemp_buf, MB_TCP_TID);
if (tid_counter == (pinfo->tid_counter - 1)) {
*ppframe = port_obj->ptemp_buf;
*plength = sz;
ESP_LOGW(TAG, "%p, "MB_SLAVE_FMT(", received packet TID = 0x%.4x:(0x%.4x), %p."),
ESP_LOGD(TAG, "%p, "MB_NODE_FMT(", get packet TID: 0x%04" PRIx16 ":0x%04" PRIx16 ", %p."),
port_obj->pdriver, pinfo->index, pinfo->sock_id, pinfo->addr_info.ip_addr_str,
tid_counter, pinfo->tid_counter, *ppframe);
(unsigned)tid_counter, (unsigned)pinfo->tid_counter, *ppframe);
uint64_t time = 0;
time = port_get_timestamp() - pinfo->send_time;
ESP_LOGW(TAG, "%p, "MB_SLAVE_FMT(", processing time[us] = %ju."), port_obj->pdriver, pinfo->index,
ESP_LOGD(TAG, "%p, "MB_NODE_FMT(", processing time[us] = %ju."), port_obj->pdriver, pinfo->index,
pinfo->sock_id, pinfo->addr_info.ip_addr_str, time);
status = true;
} else {
ESP_LOGE(TAG, "%p, "MB_SLAVE_FMT(", drop packet TID = 0x%.4x:0x%.4x, %p."),
ESP_LOGE(TAG, "%p, "MB_NODE_FMT(", drop packet TID: 0x%04" PRIx16 ":0x%04" PRIx16 ", %p."),
port_obj->pdriver, pinfo->index, pinfo->sock_id,
pinfo->addr_info.ip_addr_str, tid_counter, pinfo->tid_counter, *ppframe);
pinfo->addr_info.ip_addr_str, (unsigned)tid_counter, (unsigned)pinfo->tid_counter, *ppframe);
}
}
return status;
@@ -164,8 +255,8 @@ bool mbm_port_tcp_send_data(mb_port_base_t *inst, uint8_t address, uint8_t *pfra
bool frame_sent = false;
// get slave descriptor from its address
mb_slave_info_t *pinfo = (mb_slave_info_t *)mbm_drv_get_slave_info_from_addr(port_obj->pdriver, address);
MB_RETURN_ON_FALSE((pinfo && (MB_GET_SLAVE_STATE(pinfo) >= MB_SOCK_STATE_CONNECTED)),
mb_node_info_t *pinfo = (mb_node_info_t *)mb_drv_get_node_info_from_addr(port_obj->pdriver, address);
MB_RETURN_ON_FALSE((pinfo && (MB_GET_NODE_STATE(pinfo) >= MB_SOCK_STATE_CONNECTED)),
false, TAG, "the slave address #%d is not registered.", address);
if (pinfo && pframe) {
@@ -174,17 +265,17 @@ bool mbm_port_tcp_send_data(mb_port_base_t *inst, uint8_t address, uint8_t *pfra
pframe[MB_TCP_UID] = (uint8_t)(pinfo->addr_info.uid);
}
ESP_LOGW(TAG, "%p, send fd: %d, sock_id: %d[%s], %p, len: %d",
ESP_LOGD(TAG, "%p, send fd: %d, sock_id: %d[%s], %p, len: %d",
port_obj->pdriver, pinfo->fd, pinfo->sock_id, pinfo->addr_info.node_name_str, pframe, length);
// Write data to the modbus vfs driver send queue of the slave
int write_length = mbm_drv_write(port_obj->pdriver, pinfo->fd, pframe, length);
// Write data to the modbus driver send queue of the slave
int write_length = mb_drv_write(port_obj->pdriver, pinfo->fd, pframe, length);
if (write_length) {
frame_sent = true;
} else {
ESP_LOGE(TAG, "mbm_write fail, returns %d.", write_length);
}
// mb_port_tmr_respond_timeout_enable(inst); // the timer is set in the transport
// mb_port_timer_respond_timeout_enable(inst); // the timer is set in the transport
return frame_sent;
}
@@ -192,7 +283,7 @@ bool mbm_port_tcp_send_data(mb_port_base_t *inst, uint8_t address, uint8_t *pfra
void mbm_port_tcp_set_conn_cb(mb_port_base_t *inst, void *conn_fp, void *arg)
{
mbm_tcp_port_t *port_obj = __containerof(inst, mbm_tcp_port_t, base);
mbm_drv_set_cb(port_obj->pdriver, conn_fp, arg);
mb_drv_set_cb(port_obj->pdriver, conn_fp, arg);
}
// Timer handler to check timeout of socket response
@@ -204,20 +295,20 @@ bool mbm_port_timer_expired(void *inst)
mb_event_info_t mb_event;
esp_err_t err = ESP_FAIL;
mb_port_tmr_disable(inst);
mb_port_timer_disable(inst);
// If timer mode is respond timeout, the master event then turns EV_MASTER_EXECUTE status.
if (mb_port_get_cur_tmr_mode(inst) == MB_TMODE_RESPOND_TIMEOUT) {
if (mb_port_get_cur_timer_mode(inst) == MB_TMODE_RESPOND_TIMEOUT) {
// It is now to check solution.
mb_event.event_id = MB_EVENT_TIMEOUT;
mb_event.opt_fd = port_obj->pdriver->curr_slave_index;
mb_event.opt_fd = port_obj->pdriver->curr_node_index;
err = esp_event_isr_post_to(port_obj->pdriver->event_loop_hdl, MB_EVENT_BASE(port_obj->pdriver),
(int32_t)MB_EVENT_TIMEOUT, (void *)&mb_event, sizeof(mb_event_info_t*), &task_unblocked);
if (err != ESP_OK) {
ESP_EARLY_LOGE(TAG, "Timeout event send error: %d", err);
}
need_poll = task_unblocked;
mb_port_evt_set_err_type(inst, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_evt_post(inst, EVENT(EV_ERROR_PROCESS));
mb_port_event_set_err_type(inst, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_event_post(inst, EVENT(EV_ERROR_PROCESS));
}
return need_poll;
}
@@ -226,34 +317,376 @@ mb_uid_info_t *mbm_port_tcp_get_slave_info(mb_port_base_t *inst, uint8_t slave_a
{
mbm_tcp_port_t *port_obj = __containerof(inst, mbm_tcp_port_t, base);
mb_uid_info_t *paddr_info = NULL;
mb_slave_info_t *pinfo = mbm_drv_get_slave_info_from_addr(port_obj->pdriver, slave_addr);
if (pinfo && (MB_GET_SLAVE_STATE(pinfo) >= exp_state)) {
mb_node_info_t *pinfo = mb_drv_get_node_info_from_addr(port_obj->pdriver, slave_addr);
if (pinfo && (MB_GET_NODE_STATE(pinfo) >= exp_state)) {
paddr_info = &pinfo->addr_info;
}
return paddr_info;
}
static void mbm_port_tcp_sync_event(void *inst, mb_sync_event_t sync_event)
static uint64_t mbm_port_tcp_sync_event(void *inst, mb_sync_event_t sync_event)
{
switch(sync_event) {
case MB_SYNC_EVENT_RECV_OK:
mb_port_tmr_disable(inst);
mb_port_evt_set_err_type(inst, EV_ERROR_INIT);
mb_port_evt_post(inst, EVENT(EV_FRAME_RECEIVED));
mb_port_timer_disable(inst);
mb_port_event_set_err_type(inst, EV_ERROR_INIT);
mb_port_event_post(inst, EVENT(EV_FRAME_RECEIVED));
break;
case MB_SYNC_EVENT_RECV_FAIL:
mb_port_tmr_disable(inst);
mb_port_evt_set_err_type(inst, EV_ERROR_RECEIVE_DATA);
mb_port_evt_post(inst, EVENT(EV_ERROR_PROCESS));
mb_port_timer_disable(inst);
mb_port_event_set_err_type(inst, EV_ERROR_RECEIVE_DATA);
mb_port_event_post(inst, EVENT(EV_ERROR_PROCESS));
break;
case MB_SYNC_EVENT_SEND_OK:
mb_port_evt_post(inst, EVENT(EV_FRAME_SENT));
mb_port_event_post(inst, EVENT(EV_FRAME_SENT));
break;
default:
break;
}
return mb_port_get_trans_id(inst);
}
MB_EVENT_HANDLER(mbm_on_ready)
{
// The driver is registered
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
}
MB_EVENT_HANDLER(mbm_on_open)
{
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
}
MB_EVENT_HANDLER(mbm_on_resolve)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
if (MB_CHECK_FD_RANGE(pevent_info->opt_fd)) {
// The mdns is not used in the main app, then can use manually defined IPs
int fd = pevent_info->opt_fd;
mb_node_info_t *pslave = mb_drv_get_node(pdrv_ctx, fd);
if (pslave && (MB_GET_NODE_STATE(pslave) == MB_SOCK_STATE_OPENED)
&& FD_ISSET(pslave->index, &pdrv_ctx->open_set)) {
mb_status_flags_t status = mb_drv_wait_status_flag(pdrv_ctx, MB_FLAG_DISCONNECTED, 0);
if ((status & MB_FLAG_DISCONNECTED)) {
ESP_LOGV(TAG, "%p, slave: %d, sock: %d, IP:%s, disconnected.",
ctx, (int)pslave->index, (int)pslave->sock_id, pslave->addr_info.ip_addr_str);
return;
}
// The slave IP is defined manually
if (port_check_host_addr(pslave->addr_info.node_name_str, NULL)) {
pslave->addr_info.ip_addr_str = pslave->addr_info.node_name_str;
ESP_LOGD(TAG, "%p, slave: %d, IP address [%s], added to connection list.", ctx, (int)fd, pslave->addr_info.ip_addr_str);
MB_SET_NODE_STATE(pslave, MB_SOCK_STATE_RESOLVED);
DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, pslave->index);
} else {
#ifdef MB_MDNS_IS_INCLUDED
int ret = port_resolve_mdns_host(pslave->addr_info.node_name_str, (char **)&pslave->addr_info.ip_addr_str);
if (ret > 0) {
ESP_LOGI(TAG, "%p, slave: %d, resolved with IP:%s.", ctx, (int)fd, pslave->addr_info.ip_addr_str);
MB_SET_NODE_STATE(pslave, MB_SOCK_STATE_RESOLVED);
DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, pslave->index);
} else {
// continue resolve while not resolved
DRIVER_SEND_EVENT(ctx, MB_EVENT_RESOLVE, pslave->index);
}
#else
ESP_LOGE(TAG, "%p, slave: %d, IP:%s, mdns service is not supported.", ctx, (int)fd, pslave->addr_info.node_name_str);
DRIVER_SEND_EVENT(ctx, MB_EVENT_RESOLVE, pslave->index);
#endif
}
}
} else if (pevent_info->opt_fd < 0) {
// Todo: query for services is removed from this version
// #ifdef MB_MDNS_IS_INCLUDED
// // If the mDNS feature support is enabled, use it to resolve the slave IP
// res = mb_drv_resolve_mdns_service(ctx, "_modbus", "_tcp", pdrv_ctx->addr_type);
// ESP_LOGD(TAG, "%p, use mdns to resolve slave: %d, resolved: %d devices.", ctx, (int)pevent_info->opt_fd, res);
// #else
for (int fd = 0; fd < pdrv_ctx->mb_node_open_count; fd++) {
mb_node_info_t *pslave = mb_drv_get_node(pdrv_ctx, fd);
if (pslave && (MB_GET_NODE_STATE(pslave) == MB_SOCK_STATE_OPENED)
&& FD_ISSET(pslave->index, &pdrv_ctx->open_set)) {
DRIVER_SEND_EVENT(ctx, MB_EVENT_RESOLVE, pslave->index);
}
mb_drv_check_suspend_shutdown(ctx);
}
// #endif
}
}
MB_EVENT_HANDLER(mbm_on_connect)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_node_info_t *pnode_info = NULL;
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
err_t err = ERR_CONN;
if (MB_CHECK_FD_RANGE(pevent_info->opt_fd)) {
pnode_info = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd);
if (pnode_info && (MB_GET_NODE_STATE(pnode_info) < MB_SOCK_STATE_CONNECTED)) {
ESP_LOGD(TAG, "%p, connection phase, slave: #%d(%d) [%s].",
ctx, (int)pevent_info->opt_fd, (int)pnode_info->sock_id, pnode_info->addr_info.ip_addr_str);
if (pnode_info->sock_id != UNDEF_FD) {
port_close_connection(pnode_info);
}
err = port_connect(ctx, pnode_info);
switch (err) {
case ERR_OK:
if (!FD_ISSET(pnode_info->sock_id, &pdrv_ctx->conn_set)) {
FD_SET(pnode_info->sock_id, &pdrv_ctx->conn_set);
mb_drv_lock(ctx);
pdrv_ctx->node_conn_count++;
pdrv_ctx->max_conn_sd = (pnode_info->sock_id > pdrv_ctx->max_conn_sd) ? (int)pnode_info->sock_id : pdrv_ctx->max_conn_sd;
// Update time stamp for connected slaves
pnode_info->send_time = esp_timer_get_time();
pnode_info->recv_time = esp_timer_get_time();
mb_drv_unlock(ctx);
ESP_LOGI(TAG, "%p, slave: #%d, sock:%d, IP: %s, is connected.",
ctx, (int)pevent_info->opt_fd, (int)pnode_info->sock_id,
pnode_info->addr_info.ip_addr_str);
}
MB_SET_NODE_STATE(pnode_info, MB_SOCK_STATE_CONNECTED);
port_keep_alive(pnode_info);
break;
case ERR_INPROGRESS:
if (FD_ISSET(pnode_info->sock_id, &pdrv_ctx->conn_set)) {
FD_CLR(pnode_info->sock_id, &pdrv_ctx->conn_set);
ESP_LOGD(TAG, "%p, slave: #%d, sock:%d, IP:%s, connect fail error = %d.",
ctx, (int)pevent_info->opt_fd, (int)pnode_info->sock_id,
pnode_info->addr_info.ip_addr_str, (int)err);
mb_drv_lock(ctx);
if (pdrv_ctx->node_conn_count) {
pdrv_ctx->node_conn_count--;
}
mb_drv_unlock(ctx);
}
MB_SET_NODE_STATE(pnode_info, MB_SOCK_STATE_CONNECTING);
vTaskDelay(MB_CONN_TICK_TIMEOUT);
// try to connect to slave and check connection again if it is not connected
DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, pevent_info->opt_fd);
break;
case ERR_CONN:
ESP_LOGE(TAG, "Modbus connection phase, slave: %d [%s], connection error (%d).",
(int)pevent_info->opt_fd, pnode_info->addr_info.ip_addr_str, (int)err);
break;
default:
ESP_LOGE(TAG, "Invalid error state, slave: %d [%s], error = %d.",
(int)pevent_info->opt_fd, pnode_info->addr_info.ip_addr_str, (int)err);
break;
}
}
} else {
// if the event fd is UNDEF_FD (an event for all slaves),
// then perform connection phase for all resolved slaves sending the connection event
for (int node = 0; (node < MB_TCP_PORT_MAX_CONN); node++) {
pnode_info = mb_drv_get_node(pdrv_ctx, node);
if (pnode_info && (MB_GET_NODE_STATE(pnode_info) == MB_SOCK_STATE_RESOLVED)) {
if (((pnode_info->sock_id < 0) || !FD_ISSET(pnode_info->sock_id, &pdrv_ctx->conn_set))
&& FD_ISSET(node, &pdrv_ctx->open_set)) {
DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, pnode_info->index);
}
}
mb_drv_check_suspend_shutdown(ctx);
}
}
ESP_LOGD(TAG, "Opened/connected: %u, %u.",
(unsigned)pdrv_ctx->mb_node_open_count, (unsigned)pdrv_ctx->node_conn_count);
if (pdrv_ctx->mb_node_open_count == pdrv_ctx->node_conn_count) {
if (pdrv_ctx->event_cbs.on_conn_done_cb) {
pdrv_ctx->event_cbs.on_conn_done_cb(pdrv_ctx->event_cbs.arg);
}
ESP_LOGI(TAG, "%p, Connected: %u, %u, start polling.",
ctx, (unsigned)pdrv_ctx->mb_node_open_count, (unsigned)pdrv_ctx->node_conn_count);
}
}
MB_EVENT_HANDLER(mbm_on_error)
{
static int curr_fd = 0;
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
mb_node_info_t *pnode_info = NULL;
if (MB_CHECK_FD_RANGE(pevent_info->opt_fd)) {
mb_drv_check_suspend_shutdown(ctx);
mb_status_flags_t status = mb_drv_wait_status_flag(pdrv_ctx, MB_FLAG_DISCONNECTED, 0);
if ((status & MB_FLAG_DISCONNECTED)) {
ESP_LOGE(TAG, "%p, node: %d, is in disconnected state.", ctx, (int)pevent_info->opt_fd);
return;
}
curr_fd = pevent_info->opt_fd;
pnode_info = mb_drv_get_next_node_from_set(ctx, &curr_fd, &pdrv_ctx->conn_set);
if (pnode_info && (status > 0)) {
uint64_t last_read_div_us = esp_timer_get_time() - pnode_info->recv_time;
ESP_LOGD(TAG, "%p, slave: %d, sock: %d, IP:%s, check connection, time = %" PRId64 ", rcv_time: %" PRId64,
ctx, (int)pnode_info->index, (int)pnode_info->sock_id, pnode_info->addr_info.ip_addr_str,
(esp_timer_get_time() / 1000), pnode_info->recv_time / 1000);
if (last_read_div_us >= (uint64_t)(MB_RECONNECT_TIME_MS * 1000)) {
mb_drv_check_suspend_shutdown(ctx);
err_t err = port_check_alive(pnode_info, MB_RECONNECT_TIME_MS);
if (err < 0) {
ESP_LOGD(TAG, "%p, slave: %d, sock: %d, inactive for %" PRId64 " [ms], reconnect...",
ctx, (int)pnode_info->index, (int)pnode_info->sock_id,
(last_read_div_us / 1000));
MB_SET_NODE_STATE(pnode_info, MB_SOCK_STATE_OPENED);
FD_CLR(pnode_info->sock_id, &pdrv_ctx->conn_set);
port_close_connection(pnode_info);
mb_drv_lock(ctx);
pdrv_ctx->node_conn_count--;
mb_drv_unlock(ctx);
DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, pnode_info->index);
} else {
curr_fd++;
}
} else {
ESP_LOGD(TAG, "%p, slave: %d, sock: %d, inactive for %" PRId64 " [ms], wait reconnection...",
ctx, (int)pnode_info->index, (int)pnode_info->sock_id,
(last_read_div_us / 1000));
}
}
} else if (pevent_info->opt_fd < 0) {
// send resolve event to all slaves
for (int fd = 0; fd < pdrv_ctx->mb_node_open_count; fd++) {
mb_drv_check_suspend_shutdown(ctx);
mb_node_info_t *pslave = mb_drv_get_node(pdrv_ctx, fd);
if (pslave && (MB_GET_NODE_STATE(pslave) == MB_SOCK_STATE_OPENED)
&& FD_ISSET(pslave->index, &pdrv_ctx->open_set)) {
DRIVER_SEND_EVENT(ctx, MB_EVENT_RESOLVE, pslave->index);
}
}
}
}
MB_EVENT_HANDLER(mbm_on_send_data)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
mb_drv_check_suspend_shutdown(ctx);
mb_node_info_t *pinfo = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd);
if (pinfo && !queue_is_empty(pinfo->tx_queue)) {
uint8_t tx_buffer[MB_TCP_BUFF_MAX_SIZE] = {0};
ESP_LOGD(TAG, "%p, get info: %d, sock_id: %d, queue_state: %d, state: %d.",
ctx, (int)pevent_info->opt_fd, (int)pinfo->sock_id,
(int)queue_is_empty(pinfo->tx_queue), (int)MB_GET_NODE_STATE(pinfo));
size_t sz = queue_pop(pinfo->tx_queue, tx_buffer, sizeof(tx_buffer), NULL);
if (MB_GET_NODE_STATE(pinfo) < MB_SOCK_STATE_CONNECTED) {
// if slave is not connected, drop data.
ESP_LOGE(TAG, "%p, "MB_NODE_FMT(", is invalid, drop send data."),
ctx, (int)pinfo->index, (int)pinfo->sock_id, pinfo->addr_info.ip_addr_str);
return;
}
int ret = port_write_poll(pinfo, tx_buffer, sz, MB_TCP_SEND_TIMEOUT_MS);
if (ret < 0) {
ESP_LOGE(TAG, "%p, "MB_NODE_FMT(", send data failure, err(errno) = %d(%u)."),
ctx, (int)pinfo->index, (int)pinfo->sock_id,
pinfo->addr_info.ip_addr_str, (int)ret, (unsigned)errno);
DRIVER_SEND_EVENT(ctx, MB_EVENT_ERROR, pinfo->index);
pinfo->error = ret;
} else {
ESP_LOGD(TAG, "%p, "MB_NODE_FMT(", send data successful: TID:0x%04x, %d (bytes), errno %d"),
ctx, (int)pinfo->index, (int)pinfo->sock_id,
pinfo->addr_info.ip_addr_str, (unsigned)pinfo->tid_counter, (int)ret, (unsigned)errno);
pinfo->error = 0;
// Every successful write increase TID counter
if (pinfo->tid_counter < (USHRT_MAX - 1)) {
pinfo->tid_counter++;
} else {
pinfo->tid_counter = (uint16_t)(pinfo->index << 8U);
}
}
pdrv_ctx->event_cbs.mb_sync_event_cb(pdrv_ctx->event_cbs.port_arg, MB_SYNC_EVENT_SEND_OK);
mb_drv_lock(ctx);
pdrv_ctx->mb_node_curr = pinfo;
pdrv_ctx->curr_node_index = pinfo->index;
pinfo->send_time = esp_timer_get_time();
pinfo->send_counter = (pinfo->send_counter < (USHRT_MAX - 1)) ? (pinfo->send_counter + 1) : 0;
mb_drv_unlock(ctx);
// Get send buffer from stack
ESP_LOG_BUFFER_HEX_LEVEL("SENT", tx_buffer, sz, ESP_LOG_DEBUG);
}
}
MB_EVENT_HANDLER(mbm_on_recv_data)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
size_t sz = 0;
uint8_t pbuf[MB_TCP_BUFF_MAX_SIZE] = {0};
mb_drv_check_suspend_shutdown(ctx);
// Get frame from queue, check for correctness, push back correct frame and generate receive condition.
// Removes incorrect or expired frames from the queue, leave just correct one then sent sync event
mb_node_info_t *pnode_info = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd);
if (pnode_info) {
ESP_LOGD(TAG, "%p, slave #%d(%d) [%s], receive data ready.", ctx, (int)pevent_info->opt_fd,
(int)pnode_info->sock_id, pnode_info->addr_info.ip_addr_str);
while ((sz <= 0) && !queue_is_empty(pnode_info->rx_queue)) {
size_t sz = queue_pop(pnode_info->rx_queue, pbuf, MB_TCP_BUFF_MAX_SIZE, NULL);
if ((sz > MB_TCP_FUNC) && (sz < sizeof(pbuf))) {
uint16_t tid = MB_TCP_MBAP_GET_FIELD(pbuf, MB_TCP_TID);
ESP_LOGD(TAG, "%p, packet TID: 0x%04" PRIx16 " received.", ctx, tid);
if (tid == (pnode_info->tid_counter - 1)) {
queue_push(pnode_info->rx_queue, pbuf, sz, NULL);
mb_drv_lock(ctx);
pnode_info->recv_time = esp_timer_get_time();
mb_drv_unlock(ctx);
// send receive event to modbus object
pdrv_ctx->event_cbs.mb_sync_event_cb(pdrv_ctx->event_cbs.port_arg, MB_SYNC_EVENT_RECV_OK);
break;
}
}
mb_drv_check_suspend_shutdown(ctx);
}
}
}
MB_EVENT_HANDLER(mbm_on_close)
{
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s, fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
// if close all sockets event is received
if (pevent_info->opt_fd < 0) {
(void)mb_drv_clear_status_flag(pdrv_ctx, MB_FLAG_DISCONNECTED);
for (int fd = 0; fd < MB_MAX_FDS; fd++) {
mb_node_info_t *pslave = mb_drv_get_node(pdrv_ctx, fd);
if (pslave && (MB_GET_NODE_STATE(pslave) >= MB_SOCK_STATE_OPENED)
&& FD_ISSET(pslave->index, &pdrv_ctx->open_set)) {
mb_drv_lock(ctx);
// Check connection and unregister slave
if ((pslave->sock_id > 0) && (FD_ISSET(pslave->sock_id, &pdrv_ctx->conn_set)) ) {
FD_CLR(pslave->sock_id, &pdrv_ctx->conn_set);
if (pdrv_ctx->node_conn_count) {
pdrv_ctx->node_conn_count--;
}
}
FD_CLR(pslave->index, &pdrv_ctx->open_set);
mb_drv_unlock(ctx);
// close the socket connection, if active
(void)port_close_connection(pslave);
// change slave state immediately to release from select
MB_SET_NODE_STATE(pslave, MB_SOCK_STATE_READY);
}
}
(void)mb_drv_set_status_flag(pdrv_ctx, MB_FLAG_DISCONNECTED);
mb_drv_check_suspend_shutdown(ctx);
}
}
MB_EVENT_HANDLER(mbm_on_timeout)
{
// Socket read/write timeout is triggered
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
// Todo: this event can be used to check network state (kkep empty for now)
mb_drv_check_suspend_shutdown(ctx);
}
#endif
+12 -1
View File
@@ -15,6 +15,8 @@
#include "mb_common.h"
#include "mb_frame.h"
#include "port_tcp_driver.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -26,7 +28,16 @@ typedef struct _uid_info mb_uid_info_t;
void mbm_port_tcp_set_conn_cb(mb_port_base_t *inst, void *conn_fp, void *arg);
mb_uid_info_t *mbm_port_tcp_get_slave_info(mb_port_base_t *inst, uint8_t uid, mb_sock_state_t exp_state);
//bool mbm_port_timer_expired(void *inst);
MB_EVENT_HANDLER(mbm_on_ready);
MB_EVENT_HANDLER(mbm_on_open);
MB_EVENT_HANDLER(mbm_on_resolve);
MB_EVENT_HANDLER(mbm_on_connect);
MB_EVENT_HANDLER(mbm_on_send_data);
MB_EVENT_HANDLER(mbm_on_recv_data);
MB_EVENT_HANDLER(mbm_on_error);
MB_EVENT_HANDLER(mbm_on_close);
MB_EVENT_HANDLER(mbm_on_timeout);
#endif
+553 -21
View File
@@ -3,10 +3,18 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <string.h>
#include "port_tcp_common.h"
#include "port_tcp_slave.h"
#include "port_tcp_driver.h"
#include "port_tcp_utils.h"
#include "mb_transaction.h"
#include "port_common.h" // use common port functions
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
@@ -15,59 +23,583 @@ typedef struct
mb_port_base_t base;
// TCP communication properties
mb_tcp_opts_t tcp_opts;
uint64_t transaction_cnt;
uint16_t recv_length;
uint64_t send_time_stamp;
uint64_t recv_time_stamp;
uint32_t flags;
TaskHandle_t task_handle;
} mb_tcp_port_t;
mb_uid_info_t addr_info;
uint8_t ptemp_buf[MB_TCP_BUFF_MAX_SIZE];
// The driver object for the slave
port_driver_t *pdriver;
transaction_handle_t transaction;
uint16_t trans_count;
} mbs_tcp_port_t;
/* ----------------------- Static variables & functions ----------------------*/
static const char *TAG = "mb_port.tcp.slave";
static uint64_t mbs_port_tcp_sync_event(void *inst, mb_sync_event_t sync_event);
static esp_err_t mbs_port_tcp_register_handlers(void *ctx)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
esp_err_t ret = ESP_ERR_INVALID_STATE;
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_READY, mbs_on_ready);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_READY);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_OPEN, mbs_on_open);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_OPEN);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_CONNECT, mbs_on_connect);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CONNECT);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_ERROR, mbs_on_error);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_ERROR);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_SEND_DATA, mbs_on_send_data);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_SEND_DATA);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_RECV_DATA, mbs_on_recv_data);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_RECV_DATA);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_CLOSE, mbs_on_close);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CLOSE);
ret = mb_drv_register_handler(pdrv_ctx, MB_EVENT_TIMEOUT, mbs_on_timeout);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_TIMEOUT);
return ESP_OK;
}
static esp_err_t mbs_port_tcp_unregister_handlers(void *ctx)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
esp_err_t ret = ESP_ERR_INVALID_STATE;
ESP_LOGD(TAG, "%p, event handler %p, unregister.", pdrv_ctx, pdrv_ctx->event_handler);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_READY);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_READY);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_OPEN);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_OPEN);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_CONNECT);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CONNECT);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_SEND_DATA);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_SEND_DATA);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_RECV_DATA);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_RECV_DATA);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_CLOSE);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_CLOSE);
ret = mb_drv_unregister_handler(pdrv_ctx, MB_EVENT_TIMEOUT);
MB_RETURN_ON_FALSE((ret == ESP_OK), MB_EINVAL, TAG,
"%x, mb tcp port event registration failed.", (int)MB_EVENT_TIMEOUT);
return ESP_OK;
}
mb_err_enum_t mbs_port_tcp_create(mb_tcp_opts_t *tcp_opts, mb_port_base_t **port_obj)
{
mb_tcp_port_t *ptcp = NULL;
ptcp = (mb_tcp_port_t*)calloc(1, sizeof(mb_tcp_port_t));
MB_RETURN_ON_FALSE((port_obj && tcp_opts), MB_EINVAL, TAG, "mb tcp port invalid arguments.");
mbs_tcp_port_t *ptcp = NULL;
esp_err_t err = ESP_ERR_INVALID_STATE;
ptcp = (mbs_tcp_port_t *)calloc(1, sizeof(mbs_tcp_port_t));
MB_RETURN_ON_FALSE((ptcp && port_obj), MB_EILLSTATE, TAG, "mb tcp port creation error.");
CRITICAL_SECTION_INIT(ptcp->base.lock);
mb_err_enum_t ret = MB_EILLSTATE;
// Copy object descriptor from parent object (is used for logging)
ptcp->base.descr = ((mb_port_base_t *)*port_obj)->descr;
ptcp->pdriver = NULL;
ptcp->transaction = transaction_init();
MB_GOTO_ON_FALSE((ptcp->transaction), MB_EILLSTATE, error,
TAG, "mb transaction init failed.");
ESP_MEM_CHECK(TAG, ptcp->transaction, goto error);
err = mb_drv_register(&ptcp->pdriver);
MB_GOTO_ON_FALSE(((err == ESP_OK) && ptcp->pdriver), MB_EILLSTATE, error,
TAG, "mb tcp port driver registration failed, err = (%x).", (int)err);
err = mbs_port_tcp_register_handlers(ptcp->pdriver);
MB_GOTO_ON_FALSE(((err == ESP_OK) && ptcp->pdriver), MB_EILLSTATE, error,
TAG, "mb tcp port driver registration failed, err = (%x).", (int)err);
ptcp->pdriver->parent = ptcp; // just for logging purposes
ptcp->tcp_opts = *tcp_opts;
ptcp->pdriver->network_iface_ptr = tcp_opts->ip_netif_ptr;
ptcp->pdriver->mb_proto = tcp_opts->mode;
ptcp->pdriver->uid = tcp_opts->uid;
ptcp->pdriver->is_master = false;
ptcp->pdriver->event_cbs.mb_sync_event_cb = mbs_port_tcp_sync_event;
ptcp->pdriver->event_cbs.port_arg = (void *)ptcp;
#ifdef MB_MDNS_IS_INCLUDED
err = port_start_mdns_service(&ptcp->pdriver->dns_name, false, tcp_opts->uid, ptcp->pdriver->network_iface_ptr);
MB_GOTO_ON_FALSE((err == ESP_OK), MB_EILLSTATE, error,
TAG, "mb tcp port mdns service init failure.");
ESP_LOGD(TAG, "Start mdns for @%p", ptcp);
#endif
// ptcp->base.cb.tmr_expired = mbs_port_timer_expired;
ptcp->base.cb.tx_empty = NULL;
ptcp->base.cb.byte_rcvd = NULL;
ptcp->base.arg = (void *)ptcp;
*port_obj = &(ptcp->base);
ESP_LOGD(TAG, "created object @%p", ptcp);
return MB_ENOERR;
error:
if (ptcp && ptcp->transaction)
{
transaction_destroy(ptcp->transaction);
}
#ifdef MB_MDNS_IS_INCLUDED
port_stop_mdns_service(&ptcp->pdriver->dns_name);
#endif
if (ptcp && ptcp->pdriver)
{
if (ptcp->pdriver->event_handler)
{
mbs_port_tcp_unregister_handlers(ptcp->pdriver);
ptcp->pdriver->event_handler = NULL;
}
(void)mb_drv_unregister(ptcp->pdriver);
CRITICAL_SECTION_CLOSE(ptcp->base.lock);
}
free(ptcp);
return ret;
}
void mbs_port_tcp_delete(mb_port_base_t *inst)
{
mb_tcp_port_t *port_obj = __containerof(inst, mb_tcp_port_t, base);
//vTaskDelete(port_obj->task_handle);
mbs_tcp_port_t *port_obj = __containerof(inst, mbs_tcp_port_t, base);
if (port_obj && port_obj->transaction)
{
transaction_destroy(port_obj->transaction);
}
#ifdef MB_MDNS_IS_INCLUDED
port_stop_mdns_service(&port_obj->pdriver->dns_name);
#endif
if (port_obj && port_obj->pdriver)
{
if (port_obj->pdriver->event_handler)
{
mbs_port_tcp_unregister_handlers(port_obj->pdriver);
port_obj->pdriver->event_handler = NULL;
}
(void)mb_drv_unregister(port_obj->pdriver);
CRITICAL_SECTION_CLOSE(port_obj->base.lock);
}
CRITICAL_SECTION_CLOSE(inst->lock);
free(port_obj);
}
__attribute__((unused))
void mbs_port_tcp_enable(mb_port_base_t *inst)
{
// mb_tcp_port_t *port_obj = __containerof(inst, mb_tcp_port_t, base);
mbs_tcp_port_t *port_obj = __containerof(inst, mbs_tcp_port_t, base);
(void)mb_drv_start_task(port_obj->pdriver);
DRIVER_SEND_EVENT(port_obj->pdriver, MB_EVENT_READY, UNDEF_FD);
}
__attribute__((unused))
void mbs_port_tcp_disable(mb_port_base_t *inst)
{
// Todo: Temporary unused (needs update)
//mb_tcp_port_t *port_obj = __containerof(inst, mb_tcp_port_t, base);
mbs_tcp_port_t *port_obj = __containerof(inst, mbs_tcp_port_t, base);
// Change the state of all slaves to close
DRIVER_SEND_EVENT(port_obj->pdriver, MB_EVENT_CLOSE, UNDEF_FD);
(void)mb_drv_wait_status_flag(port_obj->pdriver, MB_FLAG_DISCONNECTED, pdMS_TO_TICKS(MB_RECONNECT_TIME_MS));
}
__attribute__((unused))
bool mbs_port_tcp_recv_data(mb_port_base_t *inst, uint8_t **ppframe, uint16_t *plength)
{
// mb_tcp_port_t *port_obj = __containerof(inst, mb_tcp_port_t, base);
return false;
mbs_tcp_port_t *port_obj = __containerof(inst, mbs_tcp_port_t, base);
port_driver_t *pdrv_ctx = port_obj->pdriver;
mb_node_info_t *pnode = NULL;
bool status = false;
transaction_item_handle_t item;
if (plength && ppframe && *ppframe)
{
mb_drv_lock(pdrv_ctx);
item = transaction_get_first(port_obj->transaction);
if (item && (transaction_item_get_state(item) == ACKNOWLEDGED))
{
uint16_t tid = 0;
int node_id = 0;
size_t len = 0;
uint8_t *pbuf = transaction_item_get_data(item, &len, &tid, &node_id);
pnode = mb_drv_get_node(pdrv_ctx, node_id);
if (pbuf && pnode && (MB_GET_NODE_STATE(pnode) >= MB_SOCK_STATE_CONNECTED))
{
memcpy(*ppframe, pbuf, len);
//*ppframe = pbuf;
*plength = (uint16_t)len;
status = true;
ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", get packet TID: 0x%04" PRIx16 ", %p."),
port_obj, pnode->index, pnode->sock_id,
pnode->addr_info.ip_addr_str, (unsigned)pnode->tid_counter, *ppframe);
if (ESP_OK != transaction_item_set_state(item, CONFIRMED)) {
ESP_LOGE(TAG, "transaction queue set state fail.");
}
}
} else {
// Delete expired frames
int frame_cnt = transaction_delete_expired(port_obj->transaction,
port_get_timestamp(),
(1000 * MB_MASTER_TIMEOUT_MS_RESPOND));
if (frame_cnt) {
ESP_LOGE(TAG, "Deleted %d expired frames.", frame_cnt);
}
}
mb_drv_unlock(pdrv_ctx);
}
return status;
}
bool mbs_port_tcp_send_data(mb_port_base_t *inst, uint8_t *pframe, uint16_t length)
{
// mb_tcp_port_t *port_obj = __containerof(inst, mb_tcp_port_t, base);
mbs_tcp_port_t *port_obj = __containerof(inst, mbs_tcp_port_t, base);
return false;
MB_RETURN_ON_FALSE((pframe && (length > 0)), false, TAG, "incorrect arguments.");
bool frame_sent = false;
uint16_t tid = MB_TCP_MBAP_GET_FIELD(pframe, MB_TCP_TID);
port_driver_t *pdrv_ctx = port_obj->pdriver;
transaction_item_handle_t item;
mb_drv_lock(pdrv_ctx);
item = transaction_dequeue(port_obj->transaction, CONFIRMED, NULL);
if (item) {
uint16_t msg_id = 0;
int node_id = 0;
uint8_t *pbuf = transaction_item_get_data(item, NULL, &msg_id, &node_id);
if (pbuf && (tid == msg_id)) {
mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, node_id);
int write_length = mb_drv_write(pdrv_ctx, node_id, pframe, length);
if (pnode && write_length) {
frame_sent = true;
ESP_LOGD(TAG, "%p, node: #%d, socket(#%d)[%s], send packet TID: 0x%04" PRIx16 ":0x%04" PRIx16 ", %p, len: %d, ",
pdrv_ctx, pnode->index, pnode->sock_id,
pnode->addr_info.node_name_str, (unsigned)tid, (unsigned)msg_id, pframe, length);
} else {
ESP_LOGE(TAG, "%p, node: #%d, socket(#%d)[%s], mbs_write fail, TID: 0x%04" PRIx16 ":0x%04" PRIx16 ", %p, len: %d, ",
pdrv_ctx, pnode->index, pnode->sock_id,
pnode->addr_info.node_name_str, (unsigned)tid, (unsigned)msg_id, pframe, length);
}
if (ESP_OK != transaction_item_set_state(item, REPLIED)) {
ESP_LOGE(TAG, "transaction queue set state fail.");
}
}
} else {
ESP_LOGE(TAG, "queue can not find the item to send.");
}
mb_drv_unlock(pdrv_ctx);
if (!frame_sent)
{
ESP_LOGE(TAG, "incorrect frame to send.");
}
return frame_sent;
}
static uint64_t mbs_port_tcp_sync_event(void *inst, mb_sync_event_t sync_event)
{
switch (sync_event)
{
case MB_SYNC_EVENT_RECV_OK:
mb_port_timer_disable(inst);
mb_port_event_set_err_type(inst, EV_ERROR_INIT);
mb_port_event_post(inst, EVENT(EV_FRAME_RECEIVED));
break;
case MB_SYNC_EVENT_RECV_FAIL:
mb_port_timer_disable(inst);
mb_port_event_set_err_type(inst, EV_ERROR_RECEIVE_DATA);
mb_port_event_post(inst, EVENT(EV_ERROR_PROCESS));
break;
case MB_SYNC_EVENT_SEND_OK:
mb_port_event_post(inst, EVENT(EV_FRAME_SENT));
break;
default:
break;
}
return mb_port_get_trans_id(inst);
}
MB_EVENT_HANDLER(mbs_on_ready)
{
// The driver is registered
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mbs_tcp_port_t *port_obj = __containerof(pdrv_ctx->parent, mbs_tcp_port_t, base);
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
ESP_LOGD(TAG, "addr_table:%p, addr_type:%d, mode:%d, port:%d", port_obj->tcp_opts.ip_addr_table,
(int)port_obj->tcp_opts.addr_type,
(int)port_obj->tcp_opts.mode,
(int)port_obj->tcp_opts.port);
int listen_sock = port_bind_addr(port_obj->tcp_opts.ip_addr_table,
port_obj->tcp_opts.addr_type,
port_obj->tcp_opts.mode,
port_obj->tcp_opts.port);
if (listen_sock < 0)
{
mb_drv_check_suspend_shutdown(ctx);
ESP_LOGE(TAG, "%s, sock: %d, bind error", (char *)base, listen_sock);
mb_drv_lock(pdrv_ctx);
if (pdrv_ctx->retry_cnt) pdrv_ctx->retry_cnt--;
mb_drv_unlock(pdrv_ctx);
if (pdrv_ctx->retry_cnt) {
vTaskDelay(TRANSACTION_TICKS);
DRIVER_SEND_EVENT(ctx, MB_EVENT_READY, UNDEF_FD);
} else {
DRIVER_SEND_EVENT(ctx, MB_EVENT_CLOSE, UNDEF_FD);
ESP_LOGE(TAG, "%s, stop binding.", (char *)base);
// mbs_port_tcp_disable(&port_obj->base);
}
}
else
{
mb_drv_lock(ctx);
pdrv_ctx->listen_sock_fd = listen_sock;
mb_drv_unlock(ctx);
ESP_LOGI(TAG, "%s %s: fd: %d, bind is done", (char *)base, __func__, (int)pevent_info->opt_fd);
}
}
MB_EVENT_HANDLER(mbs_on_open)
{
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
//port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
}
MB_EVENT_HANDLER(mbs_on_connect)
{
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd);
if (!pnode) {
ESP_LOGD(TAG, "%s %s: fd: %d, is closed.", (char *)base, __func__, (int)pevent_info->opt_fd);
return;
}
mb_drv_lock(ctx);
MB_SET_NODE_STATE(pnode, MB_SOCK_STATE_CONNECTED);
FD_SET(pnode->sock_id, &pdrv_ctx->conn_set);
mb_drv_unlock(ctx);
}
MB_EVENT_HANDLER(mbs_on_recv_data)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
mbs_tcp_port_t *port_obj = (mbs_tcp_port_t *)pdrv_ctx->parent;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd);
transaction_item_handle_t item = NULL;
if (pnode)
{
if (!queue_is_empty(pnode->rx_queue))
{
ESP_LOGD(TAG, "%p, node #%d(%d) [%s], receive data ready.", ctx, (int)pevent_info->opt_fd,
(int)pnode->sock_id, pnode->addr_info.ip_addr_str);
frame_entry_t frame_entry;
size_t sz = queue_pop(pnode->rx_queue, NULL, MB_BUFFER_SIZE, &frame_entry);
if (sz > MB_TCP_FUNC)
{
uint16_t tid_counter = MB_TCP_MBAP_GET_FIELD(frame_entry.pbuf, MB_TCP_TID);
ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", received packet TID: 0x%04" PRIx16 ", %p."),
pdrv_ctx, pnode->index, pnode->sock_id,
pnode->addr_info.ip_addr_str, (unsigned)tid_counter, frame_entry.pbuf);
mb_drv_lock(pdrv_ctx);
transaction_message_t msg;
msg.buffer = frame_entry.pbuf;
msg.len = frame_entry.len;
msg.msg_id = frame_entry.tid;
msg.node_id = pnode->index;
msg.pnode = pnode;
item = transaction_enqueue(port_obj->transaction, &msg, port_get_timestamp());
pnode->tid_counter = tid_counter; // assign the TID from frame to use it on send
mb_drv_unlock(pdrv_ctx);
}
}
mb_drv_lock(pdrv_ctx);
item = transaction_get_first(port_obj->transaction);
if (item)
{
if (transaction_item_get_state(item) == QUEUED)
{
// send receive event to modbus object to get the new data
uint16_t msg_id = 0;
uint64_t tick = 0;
(void)transaction_item_get_data(item, NULL, &msg_id, NULL);
tick = port_get_timestamp();
pdrv_ctx->event_cbs.mb_sync_event_cb(pdrv_ctx->event_cbs.port_arg, MB_SYNC_EVENT_RECV_OK);
transaction_set_tick(port_obj->transaction, msg_id, (transaction_tick_t)tick);
if (ESP_OK == transaction_item_set_state(item, ACKNOWLEDGED)) {
ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", acknoledged packet TID: 0x%04" PRIx16 "."),
pdrv_ctx, pnode->index, pnode->sock_id,
pnode->addr_info.ip_addr_str, (unsigned)msg_id);
}
}
else
{
if (transaction_item_get_state(item) != TRANSMITTED) {
// Todo: for test removing expired item
transaction_delete_expired(port_obj->transaction, port_get_timestamp(), 1000 * 1000);
}
if (MB_FLAG_TRANSACTION_DONE == mb_drv_wait_status_flag(port_obj->pdriver,
MB_FLAG_TRANSACTION_DONE,
TRANSACTION_TICKS)) {
(void)mb_drv_clear_status_flag(pdrv_ctx, MB_FLAG_TRANSACTION_DONE);
}
// postpone the packet processing
DRIVER_SEND_EVENT(ctx, MB_EVENT_RECV_DATA, pnode->index);
}
} else {
ESP_LOGE(TAG, "%p, no queued items found", ctx);
}
mb_drv_unlock(pdrv_ctx);
}
mb_drv_check_suspend_shutdown(ctx);
}
MB_EVENT_HANDLER(mbs_on_send_data)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
mbs_tcp_port_t *port_obj = (mbs_tcp_port_t *)pdrv_ctx->parent;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd);
if (pnode && !queue_is_empty(pnode->tx_queue))
{
frame_entry_t frame_entry;
// pop the frame entry, keep the buffer
size_t sz = queue_pop(pnode->tx_queue, NULL, MB_BUFFER_SIZE, &frame_entry);
if (!sz || (MB_GET_NODE_STATE(pnode) < MB_SOCK_STATE_CONNECTED)) {
ESP_LOGE(TAG, "%p, "MB_NODE_FMT(", is invalid, drop data."),
ctx, (int)pnode->index, (int)pnode->sock_id, pnode->addr_info.ip_addr_str);
return;
}
uint16_t tid = MB_TCP_MBAP_GET_FIELD(frame_entry.pbuf, MB_TCP_TID);
pnode->error = 0;
int ret = port_write_poll(pnode, frame_entry.pbuf, sz, MB_TCP_SEND_TIMEOUT_MS);
if (ret < 0)
{
ESP_LOGE(TAG, "%p, " MB_NODE_FMT(", send data failure, err(errno) = %d(%u)."),
ctx, (int)pnode->index, (int)pnode->sock_id,
pnode->addr_info.ip_addr_str, (int)ret, (unsigned)errno);
DRIVER_SEND_EVENT(ctx, MB_EVENT_ERROR, pnode->index);
pnode->error = ret;
}
else
{
pnode->error = 0;
if (tid != pnode->tid_counter)
{
ESP_LOGE(TAG, "%p, " MB_NODE_FMT(", send incorrect frame TID:0x%04" PRIx16 "!= 0x%04" PRIx16 ", %d (bytes), errno %d"),
ctx, (int)pnode->index, (int)pnode->sock_id,
pnode->addr_info.ip_addr_str, pnode->tid_counter, tid, (int)ret, (unsigned)errno);
}
else
{
ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", send data successful: TID:0x%04" PRIx16 ":0x%04" PRIx16 ", %d (bytes), errno %d"),
ctx, (int)pnode->index, (int)pnode->sock_id,
pnode->addr_info.ip_addr_str, pnode->tid_counter, tid, (int)ret, (unsigned)errno);
}
ESP_LOG_BUFFER_HEX_LEVEL("SENT", frame_entry.pbuf, ret, ESP_LOG_DEBUG);
}
(void)mb_drv_set_status_flag(pdrv_ctx, MB_FLAG_TRANSACTION_DONE);
pdrv_ctx->event_cbs.mb_sync_event_cb(pdrv_ctx->event_cbs.port_arg, MB_SYNC_EVENT_SEND_OK);
mb_drv_lock(pdrv_ctx);
transaction_set_state(port_obj->transaction, tid, TRANSMITTED);
if (transaction_delete(port_obj->transaction, tid) != ESP_OK) {
ESP_LOGE(TAG, "Failed to remove queued TID:0x%04" PRIx16, tid);
} else {
ESP_LOGD(TAG, "Remove the message TID:0x%04" PRIx16, tid);
}
free(frame_entry.pbuf);
pnode->send_time = esp_timer_get_time();
pnode->send_counter = (pnode->send_counter < (USHRT_MAX - 1)) ? (pnode->send_counter + 1) : 0;
mb_drv_unlock(pdrv_ctx);
}
}
MB_EVENT_HANDLER(mbs_on_error)
{
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd);
if (!pnode) {
ESP_LOGD(TAG, "%s %s: fd: %d, is closed.", (char *)base, __func__, (int)pevent_info->opt_fd);
return;
}
port_close_connection(pnode);
mb_drv_lock(ctx);
// Check connection and unregister slave
if ((pnode->sock_id > 0) && (FD_ISSET(pnode->sock_id, &pdrv_ctx->conn_set)))
{
FD_CLR(pnode->sock_id, &pdrv_ctx->conn_set);
if (pdrv_ctx->node_conn_count)
{
pdrv_ctx->node_conn_count--;
}
}
if (pnode->index && (FD_ISSET(pnode->index, &pdrv_ctx->open_set))) {
FD_CLR(pnode->index, &pdrv_ctx->open_set);
}
mb_drv_unlock(ctx);
mb_drv_close(pdrv_ctx, pevent_info->opt_fd);
}
MB_EVENT_HANDLER(mbs_on_close)
{
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
ESP_LOGD(TAG, "%s %s, fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
// if close all sockets event is received
if (pevent_info->opt_fd < 0)
{
(void)mb_drv_clear_status_flag(pdrv_ctx, MB_FLAG_DISCONNECTED);
for (int fd = 0; fd < MB_MAX_FDS; fd++)
{
mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, fd);
if (pnode && (MB_GET_NODE_STATE(pnode) >= MB_SOCK_STATE_OPENED)
&& FD_ISSET(pnode->index, &pdrv_ctx->open_set))
{
mb_drv_lock(ctx);
// Check connection and unregister slave
if ((pnode->sock_id > 0) && (FD_ISSET(pnode->sock_id, &pdrv_ctx->conn_set)))
{
FD_CLR(pnode->sock_id, &pdrv_ctx->conn_set);
if (pdrv_ctx->node_conn_count) {
pdrv_ctx->node_conn_count--;
}
}
FD_CLR(pnode->index, &pdrv_ctx->open_set);
mb_drv_unlock(ctx);
// close the socket connection, if active
(void)port_close_connection(pnode);
// change slave state immediately to release from select
MB_SET_NODE_STATE(pnode, MB_SOCK_STATE_READY);
}
}
(void)mb_drv_set_status_flag(pdrv_ctx, MB_FLAG_DISCONNECTED);
mb_drv_check_suspend_shutdown(ctx);
}
}
MB_EVENT_HANDLER(mbs_on_timeout)
{
// Slave timeout triggered
mb_event_info_t *pevent_info = (mb_event_info_t *)data;
//port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
ESP_LOGD(TAG, "%s %s: fd: %d", (char *)base, __func__, (int)pevent_info->opt_fd);
// Todo: add network diagnostic here (ping)? Keep empty for now.
//mb_drv_check_node_state(pdrv_ctx, UNDEF_FD);
mb_drv_check_suspend_shutdown(ctx);
}
#endif
+56
View File
@@ -0,0 +1,56 @@
#pragma once
/* ----------------------- Platform includes --------------------------------*/
#include "esp_log.h"
#include <stdio.h>
#include <string.h>
#include "esp_err.h"
#include "esp_timer.h"
#include "sys/time.h"
#include "esp_netif.h"
/* ----------------------- lwIP includes ------------------------------------*/
// #include "lwip/opt.h"
// #include "lwip/sys.h"
// #include "lwip/err.h"
// #include "lwip/sockets.h"
// #include "lwip/netdb.h"
// #include "net/if.h"
#include "mb_common.h"
#include "mb_frame.h"
#include "esp_modbus_common.h" // for common types for network options
#include "port_tcp_driver.h"
#include "sys/queue.h"
#if (CONFIG_FMB_COMM_MODE_TCP_EN)
#define TRANSACTION_TICKS pdMS_TO_TICKS(50)
/**
* @brief Modbus slave addr list item for the master
*/
typedef struct mb_data_entry_s {
int node_id;
uint64_t token;
mb_node_info_t *pnode;
frame_entry_t frame;
bool pending;
STAILQ_ENTRY(mb_data_entry_s) entries;
} mb_data_item_t;
MB_EVENT_HANDLER(mbs_on_ready);
MB_EVENT_HANDLER(mbs_on_open);
MB_EVENT_HANDLER(mbs_on_resolve);
MB_EVENT_HANDLER(mbs_on_connect);
MB_EVENT_HANDLER(mbs_on_send_data);
MB_EVENT_HANDLER(mbs_on_recv_data);
MB_EVENT_HANDLER(mbs_on_error);
MB_EVENT_HANDLER(mbs_on_close);
MB_EVENT_HANDLER(mbs_on_timeout);
#endif
+417 -223
View File
@@ -10,6 +10,7 @@
#include "port_tcp_master.h"
#include "port_tcp_utils.h"
#include "port_tcp_driver.h"
#include "sdkconfig.h"
#define TAG "port.utils"
@@ -32,13 +33,14 @@ bool port_check_host_addr(const char *host_str, ip_addr_t *host_addr)
// Do name resolution for both protocols
hint.ai_family = AF_UNSPEC;
hint.ai_flags = AI_ADDRCONFIG; // get IPV6 address if supported, otherwise IPV4
hint.ai_flags |= AI_CANONNAME;
memset(&target_addr, 0, sizeof(target_addr));
// convert domain name to IP address
// Todo: check EAI_FAIL error when resolve host name
int ret = getaddrinfo(host_str, NULL, &hint, &paddr_list);
if (ret != 0) {
ESP_LOGD(TAG, "Incorrect host name or IP: %s", host_str);
ESP_LOGD(TAG, "Incorrect host IP: %s", host_str);
return false;
}
if (paddr_list->ai_family == AF_INET) {
@@ -56,38 +58,36 @@ bool port_check_host_addr(const char *host_str, ip_addr_t *host_addr)
if (host_addr) {
*host_addr = target_addr;
}
ESP_LOGD(TAG, "Check name[IP]: \"%s\"[%s]", paddr_list->ai_canonname, pstr);
ESP_LOGD(TAG, "Check name[IP]: \"%s\"[%s]", paddr_list->ai_canonname ? paddr_list->ai_canonname : "UNK", pstr);
freeaddrinfo(paddr_list);
return true;
}
bool port_close_connection(mb_slave_info_t *pinfo)
bool port_close_connection(mb_node_info_t *pinfo)
{
if (!pinfo) {
return false;
}
if (pinfo->sock_id == -1) {
ESP_LOGE(TAG, "Wrong socket info or disconnected socket: %d, skip.", pinfo->sock_id);
if (pinfo->sock_id <= 0) {
ESP_LOGD(TAG, "wrong socket info or disconnected socket: %d, skip.", pinfo->index);
return false;
}
uint8_t tmp_buff[MB_PDU_SIZE_MAX];
// Empty tcp buffer before shutdown
(void)recv(pinfo->sock_id, &tmp_buff[0], MB_PDU_SIZE_MAX, MSG_DONTWAIT);
queue_flush(pinfo->rx_queue);
queue_flush(pinfo->tx_queue);
if (shutdown(pinfo->sock_id, SHUT_RDWR) == -1) {
ESP_LOGV(TAG, "Shutdown failed sock %d, errno=%d", pinfo->sock_id, (int)errno);
}
close(pinfo->sock_id);
MB_SET_SLAVE_STATE(pinfo, MB_SOCK_STATE_OPENED);
pinfo->sock_id = -1;
MB_SET_NODE_STATE(pinfo, MB_SOCK_STATE_OPENED);
pinfo->sock_id = UNDEF_FD;
return true;
}
mb_slave_info_t *port_get_current_info(void *ctx)
{
port_driver_t *pdrv_ctx = GET_CONFIG_PTR(ctx);
if (!pdrv_ctx->mb_slave_curr_info) {
ESP_LOGE(TAG, "Incorrect current slave info.");
}
return pdrv_ctx->mb_slave_curr_info;
}
// The helper function to get time stamp in microseconds
int64_t port_get_timestamp(void)
{
@@ -101,27 +101,6 @@ static void port_ms_to_tv(uint16_t timeout_ms, struct timeval *tv)
tv->tv_usec = (timeout_ms - (tv->tv_sec * 1000)) * 1000;
}
void port_check_shutdown(void *ctx)
{
port_driver_t *pdrv_ctx = GET_CONFIG_PTR(ctx);
// First check if the task is not flagged for shutdown
if (pdrv_ctx->close_done_sema) {
xSemaphoreGive(pdrv_ctx->close_done_sema);
vTaskDelete(NULL);
ESP_LOGW(TAG, "Destroy task...");
}
}
// Function returns time left for response processing according to response timeout
int64_t port_get_resp_time_left(mb_slave_info_t *pinfo)
{
if (!pinfo) {
return 0;
}
int64_t time_stamp = port_get_timestamp() - pinfo->send_time;
return (time_stamp > (1000 * MB_MASTER_TIMEOUT_MS_RESPOND)) ? 0 : (MB_MASTER_TIMEOUT_MS_RESPOND - (time_stamp / 1000) - 1);
}
int port_enqueue_packet(QueueHandle_t queue, uint8_t *pbuf, uint16_t len)
{
frame_entry_t frame_info = {0};
@@ -143,7 +122,7 @@ int port_enqueue_packet(QueueHandle_t queue, uint8_t *pbuf, uint16_t len)
// The packet send fail or the task which is waiting for event is already unblocked
return ERR_BUF;
} else {
ESP_LOGD(TAG, "Enqueue data, length=%d, TID=0x%.4x", frame_info.len, frame_info.tid);
ESP_LOGD(TAG, "Enqueue data, length=%d, TID=0x%" PRIx16, frame_info.len, frame_info.tid);
return (int)frame_info.len;
}
} else {
@@ -162,7 +141,7 @@ int port_dequeue_packet(QueueHandle_t queue, frame_entry_t *pframe_info)
if (ret == ESP_OK) {
if ((frame_info.pid == 0) && (frame_info.uid < MB_ADDRESS_MAX)) {
*pframe_info = frame_info;
ESP_LOGD(TAG, "Dequeue data, length=%d, TID=0x%.4x", (int)pframe_info->len, (int)pframe_info->tid);
ESP_LOGD(TAG, "Dequeue data, length=%d, TID=0x%" PRIx16, (int)pframe_info->len, (int)pframe_info->tid);
return ERR_OK;
}
} else {
@@ -172,48 +151,42 @@ int port_dequeue_packet(QueueHandle_t queue, frame_entry_t *pframe_info)
return ERR_BUF;
}
static int port_get_buf(void *ctx, mb_slave_info_t *pinfo, uint8_t *pdst_buf, uint16_t len, uint16_t read_tick_ms)
static int port_get_buf(mb_node_info_t *pinfo, uint8_t *pdst_buf, uint16_t len, uint16_t read_tick_ms)
{
int ret = 0;
uint8_t *pbuf = pdst_buf;
uint16_t bytes_left = len;
struct timeval time_val;
MB_RETURN_ON_FALSE((pinfo && (pinfo->sock_id > -1)), -1, TAG, "Try to read incorrect socket = #%d.", pinfo->sock_id);
MB_RETURN_ON_FALSE((pinfo && (pinfo->sock_id > UNDEF_FD)), -1, TAG, "Try to read incorrect socket = #%d.", pinfo->sock_id);
// Set receive timeout for socket <= slave respond time
time_val.tv_sec = read_tick_ms / 1000;
time_val.tv_usec = (read_tick_ms % 1000) * 1000;
setsockopt(pinfo->sock_id, SOL_SOCKET, SO_RCVTIMEO, &time_val, sizeof(time_val));
// Receive data from connected client
while (bytes_left > 0) {
ret = recv(pinfo->sock_id, pbuf, bytes_left, 0);
if (ret < 0) {
if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
// Read timeout occurred, check the timeout and return
//return 0;
} else if (errno == ENOTCONN) {
ESP_LOGE(TAG, "socket(#%d)(%s) connection closed, ret=%d, errno=%d.",
pinfo->sock_id, pinfo->addr_info.ip_addr_str, ret, (int)errno);
// Socket connection closed
return ERR_CONN;
} else {
// Other error occurred during receiving
ESP_LOGE(TAG, "Socket(#%d)(%s) receive error, ret = %d, errno = %d(%s)",
pinfo->sock_id, pinfo->addr_info.ip_addr_str, ret, (int)errno, strerror(errno));
return -1;
}
} else if (ret) {
pbuf += ret;
bytes_left -= ret;
// blocking read of data from socket
ret = recv(pinfo->sock_id, pbuf, bytes_left, 0);
if (ret < 0) {
if (errno == EINPROGRESS || errno == EAGAIN || errno == EWOULDBLOCK) {
// Read timeout occurred, check the timeout and return
return 0;
} else if (errno == ENOTCONN) {
ESP_LOGE(TAG, "socket(#%d)(%s) connection closed, ret=%d, errno=%d.",
pinfo->sock_id, pinfo->addr_info.ip_addr_str, ret, (int)errno);
// Socket connection closed
return ERR_CONN;
} else {
// Other error occurred during receiving
ESP_LOGE(TAG, "Socket(#%d)(%s) receive error, ret = %d, errno = %d(%s)",
pinfo->sock_id, pinfo->addr_info.ip_addr_str, ret, (int)errno, strerror(errno));
return -1;
}
port_check_shutdown(ctx);
}
return len;
}
return ret;
}
int port_read_packet(void *ctx, mb_slave_info_t *pinfo)
int port_read_packet(mb_node_info_t *pinfo)
{
uint16_t temp = 0;
int ret = 0;
@@ -223,7 +196,7 @@ int port_read_packet(void *ctx, mb_slave_info_t *pinfo)
if (pinfo) {
MB_RETURN_ON_FALSE((pinfo->sock_id > 0), -1, TAG, "try to read incorrect socket = #%d.", pinfo->sock_id);
// Read packet header
ret = port_get_buf(ctx, pinfo, ptemp_buf, MB_TCP_UID, MB_READ_TICK);
ret = port_get_buf(pinfo, ptemp_buf, MB_TCP_UID, MB_READ_TICK);
if (ret < 0) {
pinfo->recv_err = ret;
return ret;
@@ -244,13 +217,13 @@ int port_read_packet(void *ctx, mb_slave_info_t *pinfo)
// the number of bytes left to complete the current response.
temp = MB_TCP_MBAP_GET_FIELD(ptemp_buf, MB_TCP_LEN);
if (temp > MB_TCP_BUFF_MAX_SIZE) {
ESP_LOGD("RCV", "Packet length: %d", temp);
ESP_LOGD("RCV", "Incorrect packet length: %d", temp);
ESP_LOG_BUFFER_HEX_LEVEL(TAG, ptemp_buf, MB_TCP_FUNC, ESP_LOG_DEBUG);
pinfo->recv_err = ERR_BUF;
temp = MB_TCP_BUFF_MAX_SIZE; // read all remaining data from buffer
}
ret = port_get_buf(ctx, pinfo, &ptemp_buf[MB_TCP_UID], temp, MB_READ_TICK);
ret = port_get_buf(pinfo, &ptemp_buf[MB_TCP_UID], temp, MB_READ_TICK);
if (ret < 0) {
pinfo->recv_err = ret;
return ret;
@@ -278,7 +251,7 @@ int port_read_packet(void *ctx, mb_slave_info_t *pinfo)
return -1;
}
err_t port_set_blocking(mb_slave_info_t *pinfo, bool is_blocking)
err_t port_set_blocking(mb_node_info_t *pinfo, bool is_blocking)
{
if (!pinfo) {
return ERR_CONN;
@@ -296,14 +269,14 @@ err_t port_set_blocking(mb_slave_info_t *pinfo, bool is_blocking)
return ERR_OK;
}
void port_keep_alive(mb_slave_info_t *pinfo)
void port_keep_alive(mb_node_info_t *pinfo)
{
int optval = 1;
setsockopt(pinfo->sock_id, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
}
// Check connection for timeout helper
err_t port_check_alive(mb_slave_info_t *pinfo, uint32_t timeout_ms)
err_t port_check_alive(mb_node_info_t *pinfo, uint32_t timeout_ms)
{
fd_set write_set;
fd_set err_set;
@@ -322,7 +295,7 @@ err_t port_check_alive(mb_slave_info_t *pinfo, uint32_t timeout_ms)
if (errno == EINPROGRESS) {
err = ERR_INPROGRESS;
} else {
ESP_LOGV(TAG, MB_SLAVE_FMT(" connection, select write err(errno) = %d(%d)."),
ESP_LOGV(TAG, MB_NODE_FMT(" connection, select write err(errno) = %d(%d)."),
pinfo->index, pinfo->sock_id, pinfo->addr_info.ip_addr_str, err, (int)errno);
err = ERR_CONN;
}
@@ -351,12 +324,12 @@ err_t port_check_alive(mb_slave_info_t *pinfo, uint32_t timeout_ms)
}
// Unblocking connect function
err_t port_connect(void *ctx, mb_slave_info_t *pinfo)
err_t port_connect(void *ctx, mb_node_info_t *pinfo)
{
if (!pinfo) {
return ERR_CONN;
}
port_driver_t *pdrv_ctx = GET_CONFIG_PTR(ctx);
port_driver_t *pdrv_ctx = MB_GET_DRV_PTR(ctx);
err_t err = ERR_OK;
char str[HOST_STR_MAX_LEN];
char *pstr = NULL;
@@ -367,8 +340,7 @@ err_t port_connect(void *ctx, mb_slave_info_t *pinfo)
memset(&hint, 0, sizeof(hint));
// Do name resolution for both protocols
// hint.ai_family = AF_UNSPEC; Todo: Find a reason why AF_UNSPEC does not work
hint.ai_flags = AI_ADDRCONFIG; // get IPV6 address if supported, otherwise IPV4
hint.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; // get IPV6 address if supported, otherwise IPV4
hint.ai_family = (pinfo->addr_info.addr_type == MB_IPV4) ? AF_INET : AF_INET6;
hint.ai_socktype = (pinfo->addr_info.proto == MB_UDP) ? SOCK_DGRAM : SOCK_STREAM;
hint.ai_protocol = (pinfo->addr_info.proto == MB_UDP) ? IPPROTO_UDP : IPPROTO_TCP;
@@ -434,12 +406,12 @@ err_t port_connect(void *ctx, mb_slave_info_t *pinfo)
continue;
} else if (err != ERR_OK) {
// Other error occurred during connection
ESP_LOGV(TAG, "%p, "MB_SLAVE_FMT(" unable to connect, error=%d, errno %d (%s)"),
ESP_LOGV(TAG, "%p, "MB_NODE_FMT(" unable to connect, error=%d, errno %d (%s)"),
ctx, pinfo->index, pinfo->sock_id, str, err, (int)errno, strerror(errno));
port_close_connection(pinfo);
err = ERR_CONN;
} else {
ESP_LOGI(TAG, "%p, "MB_SLAVE_FMT(", successfully connected."),
ESP_LOGI(TAG, "%p, "MB_NODE_FMT(", successfully connected."),
ctx, pinfo->index, pinfo->sock_id, str);
continue;
}
@@ -449,25 +421,25 @@ err_t port_connect(void *ctx, mb_slave_info_t *pinfo)
return err;
}
int port_write_poll(mb_slave_info_t *pinfo, const uint8_t *pframe, uint16_t frame_len, uint32_t timeout)
int port_write_poll(mb_node_info_t *pinfo, const uint8_t *pframe, uint16_t frame_len, uint32_t timeout)
{
// Check if the socket is alive (writable and SO_ERROR == 0)
int res = (int)port_check_alive(pinfo, timeout);
if ((res < 0) && (res != ERR_INPROGRESS)) {
ESP_LOGE(TAG, MB_SLAVE_FMT(", is not writable, error: %d, errno %d"),
ESP_LOGE(TAG, MB_NODE_FMT(", is not writable, error: %d, errno %d"),
pinfo->index, pinfo->sock_id, pinfo->addr_info.ip_addr_str, res, (int)errno);
return res;
}
res = send(pinfo->sock_id, pframe, frame_len, TCP_NODELAY);
if (res < 0) {
ESP_LOGE(TAG, MB_SLAVE_FMT(", send data error: %d, errno %d"),
ESP_LOGE(TAG, MB_NODE_FMT(", send data error: %d, errno %d"),
pinfo->index, pinfo->sock_id, pinfo->addr_info.ip_addr_str, res, (int)errno);
}
return res;
}
// Scan IP address according to IPV settings
int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info)
int port_scan_addr_string(char *buffer, mb_uid_info_t *pinfo)
{
char *phost_str = NULL;
unsigned int a[8] = {0};
@@ -475,7 +447,7 @@ int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info)
uint16_t index = 0;
uint16_t port = 0;
MB_RETURN_ON_FALSE((buffer && (strlen(buffer) < (HOST_STR_MAX_LEN - 8)) && pslave_info),
MB_RETURN_ON_FALSE((buffer && (strlen(buffer) < (HOST_STR_MAX_LEN - 8)) && pinfo),
-1, TAG, "check input parameters fail.");
#if CONFIG_LWIP_IPV6
@@ -487,13 +459,13 @@ int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info)
if (-1 == asprintf(&phost_str, IPV6STR, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7])) {
abort();
}
pslave_info->node_name_str = phost_str;
pslave_info->ip_addr_str = phost_str;
pslave_info->uid = index;
pslave_info->fd = index;
pslave_info->port = (ret == MB_STR_LEN_IDX_IP6_PORT) ? port : 502;
pslave_info->addr_type = MB_IPV6;
pslave_info->proto = MB_TCP;
pinfo->node_name_str = phost_str;
pinfo->ip_addr_str = phost_str;
pinfo->uid = index;
pinfo->fd = UNDEF_FD;
pinfo->port = (ret == MB_STR_LEN_IDX_IP6_PORT) ? port : CONFIG_FMB_TCP_PORT_DEFAULT;
pinfo->addr_type = MB_IPV6;
pinfo->proto = MB_TCP;
return ret;
}
@@ -504,13 +476,13 @@ int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info)
if (-1 == asprintf(&phost_str, IPV6STR, a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7])) {
abort();
}
pslave_info->node_name_str = phost_str;
pslave_info->ip_addr_str = phost_str;
pslave_info->uid = 0;
pslave_info->fd = 0;
pslave_info->port = 502;
pslave_info->addr_type = MB_IPV6;
pslave_info->proto = MB_TCP;
pinfo->node_name_str = phost_str;
pinfo->ip_addr_str = phost_str;
pinfo->uid = 0;
pinfo->fd = UNDEF_FD;
pinfo->port = CONFIG_FMB_TCP_PORT_DEFAULT;
pinfo->addr_type = MB_IPV6;
pinfo->proto = MB_TCP;
return ret;
}
#endif
@@ -521,13 +493,13 @@ int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info)
if (-1 == asprintf(&phost_str, IPSTR, a[0], a[1], a[2], a[3])) {
abort();
}
pslave_info->node_name_str = phost_str;
pslave_info->ip_addr_str = phost_str;
pslave_info->uid = 0;
pslave_info->fd = 0;
pslave_info->port = 502;
pslave_info->addr_type = MB_IPV4;
pslave_info->proto = MB_TCP;
pinfo->node_name_str = phost_str;
pinfo->ip_addr_str = phost_str;
pinfo->uid = 0;
pinfo->fd = UNDEF_FD;
pinfo->port = CONFIG_FMB_TCP_PORT_DEFAULT;
pinfo->addr_type = MB_IPV4;
pinfo->proto = MB_TCP;
return ret;
}
@@ -538,40 +510,42 @@ int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info)
if (-1 == asprintf(&phost_str, IPSTR, a[0], a[1], a[2], a[3])) {
abort();
}
pslave_info->node_name_str = phost_str;
pslave_info->ip_addr_str = phost_str;
pslave_info->uid = index;
pslave_info->fd = index;
pslave_info->port = (ret == MB_STR_LEN_IDX_IP4_PORT) ? port : 502;
pslave_info->addr_type = MB_IPV4;
pslave_info->proto = MB_TCP;
pinfo->node_name_str = phost_str;
pinfo->ip_addr_str = phost_str;
pinfo->uid = index;
pinfo->fd = UNDEF_FD;
pinfo->port = (ret == MB_STR_LEN_IDX_IP4_PORT) ? port : CONFIG_FMB_TCP_PORT_DEFAULT;
pinfo->addr_type = MB_IPV4;
pinfo->proto = MB_TCP;
return ret;
}
// Configuration format:
// "01:mb_slave_tcp_01:1502"
// "01:mb_node_tcp_01:502"
ret = sscanf(buffer, "%" PRIu16 ";%m[a-z0-9_];%" PRIu16, (uint16_t*)&index, &phost_str, &port);
if ((ret == MB_STR_LEN_HOST) || (ret == MB_STR_LEN_IDX_HOST_PORT)) {
pslave_info->node_name_str = (phost_str && strlen(phost_str)) ? phost_str : pslave_info->node_name_str;
pslave_info->ip_addr_str = (pslave_info->node_name_str) ? pslave_info->node_name_str : pslave_info->ip_addr_str;
pslave_info->uid = index;
pslave_info->port = (ret == MB_STR_LEN_IDX_HOST_PORT) ? port : 502;
pslave_info->addr_type = MB_IPV4;
pslave_info->proto = MB_TCP;
pinfo->node_name_str = (phost_str && strlen(phost_str)) ? phost_str : pinfo->node_name_str;
pinfo->ip_addr_str = (pinfo->node_name_str) ? pinfo->node_name_str : pinfo->ip_addr_str;
pinfo->uid = index;
pinfo->fd = UNDEF_FD;
pinfo->port = (ret == MB_STR_LEN_IDX_HOST_PORT) ? port : CONFIG_FMB_TCP_PORT_DEFAULT;
pinfo->addr_type = MB_IPV4;
pinfo->proto = MB_TCP;
return ret;
}
// Configuration format:
// "mb_slave_tcp_01"
// "mb_node_tcp_01"
ret = sscanf(buffer, "%m[a-z0-9_]", &phost_str);
if (ret == MB_STR_LEN_HOST) {
pslave_info->node_name_str = (phost_str && strlen(phost_str)) ? phost_str : pslave_info->node_name_str;
pslave_info->ip_addr_str = (pslave_info->node_name_str) ? pslave_info->node_name_str : pslave_info->ip_addr_str;
pslave_info->uid = index;
pslave_info->port = 502;
pslave_info->addr_type = MB_IPV4;
pslave_info->proto = MB_TCP;
pinfo->node_name_str = (phost_str && strlen(phost_str)) ? phost_str : pinfo->node_name_str;
pinfo->ip_addr_str = (pinfo->node_name_str) ? pinfo->node_name_str : pinfo->ip_addr_str;
pinfo->uid = index;
pinfo->fd = UNDEF_FD;
pinfo->port = CONFIG_FMB_TCP_PORT_DEFAULT;
pinfo->addr_type = MB_IPV4;
pinfo->proto = MB_TCP;
return ret;
}
@@ -580,137 +554,357 @@ int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info)
#ifdef MB_MDNS_IS_INCLUDED
// convert MAC from binary format to string
inline char *gen_mac_str(const uint8_t *mac, char *pref, char *mac_str)
static int mdns_instance_count = 0;
inline char *gen_id_str(char *service_name, char *node_id_str)
{
sprintf(mac_str, "%s%02X%02X%02X%02X%02X%02X", pref, MAC2STR(mac));
return mac_str;
sprintf(node_id_str, "%s%02X%02X%02X%02X", service_name, MB_ID2STR(MB_DEVICE_ID));
return node_id_str;
}
inline char *gen_id_str(char *service_name, char *slave_id_str)
// This function has limitation of working with IP6 address only
esp_err_t port_start_mdns_service(char **ppdns_name, bool is_master, int uid, void *pnode_netif)
{
sprintf(slave_id_str, "%s%02X%02X%02X%02X", service_name, MB_ID2STR(MB_DEVICE_ID));
return slave_id_str;
}
void port_start_mdns_service(void *ctx)
{
char temp_str[32] = {0};
uint8_t sta_mac[6] = {0};
char temp_str[HOST_STR_MAX_LEN] = {0};
esp_ip6_addr_t ip6[LWIP_IPV6_NUM_ADDRESSES];
int ip6_addrs_count = 0;
esp_err_t err = ESP_ERR_INVALID_STATE;
err = esp_read_mac(sta_mac, ESP_MAC_WIFI_STA);
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG, "get STA mac fail, err = %d.", (uint16_t)err);
char *hostname = gen_mac_str(sta_mac, "mb_master_tcp_", temp_str);
MB_RETURN_ON_FALSE((pnode_netif),
err, TAG, "Invalid parameters for dns.");
// initialize mDNS
err = mdns_init();
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG, "mdns init fail, err = %d.", (uint16_t)err);
err = mdns_init(); // if the mdns is already initialized on higher layer, just returns
MB_RETURN_ON_FALSE(((err == ESP_OK) && pnode_netif), err, TAG, "mdns init fail, err = %d.", (int)err);
// set mDNS hostname (required if you want to advertise services)
err = mdns_hostname_set(hostname);
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG, "mdns set host name fail, err = %d.", (uint16_t)err);
esp_netif_t *pnetif = (esp_netif_t*)pnode_netif;
// set mDNS hostname (required if need to advertise services)
err = mdns_hostname_get(temp_str);
if (err != ESP_OK) {
uint8_t mac[6];
MB_RETURN_ON_FALSE((esp_netif_get_mac(pnetif, mac) == ESP_OK),
err, TAG, "get MAC fail, err = %d.", (int)err);
snprintf(temp_str, HOST_STR_MAX_LEN, "%s_%02x%02x%02x", MB_MDNS_INST_NAME(is_master), mac[3], mac[4], mac[5]);
err = mdns_hostname_set(temp_str);
MB_RETURN_ON_FALSE((err == ESP_OK),
err, TAG, "could not set mdns host name, err = %d.", (int)err);
ESP_LOGI(TAG, "hostname set to: [%s]", temp_str);
err = mdns_instance_name_set(temp_str);
MB_RETURN_ON_FALSE((err == ESP_OK),
err, TAG, "mdns instance name set fail, err = %d.", (int)err);
}
// Check if the default mdns name is defined in the configuration
if (ppdns_name && *ppdns_name && (strlen(*ppdns_name) >= MB_MDNS_STR_MIN_LENGTH)) {
strncpy(temp_str, *ppdns_name, strlen(*ppdns_name));
*ppdns_name[strlen(*ppdns_name)] = '\0';
} else {
if (snprintf(temp_str, sizeof(temp_str), "%s_%02X", MB_MDNS_INST_NAME(is_master), uid) <= 0) {
return ESP_ERR_INVALID_STATE;
};
}
// Setup the real assigned dns_name instead of constant string
if (ppdns_name) {
*ppdns_name = strdup(temp_str);
}
ESP_LOGI(TAG, "mdns hostname set to: [%s]", hostname);
esp_netif_ip_info_t ip_info;
mdns_ip_addr_t node_ip;
err = esp_netif_get_ip_info(pnetif, &ip_info);
MB_RETURN_ON_FALSE((err == ESP_OK),
err, TAG, "get IP info fail, err = %d.", (int)err);
node_ip.next = NULL;
node_ip.addr.type = ESP_IPADDR_TYPE_V4;
node_ip.addr.u_addr.ip4 = ip_info.ip;
node_ip.addr.u_addr.ip6.addr[1] = 0;
node_ip.addr.u_addr.ip6.addr[2] = 0;
node_ip.addr.u_addr.ip6.addr[3] = 0;
node_ip.addr.u_addr.ip6.zone = 0;
err = mdns_delegate_hostname_add(temp_str, &node_ip);
MB_RETURN_ON_FALSE((err == ESP_OK), err, TAG, "mdns set delegate name fail, err = %d.", (int)err);
// set default mDNS instance name
err = mdns_instance_name_set("esp32_mb_master_tcp");
MB_RETURN_ON_FALSE((err == ESP_OK), ;, TAG, "mdns instance name set fail, err = %d.", (uint16_t)err);
#if CONFIG_LWIP_IPV6
// If the IP_V6 addresses supported on current interface, delegate them as well.
ip6_addrs_count = esp_netif_get_all_ip6(pnetif, ip6);
for (int i = 0; i < ip6_addrs_count; ++i) {
ESP_LOGI(TAG, "IPv6 address: " IPV6STR, IPV62STR(ip6[i]));
node_ip.next = NULL;
node_ip.addr.type = ESP_IPADDR_TYPE_V6;
node_ip.addr.u_addr.ip6 = ip6[i];
err = mdns_delegate_hostname_add(temp_str, &node_ip);
MB_RETURN_ON_FALSE((err == ESP_OK), err, TAG, "mdns set delegate name fail, err = %d.", (int)err);
}
#endif
// setup dns name for the modbus segment
err = mdns_delegate_hostname_add(MB_MDNS_SEGMENT_NAME, &node_ip);
MB_RETURN_ON_FALSE((err == ESP_OK), err, TAG, "mdns set segment name fail, err = %d.", (int)err);
ESP_LOGI(TAG, "mdns delegate hostname set to: [%s]", temp_str);
ESP_LOGI(TAG, "IP: " IPSTR, IP2STR(&ip_info.ip));
ESP_LOGI(TAG, "GW: " IPSTR, IP2STR(&ip_info.gw));
ESP_LOGI(TAG, "NETMASK: " IPSTR, IP2STR(&ip_info.netmask));
mdns_instance_count++;
return ESP_OK;
}
char *port_get_slave_ip_str(mdns_ip_addr_t *address, mb_addr_type_t addr_type)
void port_stop_mdns_service(char **ppdns_name)
{
mdns_ip_addr_t *a = address;
char *slave_ip_str = NULL;
while (a) {
if ((a->addr.type == ESP_IPADDR_TYPE_V6) && (addr_type == MB_IPV6)) {
if (-1 == asprintf(&slave_ip_str, IPV6STR, IPV62STR(a->addr.u_addr.ip6))) {
abort();
}
} else if ((a->addr.type == ESP_IPADDR_TYPE_V4) && (addr_type == MB_IPV4)) {
if (-1 == asprintf(&slave_ip_str, IPSTR, IP2STR(&(a->addr.u_addr.ip4)))) {
abort();
}
if (ppdns_name && *ppdns_name) {
mdns_delegate_hostname_remove(*ppdns_name);
free(*ppdns_name);
*ppdns_name = NULL;
if (mdns_instance_count) {
mdns_instance_count--;
}
if (slave_ip_str) {
break;
}
a = a->next;
}
return slave_ip_str;
if (!mdns_instance_count) {
mdns_delegate_hostname_remove(MB_MDNS_SEGMENT_NAME);
mdns_service_remove_all();
mdns_free();
}
}
esp_err_t port_resolve_slave(uint8_t short_addr, mdns_result_t *result, char **resolved_ip,
mb_addr_type_t addr_type)
{
if (!short_addr || !result || !resolved_ip) {
return ESP_ERR_INVALID_ARG;
}
mdns_result_t *r = result;
int t;
char *slave_ip = NULL;
char slave_name[22] = {0};
// char *port_get_node_ip_str(mdns_ip_addr_t *address, mb_addr_type_t addr_type)
// {
// mdns_ip_addr_t *a = address;
// char *node_ip_str = NULL;
if (sprintf(slave_name, "mb_slave_tcp_%02X", short_addr) < 0) {
ESP_LOGE(TAG, "Fail to create instance name for index: %d", short_addr);
abort();
}
for (; r; r = r->next) {
if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
continue;
} else if ((r->ip_protocol == MDNS_IP_PROTOCOL_V6) && (addr_type == MB_IPV4)) {
continue;
}
// Check host name for Modbus short address and
// append it into slave ip address table
if ((strcmp(r->instance_name, slave_name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
printf(" PTR : %s\n", r->instance_name);
if (r->txt_count) {
printf(" TXT : [%u] ", r->txt_count);
for (t = 0; t < r->txt_count; t++) {
printf("%s=%s; ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL");
}
printf("\n");
}
slave_ip = port_get_slave_ip_str(r->addr, addr_type);
if (slave_ip) {
ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, slave_ip, r->port);
*resolved_ip = slave_ip;
return ESP_OK;
}
}
}
*resolved_ip = NULL;
ESP_LOGD(TAG, "Fail to resolve slave: %s", slave_name);
return ESP_ERR_NOT_FOUND;
}
// while (a) {
// if ((a->addr.type == ESP_IPADDR_TYPE_V6) && (addr_type == MB_IPV6)) {
// if (-1 == asprintf(&node_ip_str, IPV6STR, IPV62STR(a->addr.u_addr.ip6))) {
// abort();
// }
// } else if ((a->addr.type == ESP_IPADDR_TYPE_V4) && (addr_type == MB_IPV4)) {
// if (-1 == asprintf(&node_ip_str, IPSTR, IP2STR(&(a->addr.u_addr.ip4)))) {
// abort();
// }
// }
// if (node_ip_str) {
// break;
// }
// a = a->next;
// }
// return node_ip_str;
// }
// The helper to resolve host name based on service query (not used for now)
// esp_err_t port_resolve_slave(uint8_t short_addr, mdns_result_t *result, char **resolved_ip,
// mb_addr_type_t addr_type)
// {
// if (!short_addr || !result || !resolved_ip) {
// return ESP_ERR_INVALID_ARG;
// }
// mdns_result_t *r = result;
// int t;
// char *node_ip = NULL;
// char node_name[22] = {0};
// if (sprintf(node_name, "mb_node_tcp_%02X", short_addr) < 0) {
// ESP_LOGE(TAG, "Fail to create instance name for index: %d", short_addr);
// abort();
// }
// for (; r; r = r->next) {
// if ((r->ip_protocol == MDNS_IP_PROTOCOL_V4) && (addr_type == MB_IPV6)) {
// continue;
// } else if ((r->ip_protocol == MDNS_IP_PROTOCOL_V6) && (addr_type == MB_IPV4)) {
// continue;
// }
// // Check host name for Modbus short address and
// // append it into slave ip address table
// if ((strcmp(r->instance_name, node_name) == 0) && (r->port == CONFIG_FMB_TCP_PORT_DEFAULT)) {
// printf(" PTR : %s\n", r->instance_name);
// if (r->txt_count) {
// printf(" TXT : [%u] ", r->txt_count);
// for (t = 0; t < r->txt_count; t++) {
// printf("%s=%s; ", r->txt[t].key, r->txt[t].value ? r->txt[t].value : "NULL");
// }
// printf("\n");
// }
// node_ip = port_get_node_ip_str(r->addr, addr_type);
// if (node_ip) {
// ESP_LOGI(TAG, "Resolved slave %s[%s]:%u", r->hostname, node_ip, r->port);
// *resolved_ip = node_ip;
// return ESP_OK;
// }
// }
// }
// *resolved_ip = NULL;
// ESP_LOGD(TAG, "Fail to resolve slave: %s", node_name);
// return ESP_ERR_NOT_FOUND;
// }
int port_resolve_mdns_host(const char *host_name, char **paddr_str)
{
ESP_LOGW(TAG, "Query A: %s.local", host_name);
ESP_LOGD(TAG, "Query A: %s.local", host_name);
esp_ip4_addr_t addr;
addr.addr = 0;
esp_ip_addr_t addr;
char *pstr = NULL;
bzero(&addr, sizeof(esp_ip_addr_t));
esp_err_t err = mdns_query_a(host_name, MB_MDNS_QUERY_TIME_MS, &addr);
// Try to send query to obtain the IPv4 address
esp_err_t err = mdns_query_a(host_name, MB_MDNS_QUERY_TIME_MS, &addr.u_addr.ip4);
if (err) {
if(err == ESP_ERR_NOT_FOUND){
ESP_LOGE(TAG, "Host: %s, was not found!", host_name);
if (err == ESP_ERR_NOT_FOUND){
// Try to resolve using AAAA query
err = mdns_query_aaaa(host_name, MB_MDNS_QUERY_TIME_MS, &addr.u_addr.ip6);
if (err == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Host: %s, was not resolved!", host_name);
return err;
}
addr.type = ESP_IPADDR_TYPE_V6;
if (asprintf(&pstr, IPV6STR, IPV62STR(addr.u_addr.ip6) == -1)) {
abort();
}
} else {
return -1;
}
return -1;
} else {
addr.type = ESP_IPADDR_TYPE_V4;
if (asprintf(&pstr, IPSTR, IP2STR(&addr.u_addr.ip4)) == -1) {
abort();
}
}
if (asprintf(&pstr, IPSTR, IP2STR(&addr)) == -1) {
abort();
if (paddr_str) {
ESP_LOGD(TAG, "Host: %s, was resolved with IP: %s", host_name, pstr);
*paddr_str = pstr;
}
*paddr_str = pstr;
return strlen(pstr);
}
#endif // #ifdef MB_MDNS_IS_INCLUDED
// Create a listening socket on pbind_ip, with ip address_type, protocol type and port
int port_bind_addr(const char *pbind_ip, mb_addr_type_t addr_type, mb_comm_mode_t proto, uint16_t port)
{
int temp_par, ret;
int listen_sock_fd = -1;
struct addrinfo hint;
struct addrinfo *paddr_list;
struct addrinfo *pcur_addr;
char* pstr = NULL;
memset(&hint, 0, sizeof(hint));
// Bind to IPv6 and/or IPv4, but only in the desired protocol
// Todo: Find a reason why AF_UNSPEC does not work for IPv6
hint.ai_family = AF_UNSPEC;
//hint.ai_family = (addr_type == MB_IPV4) ? AF_INET : AF_INET6;
hint.ai_socktype = (proto == MB_UDP) ? SOCK_DGRAM : SOCK_STREAM;
// The LWIP has an issue when connection to IPv6 socket
hint.ai_protocol = (proto == MB_UDP) ? IPPROTO_UDP : IPPROTO_TCP;
hint.ai_flags = AI_NUMERICSERV | AI_PASSIVE | AI_CANONNAME;
if (asprintf(&pstr, "%u", port) == -1) {
abort();
}
ret = getaddrinfo(pbind_ip, pstr, &hint, &paddr_list);
free(pstr);
if ((ret != 0) ) {
return -1;
}
// Try the sockaddr until a binding succeeds
for (pcur_addr = paddr_list; pcur_addr != NULL; pcur_addr = pcur_addr->ai_next)
{
listen_sock_fd = (int)socket(pcur_addr->ai_family, pcur_addr->ai_socktype,
pcur_addr->ai_protocol);
if (listen_sock_fd < 0)
{
continue;
}
temp_par = 1;
// Allow multi client connections
if (setsockopt(listen_sock_fd, SOL_SOCKET, SO_REUSEADDR,
(const char*)&temp_par, sizeof(temp_par)) != 0)
{
close(listen_sock_fd);
listen_sock_fd = UNDEF_FD;
continue;
}
if (bind(listen_sock_fd, (struct sockaddr *)pcur_addr->ai_addr,
(socklen_t)pcur_addr->ai_addrlen) != 0 )
{
close(listen_sock_fd);
listen_sock_fd = UNDEF_FD;
continue;
}
// Listen only makes sense for TCP
if (proto == MB_TCP)
{
if (listen(listen_sock_fd, MB_TCP_NET_LISTEN_BACKLOG) != 0)
{
ESP_LOGE(TAG, "Error occurred during listen: errno=%u", (unsigned)errno);
close(listen_sock_fd);
listen_sock_fd = UNDEF_FD;
continue;
}
}
// Bind was successful
pstr = (pcur_addr->ai_canonname == NULL) ? (char *)"\0" : pcur_addr->ai_canonname;
ESP_LOGI(TAG, "Socket (#%d), listener %s on port: %u, errno=%u",
(int)listen_sock_fd, pstr, (unsigned)port, (unsigned)errno);
break;
}
freeaddrinfo(paddr_list);
return(listen_sock_fd);
}
int port_accept_connection(int listen_sock_id, mb_uid_info_t *pinfo)
{
MB_RETURN_ON_FALSE((pinfo), -1, TAG, "Wrong parameter pointer.");
MB_RETURN_ON_FALSE((listen_sock_id > 0), -1, TAG, "Incorrect listen socket ID.");
// Address structure large enough for both IPv4 or IPv6 address
struct sockaddr_storage src_addr;
char addr_str[128];
int sock_id = UNDEF_FD;
char *paddr = NULL;
socklen_t addr_size = sizeof(struct sockaddr_storage);
bzero(&src_addr, sizeof(struct sockaddr_storage));
// Accept new socket connection if not active
sock_id = accept(listen_sock_id, (struct sockaddr *)&src_addr, &addr_size);
if (sock_id < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno=%u", (unsigned)errno);
close(sock_id);
} else {
// Get the sender's ip address as string
if (src_addr.ss_family == PF_INET) {
inet_ntoa_r(((struct sockaddr_in *)&src_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
pinfo->port = ntohs(((struct sockaddr_in *)&src_addr)->sin_port);
pinfo->addr_type = MB_IPV4;
}
#if CONFIG_LWIP_IPV6
else if (src_addr.ss_family == PF_INET6) {
inet6_ntoa_r(((struct sockaddr_in6 *)&src_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);
pinfo->port = ntohs(((struct sockaddr_in6 *)&src_addr)->sin6_port);
pinfo->addr_type = MB_IPV6;
}
#endif
else {
// Make sure ss_family is valid
abort();
}
ESP_LOGI(TAG, "Socket (#%d), accept client connection from address[port]: %s[%d]", (int)sock_id, addr_str, pinfo->port);
paddr = strdup(addr_str);
if (paddr) {
pinfo->fd = sock_id;
pinfo->ip_addr_str = paddr;
pinfo->node_name_str = paddr;
pinfo->proto = MB_TCP;
pinfo->uid = 0;
}
}
return sock_id;
}
#endif
#ifdef __cplusplus
+44 -22
View File
@@ -16,6 +16,7 @@ extern "C" {
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#include "esp_netif.h"
#include "net/if.h"
#include "port_tcp_common.h"
@@ -31,7 +32,13 @@ extern "C" {
#include "mdns.h"
#endif
#define HOST_STR_MAX_LEN (64)
// Workaround for MDNS_NAME_BUF_LEN being defined in private header
#ifndef MDNS_NAME_BUF_LEN
#define MDNS_NAME_BUF_LEN 64
#endif
#define HOST_STR_MAX_LEN (MDNS_NAME_BUF_LEN)
#define MB_TCP_NET_LISTEN_BACKLOG (SOMAXCONN)
#if MB_MDNS_IS_INCLUDED
@@ -46,17 +53,17 @@ extern "C" {
#define MB_DEVICE_ID (uint32_t)CONFIG_FMB_CONTROLLER_SLAVE_ID
#endif
#define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
// #define MB_SLAVE_ADDR (CONFIG_MB_SLAVE_ADDR)
#endif
#define MB_MDNS_PORT (502)
#define MB_MDNS_PORT (CONFIG_FMB_TCP_PORT_DEFAULT)
#define MB_READ_TICK (500)
#define MB_MDNS_QUERY_TIME_MS (2000)
#define MB_STR_LEN_HOST 1 // "mb_slave_tcp_01"
#define MB_STR_LEN_IDX_HOST 2 // "12:mb_slave_tcp_01"
#define MB_STR_LEN_IDX_HOST_PORT 3 // "01:mb_slave_tcp_01:1502"
#define MB_STR_LEN_HOST 1 // "mb_node_tcp_01"
#define MB_STR_LEN_IDX_HOST 2 // "12:mb_node_tcp_01"
#define MB_STR_LEN_IDX_HOST_PORT 3 // "01:mb_node_tcp_01:1502"
#define MB_STR_LEN_IP4_ONLY 4 // "192.168.1.1"
#define MB_STR_LEN_IDX_IP4 5 // "1:192.168.1.1"
#define MB_STR_LEN_IDX_IP4_PORT 6 // "1:192.168.1.1:502"
@@ -64,43 +71,58 @@ extern "C" {
#define MB_STR_LEN_IDX_IP6 9 // "12:2001:0db8:85a3:0000:0000:8a2e:0370:7334"
#define MB_STR_LEN_IDX_IP6_PORT 10 // "12:2001:0db8:85a3:0000:0000:8a2e:0370:7334:502"
#define MB_MDNS_STR_MIN_LENGTH 10 // "mb_node_01"
#define MB_MDNS_SEGMENT_NAME "mb_tcp_segment" // "mb_node_01"
#define MB_MDNS_INST_NAME(is_master) (__extension__( \
{ \
((is_master) ? "mb_master_tcp" : "mb_slave_tcp"); \
} \
))
typedef struct _frame_queue_entry frame_entry_t;
typedef struct _mb_slave_info mb_slave_info_t;
typedef struct _mb_node_info mb_node_info_t;
typedef enum _addr_type_enum mb_tcp_addr_type_t;
bool port_check_host_addr(const char *host_str, ip_addr_t* host_addr);
mb_slave_info_t* port_get_current_info(void *ctx);
mb_node_info_t* port_get_current_info(void *ctx);
void port_check_shutdown(void *ctx);
int64_t port_get_resp_time_left(mb_slave_info_t* pinfo);
int64_t port_get_resp_time_left(mb_node_info_t* pinfo);
int port_enqueue_packet(QueueHandle_t queue, uint8_t *pbuf, uint16_t len);
int port_dequeue_packet(QueueHandle_t queue, frame_entry_t* pframe_info);
int port_read_packet(void *ctx, mb_slave_info_t* pinfo);
err_t port_set_blocking(mb_slave_info_t* pinfo, bool is_blocking);
void port_keep_alive(mb_slave_info_t* pinfo);
err_t port_check_alive(mb_slave_info_t* pinfo, uint32_t timeout_ms);
err_t port_connect(void *ctx, mb_slave_info_t* pinfo);
bool port_close_connection(mb_slave_info_t* pinfo);
int port_write_poll(mb_slave_info_t* pinfo, const uint8_t *pframe, uint16_t frame_len, uint32_t timeout);
int port_read_packet(mb_node_info_t* pinfo);
err_t port_set_blocking(mb_node_info_t* pinfo, bool is_blocking);
void port_keep_alive(mb_node_info_t* pinfo);
err_t port_check_alive(mb_node_info_t* pinfo, uint32_t timeout_ms);
err_t port_connect(void *ctx, mb_node_info_t* pinfo);
bool port_close_connection(mb_node_info_t* pinfo);
int port_write_poll(mb_node_info_t* pinfo, const uint8_t *pframe, uint16_t frame_len, uint32_t timeout);
int64_t port_get_timestamp(void);
typedef struct _uid_info mb_uid_info_t;
int port_scan_addr_string(char *buffer, mb_uid_info_t *pslave_info);
int port_scan_addr_string(char *buffer, mb_uid_info_t *pnode_info);
#if MB_MDNS_IS_INCLUDED
// convert MAC from binary format to string
char *gen_mac_str(const uint8_t *mac, char *pref, char *mac_str);
char *gen_id_str(char *service_name, char *slave_id_str);
void port_start_mdns_service();
// Init mdns service
esp_err_t port_start_mdns_service(char **ppdns_name, bool is_master, int uid, void *pnode_netif);
void port_stop_mdns_service(char **ppdns_name);
typedef struct mdns_ip_addr_s mdns_ip_addr_t;
typedef struct mdns_result_s mdns_result_t;
char *port_get_slave_ip_str(mdns_ip_addr_t *address, mb_addr_type_t addr_type);
char *port_get_node_ip_str(mdns_ip_addr_t *address, mb_addr_type_t addr_type);
esp_err_t port_resolve_slave(uint8_t short_addr, mdns_result_t *result, char **resolved_ip, mb_addr_type_t addr_type);
int port_resolve_mdns_host(const char *host_name, char **paddr_str);
#endif
// Modbus slave utility functions
int port_bind_addr(const char *pbind_ip, mb_addr_type_t addr_type, mb_comm_mode_t proto, uint16_t port);
int port_accept_connection(int listen_sock_id, mb_uid_info_t *pnode_info);
#ifdef __cplusplus
}
#endif
+21 -22
View File
@@ -25,7 +25,7 @@ typedef struct
uint16_t snd_buf_cnt;
uint16_t rcv_buf_pos;
bool frame_is_broadcast;
volatile mb_tmr_mode_enum_t cur_tmr_mode;
volatile mb_timer_mode_enum_t cur_timer_mode;
} mbm_ascii_trasp_t;
static mb_err_enum_t mbm_ascii_transp_receive(mb_trans_base_t *inst, uint8_t *rcv_addr_buf, uint8_t **frame_ptr_buf, uint16_t *len_buf);
@@ -34,7 +34,7 @@ static void mbm_ascii_transp_start(mb_trans_base_t *inst);
static void mbm_ascii_transp_stop(mb_trans_base_t *inst);
static void mbm_ascii_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
static void mbm_ascii_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
static bool mbm_ascii_transp_tmr_expired(void *inst);
static bool mbm_ascii_transp_timer_expired(void *inst);
static bool mbm_ascii_transp_rq_is_bcast(mb_trans_base_t *inst);
mb_err_enum_t mbm_ascii_transp_create(mb_serial_opts_t *ser_opts, void **in_out_inst)
@@ -60,17 +60,17 @@ mb_err_enum_t mbm_ascii_transp_create(mb_serial_opts_t *ser_opts, void **in_out_
mb_port_base_t *port_obj = (mb_port_base_t *)*in_out_inst;
ret = mb_port_ser_create(ser_opts, &port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "serial port creation, err: %d", ret);
ret = mb_port_tmr_create(port_obj, (MB_ASCII_TIMEOUT_MS * MB_TIMER_TICS_PER_MS));
ret = mb_port_timer_create(port_obj, (MB_ASCII_TIMEOUT_MS * MB_TIMER_TICS_PER_MS));
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "timer port creation, err: %d", ret);
// Override default response time if defined
if (ser_opts->response_tout_ms) {
mb_port_tmr_set_response_time(port_obj, ser_opts->response_tout_ms);
mb_port_timer_set_response_time(port_obj, ser_opts->response_tout_ms);
}
ret = mb_port_evt_create(port_obj);
ret = mb_port_event_create(port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "event port creation, err: %d", ret);
transp->base.port_obj = port_obj;
// Set callback function pointer for the timer
port_obj->cb.tmr_expired = mbm_ascii_transp_tmr_expired;
port_obj->cb.tmr_expired = mbm_ascii_transp_timer_expired;
port_obj->cb.tx_empty = NULL;
port_obj->cb.byte_rcvd = NULL;
port_obj->arg = (void *)transp;
@@ -97,8 +97,8 @@ error:
bool mbm_ascii_transp_delete(mb_trans_base_t *inst)
{
mbm_ascii_trasp_t *trans = __containerof(inst, mbm_ascii_trasp_t, base);
mb_port_tmr_delete(trans->base.port_obj);
mb_port_evt_delete(trans->base.port_obj);
mb_port_timer_delete(trans->base.port_obj);
mb_port_event_delete(trans->base.port_obj);
mb_port_ser_delete(trans->base.port_obj);
free((void *)trans->pascii_puf);
CRITICAL_SECTION_CLOSE(inst->lock);
@@ -112,18 +112,18 @@ static void mbm_ascii_transp_start(mb_trans_base_t *inst)
CRITICAL_SECTION(inst->lock) {
mb_port_ser_enable(inst->port_obj);
mb_port_tmr_enable(inst->port_obj);
mb_port_timer_enable(inst->port_obj);
};
/* No special startup required for ASCII. */
(void)mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
(void)mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
}
static void mbm_ascii_transp_stop(mb_trans_base_t *inst)
{
CRITICAL_SECTION(inst->lock) {
mb_port_ser_disable(inst->port_obj);
mb_port_tmr_disable(inst->port_obj);
mb_port_timer_disable(inst->port_obj);
};
}
@@ -199,9 +199,9 @@ static mb_err_enum_t mbm_ascii_transp_send(mb_trans_base_t *inst, uint8_t slv_ad
// If the frame is broadcast, master will enable timer of convert delay,
// else master will enable timer of respond timeout. */
if (transp->frame_is_broadcast) {
mb_port_tmr_convert_delay_enable(transp->base.port_obj);
mb_port_timer_convert_delay_enable(transp->base.port_obj);
} else {
mb_port_tmr_respond_timeout_enable(transp->base.port_obj);
mb_port_timer_respond_timeout_enable(transp->base.port_obj);
}
} else {
status = MB_EIO;
@@ -227,35 +227,35 @@ static bool mbm_ascii_transp_snd_fsm(mb_trans_base_t *inst)
}
// The timer expired function
static bool mbm_ascii_transp_tmr_expired(void *inst)
static bool mbm_ascii_transp_timer_expired(void *inst)
{
mbm_ascii_trasp_t *transp = __containerof(inst, mbm_ascii_trasp_t, base);
bool need_poll = false;
mb_tmr_mode_enum_t timer_mode = mb_port_get_cur_tmr_mode(transp->base.port_obj);
mb_timer_mode_enum_t timer_mode = mb_port_get_cur_timer_mode(transp->base.port_obj);
mb_port_tmr_disable(transp->base.port_obj);
mb_port_timer_disable(transp->base.port_obj);
switch(timer_mode) {
case MB_TMODE_T35:
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
ESP_EARLY_LOGD(TAG, "%p:EV_READY", transp->base.descr.parent);
break;
case MB_TMODE_RESPOND_TIMEOUT:
mb_port_evt_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
mb_port_event_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
ESP_EARLY_LOGD(TAG, "%p:EV_ERROR_RESPOND_TIMEOUT", transp->base.descr.parent);
break;
case MB_TMODE_CONVERT_DELAY:
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_EXECUTE));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_EXECUTE));
ESP_EARLY_LOGD(TAG, "%p:MB_TMODE_CONVERT_DELAY", transp->base.descr.parent);
break;
default:
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
break;
}
@@ -278,7 +278,6 @@ static void mbm_ascii_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_
}
}
// void mb_ascii_set_cur_tmr_mode(mb_ascii_tr_struct* inst, mb_tmr_mode_enum_t tmr_mode);
static bool mbm_ascii_transp_rq_is_bcast(mb_trans_base_t *inst)
{
mbm_ascii_trasp_t *transp = __containerof(inst, mbm_ascii_trasp_t, base);
+12 -12
View File
@@ -25,7 +25,7 @@ typedef struct
uint8_t *snd_buf_cur;
uint16_t snd_buf_cnt;
uint16_t rcv_buf_pos;
volatile mb_tmr_mode_enum_t cur_tmr_mode;
volatile mb_timer_mode_enum_t cur_timer_mode;
} mbs_ascii_trasp_t;
mb_err_enum_t mbs_ascii_transp_create(mb_serial_opts_t *ser_opts, void **in_out_inst);
@@ -35,7 +35,7 @@ static mb_err_enum_t mbs_ascii_transp_receive(mb_trans_base_t *inst, uint8_t *rc
static mb_err_enum_t mbs_ascii_transp_send(mb_trans_base_t *inst, uint8_t slv_addr, const uint8_t *frame_ptr, uint16_t len);
static bool mbs_ascii_transp_rcv_fsm(mb_trans_base_t *inst);
static bool mbs_ascii_transp_snd_fsm(mb_trans_base_t *inst);
static bool mbs_ascii_transp_tmr_expired(void *inst);
static bool mbs_ascii_transp_timer_expired(void *inst);
void mbs_ascii_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
static void mbs_ascii_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
@@ -62,14 +62,14 @@ mb_err_enum_t mbs_ascii_transp_create(mb_serial_opts_t *ser_opts, void **in_out_
mb_port_base_t *port_obj = (mb_port_base_t *)*in_out_inst;
ret = mb_port_ser_create(ser_opts, &port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "serial port creation, err: %d", ret);
ret = mb_port_tmr_create(port_obj, (MB_ASCII_TIMEOUT_MS * MB_TIMER_TICS_PER_MS));
ret = mb_port_timer_create(port_obj, (MB_ASCII_TIMEOUT_MS * MB_TIMER_TICS_PER_MS));
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "timer port creation, err: %d", ret);
ret = mb_port_evt_create(port_obj);
ret = mb_port_event_create(port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "event port creation, err: %d", ret);
transp->base.port_obj = port_obj;
transp->rcv_buf = (uint8_t *)&transp->pdu_buf[0];
// Set callback function pointer for the timer
port_obj->cb.tmr_expired = mbs_ascii_transp_tmr_expired;
port_obj->cb.tmr_expired = mbs_ascii_transp_timer_expired;
port_obj->cb.tx_empty = NULL;
port_obj->cb.byte_rcvd = NULL;
port_obj->arg = (void *)transp;
@@ -94,8 +94,8 @@ error:
bool mbs_ascii_transp_delete(mb_trans_base_t *inst)
{
mbs_ascii_trasp_t *transp = __containerof(inst, mbs_ascii_trasp_t, base);
mb_port_tmr_delete(transp->base.port_obj);
mb_port_evt_delete(transp->base.port_obj);
mb_port_timer_delete(transp->base.port_obj);
mb_port_event_delete(transp->base.port_obj);
mb_port_ser_delete(transp->base.port_obj);
free(transp->pascii_puf);
CRITICAL_SECTION_CLOSE(inst->lock);
@@ -108,18 +108,18 @@ static void mbs_ascii_transp_start(mb_trans_base_t *inst)
mbs_ascii_trasp_t *transp = __containerof(inst, mbs_ascii_trasp_t, base);
CRITICAL_SECTION(inst->lock) {
mb_port_ser_enable(inst->port_obj);
mb_port_tmr_enable(inst->port_obj);
mb_port_timer_enable(inst->port_obj);
};
/* No special startup required for ASCII. */
(void)mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
(void)mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
}
static void mbs_ascii_transp_stop(mb_trans_base_t *inst)
{
CRITICAL_SECTION(inst->lock) {
mb_port_ser_disable(inst->port_obj);
mb_port_tmr_disable(inst->port_obj);
mb_port_timer_disable(inst->port_obj);
};
}
@@ -208,11 +208,11 @@ static bool mbs_ascii_transp_snd_fsm(mb_trans_base_t *inst)
return false;
}
static bool mbs_ascii_transp_tmr_expired(void *inst)
static bool mbs_ascii_transp_timer_expired(void *inst)
{
mbs_ascii_trasp_t *transp = __containerof(inst, mbs_ascii_trasp_t, base);
mb_port_tmr_disable(transp->base.port_obj);
mb_port_timer_disable(transp->base.port_obj);
return false;
}
+23 -23
View File
@@ -24,7 +24,7 @@ typedef struct
uint16_t snd_buf_cnt;
uint16_t rcv_buf_pos;
bool frame_is_broadcast;
volatile mb_tmr_mode_enum_t cur_tmr_mode;
volatile mb_timer_mode_enum_t cur_timer_mode;
mb_rtu_state_enum_t state;
} mbm_rtu_transp_t;
@@ -35,7 +35,7 @@ static mb_err_enum_t mbm_rtu_transp_receive(mb_trans_base_t *inst, uint8_t *rcv_
static mb_err_enum_t mbm_rtu_transp_send(mb_trans_base_t *inst, uint8_t slv_addr, const uint8_t *frame_ptr, uint16_t len);
static bool mbm_rtu_transp_rcv_fsm(mb_trans_base_t *inst);
static bool mbm_rtu_transp_snd_fsm(mb_trans_base_t *inst);
static bool mbm_rtu_transp_tmr_35_expired(void *inst);
static bool mbm_rtu_transp_timer_expired(void *inst);
static void mbm_rtu_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
static void mbm_rtu_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
// static uint16_t mbm_rtu_transp_get_snd_len(mb_trans_base_t *inst);
@@ -66,17 +66,17 @@ mb_err_enum_t mbm_rtu_transp_create(mb_serial_opts_t *ser_opts, void **in_out_in
mb_port_base_t *port_obj = (mb_port_base_t *)*in_out_inst;
ret = mb_port_ser_create(ser_opts, &port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EILLSTATE, error, TAG, "serial port creation, err: %d", ret);
ret = mb_port_tmr_create(port_obj, MB_RTU_GET_T35_VAL(ser_opts->baudrate));
ret = mb_port_timer_create(port_obj, MB_RTU_GET_T35_VAL(ser_opts->baudrate));
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EILLSTATE, error, TAG, "timer port creation, err: %d", ret);
// Override default response time if defined
if (ser_opts->response_tout_ms) {
mb_port_tmr_set_response_time(port_obj, ser_opts->response_tout_ms);
mb_port_timer_set_response_time(port_obj, ser_opts->response_tout_ms);
}
ret = mb_port_evt_create(port_obj);
ret = mb_port_event_create(port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EILLSTATE, error, TAG, "event port creation, err: %d", ret);
transp->base.port_obj = port_obj;
// Set callback function pointer for the timer
port_obj->cb.tmr_expired = mbm_rtu_transp_tmr_35_expired;
port_obj->cb.tmr_expired = mbm_rtu_transp_timer_expired;
port_obj->cb.tx_empty = NULL;
port_obj->cb.byte_rcvd = NULL;
port_obj->arg = (void *)transp;
@@ -88,10 +88,10 @@ mb_err_enum_t mbm_rtu_transp_create(mb_serial_opts_t *ser_opts, void **in_out_in
error:
if (port_obj->timer_obj) {
mb_port_tmr_delete(port_obj);
mb_port_timer_delete(port_obj);
}
if (port_obj->event_obj) {
mb_port_evt_delete(port_obj);
mb_port_event_delete(port_obj);
}
if (port_obj) {
mb_port_ser_delete(port_obj);
@@ -105,8 +105,8 @@ bool mbm_rtu_transp_delete(mb_trans_base_t *inst)
{
mbm_rtu_transp_t *transp = __containerof(inst, mbm_rtu_transp_t, base);
mb_port_ser_delete(transp->base.port_obj);
mb_port_tmr_delete(transp->base.port_obj);
mb_port_evt_delete(transp->base.port_obj);
mb_port_timer_delete(transp->base.port_obj);
mb_port_event_delete(transp->base.port_obj);
CRITICAL_SECTION_CLOSE(inst->lock);
free(transp);
return true;
@@ -118,17 +118,17 @@ static void mbm_rtu_transp_start(mb_trans_base_t *inst)
transp->state = MB_RTU_STATE_INIT;
CRITICAL_SECTION(inst->lock) {
mb_port_ser_enable(inst->port_obj);
mb_port_tmr_enable(inst->port_obj);
mb_port_timer_enable(inst->port_obj);
};
/* No special startup required for RTU. */
(void)mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
(void)mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
}
static void mbm_rtu_transp_stop(mb_trans_base_t *inst)
{
CRITICAL_SECTION(inst->lock) {
mb_port_ser_disable(inst->port_obj);
mb_port_tmr_disable(inst->port_obj);
mb_port_timer_disable(inst->port_obj);
};
}
@@ -206,9 +206,9 @@ static mb_err_enum_t mbm_rtu_transp_send(mb_trans_base_t *inst, uint8_t slv_addr
// If the frame is broadcast, master will enable timer of convert delay,
// else master will enable timer of respond timeout. */
if (transp->frame_is_broadcast) {
mb_port_tmr_convert_delay_enable(transp->base.port_obj);
mb_port_timer_convert_delay_enable(transp->base.port_obj);
} else {
mb_port_tmr_respond_timeout_enable(transp->base.port_obj);
mb_port_timer_respond_timeout_enable(transp->base.port_obj);
}
} else {
@@ -230,35 +230,35 @@ static bool mbm_rtu_transp_snd_fsm(mb_trans_base_t *inst)
}
static bool mbm_rtu_transp_tmr_35_expired(void *inst)
static bool mbm_rtu_transp_timer_expired(void *inst)
{
mbm_rtu_transp_t *transp = __containerof(inst, mbm_rtu_transp_t, base);
bool need_poll = false;
mb_tmr_mode_enum_t timer_mode = mb_port_get_cur_tmr_mode(transp->base.port_obj);
mb_timer_mode_enum_t timer_mode = mb_port_get_cur_timer_mode(transp->base.port_obj);
mb_port_tmr_disable(transp->base.port_obj);
mb_port_timer_disable(transp->base.port_obj);
switch(timer_mode) {
case MB_TMODE_T35:
//need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
//need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
//ESP_EARLY_LOGD(TAG, "%p:EV_READY", transp->base.descr.parent);
break;
case MB_TMODE_RESPOND_TIMEOUT:
mb_port_evt_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
mb_port_event_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
ESP_EARLY_LOGW(TAG, "%p:EV_ERROR_RESPOND_TIMEOUT", transp->base.descr.parent);
break;
case MB_TMODE_CONVERT_DELAY:
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_EXECUTE));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_EXECUTE));
ESP_EARLY_LOGD(TAG, "%p:MB_TMODE_CONVERT_DELAY", transp->base.descr.parent);
break;
default:
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
break;
}
+13 -14
View File
@@ -21,7 +21,7 @@ typedef struct
uint8_t *snd_buf_cur;
uint16_t snd_buf_cnt;
uint16_t rcv_buf_pos;
volatile mb_tmr_mode_enum_t cur_tmr_mode;
volatile mb_timer_mode_enum_t cur_timer_mode;
mb_rtu_state_enum_t state;
} mbs_rtu_transp_t;
@@ -32,7 +32,7 @@ static mb_err_enum_t mbs_rtu_transp_receive(mb_trans_base_t *inst, uint8_t *rcv_
static mb_err_enum_t mbs_rtu_transp_send(mb_trans_base_t *inst, uint8_t slv_addr, const uint8_t *frame_ptr, uint16_t len);
static bool mbs_rtu_transp_rcv_fsm(mb_trans_base_t *inst);
static bool mbs_rtu_transp_snd_fsm(mb_trans_base_t *inst);
static bool mbs_rtu_transp_tmr_35_expired(void *inst);
static bool mbs_rtu_transp_timer_expired(void *inst);
static void mbs_rtu_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
void mbs_rtu_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
static uint16_t mbs_rtu_transp_get_snd_len(mb_trans_base_t *inst);
@@ -61,13 +61,13 @@ mb_err_enum_t mbs_rtu_transp_create(mb_serial_opts_t *ser_opts, void **in_out_in
mb_port_base_t *port_obj = (mb_port_base_t *)*in_out_inst;
ret = mb_port_ser_create(ser_opts, &port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "serial port creation, err: %d", ret);
ret = mb_port_tmr_create(port_obj, MB_RTU_GET_T35_VAL(ser_opts->baudrate));
ret = mb_port_timer_create(port_obj, MB_RTU_GET_T35_VAL(ser_opts->baudrate));
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "timer port creation, err: %d", ret);
ret = mb_port_evt_create(port_obj);
ret = mb_port_event_create(port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "event port creation, err: %d", ret);
transp->base.port_obj = port_obj;
// Set callback function pointer for the timer
port_obj->cb.tmr_expired = mbs_rtu_transp_tmr_35_expired;
port_obj->cb.tmr_expired = mbs_rtu_transp_timer_expired;
port_obj->cb.tx_empty = NULL;
port_obj->cb.byte_rcvd = NULL;
port_obj->arg = (void *)transp;
@@ -94,8 +94,8 @@ bool mbs_rtu_transp_delete(mb_trans_base_t *inst)
mbs_rtu_transp_t *transp = __containerof(inst, mbs_rtu_transp_t, base);
CRITICAL_SECTION(inst->lock) {
mb_port_ser_delete(transp->base.port_obj);
mb_port_tmr_delete(transp->base.port_obj);
mb_port_evt_delete(transp->base.port_obj);
mb_port_timer_delete(transp->base.port_obj);
mb_port_event_delete(transp->base.port_obj);
}
CRITICAL_SECTION_CLOSE(inst->lock);
free(transp);
@@ -108,16 +108,16 @@ static void mbs_rtu_transp_start(mb_trans_base_t *inst)
transp->state = MB_RTU_STATE_INIT;
CRITICAL_SECTION(inst->lock) {
mb_port_ser_enable(inst->port_obj);
//mb_port_tmr_enable(inst->port_obj);
//mb_port_timer_enable(inst->port_obj);
};
(void)mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
(void)mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
}
static void mbs_rtu_transp_stop(mb_trans_base_t *inst)
{
CRITICAL_SECTION(inst->lock) {
mb_port_ser_disable(inst->port_obj);
mb_port_tmr_disable(inst->port_obj);
mb_port_timer_disable(inst->port_obj);
};
}
@@ -208,14 +208,13 @@ static bool mbs_rtu_transp_snd_fsm(mb_trans_base_t *inst)
return false;
}
IRAM_ATTR
static bool mbs_rtu_transp_tmr_35_expired(void *inst)
static bool mbs_rtu_transp_timer_expired(void *inst)
{
mbs_rtu_transp_t *transp = __containerof(inst, mbs_rtu_transp_t, base);
bool need_poll = false;
//mb_tmr_mode_enum_t timer_mode = mb_port_get_cur_tmr_mode(transp->base.port_obj);
//mb_timer_mode_enum_t timer_mode = mb_port_get_cur_timer_mode(transp->base.port_obj);
mb_port_tmr_disable(transp->base.port_obj);
mb_port_timer_disable(transp->base.port_obj);
return need_poll;
}
+1 -1
View File
@@ -41,7 +41,7 @@ extern "C" {
/* ----------------------- Defines ------------------------------------------*/
#define MB_RTU_SER_PDU_SIZE_MIN 4 /*!< Minimum size of a Modbus RTU frame. */
#define MB_RTU_SER_PDU_SIZE_MAX MB_BUFFER_SIZE /*!< Maximum size of a Modbus RTU frame. */
#define MB_RTU_SER_PDU_SIZE_MAX MB_BUFFER_SIZE /*!< Maximum size of a Modbus RTU frame. */
#define MB_RTU_SER_PDU_SIZE_CRC 2 /*!< Size of CRC field in PDU. */
#define MB_RTU_SER_PDU_ADDR_OFF 0 /*!< Offset of slave address in Ser-PDU. */
#define MB_RTU_SER_PDU_PDU_OFF 1 /*!< Offset of Modbus-PDU in Ser-PDU. */
+11 -19
View File
@@ -34,7 +34,6 @@ static void mbm_tcp_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_pt
static void mbm_tcp_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
bool mbm_tcp_transp_delete(mb_trans_base_t *inst);
static bool mbm_tcp_transp_rq_is_bcast(mb_trans_base_t *inst);
//static bool mbm_tcp_transp_tmr_expired(void *inst);
mb_err_enum_t mbm_tcp_transp_create(mb_tcp_opts_t *tcp_opts, void **in_out_inst)
{
@@ -58,16 +57,16 @@ mb_err_enum_t mbm_tcp_transp_create(mb_tcp_opts_t *tcp_opts, void **in_out_inst)
mb_port_base_t *port_obj = (mb_port_base_t *)*in_out_inst;
ret = mbm_port_tcp_create(tcp_opts, &port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "port creation, err: %d", ret);
ret = mb_port_tmr_create(port_obj, MB_TCP_TIMEOUT_MS * MB_TIMER_TICS_PER_MS);
ret = mb_port_timer_create(port_obj, MB_TCP_TIMEOUT_MS * MB_TIMER_TICS_PER_MS);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "timer port creation, err: %d", ret);
// Override default response time if defined
if (tcp_opts->response_tout_ms) {
mb_port_tmr_set_response_time(port_obj, tcp_opts->response_tout_ms);
mb_port_timer_set_response_time(port_obj, tcp_opts->response_tout_ms);
}
ret = mb_port_evt_create(port_obj);
ret = mb_port_event_create(port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "event port creation, err: %d", ret);
// Set callback function pointer for the timer
// port_obj->cb.tmr_expired = mbm_tcp_transp_tmr_expired;
// port_obj->cb.tmr_expired = mbm_tcp_transp_timer_expired;
// port_obj->cb.tx_empty = NULL;
// port_obj->cb.byte_rcvd = NULL;
// port_obj->arg = (void *)transp;
@@ -83,6 +82,7 @@ error:
free(port_obj->timer_obj);
}
free(port_obj);
CRITICAL_SECTION_UNLOCK(transp->base.lock);
CRITICAL_SECTION_CLOSE(transp->base.lock);
free(transp);
return ret;
@@ -94,8 +94,8 @@ bool mbm_tcp_transp_delete(mb_trans_base_t *inst)
// destroy method of port tcp master is here
CRITICAL_SECTION(inst->lock) {
mbm_port_tcp_delete(inst->port_obj);
mb_port_tmr_delete(inst->port_obj);
mb_port_evt_delete(inst->port_obj);
mb_port_timer_delete(inst->port_obj);
mb_port_event_delete(inst->port_obj);
}
CRITICAL_SECTION_CLOSE(inst->lock);
free(transp);
@@ -108,10 +108,10 @@ static void mbm_tcp_transp_start(mb_trans_base_t *inst)
transp->state = MB_TCP_STATE_INIT;
CRITICAL_SECTION(inst->lock) {
mbm_port_tcp_enable(inst->port_obj);
mb_port_tmr_enable(inst->port_obj);
mb_port_timer_enable(inst->port_obj);
};
/* No special startup required for TCP. */
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_READY));
(void)mb_port_event_post(inst->port_obj, EVENT(EV_READY));
}
static void mbm_tcp_transp_stop(mb_trans_base_t *inst)
@@ -119,7 +119,7 @@ static void mbm_tcp_transp_stop(mb_trans_base_t *inst)
/* Make sure that no more clients are connected. */
CRITICAL_SECTION(inst->lock) {
mbm_port_tcp_disable(inst->port_obj);
mb_port_tmr_disable(inst->port_obj);
mb_port_timer_disable(inst->port_obj);
};
}
@@ -181,18 +181,10 @@ static mb_err_enum_t mbm_tcp_transp_send(mb_trans_base_t *inst, uint8_t address,
if (mbm_port_tcp_send_data(inst->port_obj, address, frame_ptr, tcp_len) == false) {
status = MB_EIO;
}
mb_port_tmr_respond_timeout_enable(inst->port_obj);
mb_port_timer_respond_timeout_enable(inst->port_obj);
return status;
}
// IRAM_ATTR
// static bool mbm_tcp_transp_tmr_expired(void *inst)
// {
// mbm_tcp_transp_t *transp = __containerof(inst, mbm_tcp_transp_t, base);
// return mbm_port_timer_expired(transp->base.port_obj);
// }
static void mbm_tcp_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf)
{
mbm_tcp_transp_t *transp = __containerof(inst, mbm_tcp_transp_t, base);
+29 -23
View File
@@ -31,7 +31,7 @@ static mb_err_enum_t mbs_tcp_transp_send(mb_trans_base_t *inst, uint8_t _unused,
static void mbs_tcp_transp_get_rcv_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
static void mbs_tcp_transp_get_snd_buf(mb_trans_base_t *inst, uint8_t **frame_ptr_buf);
bool mbs_tcp_transp_delete(mb_trans_base_t *inst);
static bool mbs_tcp_transp_tmr_expired(void *inst);
static bool mbs_tcp_transp_timer_expired(void *inst);
mb_err_enum_t mbs_tcp_transp_create(mb_tcp_opts_t *tcp_opts, void **in_out_inst)
{
@@ -55,17 +55,17 @@ mb_err_enum_t mbs_tcp_transp_create(mb_tcp_opts_t *tcp_opts, void **in_out_inst)
mb_port_base_t *port_obj = (mb_port_base_t *)*in_out_inst;
ret = mbs_port_tcp_create(tcp_opts, &port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "tcp port creation, err: %d", ret);
ret = mb_port_tmr_create(port_obj, MB_TCP_TIMEOUT_MS * MB_TIMER_TICS_PER_MS);
ret = mb_port_timer_create(port_obj, MB_TCP_TIMEOUT_MS * MB_TIMER_TICS_PER_MS);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "timer port creation, err: %d", ret);
// Override default response time if defined
if (tcp_opts->response_tout_ms) {
mb_port_tmr_set_response_time(port_obj, tcp_opts->response_tout_ms);
mb_port_timer_set_response_time(port_obj, tcp_opts->response_tout_ms);
}
ret = mb_port_evt_create(port_obj);
ret = mb_port_event_create(port_obj);
MB_GOTO_ON_FALSE((ret == MB_ENOERR), MB_EPORTERR, error, TAG, "event port creation, err: %d", ret);
transp->base.port_obj = port_obj;
// Set callback function pointer for the timer
port_obj->cb.tmr_expired = mbs_tcp_transp_tmr_expired;
port_obj->cb.tmr_expired = mbs_tcp_transp_timer_expired;
port_obj->cb.tx_empty = NULL;
port_obj->cb.byte_rcvd = NULL;
port_obj->arg = (void *)transp;
@@ -80,6 +80,7 @@ error:
free(port_obj->timer_obj);
}
free(port_obj);
CRITICAL_SECTION_UNLOCK(transp->base.lock);
CRITICAL_SECTION_CLOSE(transp->base.lock);
free(transp);
return ret;
@@ -91,8 +92,8 @@ bool mbs_tcp_transp_delete(mb_trans_base_t *inst)
// destroy method of port tcp slave is here
CRITICAL_SECTION(inst->lock) {
mbs_port_tcp_delete(inst->port_obj);
mb_port_tmr_delete(inst->port_obj);
mb_port_evt_delete(inst->port_obj);
mb_port_timer_delete(inst->port_obj);
mb_port_event_delete(inst->port_obj);
}
CRITICAL_SECTION_CLOSE(inst->lock);
free(transp);
@@ -103,10 +104,10 @@ static void mbs_tcp_transp_start(mb_trans_base_t *inst)
{
CRITICAL_SECTION(inst->lock) {
mbs_port_tcp_enable(inst->port_obj);
mb_port_tmr_enable(inst->port_obj);
mb_port_timer_enable(inst->port_obj);
};
/* No special startup required for TCP. */
(void)mb_port_evt_post(inst->port_obj, EVENT(EV_READY));
(void)mb_port_event_post(inst->port_obj, EVENT(EV_READY));
}
static void mbs_tcp_transp_stop(mb_trans_base_t *inst)
@@ -114,24 +115,30 @@ static void mbs_tcp_transp_stop(mb_trans_base_t *inst)
/* Make sure that no more clients are connected. */
CRITICAL_SECTION(inst->lock) {
mbs_port_tcp_disable(inst->port_obj);
mb_port_tmr_disable(inst->port_obj);
mb_port_timer_disable(inst->port_obj);
};
}
static mb_err_enum_t mbs_tcp_transp_receive(mb_trans_base_t *inst, uint8_t *rcv_addr, uint8_t **frame_ptr_buf, uint16_t *pbuf_len)
{
if (!pbuf_len || !frame_ptr_buf || !pbuf_len) {
return MB_EIO;
}
mbs_tcp_transp_t *transp = __containerof(inst, mbs_tcp_transp_t, base);
uint8_t *frame_ptr = (uint8_t *)transp->recv_buf;
uint16_t length = *pbuf_len;
mb_err_enum_t status = MB_EIO;
uint8_t *frame_ptr;
uint16_t len = *pbuf_len;
uint16_t pid;
if (mbs_port_tcp_recv_data(inst->port_obj, &frame_ptr, &len) != false) {
if (mbs_port_tcp_recv_data(inst->port_obj, &frame_ptr, &length) != false) {
pid = frame_ptr[MB_TCP_PID] << 8U;
pid |= frame_ptr[MB_TCP_PID + 1];
if (pid == MB_TCP_PROTOCOL_ID) {
*frame_ptr_buf = &frame_ptr[MB_TCP_FUNC];
*pbuf_len = len - MB_TCP_FUNC;
*pbuf_len = length - MB_TCP_FUNC;
status = MB_ENOERR;
/* Get MBAP UID field if its support is enabled.
@@ -170,36 +177,35 @@ static mb_err_enum_t mbs_tcp_transp_send(mb_trans_base_t *inst, uint8_t _unused,
return status;
}
__attribute__((unused))
static bool mbs_tcp_transp_tmr_expired(void *inst)
static bool mbs_tcp_transp_timer_expired(void *inst)
{
mbs_tcp_transp_t *transp = __containerof(inst, mbs_tcp_transp_t, base);
bool need_poll = false;
mb_tmr_mode_enum_t timer_mode = mb_port_get_cur_tmr_mode(transp->base.port_obj);
mb_timer_mode_enum_t timer_mode = mb_port_get_cur_timer_mode(transp->base.port_obj);
mb_port_tmr_disable(transp->base.port_obj);
mb_port_timer_disable(transp->base.port_obj);
switch(timer_mode) {
case MB_TMODE_T35:
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
ESP_EARLY_LOGD(TAG, "EV_READY");
break;
case MB_TMODE_RESPOND_TIMEOUT:
mb_port_evt_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
mb_port_event_set_err_type(transp->base.port_obj, EV_ERROR_RESPOND_TIMEOUT);
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_ERROR_PROCESS));
ESP_EARLY_LOGD(TAG, "EV_ERROR_RESPOND_TIMEOUT");
break;
case MB_TMODE_CONVERT_DELAY:
/* If timer mode is convert delay, the master event then turns EV_MASTER_EXECUTE status. */
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_EXECUTE));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_EXECUTE));
ESP_EARLY_LOGD(TAG, "MB_TMODE_CONVERT_DELAY");
break;
default:
need_poll = mb_port_evt_post(transp->base.port_obj, EVENT(EV_READY));
need_poll = mb_port_event_post(transp->base.port_obj, EVENT(EV_READY));
break;
}