16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 # GNU General Public License for more details. |
17 # GNU General Public License for more details. |
18 # |
18 # |
19 # You should have received a copy of the GNU General Public License |
19 # You should have received a copy of the GNU General Public License |
20 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
20 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 # |
21 # |
22 # This code is made available on the understanding that it will not be |
22 # This code is made available on the understanding that it will not be |
23 # used in safety-critical situations without a full and competent review. |
23 # used in safety-critical situations without a full and competent review. |
24 |
24 |
25 |
25 |
26 |
26 # dictionary implementing: |
27 |
27 # key - string with the description we want in the request plugin GUI |
28 #dictionary implementing: |
28 # tuple - (modbus function number, request type, max count value, |
29 #key - string with the description we want in the request plugin GUI |
29 # data_type, bit_size) |
30 #tuple - (modbus function number, request type, max count value, data_type, bit_size) |
30 modbus_function_dict = { |
31 modbus_function_dict = {"01 - Read Coils" : ( '1', 'req_input', 2000, "BOOL", 1 , "Q", "X", "Coil"), |
31 "01 - Read Coils": ('1', 'req_input', 2000, "BOOL", 1, "Q", "X", "Coil"), |
32 "02 - Read Input Discretes" : ( '2', 'req_input', 2000, "BOOL", 1 , "I", "X", "Input Discrete"), |
32 "02 - Read Input Discretes": ('2', 'req_input', 2000, "BOOL", 1, "I", "X", "Input Discrete"), |
33 "03 - Read Holding Registers" : ( '3', 'req_input', 125, "WORD", 16, "Q", "W", "Holding Register"), |
33 "03 - Read Holding Registers": ('3', 'req_input', 125, "WORD", 16, "Q", "W", "Holding Register"), |
34 "04 - Read Input Registers" : ( '4', 'req_input', 125, "WORD", 16, "I", "W", "Input Register"), |
34 "04 - Read Input Registers": ('4', 'req_input', 125, "WORD", 16, "I", "W", "Input Register"), |
35 "05 - Write Single coil" : ( '5','req_output', 1, "BOOL", 1 , "Q", "X", "Coil"), |
35 "05 - Write Single coil": ('5', 'req_output', 1, "BOOL", 1, "Q", "X", "Coil"), |
36 "06 - Write Single Register" : ( '6','req_output', 1, "WORD", 16, "Q", "W", "Holding Register"), |
36 "06 - Write Single Register": ('6', 'req_output', 1, "WORD", 16, "Q", "W", "Holding Register"), |
37 "15 - Write Multiple Coils" : ('15','req_output', 1968, "BOOL", 1 , "Q", "X", "Coil"), |
37 "15 - Write Multiple Coils": ('15', 'req_output', 1968, "BOOL", 1, "Q", "X", "Coil"), |
38 "16 - Write Multiple Registers" : ('16','req_output', 123, "WORD", 16, "Q", "W", "Holding Register"), |
38 "16 - Write Multiple Registers": ('16', 'req_output', 123, "WORD", 16, "Q", "W", "Holding Register")} |
39 } |
39 |
40 |
40 |
|
41 # Configuration tree value acces helper |
|
42 def GetCTVal(child, index): |
|
43 return child.GetParamsAttributes()[0]["children"][index]["value"] |
|
44 |
|
45 |
|
46 # Configuration tree value acces helper, for multiple values |
|
47 def GetCTVals(child, indexes): |
|
48 return map(lambda index: GetCTVal(child, index), indexes) |
41 |
49 |
42 |
50 |
43 def GetTCPServerNodePrinted(self, child): |
51 def GetTCPServerNodePrinted(self, child): |
44 """ |
52 """ |
45 Outputs a string to be used on C files |
53 Outputs a string to be used on C files |
47 """ |
55 """ |
48 node_init_template = '''/*node %(locnodestr)s*/ |
56 node_init_template = '''/*node %(locnodestr)s*/ |
49 {"%(locnodestr)s", %(slaveid)s, {naf_tcp, {.tcp = {%(host)s, "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */}''' |
57 {"%(locnodestr)s", %(slaveid)s, {naf_tcp, {.tcp = {%(host)s, "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */}''' |
50 |
58 |
51 location = ".".join(map(str, child.GetCurrentLocation())) |
59 location = ".".join(map(str, child.GetCurrentLocation())) |
52 host = child.GetParamsAttributes()[0]["children"][0]["value"] |
60 host, port, slaveid = GetCTVals(child, range(3)) |
53 port = child.GetParamsAttributes()[0]["children"][1]["value"] |
61 if host == "#ANY#": |
54 slaveid = child.GetParamsAttributes()[0]["children"][2]["value"] |
62 host = 'INADDR_ANY' |
55 if host=="#ANY#": |
|
56 host='INADDR_ANY' |
|
57 else: |
63 else: |
58 host='"'+host+'"' |
64 host = '"' + host + '"' |
59 #slaveid = child.GetParamsAttributes()[0]["children"][2]["value"] |
65 # slaveid = GetCTVal(child, 2) |
60 #if int(slaveid) not in xrange(256): |
66 # if int(slaveid) not in xrange(256): |
61 #self.GetCTRoot().logger.write_error("Error: Wrong slave ID in %s server node\nModbus Plugin C code returns empty\n"%location) |
67 # self.GetCTRoot().logger.write_error("Error: Wrong slave ID in %s server node\nModbus Plugin C code returns empty\n"%location) |
62 #return None |
68 # return None |
63 |
69 |
64 node_dict = {"locnodestr" : location, |
70 node_dict = {"locnodestr": location, |
65 "host" : host, |
71 "host": host, |
66 "port" : port, |
72 "port": port, |
67 "slaveid" : slaveid, |
73 "slaveid": slaveid, |
68 } |
74 } |
69 return node_init_template % node_dict |
75 return node_init_template % node_dict |
70 |
|
71 |
|
72 |
76 |
73 |
77 |
74 def GetTCPServerMemAreaPrinted(self, child, nodeid): |
78 def GetTCPServerMemAreaPrinted(self, child, nodeid): |
75 """ |
79 """ |
76 Outputs a string to be used on C files |
80 Outputs a string to be used on C files |
82 """ |
86 """ |
83 request_dict = {} |
87 request_dict = {} |
84 |
88 |
85 request_dict["locreqstr"] = "_".join(map(str, child.GetCurrentLocation())) |
89 request_dict["locreqstr"] = "_".join(map(str, child.GetCurrentLocation())) |
86 request_dict["nodeid"] = str(nodeid) |
90 request_dict["nodeid"] = str(nodeid) |
87 request_dict["address"] = child.GetParamsAttributes()[0]["children"][2]["value"] |
91 request_dict["address"] = GetCTVal(child, 2) |
88 if int(request_dict["address"]) not in xrange(65536): |
92 if int(request_dict["address"]) not in xrange(65536): |
89 self.GetCTRoot().logger.write_error("Modbus plugin: Invalid Start Address in server memory area node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n"%request_dict) |
93 self.GetCTRoot().logger.write_error( |
90 return None |
94 "Modbus plugin: Invalid Start Address in server memory area node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n" % request_dict) |
91 request_dict["count"] = child.GetParamsAttributes()[0]["children"][1]["value"] |
95 return None |
|
96 request_dict["count"] = GetCTVal(child, 1) |
92 if int(request_dict["count"]) not in xrange(1, 65536): |
97 if int(request_dict["count"]) not in xrange(1, 65536): |
93 self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n"%request_dict) |
98 self.GetCTRoot().logger.write_error( |
94 return None |
99 "Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n" % request_dict) |
95 if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1,65537): |
100 return None |
96 self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n"%request_dict) |
101 if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1, 65537): |
97 return None |
102 self.GetCTRoot().logger.write_error( |
98 |
103 "Modbus plugin: Invalid number of channels in server memory area node %(locreqstr)s (Must be in the range [1..65536-start_address])\nModbus plugin: Aborting C code generation for this node\n" % request_dict) |
|
104 return None |
|
105 |
99 return "" |
106 return "" |
100 |
107 |
101 |
108 |
102 |
109 modbus_serial_baudrate_list = [ |
103 |
110 "110", "300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"] |
104 modbus_serial_baudrate_list = ["110", "300", "600", "1200", "2400", "4800", "9600", "19200", "38400", "57600", "115200"] |
|
105 modbus_serial_stopbits_list = ["1", "2"] |
111 modbus_serial_stopbits_list = ["1", "2"] |
106 modbus_serial_parity_dict = {"none": 0, "odd": 1, "even": 2} |
112 modbus_serial_parity_dict = {"none": 0, "odd": 1, "even": 2} |
107 |
|
108 |
113 |
109 |
114 |
110 def GetRTUSlaveNodePrinted(self, child): |
115 def GetRTUSlaveNodePrinted(self, child): |
111 """ |
116 """ |
112 Outputs a string to be used on C files |
117 Outputs a string to be used on C files |
114 """ |
119 """ |
115 node_init_template = '''/*node %(locnodestr)s*/ |
120 node_init_template = '''/*node %(locnodestr)s*/ |
116 {"%(locnodestr)s", %(slaveid)s, {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */}''' |
121 {"%(locnodestr)s", %(slaveid)s, {naf_rtu, {.rtu = {"%(device)s", %(baud)s /*baud*/, %(parity)s /*parity*/, 8 /*data bits*/, %(stopbits)s, 0 /* ignore echo */}}}, -1 /* mb_nd */, 0 /* init_state */}''' |
117 |
122 |
118 location = ".".join(map(str, child.GetCurrentLocation())) |
123 location = ".".join(map(str, child.GetCurrentLocation())) |
119 device = child.GetParamsAttributes()[0]["children"][0]["value"] |
124 device, baud, parity, stopbits, slaveid = GetCTVals(child, range(5)) |
120 baud = child.GetParamsAttributes()[0]["children"][1]["value"] |
125 |
121 parity = child.GetParamsAttributes()[0]["children"][2]["value"] |
126 node_dict = {"locnodestr": location, |
122 stopbits = child.GetParamsAttributes()[0]["children"][3]["value"] |
127 "device": device, |
123 slaveid = child.GetParamsAttributes()[0]["children"][4]["value"] |
128 "baud": baud, |
124 |
129 "parity": modbus_serial_parity_dict[parity], |
125 node_dict = {"locnodestr" : location, |
130 "stopbits": stopbits, |
126 "device" : device, |
131 "slaveid": slaveid |
127 "baud" : baud, |
132 } |
128 "parity" : modbus_serial_parity_dict[parity], |
133 return node_init_template % node_dict |
129 "stopbits" : stopbits, |
134 |
130 "slaveid" : slaveid |
|
131 } |
|
132 return node_init_template % node_dict |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
135 |
138 def GetRTUClientNodePrinted(self, child): |
136 def GetRTUClientNodePrinted(self, child): |
139 """ |
137 """ |
140 Outputs a string to be used on C files |
138 Outputs a string to be used on C files |
141 params: child - the correspondent subplugin in Beremiz |
139 params: child - the correspondent subplugin in Beremiz |
142 """ |
140 """ |
143 node_init_template = '''/*node %(locnodestr)s*/ |
141 node_init_template = '''/*node %(locnodestr)s*/ |
144 {"%(locnodestr)s", {naf_rtu, {.rtu = {"%(device)s", %(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 */}''' |
142 {"%(locnodestr)s", {naf_rtu, {.rtu = {"%(device)s", %(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 */}''' |
145 |
143 |
146 location = ".".join(map(str, child.GetCurrentLocation())) |
144 location = ".".join(map(str, child.GetCurrentLocation())) |
147 device = child.GetParamsAttributes()[0]["children"][0]["value"] |
145 device, baud, parity, stopbits, coms_period = GetCTVals(child, range(5)) |
148 baud = child.GetParamsAttributes()[0]["children"][1]["value"] |
146 |
149 parity = child.GetParamsAttributes()[0]["children"][2]["value"] |
147 node_dict = {"locnodestr": location, |
150 stopbits = child.GetParamsAttributes()[0]["children"][3]["value"] |
148 "device": device, |
151 coms_period = child.GetParamsAttributes()[0]["children"][4]["value"] |
149 "baud": baud, |
152 |
150 "parity": modbus_serial_parity_dict[parity], |
153 node_dict = {"locnodestr" : location, |
151 "stopbits": stopbits, |
154 "device" : device, |
152 "coms_period": coms_period |
155 "baud" : baud, |
153 } |
156 "parity" : modbus_serial_parity_dict[parity], |
154 return node_init_template % node_dict |
157 "stopbits" : stopbits, |
|
158 "coms_period" : coms_period |
|
159 } |
|
160 return node_init_template % node_dict |
|
161 |
|
162 |
|
163 |
155 |
164 |
156 |
165 def GetTCPClientNodePrinted(self, child): |
157 def GetTCPClientNodePrinted(self, child): |
166 """ |
158 """ |
167 Outputs a string to be used on C files |
159 Outputs a string to be used on C files |
169 """ |
161 """ |
170 node_init_template = '''/*node %(locnodestr)s*/ |
162 node_init_template = '''/*node %(locnodestr)s*/ |
171 {"%(locnodestr)s", {naf_tcp, {.tcp = {"%(host)s", "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */, 0 /* prev_error */}''' |
163 {"%(locnodestr)s", {naf_tcp, {.tcp = {"%(host)s", "%(port)s", DEF_CLOSE_ON_SILENCE}}}, -1 /* mb_nd */, 0 /* init_state */, %(coms_period)s /* communication period */, 0 /* prev_error */}''' |
172 |
164 |
173 location = ".".join(map(str, child.GetCurrentLocation())) |
165 location = ".".join(map(str, child.GetCurrentLocation())) |
174 host = child.GetParamsAttributes()[0]["children"][0]["value"] |
166 host, port, coms_period = GetCTVals(child, range(3)) |
175 port = child.GetParamsAttributes()[0]["children"][1]["value"] |
167 |
176 coms_period = child.GetParamsAttributes()[0]["children"][2]["value"] |
168 node_dict = {"locnodestr": location, |
177 |
169 "host": host, |
178 node_dict = {"locnodestr" : location, |
170 "port": port, |
179 "host" : host, |
171 "coms_period": coms_period |
180 "port" : port, |
172 } |
181 "coms_period" : coms_period |
173 return node_init_template % node_dict |
182 } |
|
183 return node_init_template % node_dict |
|
184 |
|
185 |
|
186 |
174 |
187 |
175 |
188 def GetClientRequestPrinted(self, child, nodeid): |
176 def GetClientRequestPrinted(self, child, nodeid): |
189 """ |
177 """ |
190 Outputs a string to be used on C files |
178 Outputs a string to be used on C files |
197 |
185 |
198 req_init_template = '''/*request %(locreqstr)s*/ |
186 req_init_template = '''/*request %(locreqstr)s*/ |
199 {"%(locreqstr)s", %(nodeid)s, %(slaveid)s, %(iotype)s, %(func_nr)s, %(address)s , %(count)s, |
187 {"%(locreqstr)s", %(nodeid)s, %(slaveid)s, %(iotype)s, %(func_nr)s, %(address)s , %(count)s, |
200 DEF_REQ_SEND_RETRIES, 0 /* error_code */, 0 /* prev_code */, {%(timeout_s)d, %(timeout_ns)d} /* timeout */, |
188 DEF_REQ_SEND_RETRIES, 0 /* error_code */, 0 /* prev_code */, {%(timeout_s)d, %(timeout_ns)d} /* timeout */, |
201 {%(buffer)s}, {%(buffer)s}}''' |
189 {%(buffer)s}, {%(buffer)s}}''' |
202 |
190 |
203 timeout = int(child.GetParamsAttributes()[0]["children"][4]["value"]) |
191 timeout = int(GetCTVal(child, 4)) |
204 timeout_s = int(timeout / 1000) |
192 timeout_s = int(timeout / 1000) |
205 timeout_ms = timeout - (timeout_s * 1000) |
193 timeout_ms = timeout - (timeout_s * 1000) |
206 timeout_ns = timeout_ms * 1000000 |
194 timeout_ns = timeout_ms * 1000000 |
207 |
195 |
208 request_dict = {} |
196 request_dict = { |
209 |
197 "locreqstr": "_".join(map(str, child.GetCurrentLocation())), |
210 request_dict["locreqstr" ] = "_".join(map(str, child.GetCurrentLocation())) |
198 "nodeid": str(nodeid), |
211 request_dict["nodeid" ] = str(nodeid) |
199 "slaveid": GetCTVal(child, 1), |
212 request_dict["slaveid" ] = child.GetParamsAttributes()[0]["children"][1]["value"] |
200 "address": GetCTVal(child, 3), |
213 request_dict["address" ] = child.GetParamsAttributes()[0]["children"][3]["value"] |
201 "count": GetCTVal(child, 2), |
214 request_dict["count" ] = child.GetParamsAttributes()[0]["children"][2]["value"] |
202 "timeout": timeout, |
215 request_dict["timeout" ] = timeout |
203 "timeout_s": timeout_s, |
216 request_dict["timeout_s" ] = timeout_s |
204 "timeout_ns": timeout_ns, |
217 request_dict["timeout_ns"] = timeout_ns |
205 "buffer": ",".join(['0'] * int(GetCTVal(child, 2))), |
218 request_dict["buffer" ] = ",".join(['0'] * int(child.GetParamsAttributes()[0]["children"][2]["value"])) |
206 "func_nr": modbus_function_dict[GetCTVal(child, 0)][0], |
219 request_dict["func_nr" ] = modbus_function_dict[child.GetParamsAttributes()[0]["children"][0]["value"]][0] |
207 "iotype": modbus_function_dict[GetCTVal(child, 0)][1], |
220 request_dict["iotype" ] = modbus_function_dict[child.GetParamsAttributes()[0]["children"][0]["value"]][1] |
208 "maxcount": modbus_function_dict[GetCTVal(child, 0)][2]} |
221 request_dict["maxcount" ] = modbus_function_dict[child.GetParamsAttributes()[0]["children"][0]["value"]][2] |
209 |
222 |
|
223 if int(request_dict["slaveid"]) not in xrange(256): |
210 if int(request_dict["slaveid"]) not in xrange(256): |
224 self.GetCTRoot().logger.write_error("Modbus plugin: Invalid slaveID in TCP client request node %(locreqstr)s (Must be in the range [0..255])\nModbus plugin: Aborting C code generation for this node\n"%request_dict) |
211 self.GetCTRoot().logger.write_error( |
|
212 "Modbus plugin: Invalid slaveID in TCP client request node %(locreqstr)s (Must be in the range [0..255])\nModbus plugin: Aborting C code generation for this node\n" % request_dict) |
225 return None |
213 return None |
226 if int(request_dict["address"]) not in xrange(65536): |
214 if int(request_dict["address"]) not in xrange(65536): |
227 self.GetCTRoot().logger.write_error("Modbus plugin: Invalid Start Address in TCP client request node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n"%request_dict) |
215 self.GetCTRoot().logger.write_error( |
228 return None |
216 "Modbus plugin: Invalid Start Address in TCP client request node %(locreqstr)s (Must be in the range [0..65535])\nModbus plugin: Aborting C code generation for this node\n" % request_dict) |
229 if int(request_dict["count"]) not in xrange(1, 1+int(request_dict["maxcount"])): |
217 return None |
230 self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (Must be in the range [1..%(maxcount)s])\nModbus plugin: Aborting C code generation for this node\n"%request_dict) |
218 if int(request_dict["count"]) not in xrange(1, 1 + int(request_dict["maxcount"])): |
231 return None |
219 self.GetCTRoot().logger.write_error( |
232 if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1,65537): |
220 "Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (Must be in the range [1..%(maxcount)s])\nModbus plugin: Aborting C code generation for this node\n" % request_dict) |
233 self.GetCTRoot().logger.write_error("Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (start_address + nr_channels must be less than 65536)\nModbus plugin: Aborting C code generation for this node\n"%request_dict) |
221 return None |
234 return None |
222 if (int(request_dict["address"]) + int(request_dict["count"])) not in xrange(1, 65537): |
235 |
223 self.GetCTRoot().logger.write_error( |
|
224 "Modbus plugin: Invalid number of channels in TCP client request node %(locreqstr)s (start_address + nr_channels must be less than 65536)\nModbus plugin: Aborting C code generation for this node\n" % request_dict) |
|
225 return None |
|
226 |
236 return req_init_template % request_dict |
227 return req_init_template % request_dict |