Modbus plugin: add optional delay between two consecutive modbus requests sent by master/client
--- a/modbus/mb_runtime.c Wed Sep 28 09:19:07 2022 +0200
+++ b/modbus/mb_runtime.c Sun Feb 19 08:37:27 2023 +0000
@@ -373,6 +373,14 @@
clock_gettime(CLOCK_MONOTONIC, &cur_time);
fprintf(stderr, "Modbus client thread (%%d) - new cycle (%%ld:%%ld)!\n", client_node_id, cur_time.tv_sec, cur_time.tv_nsec);
*/
+
+ /* Variable use to specify delay to introduce between any two consecutive requests we send out to the same client
+ * Initially set to 0 since we don't want to introduce a delay before the very first request.
+ */
+ struct timespec inter_request_delay;
+ inter_request_delay.tv_sec = 0;
+ inter_request_delay.tv_nsec = 0;
+
int req;
for (req=0; req < NUMBER_OF_CLIENT_REQTS; req ++){
/* just do the requests belonging to the client */
@@ -392,6 +400,14 @@
fprintf(stderr, "Modbus client thread (%%d): RUNNING Modbus request %%d (periodic = %%d flag_exec_req = %%d)\n",
client_node_id, req, client_nodes[client_requests[req].client_node_id].periodic_act, client_requests[req].flag_exec_req );
*/
+
+ /* Insert a delay between any two consecutive requests to the same client
+ * Needed because some clients will ignore our requests if we send them out too fast.
+ *
+ * Note that since we don't want to insert a delay before the very first request we will send, the inter_request_delay variable
+ * is first initialised to 0. It will be set to the correct delay after the first (and second, third, etc..) request has completed.
+ */
+ clock_nanosleep(CLOCK_MONOTONIC, 0 /* relative sleep */, &inter_request_delay, NULL);
int res_tmp = __execute_mb_request(req);
client_requests[req].tn_error_code = 0; // assume success
@@ -449,7 +465,7 @@
client_requests[req].flag_mb_error_code = client_requests[req].mb_error_code;
client_requests[req].flag_tn_error_code = client_requests[req].tn_error_code;
- /* We have just finished excuting a client transcation request.
+ /* We have just finished executing a client transaction request.
* If the current cycle was activated by user request we reset the flag used to ask to run it
*/
if (0 != client_requests[req].flag_exec_req) {
@@ -457,6 +473,12 @@
client_requests[req].flag_exec_started = 0;
}
+ /* We have just finished executing a client transaction request.
+ * Set the inter request delay before we send the next request. Value of delay is set by user in beremiz GUI
+ */
+ inter_request_delay.tv_sec = client_nodes[client_node_id].req_delay / 1000; /* ms to seconds */
+ inter_request_delay.tv_nsec = (client_nodes[client_node_id].req_delay %% 1000) * 1000 * 1000; /* ms to ns */
+
//fprintf(stderr, "Modbus plugin: RUNNING<---> of Modbus request %%d (periodic = %%d flag_exec_req = %%d)\n",
// req, client_nodes[client_requests[req].client_node_id].periodic_act, client_requests[req].flag_exec_req );
}
@@ -956,7 +978,7 @@
* running (i.e. before or after __init_() ets called)!
*
* The following functions are never called from other C code. They are
- * called instead from the python code in runtime/Modbus_config.py, that
+ * called instead from the python code in modbus/web_settings.py, that
* implements the web server extension for configuring Modbus parameters.
*/
@@ -974,7 +996,7 @@
-/* NOTE: We could have the python code in runtime/Modbus_config.py
+/* NOTE: We could have the python code in modbus/web_settings.py
* directly access the server_node_t and client_node_t structures,
* however this would create a tight coupling between these two
* disjoint pieces of code.
@@ -1017,6 +1039,7 @@
int __modbus_get_ClientNode_parity (int nodeid) {return client_nodes[nodeid].node_address.addr.rtu.parity; }
int __modbus_get_ClientNode_stop_bits (int nodeid) {return client_nodes[nodeid].node_address.addr.rtu.stop_bits;}
u64 __modbus_get_ClientNode_comm_period(int nodeid) {return client_nodes[nodeid].comm_period; }
+u64 __modbus_get_ClientNode_req_delay (int nodeid) {return client_nodes[nodeid].req_delay; }
const char * __modbus_get_ClientNode_addr_type (int nodeid) {return addr_type_str[client_nodes[nodeid].node_address.naf];}
const char * __modbus_get_ServerNode_config_name(int nodeid) {return server_nodes[nodeid].config_name; }
@@ -1037,6 +1060,7 @@
void __modbus_set_ClientNode_parity (int nodeid, int value) {client_nodes[nodeid].node_address.addr.rtu.parity = value;}
void __modbus_set_ClientNode_stop_bits (int nodeid, int value) {client_nodes[nodeid].node_address.addr.rtu.stop_bits = value;}
void __modbus_set_ClientNode_comm_period(int nodeid, u64 value) {client_nodes[nodeid].comm_period = value;}
+void __modbus_set_ClientNode_req_delay (int nodeid, u64 value) {client_nodes[nodeid].req_delay = value;}
void __modbus_set_ServerNode_host (int nodeid, const char * value) {if (strcmp(value,"#ANY#")==0) value = "";
--- a/modbus/mb_runtime.h Wed Sep 28 09:19:07 2022 +0200
+++ b/modbus/mb_runtime.h Sun Feb 19 08:37:27 2023 +0000
@@ -124,7 +124,8 @@
node_addr_t node_address;
int mb_nd; // modbus library node used for this client
int init_state; // store how far along the client's initialization has progressed
- u64 comm_period;// period to use when periodically sending requests to remote server
+ u64 comm_period;// period to use when periodically sending requests to remote server (in ms)
+ u64 req_delay; // delay between 2 consecutive requests sent to remote slaves/server (in ms)
int prev_error; // error code of the last printed error message (0 when no error)
pthread_t thread_id; // thread handling all communication for this client node
pthread_t timer_thread_id; // thread handling periodical timer for this client node
--- a/modbus/mb_utils.py Wed Sep 28 09:19:07 2022 +0200
+++ b/modbus/mb_utils.py Sun Feb 19 08:37:27 2023 +0000
@@ -140,10 +140,10 @@
params: child - the correspondent subplugin in Beremiz
"""
node_init_template = '''/*node %(locnodestr)s*/
-{"%(locnodestr)s", "%(config_name)s", "%(device)s", "", {naf_rtu, {.rtu = {NULL, %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */}'''
-
- location = ".".join(map(str, child.GetCurrentLocation()))
- config_name, device, baud, parity, stopbits, coms_period = GetCTVals(child, range(6))
+{"%(locnodestr)s", "%(config_name)s", "%(device)s", "", {naf_rtu, {.rtu = {NULL, %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period (ms)*/, %(coms_delay)s /* inter request delay (ms)*/, 0 /* prev_error */}'''
+
+ location = ".".join(map(str, child.GetCurrentLocation()))
+ config_name, device, baud, parity, stopbits, coms_period, coms_delay = GetCTVals(child, range(7))
node_dict = {"locnodestr": location,
"config_name": config_name,
@@ -151,7 +151,8 @@
"baud": baud,
"parity": modbus_serial_parity_dict[parity],
"stopbits": stopbits,
- "coms_period": coms_period}
+ "coms_period": coms_period,
+ "coms_delay": coms_delay}
return node_init_template % node_dict
@@ -161,16 +162,17 @@
params: child - the correspondent subplugin in Beremiz
"""
node_init_template = '''/*node %(locnodestr)s*/
-{"%(locnodestr)s", "%(config_name)s", "%(host)s", "%(port)s", {naf_tcp, {.tcp = {NULL, NULL, DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */, 0 /* prev_error */}'''
-
- location = ".".join(map(str, child.GetCurrentLocation()))
- config_name, host, port, coms_period = GetCTVals(child, range(4))
+{"%(locnodestr)s", "%(config_name)s", "%(host)s", "%(port)s", {naf_tcp, {.tcp = {NULL, NULL, DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period (ms)*/, %(coms_delay)s /* inter request delay (ms)*/, 0 /* prev_error */}'''
+
+ location = ".".join(map(str, child.GetCurrentLocation()))
+ config_name, host, port, coms_period, coms_delay = GetCTVals(child, range(5))
node_dict = {"locnodestr": location,
"config_name": config_name,
"host": host,
"port": port,
- "coms_period": coms_period}
+ "coms_period": coms_period,
+ "coms_delay": coms_delay}
return node_init_template % node_dict
--- a/modbus/modbus.py Wed Sep 28 09:19:07 2022 +0200
+++ b/modbus/modbus.py Sun Feb 19 08:37:27 2023 +0000
@@ -319,11 +319,19 @@
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
+ <xsd:attribute name="Request_Delay_in_ms" use="optional" default="0">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="2147483647"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""
- # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms
+ # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms and Request_Delay_in_ms
# corresponds to aprox 25 days.
CTNChildrenTypes = [("ModbusRequest", _RequestPlug, "Request")]
# TODO: Replace with CTNType !!!
@@ -565,11 +573,19 @@
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
+ <xsd:attribute name="Request_Delay_in_ms" use="optional" default="0">
+ <xsd:simpleType>
+ <xsd:restriction base="xsd:integer">
+ <xsd:minInclusive value="0"/>
+ <xsd:maxInclusive value="2147483647"/>
+ </xsd:restriction>
+ </xsd:simpleType>
+ </xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
"""
- # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms
+ # NOTE: Max value of 2147483647 (i32_max) for Invocation_Rate_in_ms and Request_Delay_in_ms
# corresponds to aprox 25 days.
CTNChildrenTypes = [("ModbusRequest", _RequestPlug, "Request")]
# TODO: Replace with CTNType !!!
--- a/modbus/web_settings.py Wed Sep 28 09:19:07 2022 +0200
+++ b/modbus/web_settings.py Sun Feb 19 08:37:27 2023 +0000
@@ -149,7 +149,8 @@
# annotate.Integer, ...)
("host" , _("Remote IP Address") , ctypes.c_char_p, MB_StrippedString),
("port" , _("Remote Port Number") , ctypes.c_char_p, MB_StrippedString),
- ("comm_period" , _("Invocation Rate (ms)") , ctypes.c_ulonglong, annotate.Integer )
+ ("comm_period" , _("Invocation Rate (ms)") , ctypes.c_ulonglong, annotate.Integer ),
+ ("req_delay" , _("Request Delay (ms)") , ctypes.c_ulonglong, annotate.Integer )
]
RTUclient_parameters = [
@@ -161,7 +162,8 @@
("baud" , _("Baud Rate") , ctypes.c_int, MB_Baud ),
("parity" , _("Parity") , ctypes.c_int, MB_Parity ),
("stop_bits" , _("Stop Bits") , ctypes.c_int, MB_StopBits ),
- ("comm_period" , _("Invocation Rate (ms)") , ctypes.c_ulonglong, annotate.Integer)
+ ("comm_period" , _("Invocation Rate (ms)") , ctypes.c_ulonglong, annotate.Integer),
+ ("req_delay" , _("Request Delay (ms)") , ctypes.c_ulonglong, annotate.Integer)
]
TCPserver_parameters = [