From d04ff303dd87ffc8ae499818bb8be24bfe2417ec Mon Sep 17 00:00:00 2001 From: aleks Date: Fri, 25 Jul 2025 10:08:24 +0200 Subject: [PATCH] fix nodes reconnection issues --- Kconfig | 10 +- modbus/mb_ports/common/mb_transaction.c | 26 ++++ modbus/mb_ports/common/mb_transaction.h | 2 + modbus/mb_ports/common/port_other.c | 8 +- modbus/mb_ports/tcp/port_tcp_driver.c | 22 ++- modbus/mb_ports/tcp/port_tcp_driver.h | 1 + modbus/mb_ports/tcp/port_tcp_slave.c | 191 ++++++++++++++++-------- modbus/mb_ports/tcp/port_tcp_utils.c | 6 +- 8 files changed, 184 insertions(+), 82 deletions(-) diff --git a/Kconfig b/Kconfig index 57a01cb..2fb9b84 100644 --- a/Kconfig +++ b/Kconfig @@ -72,12 +72,12 @@ menu "Modbus configuration" then master can send next frame. config FMB_QUEUE_LENGTH - int "Modbus serial task queue length" - range 0 200 - default 20 + int "Modbus event task queue length" + range 10 500 + default 50 help - Modbus serial driver queue length. It is used by event queue task. - See the serial driver API for more information. + Modbus event queue length. It is used by event queue tasks + for corresponding communication mode. config FMB_PORT_TASK_STACK_SIZE int "Modbus port task stack size" diff --git a/modbus/mb_ports/common/mb_transaction.c b/modbus/mb_ports/common/mb_transaction.c index 78a4d2f..1a8d06c 100644 --- a/modbus/mb_ports/common/mb_transaction.c +++ b/modbus/mb_ports/common/mb_transaction.c @@ -201,6 +201,14 @@ esp_err_t transaction_item_set_state(transaction_item_handle_t item, pending_sta return ESP_FAIL; } +transaction_tick_t transaction_item_get_tick(transaction_item_handle_t item) +{ + if (item) { + return atomic_load(&(item->tick)); + } + return 0; +} + 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); @@ -232,6 +240,24 @@ int transaction_delete_single_expired(transaction_handle_t transaction, transact return msg_id; } +int transaction_delete_by_node_id(transaction_handle_t transaction, int node_id) +{ + int deleted_items = 0; + transaction_item_handle_t item, tmp; + CRITICAL_SECTION_LOCK(transaction->lock); + STAILQ_FOREACH_SAFE(item, transaction->list, next, tmp) { + if (item->node_id == node_id) { + 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; +} + int transaction_delete_expired(transaction_handle_t transaction, transaction_tick_t current_tick, transaction_tick_t timeout) { int deleted_items = 0; diff --git a/modbus/mb_ports/common/mb_transaction.h b/modbus/mb_ports/common/mb_transaction.h index d189ac3..e2be7ea 100644 --- a/modbus/mb_ports/common/mb_transaction.h +++ b/modbus/mb_ports/common/mb_transaction.h @@ -54,6 +54,7 @@ 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_by_node_id(transaction_handle_t transaction, int node_id); int transaction_delete_expired(transaction_handle_t transaction, transaction_tick_t current_tick, transaction_tick_t timeout); /** @@ -66,6 +67,7 @@ esp_err_t transaction_set_state(transaction_handle_t transaction, int msg_id, pe 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); +transaction_tick_t transaction_item_get_tick(transaction_item_handle_t item); 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); diff --git a/modbus/mb_ports/common/port_other.c b/modbus/mb_ports/common/port_other.c index 51d3925..ff369ef 100644 --- a/modbus/mb_ports/common/port_other.c +++ b/modbus/mb_ports/common/port_other.c @@ -63,7 +63,11 @@ 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) - return -1; + return ESP_ERR_INVALID_ARG; + } + + if (!uxQueueSpacesAvailable(queue)) { + return ESP_ERR_NO_MEM; } if (pframe) { @@ -114,7 +118,7 @@ ssize_t queue_pop(QueueHandle_t queue, void *pbuf, size_t len, frame_entry_t *pf } return len; err: - return -1; + return ESP_ERR_INVALID_STATE; } bool queue_is_empty(QueueHandle_t queue) diff --git a/modbus/mb_ports/tcp/port_tcp_driver.c b/modbus/mb_ports/tcp/port_tcp_driver.c index 5b73a77..3b1e548 100644 --- a/modbus/mb_ports/tcp/port_tcp_driver.c +++ b/modbus/mb_ports/tcp/port_tcp_driver.c @@ -302,7 +302,7 @@ int mb_drv_open(void *ctx, mb_uid_info_t addr_info, int flags) goto err; } if (pdrv_ctx->mb_node_open_count > MB_MAX_FDS) { - ESP_LOGD(TAG, "Exceeded maximum node count: %d", pdrv_ctx->mb_node_open_count); + ESP_LOGE(TAG, "Exceeded maximum node count: %d", pdrv_ctx->mb_node_open_count); goto err; } pdrv_ctx->mb_node_open_count++; @@ -461,7 +461,6 @@ mb_node_info_t *mb_drv_get_next_node_from_set(void *ctx, int *pfd, fd_set *pfdse && (MB_GET_NODE_STATE(pnode_info) >= MB_SOCK_STATE_CONNECTED) && (FD_ISSET(pnode_info->index, pfdset) || (FD_ISSET(pnode_info->sock_id, pfdset)))) { *pfd = fd; - //FD_CLR(pnode_info->sock_id, pfdset); return pnode_info; } } @@ -576,7 +575,7 @@ err_t mb_drv_check_node_state(void *ctx, int *pfd, uint32_t timeout_ms) pnode = mb_drv_get_next_node_from_set(ctx, pfd, &pdrv_ctx->conn_set); if (pnode && FD_ISSET(pnode->sock_id, &pdrv_ctx->conn_set)) { uint64_t last_read_div_us = (esp_timer_get_time() - pnode->recv_time); - ESP_LOGD(TAG, "%p, node: %d, sock: %d, IP:%s, check connection timeout = %" PRId64 ", rcv_time: %" PRId64 " %" PRId32, + ESP_LOGD(TAG, "%p, node: %d, sock: %d, IP:%s, check connection timeout = %" PRId64 ", rcv_time: %" PRId64 " %" PRIu32, ctx, (int)pnode->index, (int)pnode->sock_id, pnode->addr_info.ip_addr_str, (esp_timer_get_time() / 1000), pnode->recv_time / 1000, timeout_ms); if (last_read_div_us >= (uint64_t)(timeout_ms * 1000)) { @@ -631,11 +630,20 @@ void mb_drv_tcp_task(void *ctx) mb_uid_info_t node_info; int sock_id = port_accept_connection(pdrv_ctx->listen_sock_fd, &node_info); if (sock_id) { - int fd = mb_drv_open(pdrv_ctx, node_info, 0); - if (fd < 0) { - ESP_LOGE(TAG, "%p, unable to open node: %s", pdrv_ctx, node_info.ip_addr_str); + if (pdrv_ctx->mb_node_open_count >= MB_MAX_FDS) { + ESP_LOGE(TAG, "%p, unable to accept node, maximum is %u connections.", pdrv_ctx, MB_MAX_FDS); + struct linger sl; + sl.l_onoff = 1; // non-zero value enables linger option in kernel + sl.l_linger = 0; // timeout interval in seconds + setsockopt(sock_id, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)); + close(sock_id); } else { - DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, fd); + int fd = mb_drv_open(pdrv_ctx, node_info, 0); + if (fd < 0) { + ESP_LOGE(TAG, "%p, unable to open node: #%d, %s", pdrv_ctx, fd, node_info.ip_addr_str); + } else { + DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, fd); + } } } } else { diff --git a/modbus/mb_ports/tcp/port_tcp_driver.h b/modbus/mb_ports/tcp/port_tcp_driver.h index 98692fa..daf691b 100644 --- a/modbus/mb_ports/tcp/port_tcp_driver.h +++ b/modbus/mb_ports/tcp/port_tcp_driver.h @@ -198,6 +198,7 @@ typedef enum _mb_sync_event { MB_SYNC_EVENT_RECV_OK = 0x0001, MB_SYNC_EVENT_RECV_FAIL = 0x0002, MB_SYNC_EVENT_SEND_OK = 0x0003, + MB_SYNC_EVENT_SEND_ERR = 0x0004, MB_SYNC_EVENT_TOUT } mb_sync_event_t; diff --git a/modbus/mb_ports/tcp/port_tcp_slave.c b/modbus/mb_ports/tcp/port_tcp_slave.c index 05e5fa5..0a99d18 100644 --- a/modbus/mb_ports/tcp/port_tcp_slave.c +++ b/modbus/mb_ports/tcp/port_tcp_slave.c @@ -230,7 +230,7 @@ bool mbs_port_tcp_recv_data(mb_port_base_t *inst, uint8_t **ppframe, uint16_t *p //*ppframe = pbuf; *plength = (uint16_t)len; status = true; - ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", get packet TID: 0x%04" PRIx16 ", %p."), + ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", read 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)) { @@ -263,8 +263,9 @@ bool mbs_port_tcp_send_data(mb_port_base_t *inst, uint8_t *pframe, uint16_t leng transaction_item_handle_t item; mb_drv_lock(pdrv_ctx); - item = transaction_dequeue(port_obj->transaction, CONFIRMED, NULL); - if (item) { + //item = transaction_dequeue(port_obj->transaction, CONFIRMED, NULL); + item = transaction_get(port_obj->transaction, tid); + if (item && transaction_item_get_state(item) == CONFIRMED) { uint16_t msg_id = 0; int node_id = 0; uint8_t *pbuf = transaction_item_get_data(item, NULL, &msg_id, &node_id); @@ -277,16 +278,16 @@ bool mbs_port_tcp_send_data(mb_port_base_t *inst, uint8_t *pframe, uint16_t leng 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, ", + ESP_LOGE(TAG, "%p, node: #%d, socket(#%d)[%s], modbus 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."); + ESP_LOGE(TAG, "transaction queue set reply state fail."); } } } else { - ESP_LOGE(TAG, "queue can not find the item to send."); + ESP_LOGE(TAG, "queue can not find transaction TID: 0x%04" PRIx16 ", drop frame", tid); } mb_drv_unlock(pdrv_ctx); @@ -316,6 +317,13 @@ static uint64_t mbs_port_tcp_sync_event(void *inst, mb_sync_event_t sync_event) case MB_SYNC_EVENT_SEND_OK: mb_port_event_post(inst, EVENT(EV_FRAME_SENT)); break; + + case MB_SYNC_EVENT_SEND_ERR: + mb_port_timer_disable(inst); + mb_port_event_set_err_type(inst, EV_ERROR_RESPOND_TIMEOUT); + mb_port_event_post(inst, EVENT(EV_ERROR_PROCESS)); + break; + default: break; } @@ -404,16 +412,16 @@ MB_EVENT_HANDLER(mbs_on_recv_data) { if (!queue_is_empty(pnode->rx_queue)) { - ESP_LOGD(TAG, "%p, node #%d(%d) [%s], receive data ready.", ctx, (int)pevent_info->opt_fd, + ESP_LOGD(TAG, "%p, node #%d, socket(#%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."), + ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", received packet TID: 0x%04" PRIx16), pdrv_ctx, pnode->index, pnode->sock_id, - pnode->addr_info.ip_addr_str, (unsigned)tid_counter, frame_entry.pbuf); + pnode->addr_info.ip_addr_str, (unsigned)tid_counter); mb_drv_lock(pdrv_ctx); transaction_message_t msg; msg.buffer = frame_entry.pbuf; @@ -421,6 +429,7 @@ MB_EVENT_HANDLER(mbs_on_recv_data) msg.msg_id = frame_entry.tid; msg.node_id = pnode->index; msg.pnode = pnode; + // Enqueue the transaction, keep time of receiving. 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); @@ -442,11 +451,11 @@ MB_EVENT_HANDLER(mbs_on_recv_data) // send receive event to modbus object to get the new data mb_drv_lock(pdrv_ctx); uint16_t msg_id = 0; - uint64_t tick = 0; - (void)transaction_item_get_data(item, NULL, &msg_id, NULL); - tick = port_get_timestamp(); + int node_id = 0; + (void)transaction_item_get_data(item, NULL, &msg_id, &node_id); + pnode = mb_drv_get_node(pdrv_ctx, node_id); 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); + // transaction_set_tick(port_obj->transaction, msg_id, (transaction_tick_t)port_get_timestamp()); 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, @@ -473,67 +482,97 @@ 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; + transaction_item_handle_t item = NULL; + frame_entry_t frame_entry = {0}; 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 + if (pnode && !queue_is_empty(pnode->tx_queue)) { + // 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); - pnode->tid_counter = tid; // update the TID to the current one + if (sz) { + uint16_t tid = MB_TCP_MBAP_GET_FIELD(frame_entry.pbuf, MB_TCP_TID); + // Try to find actual transaction for current TID, + // if not found just ignore the frame as expired + item = transaction_get(port_obj->transaction, tid); + if (item && pnode) { + // Check if the TID is equal to the current received TID for this node. + // If not, means the slave was not able to process the previous transaction on time. + if ((tid != pnode->tid_counter) || (MB_GET_NODE_STATE(pnode) < MB_SOCK_STATE_CONNECTED)) { + mb_drv_lock(pdrv_ctx); + pdrv_ctx->event_cbs.mb_sync_event_cb(pdrv_ctx->event_cbs.port_arg, MB_SYNC_EVENT_SEND_ERR); + if (transaction_delete(port_obj->transaction, tid) != ESP_OK) { + ESP_LOGE(TAG, "Failed to remove queued TID:0x%04" PRIx16, (int)tid); + } else { + ESP_LOGD(TAG, "Remove the message TID:0x%04" PRIx16, (int)tid); + } + (void)mb_drv_set_status_flag(pdrv_ctx, MB_FLAG_TRANSACTION_READY); + mb_drv_unlock(pdrv_ctx); + uint64_t tick = (transaction_tick_t)transaction_item_get_tick(item); + uint64_t time_div_us = (esp_timer_get_time() - tick); + ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", frame TID:0x%04" PRIx16 "!=0x%04" PRIx16 ", slave is busy."), + ctx, (int)pnode->index, (int)pnode->sock_id, + pnode->addr_info.ip_addr_str, pnode->tid_counter, tid); + ESP_LOGW(TAG, "%p, " MB_NODE_FMT(", handling time [ms]: %" PRIu64 ", exceeds master response time."), + ctx, (int)pnode->index, (int)pnode->sock_id, + pnode->addr_info.ip_addr_str, (time_div_us / 1000)); + } else { + mb_drv_lock(pdrv_ctx); + 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; + ESP_LOG_BUFFER_HEX_LEVEL("SENT", frame_entry.pbuf, ret, ESP_LOG_DEBUG); + } + (void)mb_drv_set_status_flag(pdrv_ctx, MB_FLAG_TRANSACTION_READY); + pdrv_ctx->event_cbs.mb_sync_event_cb(pdrv_ctx->event_cbs.port_arg, MB_SYNC_EVENT_SEND_OK); + esp_err_t err = transaction_set_state(port_obj->transaction, tid, TRANSMITTED); + if (err == ESP_OK) { + ESP_LOGD(TAG, "%p, " MB_NODE_FMT(", sent packet TID: 0x%04" PRIx16 ", %p."), + pdrv_ctx, pnode->index, pnode->sock_id, + pnode->addr_info.ip_addr_str, tid, frame_entry.pbuf); + } else { + ESP_LOGE(TAG, "%p, " MB_NODE_FMT(", transaction set state fail for TID: 0x%04" PRIx16 ", %p."), + pdrv_ctx, pnode->index, pnode->sock_id, + pnode->addr_info.ip_addr_str, tid, frame_entry.pbuf); + } + if (transaction_delete_item(port_obj->transaction, item) != 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); + } + 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); + } + } else { + // Note: the transaction processing time is increase proportional to number of connected Masters. + // If it is still needed to connect several number of Masters simultaneously, + // then the slave response time option needs to be increased in Masters. + ESP_LOGE(TAG, "%p, " MB_NODE_FMT(", transaction not found for TID: 0x%04" PRIx16 ", drop data %p."), + ctx, (int)pnode->index, (int)pnode->sock_id, + pnode->addr_info.ip_addr_str, tid, pnode); + pdrv_ctx->event_cbs.mb_sync_event_cb(pdrv_ctx->event_cbs.port_arg, MB_SYNC_EVENT_SEND_ERR); + (void)mb_drv_set_status_flag(pdrv_ctx, MB_FLAG_TRANSACTION_READY); } - 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_READY); - 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); + ESP_LOGE(TAG, "%p, "MB_NODE_FMT(", frame is invalid, drop data."), + ctx, (int)pnode->index, (int)pnode->sock_id, pnode->addr_info.ip_addr_str); } 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_drv_check_suspend_shutdown(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; + 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); mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd); if (!pnode) { @@ -541,11 +580,26 @@ MB_EVENT_HANDLER(mbs_on_error) return; } // Check if the node is not alive for timeout - int ret = mb_drv_check_node_state(pdrv_ctx, (int *)&pevent_info->opt_fd, MB_TCP_EVENT_LOOP_TICK_MS); - if ((ret != ERR_OK) && (ret != ERR_TIMEOUT)) { - ESP_LOGE(TAG, "Node: #%d is not alive, err= %d", (int)pevent_info->opt_fd, ret); + // int ret = mb_drv_check_node_state(pdrv_ctx, (int *)&pevent_info->opt_fd, MB_EVENT_SEND_RCV_TOUT_MS); + // if ((ret != ERR_OK) && (ret != ERR_TIMEOUT)) { + mb_status_flags_t flags = mb_drv_wait_status_flag(port_obj->pdriver, MB_FLAG_TRANSACTION_READY, TRANSACTION_TICKS); + if (MB_FLAG_TRANSACTION_READY == flags) { + (void)mb_drv_clear_status_flag(pdrv_ctx, MB_FLAG_TRANSACTION_READY); + mb_drv_lock(pdrv_ctx); + int ret = pnode->error; + ESP_LOGE(TAG, "%p, " MB_NODE_FMT(", communication fail, err= %d"), + port_obj, pnode->index, pnode->sock_id, + pnode->addr_info.ip_addr_str, (int)ret); + (void)transaction_delete_by_node_id(port_obj->transaction, pevent_info->opt_fd); + mb_drv_unlock(pdrv_ctx); mb_drv_close(pdrv_ctx, pevent_info->opt_fd); + (void)mb_drv_set_status_flag(pdrv_ctx, MB_FLAG_TRANSACTION_READY); + } else { + // postpone the packet processing + DRIVER_SEND_EVENT(ctx, MB_EVENT_ERROR, pnode->index); + return; } + mb_drv_check_suspend_shutdown(ctx); } MB_EVENT_HANDLER(mbs_on_close) @@ -553,6 +607,7 @@ 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); + mbs_tcp_port_t *port_obj = __containerof(pdrv_ctx->parent, mbs_tcp_port_t, base); mb_node_info_t *pnode =NULL; // if close all sockets event is received if (pevent_info->opt_fd < 0) @@ -573,6 +628,7 @@ MB_EVENT_HANDLER(mbs_on_close) pnode = mb_drv_get_node(pdrv_ctx, pevent_info->opt_fd); if (pnode && (MB_GET_NODE_STATE(pnode) >= MB_SOCK_STATE_OPENED)) { if ((pnode->sock_id < 0) && FD_ISSET(pnode->sock_id, &pdrv_ctx->open_set)) { + (void)transaction_delete_by_node_id(port_obj->transaction, pevent_info->opt_fd); mb_drv_close(ctx, pevent_info->opt_fd); } } @@ -585,12 +641,17 @@ 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); + mbs_tcp_port_t *port_obj = __containerof(pdrv_ctx->parent, mbs_tcp_port_t, base); static int curr_fd = 0; - ESP_LOGD(TAG, "%s %s: fd: %d, %d", (char *)base, __func__, (int)curr_fd, pdrv_ctx->node_conn_count); + mb_node_info_t *pnode = mb_drv_get_node(pdrv_ctx, curr_fd); + ESP_LOGD(TAG, "%s %s: fd: %d, count: %d", (char *)base, __func__, (int)curr_fd, pdrv_ctx->node_conn_count); mb_drv_check_suspend_shutdown(ctx); int ret = mb_drv_check_node_state(pdrv_ctx, &curr_fd, MB_RECONNECT_TIME_MS); if ((ret != ERR_OK) && (ret != ERR_TIMEOUT)) { - ESP_LOGE(TAG, "Node: %d, connection lost, err= %d", curr_fd, ret); + ESP_LOGE(TAG, "%p, " MB_NODE_FMT(", connection lost, err=%d, drop connection."), + port_obj, pnode->index, pnode->sock_id, + pnode->addr_info.ip_addr_str, (int)ret); + (void)transaction_delete_by_node_id(port_obj->transaction, curr_fd); mb_drv_close(pdrv_ctx, curr_fd); } if ((curr_fd + 1) >= (pdrv_ctx->node_conn_count)) { diff --git a/modbus/mb_ports/tcp/port_tcp_utils.c b/modbus/mb_ports/tcp/port_tcp_utils.c index 0909397..704dc62 100644 --- a/modbus/mb_ports/tcp/port_tcp_utils.c +++ b/modbus/mb_ports/tcp/port_tcp_utils.c @@ -201,8 +201,8 @@ int port_read_packet(mb_node_info_t *pinfo) pinfo->recv_err = ret; return ret; } else if (ret != MB_TCP_UID) { - ESP_LOGD(TAG, "Socket (#%d)(%s), fail to read modbus header. ret=%d", - pinfo->sock_id, pinfo->addr_info.ip_addr_str, ret); + ESP_LOGD(TAG, "node #%d, Socket (#%d)(%s), fail to read modbus header, err=%d", + pinfo->fd, pinfo->sock_id, pinfo->addr_info.ip_addr_str, ret); pinfo->recv_err = ERR_VAL; return ERR_VAL; } @@ -914,7 +914,7 @@ int port_accept_connection(int listen_sock_id, mb_uid_info_t *pinfo) // 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); + ESP_LOGI(TAG, "Socket (#%d), accept client connection from address[port]: %s[%u]", (int)sock_id, addr_str, pinfo->port); paddr = strdup(addr_str); if (paddr) { pinfo->fd = sock_id;