SVGHMI: Fixing last commit's multiclient implementation, in case of watchdog. To be continued, since multiclient still fail... svghmi
authorEdouard Tisserant
Fri, 09 Jul 2021 15:47:43 +0200
branchsvghmi
changeset 3271 561dbd1e3e04
parent 3270 38f7122ccbf9
child 3272 c8182e066545
SVGHMI: Fixing last commit's multiclient implementation, in case of watchdog. To be continued, since multiclient still fail...
svghmi/svghmi.c
svghmi/svghmi_server.py
--- a/svghmi/svghmi.c	Wed Jul 07 16:31:13 2021 +0200
+++ b/svghmi/svghmi.c	Fri Jul 09 15:47:43 2021 +0200
@@ -242,10 +242,13 @@
 }
 
 /* PYTHON CALLS */
+int svghmi_wait(void){
+
+    SVGHMI_SuspendFromPythonThread();
+}
+
 int svghmi_send_collect(uint32_t session_index, uint32_t *size, char **ptr){
 
-    SVGHMI_SuspendFromPythonThread();
-
     if(continue_collect) {
         int res;
         sbufidx = HMI_HASH_SIZE;
@@ -275,6 +278,12 @@
     subscribe = 2
 } cmd_from_JS;
 
+int svghmi_reset(uint32_t session_index){
+    reset_session_index = session_index;
+    traverse_hmi_tree(reset_iterator);
+    return 1;
+}
+
 // Returns :
 //   0 is OK, <0 is error, 1 is heartbeat
 int svghmi_recv_dispatch(uint32_t session_index, uint32_t size, const uint8_t *ptr){
--- a/svghmi/svghmi_server.py	Wed Jul 07 16:31:13 2021 +0200
+++ b/svghmi/svghmi_server.py	Fri Jul 09 15:47:43 2021 +0200
@@ -26,6 +26,11 @@
 max_svghmi_sessions = None
 svghmi_watchdog = None
 
+
+svghmi_wait = PLCBinary.svghmi_wait
+svghmi_wait.restype = ctypes.c_int # error or 0
+svghmi_wait.argtypes = []
+
 svghmi_send_collect = PLCBinary.svghmi_send_collect
 svghmi_send_collect.restype = ctypes.c_int # error or 0
 svghmi_send_collect.argtypes = [
@@ -33,6 +38,11 @@
     ctypes.POINTER(ctypes.c_uint32),  # size
     ctypes.POINTER(ctypes.c_void_p)]  # data ptr
 
+svghmi_reset = PLCBinary.svghmi_reset
+svghmi_reset.restype = ctypes.c_int # error or 0
+svghmi_reset.argtypes = [
+    ctypes.c_uint32]  # index
+
 svghmi_recv_dispatch = PLCBinary.svghmi_recv_dispatch
 svghmi_recv_dispatch.restype = ctypes.c_int # error or 0
 svghmi_recv_dispatch.argtypes = [
@@ -67,9 +77,7 @@
             if session.is_watchdog_session:
                 # Creating a new watchdog session closes pre-existing one
                 if self.watchdog_session is not None:
-                    self.watchdog_session.close()
                     self.unregister(self.watchdog_session)
-                    self.free_index(self.watchdog_session.session_index)
                 else:
                     assert(self.session_count < max_svghmi_sessions)
                     self.session_count += 1
@@ -83,13 +91,18 @@
 
     def unregister(self, session):
         with self.lock:
-            if session.is_watchdog_session:
-                assert(self.watchdog_session == session)
+            if session.is_watchdog_session :
+                if self.watchdog_session != session:
+                    return
                 self.watchdog_session = None
             else:
-                self.multiclient_sessions.remove(self)
-            self.free_index(self.watchdog_session.get_index())
+                try:
+                    self.multiclient_sessions.remove(self)
+                except KeyError:
+                    return
+            self.free_index(session.session_index)
             self.session_count -= 1
+        session.kill()
         
     def close_all(self):
         with self.lock:
@@ -97,7 +110,6 @@
             if self.watchdog_session:
                 close_list.append(self.watchdog_session)
             for session in close_list:
-                session.close()
                 self.unregister(session)
         
     def iter_sessions(self):
@@ -122,6 +134,7 @@
     def __init__(self, protocol_instance):
         self.protocol_instance = protocol_instance
         self._session_index = None
+        self.closed = False
 
     @property
     def is_watchdog_session(self):
@@ -135,14 +148,27 @@
     def session_index(self, value):
         self._session_index = value
 
+    def reset(self):
+        return svghmi_reset(self.session_index)
+
     def close(self):
+        if self.closed: return
         self.protocol_instance.sendClose(WebSocketProtocol.CLOSE_STATUS_CODE_NORMAL)
 
+    def notify_closed(self):
+        self.closed = True
+
+    def kill(self):
+        self.close()
+        self.reset()
+
     def onMessage(self, msg):
         # pass message to the C side recieve_message()
+        if self.closed: return
         return svghmi_recv_dispatch(self.session_index, len(msg), msg)
 
     def sendMessage(self, msg):
+        if self.closed: return
         self.protocol_instance.sendMessage(msg, True)
         return 0
 
@@ -199,10 +225,11 @@
         global svghmi_session_manager
         assert(self._hmi_session is None)
         self._hmi_session = HMISession(self)
-        svghmi_session_manager.register(self._hmi_session)
+        registered = svghmi_session_manager.register(self._hmi_session)
 
     def onClose(self, wasClean, code, reason):
         global svghmi_session_manager
+        self._hmi_session.notify_closed()
         svghmi_session_manager.unregister(self._hmi_session)
         self._hmi_session = None
 
@@ -228,7 +255,10 @@
     res = 0
     finished = False
     while not(finished):
+        svghmi_wait()
         for svghmi_session in svghmi_session_manager.iter_sessions():
+            # TODO make svghmi_send_collect waiting only once per
+            # svghmi_session_manager.iter_sessions cycle
             res = svghmi_send_collect(
                 svghmi_session.session_index,
                 ctypes.byref(size), ctypes.byref(ptr))
@@ -237,9 +267,9 @@
                     ctypes.string_at(ptr.value,size.value))
             elif res == errno.ENODATA:
                 # this happens when there is no data after wakeup
-                # because of hmi data refresh period longer than 
+                # because of hmi data refresh period longer than
                 # PLC common ticktime
-                pass 
+                pass
             else:
                 # this happens when finishing
                 finished = True