diff -r d92d201d22e1 -r 9101a72a1da0 svghmi/svghmi_server.py --- a/svghmi/svghmi_server.py Wed Dec 18 13:31:22 2019 +0100 +++ b/svghmi/svghmi_server.py Fri Jan 10 13:15:07 2020 +0100 @@ -7,6 +7,7 @@ from __future__ import absolute_import import errno +from threading import RLock, Timer from twisted.web.server import Site from twisted.web.resource import Resource @@ -20,8 +21,10 @@ # TODO multiclient : # session list lock # svghmi_sessions = [] +# svghmi_watchdogs = [] svghmi_session = None +svghmi_watchdog = None svghmi_send_collect = PLCBinary.svghmi_send_collect svghmi_send_collect.restype = ctypes.c_int # error or 0 @@ -61,15 +64,45 @@ def onMessage(self, msg): # pass message to the C side recieve_message() - svghmi_recv_dispatch(len(msg), msg) + return svghmi_recv_dispatch(len(msg), msg) # TODO multiclient : pass client index as well - def sendMessage(self, msg): self.protocol_instance.sendMessage(msg, True) return 0 +class Watchdog(object): + def __init__(self, initial_timeout, callback): + self._callback = callback + self.lock = RLock() + self.initial_timeout = initial_timeout + self.callback = callback + with self.lock: + self._start() + + def _start(self): + self.timer = Timer(self.initial_timeout, self.trigger) + self.timer.start() + + def _stop(self): + if self.timer is not None: + self.timer.cancel() + self.timer = None + + def cancel(self): + with self.lock: + self._stop() + + def feed(self): + with self.lock: + self._stop() + self._start() + + def trigger(self): + self._callback() + self.feed() + class HMIProtocol(WebSocketServerProtocol): def __init__(self, *args, **kwargs): @@ -85,7 +118,11 @@ def onMessage(self, msg, isBinary): assert(self._hmi_session is not None) - self._hmi_session.onMessage(msg) + + result = self._hmi_session.onMessage(msg) + if result == 1 : # was heartbeat + if svghmi_watchdog is not None: + svghmi_watchdog.feed() class HMIWebSocketServerFactory(WebSocketServerFactory): protocol = HMIProtocol @@ -114,11 +151,13 @@ break - +def watchdog_trigger(): + print("SVGHMI watchdog trigger") + # Called by PLCObject at start def _runtime_svghmi0_start(): - global svghmi_listener, svghmi_root, svghmi_send_thread + global svghmi_listener, svghmi_root, svghmi_send_thread, svghmi_watchdog svghmi_root = Resource() svghmi_root.putChild("ws", WebSocketResource(HMIWebSocketServerFactory())) @@ -129,10 +168,16 @@ svghmi_send_thread = Thread(target=SendThreadProc, name="SVGHMI Send") svghmi_send_thread.start() + svghmi_watchdog = Watchdog(5, watchdog_trigger) # Called by PLCObject at stop def _runtime_svghmi0_stop(): - global svghmi_listener, svghmi_root, svghmi_send_thread, svghmi_session + global svghmi_listener, svghmi_root, svghmi_send_thread, svghmi_session, svghmi_watchdog + + if svghmi_watchdog is not None: + svghmi_watchdog.cancel() + svghmi_watchdog = None + if svghmi_session is not None: svghmi_session.close() svghmi_root.delEntity("ws")