--- a/modbus/mb_runtime.c Tue Feb 23 16:16:12 2021 +0100
+++ b/modbus/mb_runtime.c Fri Apr 09 09:45:28 2021 +0200
@@ -200,12 +200,42 @@
}
-static int __read_inbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes)
- {return __pack_bits(((server_mem_t *)mem_map)->ro_bits, start_addr, bit_count, data_bytes);}
-static int __read_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes)
- {return __pack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes);}
-static int __write_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes)
- {return __unpack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes); }
+static int __read_inbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) {
+ int res = __pack_bits(((server_mem_t *)mem_map)->ro_bits, start_addr, bit_count, data_bytes);
+
+ if (res >= 0) {
+ /* update the flag and counter of Modbus requests we have processed. */
+ ((server_mem_t *)mem_map)->flag_read_req_counter++;
+ ((server_mem_t *)mem_map)->flag_read_req_flag = 1;
+ }
+
+ return res;
+}
+
+static int __read_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) {
+ int res = __pack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes);
+
+ if (res >= 0) {
+ /* update the flag and counter of Modbus requests we have processed. */
+ ((server_mem_t *)mem_map)->flag_read_req_counter++;
+ ((server_mem_t *)mem_map)->flag_read_req_flag = 1;
+ }
+
+ return res;
+}
+
+static int __write_outbits (void *mem_map, u16 start_addr, u16 bit_count, u8 *data_bytes) {
+ int res = __unpack_bits(((server_mem_t *)mem_map)->rw_bits, start_addr, bit_count, data_bytes);
+
+ if (res >= 0) {
+ /* update the flag and counter of Modbus requests we have processed. */
+ ((server_mem_t *)mem_map)->flag_write_req_counter++;
+ ((server_mem_t *)mem_map)->flag_write_req_flag = 1;
+ }
+
+ return res;
+}
+
@@ -214,6 +244,10 @@
if ((start_addr + word_count) > MEM_AREA_SIZE)
return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+ /* update the flag and counter of Modbus requests we have processed. */
+ ((server_mem_t *)mem_map)->flag_read_req_counter++;
+ ((server_mem_t *)mem_map)->flag_read_req_flag = 1;
+
/* use memcpy() because loop with pointers (u16 *) caused alignment problems */
memcpy(/* dest */ (void *)data_words,
/* src */ (void *)&(((server_mem_t *)mem_map)->ro_words[start_addr]),
@@ -228,6 +262,10 @@
if ((start_addr + word_count) > MEM_AREA_SIZE)
return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+ /* update the flag and counter of Modbus requests we have processed. */
+ ((server_mem_t *)mem_map)->flag_read_req_counter++;
+ ((server_mem_t *)mem_map)->flag_read_req_flag = 1;
+
/* use memcpy() because loop with pointers (u16 *) caused alignment problems */
memcpy(/* dest */ (void *)data_words,
/* src */ (void *)&(((server_mem_t *)mem_map)->rw_words[start_addr]),
@@ -243,6 +281,10 @@
if ((start_addr + word_count) > MEM_AREA_SIZE)
return -ERR_ILLEGAL_DATA_ADDRESS; /* ERR_ILLEGAL_DATA_ADDRESS defined in mb_util.h */
+ /* update the flag and counter of Modbus requests we have processed. */
+ ((server_mem_t *)mem_map)->flag_write_req_counter++;
+ ((server_mem_t *)mem_map)->flag_write_req_flag = 1;
+
/* WARNING: The data returned in the data_words[] array is not guaranteed to be 16 bit aligned.
* It is not therefore safe to cast it to an u16 data type.
* The following code cannot be used. memcpy() is used instead.
@@ -545,6 +587,10 @@
// -1 --> modbus node created!; no thread created
// >=0 --> modbus node created!; thread created!
server_nodes[index].mb_nd = -2;
+ server_nodes[index].mem_area.flag_write_req_flag = 0;
+ server_nodes[index].mem_area.flag_write_req_counter = 0;
+ server_nodes[index].mem_area.flag_read_req_counter = 0;
+ server_nodes[index].mem_area.flag_read_req_flag = 0;
/* see comment in mb_runtime.h to understad why we need to initialize these entries */
switch (server_nodes[index].node_address.naf) {
case naf_tcp:
--- a/modbus/modbus.py Tue Feb 23 16:16:12 2021 +0100
+++ b/modbus/modbus.py Fri Apr 09 09:45:28 2021 +0200
@@ -447,6 +447,82 @@
""" Return the node's Configuration_Name """
return self.ModbusServerNode.getConfiguration_Name()
+ def GetVariableLocationTree(self):
+ current_location = self.GetCurrentLocation()
+ name = self.BaseParams.getName()
+ # start off with flags that count the number of Modbus requests/transactions
+ # handled by this Modbus server/slave.
+ # These flags are mapped onto located variables and therefore available to the user programs
+ # May be used to detect communication errors.
+ # execute the Modbus request.
+ # NOTE: If the Modbus slave has a 'current_location' of
+ # %QX1.2
+ # then the "Modbus Read Request Counter" will be %MD1.2.0
+ # then the "Modbus Write Request Counter" will be %MD1.2.1
+ # then the "Modbus Read Request Flag" will be %MD1.2.2
+ # then the "Modbus Write Request Flag" will be %MD1.2.3
+ #
+ # Note that any MemoryArea contained under this server/slave
+ # will ocupy the locations of type
+ # %MX or %MW
+ # which will never clash with the %MD used here.
+ # Additionaly, any MemoryArea contained under this server/slave
+ # will ocupy locations with
+ # %M1.2.a.b (with a and b being numbers in range 0, 1, ...)
+ # and therefore never ocupy the locations
+ # %M1.2.0
+ # %M1.2.1
+ # %M1.2.2
+ # %M1.2.3
+ # used by the following flags/counters.
+ entries = []
+ entries.append({
+ "name": "Modbus Read Request Counter",
+ "type": LOCATION_VAR_MEMORY,
+ "size": 32, # UDINT flag
+ "IEC_type": "UDINT", # UDINT flag
+ "var_name": "var_name",
+ "location": "D" + ".".join([str(i) for i in current_location]) + ".0",
+ "description": "Modbus read request counter",
+ "children": []})
+ entries.append({
+ "name": "Modbus Write Request Counter",
+ "type": LOCATION_VAR_MEMORY,
+ "size": 32, # UDINT flag
+ "IEC_type": "UDINT", # UDINT flag
+ "var_name": "var_name",
+ "location": "D" + ".".join([str(i) for i in current_location]) + ".1",
+ "description": "Modbus write request counter",
+ "children": []})
+ entries.append({
+ "name": "Modbus Read 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]) + ".2",
+ "description": "Modbus read request flag",
+ "children": []})
+ entries.append({
+ "name": "Modbus write 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]) + ".3",
+ "description": "Modbus write request flag",
+ "children": []})
+ # recursively call all the Memory Areas under this Modbus server/save
+ # i.e., all the children objects which will be of class _MemoryAreaPlug
+ for child in self.IECSortedChildren():
+ entries.append(child.GetVariableLocationTree())
+
+ return {"name": name,
+ "type": LOCATION_CONFNODE,
+ "location": ".".join([str(i) for i in current_location]) + ".x",
+ "children": entries}
+
+
def CTNGenerate_C(self, buildpath, locations):
"""
Generate C code
@@ -631,6 +707,82 @@
""" Return the node's Configuration_Name """
return self.ModbusRTUslave.getConfiguration_Name()
+ def GetVariableLocationTree(self):
+ current_location = self.GetCurrentLocation()
+ name = self.BaseParams.getName()
+ # start off with flags that count the number of Modbus requests/transactions
+ # handled by this Modbus server/slave.
+ # These flags are mapped onto located variables and therefore available to the user programs
+ # May be used to detect communication errors.
+ # execute the Modbus request.
+ # NOTE: If the Modbus slave has a 'current_location' of
+ # %QX1.2
+ # then the "Modbus Read Request Counter" will be %MD1.2.0
+ # then the "Modbus Write Request Counter" will be %MD1.2.1
+ # then the "Modbus Read Request Flag" will be %MD1.2.2
+ # then the "Modbus Write Request Flag" will be %MD1.2.3
+ #
+ # Note that any MemoryArea contained under this server/slave
+ # will ocupy the locations of type
+ # %MX or %MW
+ # which will never clash with the %MD used here.
+ # Additionaly, any MemoryArea contained under this server/slave
+ # will ocupy locations with
+ # %M1.2.a.b (with a and b being numbers in range 0, 1, ...)
+ # and therefore never ocupy the locations
+ # %M1.2.0
+ # %M1.2.1
+ # %M1.2.2
+ # %M1.2.3
+ # used by the following flags/counters.
+ entries = []
+ entries.append({
+ "name": "Modbus Read Request Counter",
+ "type": LOCATION_VAR_MEMORY,
+ "size": 32, # UDINT flag
+ "IEC_type": "UDINT", # UDINT flag
+ "var_name": "var_name",
+ "location": "D" + ".".join([str(i) for i in current_location]) + ".0",
+ "description": "Modbus read request counter",
+ "children": []})
+ entries.append({
+ "name": "Modbus Write Request Counter",
+ "type": LOCATION_VAR_MEMORY,
+ "size": 32, # UDINT flag
+ "IEC_type": "UDINT", # UDINT flag
+ "var_name": "var_name",
+ "location": "D" + ".".join([str(i) for i in current_location]) + ".1",
+ "description": "Modbus write request counter",
+ "children": []})
+ entries.append({
+ "name": "Modbus Read 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]) + ".2",
+ "description": "Modbus read request flag",
+ "children": []})
+ entries.append({
+ "name": "Modbus write 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]) + ".3",
+ "description": "Modbus write request flag",
+ "children": []})
+ # recursively call all the Memory Areas under this Modbus server/save
+ # i.e., all the children objects which will be of class _MemoryAreaPlug
+ for child in self.IECSortedChildren():
+ entries.append(child.GetVariableLocationTree())
+
+ return {"name": name,
+ "type": LOCATION_CONFNODE,
+ "location": ".".join([str(i) for i in current_location]) + ".x",
+ "children": entries}
+
+
def CTNGenerate_C(self, buildpath, locations):
"""
Generate C code
@@ -819,29 +971,52 @@
new_node = GetTCPServerNodePrinted(self, child)
if new_node is None:
return [], "", False
- server_node_list.append(new_node)
+ server_node_list.append(new_node)
+ # We currently add 4 flags/counters to each Modbus server/slave
#
+ # We add the Modbus read/write counter/flag to each Modbus slave/server
+ # to allow the user program to determine if the slave is being actively
+ # read from or written by by a remote Modbus client.
+ for iecvar in child.GetLocations():
+ #print "child" + repr(iecvar)
+ if (len(iecvar["LOC"]) == 3) and (str(iecvar["NAME"]) not in loc_vars_list):
+ # Add if it is a "Modbus Read Request Counter" (mapped onto %MDa.b.0), so last number is a '0'
+ if iecvar["LOC"][2] == 0:
+ loc_vars.append("u32 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_read_req_counter;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a "Modbus Write Request Counter" (mapped onto %MDa.b.1), so last number is a '1'
+ if iecvar["LOC"][2] == 1:
+ loc_vars.append("u32 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_write_req_counter;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a "Modbus Read Request Flag" (mapped onto %MDa.b.2), so last number is a '2'
+ if iecvar["LOC"][2] == 2:
+ loc_vars.append("u8 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_read_req_flag;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a "Modbus Write Request Counter" (mapped onto %MDa.b.3), so last number is a '3'
+ if iecvar["LOC"][2] == 3:
+ loc_vars.append("u8 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_write_req_flag;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+
for subchild in child.IECSortedChildren():
- new_memarea = GetTCPServerMemAreaPrinted(
- self, subchild, nodeid)
+ new_memarea = GetTCPServerMemAreaPrinted(self, subchild, nodeid)
if new_memarea is None:
return [], "", False
server_memarea_list.append(new_memarea)
- function = subchild.GetParamsAttributes()[
- 0]["children"][0]["value"]
+ function = subchild.GetParamsAttributes()[0]["children"][0]["value"]
# 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
memarea = modbus_memtype_dict[function][1]
for iecvar in subchild.GetLocations():
- # print repr(iecvar)
- absloute_address = iecvar["LOC"][3]
- start_address = int(GetCTVal(subchild, 2))
- relative_addr = absloute_address - start_address
- # test if relative address in request specified range
- if relative_addr in xrange(int(GetCTVal(subchild, 1))):
- if str(iecvar["NAME"]) not in loc_vars_list:
- loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
- server_id, memarea, absloute_address))
- loc_vars_list.append(str(iecvar["NAME"]))
+ if len(iecvar["LOC"]) == 4:
+ #print "subchild" + repr(iecvar)
+ absloute_address = iecvar["LOC"][3]
+ start_address = int(GetCTVal(subchild, 2))
+ relative_addr = absloute_address - start_address
+ # test if relative address in request specified range
+ if relative_addr in xrange(int(GetCTVal(subchild, 1))):
+ if str(iecvar["NAME"]) not in loc_vars_list:
+ loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
+ server_id, memarea, absloute_address))
+ loc_vars_list.append(str(iecvar["NAME"]))
server_id += 1
#
if child.PlugType == "ModbusRTUslave":
@@ -850,28 +1025,52 @@
if new_node is None:
return [], "", False
server_node_list.append(new_node)
+ # We currently add 4 flags/counters to each Modbus server/slave
#
+ # We add the Modbus read/write counter/flag to each Modbus slave/server
+ # to allow the user program to determine if the slave is being actively
+ # read from or written by by a remote Modbus client.
+ for iecvar in child.GetLocations():
+ #print "child" + repr(iecvar)
+ if (len(iecvar["LOC"]) == 3) and (str(iecvar["NAME"]) not in loc_vars_list):
+ # Add if it is a "Modbus Read Request Counter" (mapped onto %MDa.b.0), so last number is a '0'
+ if iecvar["LOC"][2] == 0:
+ loc_vars.append("u32 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_read_req_counter;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a "Modbus Write Request Counter" (mapped onto %MDa.b.1), so last number is a '1'
+ if iecvar["LOC"][2] == 1:
+ loc_vars.append("u32 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_write_req_counter;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a "Modbus Read Request Flag" (mapped onto %MDa.b.2), so last number is a '2'
+ if iecvar["LOC"][2] == 2:
+ loc_vars.append("u8 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_read_req_flag;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+ # Add if it is a "Modbus Write Request Counter" (mapped onto %MDa.b.3), so last number is a '3'
+ if iecvar["LOC"][2] == 3:
+ loc_vars.append("u8 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.flag_write_req_flag;" % (server_id))
+ loc_vars_list.append(str(iecvar["NAME"]))
+
for subchild in child.IECSortedChildren():
new_memarea = GetTCPServerMemAreaPrinted(
self, subchild, nodeid)
if new_memarea is None:
return [], "", False
server_memarea_list.append(new_memarea)
- function = subchild.GetParamsAttributes()[
- 0]["children"][0]["value"]
+ function = subchild.GetParamsAttributes()[0]["children"][0]["value"]
# 'ro_bits', 'rw_bits', 'ro_words' or 'rw_words'
memarea = modbus_memtype_dict[function][1]
for iecvar in subchild.GetLocations():
- # print repr(iecvar)
- absloute_address = iecvar["LOC"][3]
- start_address = int(GetCTVal(subchild, 2))
- relative_addr = absloute_address - start_address
- # test if relative address in request specified range
- if relative_addr in xrange(int(GetCTVal(subchild, 1))):
- if str(iecvar["NAME"]) not in loc_vars_list:
- loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
- server_id, memarea, absloute_address))
- loc_vars_list.append(str(iecvar["NAME"]))
+ if len(iecvar["LOC"]) == 4:
+ # print repr(iecvar)
+ absloute_address = iecvar["LOC"][3]
+ start_address = int(GetCTVal(subchild, 2))
+ relative_addr = absloute_address - start_address
+ # test if relative address in request specified range
+ if relative_addr in xrange(int(GetCTVal(subchild, 1))):
+ if str(iecvar["NAME"]) not in loc_vars_list:
+ loc_vars.append("u16 *" + str(iecvar["NAME"]) + " = &server_nodes[%d].mem_area.%s[%d];" % (
+ server_id, memarea, absloute_address))
+ loc_vars_list.append(str(iecvar["NAME"]))
server_id += 1
#
if child.PlugType == "ModbusTCPclient":