diff --git a/plugins/modbus/modbus-rtu.json b/plugins/modbus/modbus-rtu.json index e5f2acee..bb02f2dd 100644 --- a/plugins/modbus/modbus-rtu.json +++ b/plugins/modbus/modbus-rtu.json @@ -76,6 +76,32 @@ "max": 30000 } }, + "max_retries": { + "name": "Maximum Retry Times", + "name_zh": "最大重试次数", + "description": "The maximum number of retries after a failed attempt to send a read command", + "description_zh": "发送读取指令失败后最大重试次数", + "attribute": "required", + "type": "int", + "default": 0, + "valid": { + "min": 0, + "max": 3 + } + }, + "retry_interval": { + "name": "Retry Interval", + "name_zh": "指令重新发送间隔", + "description": "Resend reading instruction interval(ms) after a failed attempt to send a read command", + "description_zh": "发送读取指令失败后重新发送读指令时间间隔,单位为毫秒", + "attribute": "required", + "type": "int", + "default": 0, + "valid": { + "min": 20, + "max": 10000 + } + }, "interval": { "name": "Send Interval", "name_zh": "指令发送间隔", @@ -304,7 +330,7 @@ "transport_mode": { "name": "Transport Mode", "name_zh": "传输模式", - "description": "Neuron as the client, or as the server", + "description": "TCP transfer or UDP transfer", "description_zh": "TCP 传输或 UDP 传输", "attribute": "required", "type": "map", diff --git a/plugins/modbus/modbus-tcp.json b/plugins/modbus/modbus-tcp.json index ab008a2c..343e8bfd 100644 --- a/plugins/modbus/modbus-tcp.json +++ b/plugins/modbus/modbus-tcp.json @@ -45,7 +45,7 @@ "transport_mode": { "name": "Transport Mode", "name_zh": "传输模式", - "description": "Neuron as the client, or as the server", + "description": "TCP transfer or UDP transfer", "description_zh": "TCP 传输或 UDP 传输", "attribute": "required", "type": "map", @@ -88,6 +88,32 @@ "value": 0 } }, + "max_retries": { + "name": "Maximum Retry Times", + "name_zh": "最大重试次数", + "description": "The maximum number of retries after a failed attempt to send a read command", + "description_zh": "发送读取指令失败后最大重试次数", + "attribute": "required", + "type": "int", + "default": 0, + "valid": { + "min": 0, + "max": 3 + } + }, + "retry_interval": { + "name": "Retry Interval", + "name_zh": "指令重新发送间隔", + "description": "Resend reading instruction interval(ms) after a failed attempt to send a read command", + "description_zh": "发送读取指令失败后重新发送读指令时间间隔,单位为毫秒", + "attribute": "required", + "type": "int", + "default": 0, + "valid": { + "min": 20, + "max": 10000 + } + }, "interval": { "name": "Send Interval", "name_zh": "指令发送间隔", diff --git a/plugins/modbus/modbus_req.c b/plugins/modbus/modbus_req.c index 2d900c6d..b3d1c536 100644 --- a/plugins/modbus/modbus_req.c +++ b/plugins/modbus/modbus_req.c @@ -110,6 +110,22 @@ int modbus_send_msg(void *ctx, uint16_t n_byte, uint8_t *bytes) return ret; } +int modbus_stack_read_retry(neu_plugin_t *plugin, struct modbus_group_data *gd, + uint16_t i, uint16_t j, uint16_t *response_size) +{ + struct timespec t3 = { .tv_sec = plugin->retry_interval / 1000, + .tv_nsec = + 1000 * 1000 * (plugin->retry_interval % 1000) }; + struct timespec t4 = { 0 }; + nanosleep(&t3, &t4); + plog_notice(plugin, "Resend read req. Times:%hu", j + 1); + int ret = modbus_stack_read(plugin->stack, gd->cmd_sort->cmd[i].slave_id, + gd->cmd_sort->cmd[i].area, + gd->cmd_sort->cmd[i].start_address, + gd->cmd_sort->cmd[i].n_register, response_size); + return ret; +} + int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group, uint16_t max_byte) { @@ -156,10 +172,20 @@ int modbus_group_timer(neu_plugin_t *plugin, neu_plugin_group_t *group, rtt = neu_time_ms() - read_tms; } if (ret <= 0) { - modbus_value_handle(plugin, gd->cmd_sort->cmd[i].slave_id, 0, NULL, - NEU_ERR_PLUGIN_DISCONNECTED); - rtt = NEU_METRIC_LAST_RTT_MS_MAX; - neu_conn_disconnect(plugin->conn); + for (uint16_t j = 0; j < plugin->max_retries; j++) { + ret = modbus_stack_read_retry(plugin, gd, i, j, &response_size); + if (ret > 0) { + ret = process_protocol_buf(plugin, response_size); + rtt = neu_time_ms() - read_tms; + break; + } + } + if (ret <= 0) { + modbus_value_handle(plugin, gd->cmd_sort->cmd[i].slave_id, 0, + NULL, NEU_ERR_PLUGIN_DISCONNECTED); + rtt = NEU_METRIC_LAST_RTT_MS_MAX; + neu_conn_disconnect(plugin->conn); + } } if (plugin->interval > 0) { struct timespec t1 = { .tv_sec = plugin->interval / 1000, diff --git a/plugins/modbus/modbus_req.h b/plugins/modbus/modbus_req.h index 81f42f5b..30c666a1 100644 --- a/plugins/modbus/modbus_req.h +++ b/plugins/modbus/modbus_req.h @@ -41,6 +41,8 @@ struct neu_plugin { modbus_protocol_e protocol; uint16_t interval; + uint16_t retry_interval; + uint16_t max_retries; }; void modbus_conn_connected(void *data, int fd); diff --git a/plugins/modbus/modbus_rtu.c b/plugins/modbus/modbus_rtu.c index 8b6716c4..6d97da9d 100644 --- a/plugins/modbus/modbus_rtu.c +++ b/plugins/modbus/modbus_rtu.c @@ -158,6 +158,10 @@ static int driver_config(neu_plugin_t *plugin, const char *config) neu_json_elem_t baud = { .name = "baud", .t = NEU_JSON_INT }; neu_json_elem_t data = { .name = "data", .t = NEU_JSON_INT }; + neu_json_elem_t max_retries = { .name = "max_retries", .t = NEU_JSON_INT }; + neu_json_elem_t retry_interval = { .name = "retry_interval", + .t = NEU_JSON_INT }; + ret = neu_parse_param((char *) config, &err_param, 3, &link, &timeout, &interval); if (ret != 0) { @@ -189,7 +193,18 @@ static int driver_config(neu_plugin_t *plugin, const char *config) return -1; } - param.log = plugin->common.log; + ret = neu_parse_param((char *) config, &err_param, 2, &port, &max_retries, + &retry_interval); + if (ret != 0) { + free(err_param); + max_retries.v.val_int = 0; + retry_interval.v.val_int = 0; + } + + param.log = plugin->common.log; + plugin->max_retries = max_retries.v.val_int; + plugin->retry_interval = retry_interval.v.val_int; + if (link.v.val_int == 0) { param.type = NEU_CONN_TTY_CLIENT; diff --git a/plugins/modbus/modbus_tcp.c b/plugins/modbus/modbus_tcp.c index 16dfdb3d..fad07bf1 100644 --- a/plugins/modbus/modbus_tcp.c +++ b/plugins/modbus/modbus_tcp.c @@ -148,6 +148,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config) neu_json_elem_t mode = { .name = "connection_mode", .t = NEU_JSON_INT }; neu_json_elem_t tmode = { .name = "transport_mode", .t = NEU_JSON_INT }; neu_conn_param_t param = { 0 }; + neu_json_elem_t max_retries = { .name = "max_retries", .t = NEU_JSON_INT }; + neu_json_elem_t retry_interval = { .name = "retry_interval", + .t = NEU_JSON_INT }; ret = neu_parse_param((char *) config, &err_param, 6, &port, &host, &mode, &timeout, &interval, &tmode); @@ -166,8 +169,18 @@ static int driver_config(neu_plugin_t *plugin, const char *config) return -1; } - param.log = plugin->common.log; - plugin->interval = interval.v.val_int; + ret = neu_parse_param((char *) config, &err_param, 2, &port, &max_retries, + &retry_interval); + if (ret != 0) { + free(err_param); + max_retries.v.val_int = 0; + retry_interval.v.val_int = 0; + } + + param.log = plugin->common.log; + plugin->interval = interval.v.val_int; + plugin->max_retries = max_retries.v.val_int; + plugin->retry_interval = retry_interval.v.val_int; if (tmode.v.val_int == 1) { param.type = NEU_CONN_UDP;