forked from espressif/esp-modbus
feature modbus tcp master slave v2
This commit is contained in:
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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 ---------------------------------*/
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user