Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions modbus/mb_ports/tcp/port_tcp_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,22 @@ mb_uid_info_t *mbm_port_tcp_get_slave_info(mb_port_base_t *inst, uint8_t uid, mb
{
mbm_tcp_port_t *port_obj = __containerof(inst, mbm_tcp_port_t, base);
mb_uid_info_t *addr_info = NULL;
mb_node_info_t *info_ptr = mb_drv_get_node_info_from_addr(port_obj->drv_obj, uid);
if (info_ptr && (MB_GET_NODE_STATE(info_ptr) >= exp_state)) {
addr_info = &info_ptr->addr_info;
mb_node_info_t *node_ptr = mb_drv_get_node_info_from_addr(port_obj->drv_obj, uid);
if (!node_ptr) {
return NULL;
} else {
if (MB_GET_NODE_STATE(node_ptr) >= exp_state) {
addr_info = &node_ptr->addr_info;
} else {
ESP_LOGW(TAG, "The node #%d, uid = %d, is not alive, try to repair connection.", node_ptr->index, node_ptr->addr_info.uid);
addr_info = NULL;
if ((node_ptr->sock_id < 0) && FD_ISSET(node_ptr->index, &port_obj->drv_obj->open_set)) {
// Try to restore node connection as soon as possible
DRIVER_SEND_EVENT(port_obj->drv_obj, MB_EVENT_RESOLVE, node_ptr->index);
}
}
}

return addr_info;
}

Expand Down Expand Up @@ -478,21 +490,24 @@ MB_EVENT_HANDLER(mbm_on_connect)
drv_obj->node_conn_count--;
}
mb_drv_unlock(ctx);
DRIVER_SEND_EVENT(ctx, MB_EVENT_CLOSE, event_info->opt_fd);
port_close_connection(node_ptr);
} else {
ESP_LOGD(TAG, "%p, slave: #%d, sock:%d, IP:%s, connection is in progress.",
ctx, (int)event_info->opt_fd, (int)node_ptr->sock_id,
node_ptr->addr_info.ip_addr_str);
MB_SET_NODE_STATE(node_ptr, 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_TIMEOUT, node_ptr->index);
// Follow reconnecion cycle
DRIVER_SEND_EVENT(ctx, MB_EVENT_CONNECT, event_info->opt_fd);
}
break;
case ERR_CONN:
ESP_LOGE(TAG, "Modbus connection phase, slave: %d (%s), connection error (%d).",
(int)event_info->opt_fd, node_ptr->addr_info.ip_addr_str, (int)err);
port_close_connection(node_ptr);
DRIVER_SEND_EVENT(ctx, MB_EVENT_TIMEOUT, node_ptr->index);
// On connection error, try to reconnect node as soon as possible
DRIVER_SEND_EVENT(ctx, MB_EVENT_RESOLVE, node_ptr->index);
break;
default:
ESP_LOGE(TAG, "Invalid error state, slave: %d (%s), error = %d.",
Expand Down
78 changes: 40 additions & 38 deletions modbus/mb_ports/tcp/port_tcp_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,52 +317,54 @@ int port_keep_alive_enable(int sock, int timeout_sec)
return 0;
}

// Check connection for timeout helper
// Check if connection is alive
err_t port_check_alive(mb_node_info_t *info_ptr, uint32_t timeout_ms)
{
fd_set write_set;
fd_set err_set;
err_t err = -1;
struct timeval time_val;

if (info_ptr && info_ptr->sock_id != -1) {
FD_ZERO(&write_set);
FD_ZERO(&err_set);
FD_SET(info_ptr->sock_id, &write_set);
FD_SET(info_ptr->sock_id, &err_set);
port_ms_to_tv(timeout_ms, &time_val);
// Check if the socket is writable
err = select(info_ptr->sock_id + 1, NULL, &write_set, &err_set, &time_val);
if ((err < 0) || FD_ISSET(info_ptr->sock_id, &err_set)) {
if (errno == EINPROGRESS) {
err = ERR_INPROGRESS;
} else {
ESP_LOGV(TAG, MB_NODE_FMT(" connection, select write err(errno) = %d(%d)."),
info_ptr->index, info_ptr->sock_id, info_ptr->addr_info.ip_addr_str, err, (int)errno);
err = ERR_CONN;
}
} else if (err == 0) {
ESP_LOGV(TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
info_ptr->sock_id, info_ptr->addr_info.ip_addr_str, err, (int)errno);
return ERR_INPROGRESS;
} else {
int opt_err = 0;
uint32_t opt_len = sizeof(opt_err);
// Check socket error
err = getsockopt(info_ptr->sock_id, SOL_SOCKET, SO_ERROR, (void *)&opt_err, (socklen_t *)&opt_len);
if (opt_err != 0) {
ESP_LOGD(TAG, "Socket(#%d)(%s), sock error occurred (%d).",
info_ptr->sock_id, info_ptr->addr_info.ip_addr_str, opt_err);
return ERR_CONN;
}
ESP_LOGV(TAG, "Socket(#%d)(%s), is alive.",
info_ptr->sock_id, info_ptr->addr_info.ip_addr_str);
return ERR_OK;
}
} else {
err = ERR_CONN;
if (!info_ptr || info_ptr->sock_id == -1) {
return ERR_VAL;
}
FD_ZERO(&write_set);
FD_ZERO(&err_set);
FD_SET(info_ptr->sock_id, &write_set);
FD_SET(info_ptr->sock_id, &err_set);
port_ms_to_tv(timeout_ms, &time_val);
// Check if the socket is writable and no errors
err = select(info_ptr->sock_id + 1, NULL, &write_set, &err_set, &time_val);
if (err < 0 || FD_ISSET(info_ptr->sock_id, &err_set)) {
ESP_LOGV(TAG, MB_NODE_FMT(" connection, select write err(errno) = %d(%d)."),
info_ptr->index, info_ptr->sock_id, info_ptr->addr_info.ip_addr_str, err, (int)errno);
return ERR_CONN;
}
return err;
if (err == 0) {
ESP_LOGV(TAG, "Socket(#%d)(%s), connection timeout occurred, err(errno) = %d(%d).",
info_ptr->sock_id, info_ptr->addr_info.ip_addr_str, err, (int)errno);
return ERR_INPROGRESS;
}
int opt_err = 0;
socklen_t opt_len = sizeof(opt_err);
// Check socket error
if (getsockopt(info_ptr->sock_id, SOL_SOCKET, SO_ERROR, &opt_err, &opt_len) < 0) {
ESP_LOGV(TAG, "Socket(#%d)(%s), sock error occurred (%d).",
info_ptr->sock_id, info_ptr->addr_info.ip_addr_str, opt_err);
return ERR_CONN;
}
if (opt_err == 0) {
ESP_LOGV(TAG, "Socket(#%d)(%s), is alive.",
info_ptr->sock_id, info_ptr->addr_info.ip_addr_str);
return ERR_OK;
}
if (opt_err == EINPROGRESS || opt_err == EALREADY) {
return ERR_INPROGRESS;
}
ESP_LOGV(TAG, "Socket(#%d)(%s), sock error occurred (%d).",
info_ptr->sock_id, info_ptr->addr_info.ip_addr_str, opt_err);
errno = opt_err; // optional, only for logging
return ERR_CONN;
}

// Unblocking connect function
Expand Down