45 |
45 |
46 hmi_tree_root = None |
46 hmi_tree_root = None |
47 |
47 |
48 on_hmitree_update = None |
48 on_hmitree_update = None |
49 |
49 |
|
50 maxConnectionsTotal = 0 |
|
51 |
50 class SVGHMILibrary(POULibrary): |
52 class SVGHMILibrary(POULibrary): |
51 def GetLibraryPath(self): |
53 def GetLibraryPath(self): |
52 return paths.AbsNeighbourFile(__file__, "pous.xml") |
54 return paths.AbsNeighbourFile(__file__, "pous.xml") |
53 |
55 |
54 def Generate_C(self, buildpath, varlist, IECCFLAGS): |
56 def Generate_C(self, buildpath, varlist, IECCFLAGS): |
55 global hmi_tree_root, on_hmitree_update |
57 global hmi_tree_root, on_hmitree_update, maxConnectionsTotal |
56 |
58 |
57 """ |
59 """ |
58 PLC Instance Tree: |
60 PLC Instance Tree: |
59 prog0 |
61 prog0 |
60 +->v1 HMI_INT |
62 +->v1 HMI_INT |
194 |
196 |
195 # TODO check if programs need to be declared separately |
197 # TODO check if programs need to be declared separately |
196 # "programs_declarations": "\n".join(["extern %(type)s %(C_path)s;" % |
198 # "programs_declarations": "\n".join(["extern %(type)s %(C_path)s;" % |
197 # p for p in self._ProgramList]), |
199 # p for p in self._ProgramList]), |
198 |
200 |
|
201 for CTNChild in self.GetCTR().IterChildren(): |
|
202 if isinstance(CTNChild, SVGHMI): |
|
203 maxConnectionsTotal += CTNChild.GetParamsAttributes("SVGHMI.MaxConnections")["value"] |
|
204 |
|
205 |
199 # C code to observe/access HMI tree variables |
206 # C code to observe/access HMI tree variables |
200 svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c") |
207 svghmi_c_filepath = paths.AbsNeighbourFile(__file__, "svghmi.c") |
201 svghmi_c_file = open(svghmi_c_filepath, 'r') |
208 svghmi_c_file = open(svghmi_c_filepath, 'r') |
202 svghmi_c_code = svghmi_c_file.read() |
209 svghmi_c_code = svghmi_c_file.read() |
203 svghmi_c_file.close() |
210 svghmi_c_file.close() |
206 "extern_variables_declarations": "\n".join(extern_variables_declarations), |
213 "extern_variables_declarations": "\n".join(extern_variables_declarations), |
207 "buffer_size": buf_index, |
214 "buffer_size": buf_index, |
208 "item_count": item_count, |
215 "item_count": item_count, |
209 "var_access_code": targets.GetCode("var_access.c"), |
216 "var_access_code": targets.GetCode("var_access.c"), |
210 "PLC_ticktime": self.GetCTR().GetTicktime(), |
217 "PLC_ticktime": self.GetCTR().GetTicktime(), |
211 "hmi_hash_ints": ",".join(map(str,hmi_tree_root.hash())) |
218 "hmi_hash_ints": ",".join(map(str,hmi_tree_root.hash())), |
|
219 "max_connections": maxConnectionsTotal |
212 } |
220 } |
213 |
221 |
214 gen_svghmi_c_path = os.path.join(buildpath, "svghmi.c") |
222 gen_svghmi_c_path = os.path.join(buildpath, "svghmi.c") |
215 gen_svghmi_c = open(gen_svghmi_c_path, 'w') |
223 gen_svghmi_c = open(gen_svghmi_c_path, 'w') |
216 gen_svghmi_c.write(svghmi_c_code) |
224 gen_svghmi_c.write(svghmi_c_code) |
285 <xsd:attribute name="OnWatchdog" type="xsd:string" use="optional" default="chromium {url}"/> |
293 <xsd:attribute name="OnWatchdog" type="xsd:string" use="optional" default="chromium {url}"/> |
286 <xsd:attribute name="WatchdogInitial" type="xsd:integer" use="optional" default="30"/> |
294 <xsd:attribute name="WatchdogInitial" type="xsd:integer" use="optional" default="30"/> |
287 <xsd:attribute name="WatchdogInterval" type="xsd:integer" use="optional" default="5"/> |
295 <xsd:attribute name="WatchdogInterval" type="xsd:integer" use="optional" default="5"/> |
288 <xsd:attribute name="Port" type="xsd:integer" use="optional" default="8008"/> |
296 <xsd:attribute name="Port" type="xsd:integer" use="optional" default="8008"/> |
289 <xsd:attribute name="Interface" type="xsd:string" use="optional" default="localhost"/> |
297 <xsd:attribute name="Interface" type="xsd:string" use="optional" default="localhost"/> |
290 <xsd:attribute name="Path" type="xsd:string" use="optional" default=""/> |
298 <xsd:attribute name="Path" type="xsd:string" use="optional" default="{name}"/> |
|
299 <xsd:attribute name="MaxConnections" type="xsd:integer" use="optional" default="16"/> |
291 </xsd:complexType> |
300 </xsd:complexType> |
292 </xsd:element> |
301 </xsd:element> |
293 </xsd:schema> |
302 </xsd:schema> |
294 """ |
303 """ |
295 |
304 |
560 runtimefile.write(""" |
569 runtimefile.write(""" |
561 # TODO : multiple watchdog (one for each svghmi instance) |
570 # TODO : multiple watchdog (one for each svghmi instance) |
562 def svghmi_{location}_watchdog_trigger(): |
571 def svghmi_{location}_watchdog_trigger(): |
563 {svghmi_cmds[Watchdog]} |
572 {svghmi_cmds[Watchdog]} |
564 |
573 |
565 svghmi_watchdog = None |
574 max_svghmi_sessions = {maxConnections_total} |
566 |
575 |
567 def _runtime_{location}_svghmi_start(): |
576 def _runtime_{location}_svghmi_start(): |
568 global svghmi_watchdog, svghmi_servers |
577 global svghmi_watchdog, svghmi_servers |
569 |
578 |
570 srv = svghmi_servers.get("{interface}:{port}", None) |
579 srv = svghmi_servers.get("{interface}:{port}", None) |
571 if srv is not None: |
580 if srv is not None: |
572 svghmi_root, svghmi_listener, path_list = srv |
581 svghmi_root, svghmi_listener, path_list = srv |
573 if '{path}' in path_list: |
582 if '{path}' in path_list: |
574 raise Exception("SVGHMI {view_name}: path {path} already used on {interface}:{port}") |
583 raise Exception("SVGHMI {view_name}: path {path} already used on {interface}:{port}") |
575 else: |
584 else: |
576 svghmi_root = Resource() |
585 svghmi_root = Resource() |
577 svghmi_root.putChild("ws", WebSocketResource(HMIWebSocketServerFactory())) |
586 factory = HMIWebSocketServerFactory() |
|
587 factory.setProtocolOptions(maxConnections={maxConnections}) |
|
588 |
|
589 svghmi_root.putChild("ws", WebSocketResource(factory)) |
578 |
590 |
579 svghmi_listener = reactor.listenTCP({port}, Site(svghmi_root), interface='{interface}') |
591 svghmi_listener = reactor.listenTCP({port}, Site(svghmi_root), interface='{interface}') |
580 path_list = [] |
592 path_list = [] |
581 svghmi_servers["{interface}:{port}"] = (svghmi_root, svghmi_listener, path_list) |
593 svghmi_servers["{interface}:{port}"] = (svghmi_root, svghmi_listener, path_list) |
582 |
594 |
590 {svghmi_cmds[Start]} |
602 {svghmi_cmds[Start]} |
591 |
603 |
592 if {enable_watchdog}: |
604 if {enable_watchdog}: |
593 if svghmi_watchdog is None: |
605 if svghmi_watchdog is None: |
594 svghmi_watchdog = Watchdog( |
606 svghmi_watchdog = Watchdog( |
595 {watchdog_initial}, |
607 {watchdog_initial}, |
596 {watchdog_interval}, |
608 {watchdog_interval}, |
597 svghmi_{location}_watchdog_trigger) |
609 svghmi_{location}_watchdog_trigger) |
598 else: |
610 else: |
599 raise Exception("SVGHMI {view_name}: only one watchdog allowed") |
611 raise Exception("SVGHMI {view_name}: only one watchdog allowed") |
600 |
612 |
601 |
613 |
626 interface = interface, |
638 interface = interface, |
627 path = path, |
639 path = path, |
628 enable_watchdog = enable_watchdog, |
640 enable_watchdog = enable_watchdog, |
629 watchdog_initial = self.GetParamsAttributes("SVGHMI.WatchdogInitial")["value"], |
641 watchdog_initial = self.GetParamsAttributes("SVGHMI.WatchdogInitial")["value"], |
630 watchdog_interval = self.GetParamsAttributes("SVGHMI.WatchdogInterval")["value"], |
642 watchdog_interval = self.GetParamsAttributes("SVGHMI.WatchdogInterval")["value"], |
|
643 maxConnections = self.GetParamsAttributes("SVGHMI.MaxConnections")["value"], |
|
644 maxConnections_total = maxConnectionsTotal |
631 )) |
645 )) |
632 |
646 |
633 runtimefile.close() |
647 runtimefile.close() |
634 |
648 |
635 res += (("runtime_%s_svghmi.py" % location_str, open(runtimefile_path, "rb")),) |
649 res += (("runtime_%s_svghmi.py" % location_str, open(runtimefile_path, "rb")),) |