Modbus plugin: provide user programs feedback on current connection status mapped onto a WORD located variable
--- a/modbus/mb_runtime.c Sun Jun 07 23:46:16 2020 +0100
+++ b/modbus/mb_runtime.c Mon Dec 21 21:15:47 2020 +0000
@@ -60,7 +60,7 @@
(int) client_requests[request_id].count,
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -72,7 +72,7 @@
(int) client_requests[request_id].count,
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -84,7 +84,7 @@
(int) client_requests[request_id].count,
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -96,7 +96,7 @@
(int) client_requests[request_id].count,
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -106,7 +106,7 @@
client_requests[request_id].coms_buffer[0],
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -116,7 +116,7 @@
client_requests[request_id].coms_buffer[0],
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -136,7 +136,7 @@
client_requests[request_id].coms_buffer,
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -147,7 +147,7 @@
client_requests[request_id].coms_buffer,
client_nodes[client_requests[request_id].client_node_id].mb_nd,
client_requests[request_id].retries,
- &(client_requests[request_id].error_code),
+ &(client_requests[request_id].mb_error_code),
&(client_requests[request_id].resp_timeout),
&(client_requests[request_id].coms_buf_mutex));
@@ -362,34 +362,39 @@
// req, client_nodes[client_requests[req].client_node_id].periodic_act, client_requests[req].flag_exec_req );
int res_tmp = __execute_mb_request(req);
+ client_requests[req].tn_error_code = 0; // assume success
switch (res_tmp) {
case PORT_FAILURE: {
if (res_tmp != client_nodes[client_node_id].prev_error)
fprintf(stderr, "Modbus plugin: Error connecting Modbus client %%s to remote server.\n", client_nodes[client_node_id].location);
client_nodes[client_node_id].prev_error = res_tmp;
+ client_requests[req].tn_error_code = 1; // error accessing IP network, or serial interface
break;
}
case INVALID_FRAME: {
if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error))
fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned an invalid/corrupted frame.\n", client_requests[req].location);
client_requests[req].prev_error = res_tmp;
+ client_requests[req].tn_error_code = 2; // reply received from server was an invalid frame
break;
}
case TIMEOUT: {
if ((res_tmp != client_requests[req].prev_error) && (0 == client_nodes[client_node_id].prev_error))
fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s timed out waiting for reply from server.\n", client_requests[req].location);
client_requests[req].prev_error = res_tmp;
+ client_requests[req].tn_error_code = 3; // server did not reply before timeout expired
break;
}
case MODBUS_ERROR: {
- if (client_requests[req].prev_error != client_requests[req].error_code) {
- fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned error code 0x%%2x", client_requests[req].location, client_requests[req].error_code);
- if (client_requests[req].error_code <= MAX_MODBUS_ERROR_CODE ) {
- fprintf(stderr, "(%%s)", modbus_error_messages[client_requests[req].error_code]);
+ if (client_requests[req].prev_error != client_requests[req].mb_error_code) {
+ fprintf(stderr, "Modbus plugin: Modbus client request configured at location %%s was unsuccesful. Server/slave returned error code 0x%%2x", client_requests[req].location, client_requests[req].mb_error_code);
+ if (client_requests[req].mb_error_code <= MAX_MODBUS_ERROR_CODE ) {
+ fprintf(stderr, "(%%s)", modbus_error_messages[client_requests[req].mb_error_code]);
fprintf(stderr, ".\n");
}
}
- client_requests[req].prev_error = client_requests[req].error_code;
+ client_requests[req].prev_error = client_requests[req].mb_error_code;
+ client_requests[req].tn_error_code = 4; // server returned a valid Modbus error frame
break;
}
default: {
@@ -404,7 +409,13 @@
break;
}
}
-
+
+ /* Set the flag_exec_status that is mapped onto a located WORD variable, so the user program
+ * knows how the communication is going.
+ * This flag is an ammalgamation of the data in mb_error_code and tn_error_code
+ */
+ client_requests[req].flag_exec_status = client_requests[req].tn_error_code * 256 + client_requests[req].mb_error_code;
+
/* We have just finished excuting a client transcation request.
* If the current cycle was activated by user request we reset the flag used to ask to run it
*/
--- a/modbus/mb_runtime.h Sun Jun 07 23:46:16 2020 +0100
+++ b/modbus/mb_runtime.h Mon Dec 21 21:15:47 2020 +0000
@@ -147,7 +147,8 @@
u16 address;
u16 count;
int retries;
- u8 error_code; // modbus error code (if any) of current request
+ u8 mb_error_code; // modbus error code (if any) of last executed request
+ u8 tn_error_code; // transaction error code (if any) of last executed request
int prev_error; // error code of the last printed error message (0 when no error)
struct timespec resp_timeout;
u8 write_on_change; // boolean flag. If true => execute MB request when data to send changes
@@ -176,9 +177,12 @@
* 1 -> error accessing IP network, or serial interface
* 2 -> reply received from server was an invalid frame
* 3 -> server did not reply before timeout expired
- * 4 -> server returned a valid error frame
+ * 4 -> server returned a valid Modbus error frame
* -> if the MSByte is 4, the LSByte will store the MB error code returned by the server
* -> will be reset (set to 0) once this MB transaction has completed sucesfully
+ *
+ * In other words, this variable will be set from the current status of the
+ * mb_error_code and tn_error_code flags after each request.
*/
u16 flag_exec_status;
} client_request_t;
--- a/modbus/mb_utils.py Sun Jun 07 23:46:16 2020 +0100
+++ b/modbus/mb_utils.py Mon Dec 21 21:15:47 2020 +0000
@@ -186,7 +186,7 @@
req_init_template = '''/*request %(locreqstr)s*/
{"%(locreqstr)s", %(nodeid)s, %(slaveid)s, %(iotype)s, %(func_nr)s, %(address)s , %(count)s,
-DEF_REQ_SEND_RETRIES, 0 /* error_code */, 0 /* prev_code */, {%(timeout_s)d, %(timeout_ns)d} /* timeout */, %(write_on_change)d /* write_on_change */,
+DEF_REQ_SEND_RETRIES, 0 /* mb_error_code */, 0 /* tn_error_code */, 0 /* prev_code */, {%(timeout_s)d, %(timeout_ns)d} /* timeout */, %(write_on_change)d /* write_on_change */,
{%(buffer)s}, {%(buffer)s}}'''
timeout = int(GetCTVal(child, 4))
--- a/modbus/modbus.py Sun Jun 07 23:46:16 2020 +0100
+++ b/modbus/modbus.py Mon Dec 21 21:15:47 2020 +0000
@@ -131,13 +131,22 @@
# %QX1.2.3.n
entries = []
entries.append({
- "name": "Exec. request flag",
+ "name": "Execute request flag",
"type": LOCATION_VAR_MEMORY,
"size": 1, # BOOL flag
"IEC_type": "BOOL", # BOOL flag
"var_name": "var_name",
"location": "X" + ".".join([str(i) for i in current_location]) + ".0.0",
- "description": "MB request execution control flag",
+ "description": "Modbus request execution control flag",
+ "children": []})
+ entries.append({
+ "name": "Request Status flag",
+ "type": LOCATION_VAR_MEMORY,
+ "size": 16, # WORD flag
+ "IEC_type": "WORD", # WORD flag
+ "var_name": "var_name",
+ "location": "W" + ".".join([str(i) for i in current_location]) + ".0.1",
+ "description": "Modbus request status flag",
"children": []})
for offset in range(address, address + count):
entries.append({
@@ -879,15 +888,19 @@
if ( relative_addr in xrange(int(GetCTVal(subchild, 2))) # condition (a) explained above
and len(iecvar["LOC"]) < 5): # condition (b) explained above
if str(iecvar["NAME"]) not in loc_vars_list:
- loc_vars.append(
- "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
+ loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].plcv_buffer[%d];" % (client_requestid, relative_addr))
loc_vars_list.append(str(iecvar["NAME"]))
# Now add the located variable in case it is a flag (condition (b) above
if len(iecvar["LOC"]) >= 5: # condition (b) explained above
if str(iecvar["NAME"]) not in loc_vars_list:
- loc_vars.append(
- "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].flag_exec_req;" % (client_requestid))
- loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a Execution Request Flag (mapped onto %QXa.b.c.0.0), so last number is a '0'
+ if iecvar["LOC"][4] == 0:
+ loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].flag_exec_req;" % (client_requestid))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a Communication Status Flag (mapped onto %QWa.b.c.0.1), so last number is a '1'
+ if iecvar["LOC"][4] == 1:
+ loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].flag_exec_status;" % (client_requestid))
+ loc_vars_list.append(str(iecvar["NAME"]))
client_requestid += 1
tcpclient_node_count += 1
client_nodeid += 1
@@ -920,7 +933,7 @@
# onto a location with 4 numbers (e.g. %QX0.1.2.0.0), where the last
# two numbers are always '0.0', and the first two identify the request.
# In the following if, we check for this condition by checking
- # if their are at least 4 or more number in the location's address.
+ # if there are at least 4 or more number in the location's address.
if ( relative_addr in xrange(int(GetCTVal(subchild, 2))) # condition (a) explained above
and len(iecvar["LOC"]) < 5): # condition (b) explained above
if str(iecvar["NAME"]) not in loc_vars_list:
@@ -930,9 +943,14 @@
# Now add the located variable in case it is a flag (condition (b) above
if len(iecvar["LOC"]) >= 5: # condition (b) explained above
if str(iecvar["NAME"]) not in loc_vars_list:
- loc_vars.append(
- "u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].flag_exec_req;" % (client_requestid))
- loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a Execution Request Flag (mapped onto %QXa.b.c.0.0), so last number is a '0'
+ if iecvar["LOC"][4] == 0:
+ loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].flag_exec_req;" % (client_requestid))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a Communication Status Flag (mapped onto %QWa.b.c.0.1), so last number is a '1'
+ if iecvar["LOC"][4] == 1:
+ loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &client_requests[%d].flag_exec_status;" % (client_requestid))
+ loc_vars_list.append(str(iecvar["NAME"]))
client_requestid += 1
rtuclient_node_count += 1
client_nodeid += 1