svghmi/svghmi_server.py
branchsvghmi
changeset 3271 561dbd1e3e04
parent 3270 38f7122ccbf9
child 3272 c8182e066545
equal deleted inserted replaced
3270:38f7122ccbf9 3271:561dbd1e3e04
    23 from autobahn.websocket.protocol import WebSocketProtocol
    23 from autobahn.websocket.protocol import WebSocketProtocol
    24 from autobahn.twisted.resource import  WebSocketResource
    24 from autobahn.twisted.resource import  WebSocketResource
    25 
    25 
    26 max_svghmi_sessions = None
    26 max_svghmi_sessions = None
    27 svghmi_watchdog = None
    27 svghmi_watchdog = None
       
    28 
       
    29 
       
    30 svghmi_wait = PLCBinary.svghmi_wait
       
    31 svghmi_wait.restype = ctypes.c_int # error or 0
       
    32 svghmi_wait.argtypes = []
    28 
    33 
    29 svghmi_send_collect = PLCBinary.svghmi_send_collect
    34 svghmi_send_collect = PLCBinary.svghmi_send_collect
    30 svghmi_send_collect.restype = ctypes.c_int # error or 0
    35 svghmi_send_collect.restype = ctypes.c_int # error or 0
    31 svghmi_send_collect.argtypes = [
    36 svghmi_send_collect.argtypes = [
    32     ctypes.c_uint32,  # index
    37     ctypes.c_uint32,  # index
    33     ctypes.POINTER(ctypes.c_uint32),  # size
    38     ctypes.POINTER(ctypes.c_uint32),  # size
    34     ctypes.POINTER(ctypes.c_void_p)]  # data ptr
    39     ctypes.POINTER(ctypes.c_void_p)]  # data ptr
       
    40 
       
    41 svghmi_reset = PLCBinary.svghmi_reset
       
    42 svghmi_reset.restype = ctypes.c_int # error or 0
       
    43 svghmi_reset.argtypes = [
       
    44     ctypes.c_uint32]  # index
    35 
    45 
    36 svghmi_recv_dispatch = PLCBinary.svghmi_recv_dispatch
    46 svghmi_recv_dispatch = PLCBinary.svghmi_recv_dispatch
    37 svghmi_recv_dispatch.restype = ctypes.c_int # error or 0
    47 svghmi_recv_dispatch.restype = ctypes.c_int # error or 0
    38 svghmi_recv_dispatch.argtypes = [
    48 svghmi_recv_dispatch.argtypes = [
    39     ctypes.c_uint32,  # index
    49     ctypes.c_uint32,  # index
    65         global max_svghmi_sessions
    75         global max_svghmi_sessions
    66         with self.lock:
    76         with self.lock:
    67             if session.is_watchdog_session:
    77             if session.is_watchdog_session:
    68                 # Creating a new watchdog session closes pre-existing one
    78                 # Creating a new watchdog session closes pre-existing one
    69                 if self.watchdog_session is not None:
    79                 if self.watchdog_session is not None:
    70                     self.watchdog_session.close()
       
    71                     self.unregister(self.watchdog_session)
    80                     self.unregister(self.watchdog_session)
    72                     self.free_index(self.watchdog_session.session_index)
       
    73                 else:
    81                 else:
    74                     assert(self.session_count < max_svghmi_sessions)
    82                     assert(self.session_count < max_svghmi_sessions)
    75                     self.session_count += 1
    83                     self.session_count += 1
    76 
    84 
    77                 self.watchdog_session = session
    85                 self.watchdog_session = session
    81                 self.session_count += 1
    89                 self.session_count += 1
    82             session.session_index = self.next_index()
    90             session.session_index = self.next_index()
    83 
    91 
    84     def unregister(self, session):
    92     def unregister(self, session):
    85         with self.lock:
    93         with self.lock:
    86             if session.is_watchdog_session:
    94             if session.is_watchdog_session :
    87                 assert(self.watchdog_session == session)
    95                 if self.watchdog_session != session:
       
    96                     return
    88                 self.watchdog_session = None
    97                 self.watchdog_session = None
    89             else:
    98             else:
    90                 self.multiclient_sessions.remove(self)
    99                 try:
    91             self.free_index(self.watchdog_session.get_index())
   100                     self.multiclient_sessions.remove(self)
       
   101                 except KeyError:
       
   102                     return
       
   103             self.free_index(session.session_index)
    92             self.session_count -= 1
   104             self.session_count -= 1
       
   105         session.kill()
    93         
   106         
    94     def close_all(self):
   107     def close_all(self):
    95         with self.lock:
   108         with self.lock:
    96             close_list = list(self.multiclient_sessions)
   109             close_list = list(self.multiclient_sessions)
    97             if self.watchdog_session:
   110             if self.watchdog_session:
    98                 close_list.append(self.watchdog_session)
   111                 close_list.append(self.watchdog_session)
    99             for session in close_list:
   112             for session in close_list:
   100                 session.close()
       
   101                 self.unregister(session)
   113                 self.unregister(session)
   102         
   114         
   103     def iter_sessions(self):
   115     def iter_sessions(self):
   104         with self.lock:
   116         with self.lock:
   105             nxt_session = self.watchdog_session
   117             nxt_session = self.watchdog_session
   120 
   132 
   121 class HMISession(object):
   133 class HMISession(object):
   122     def __init__(self, protocol_instance):
   134     def __init__(self, protocol_instance):
   123         self.protocol_instance = protocol_instance
   135         self.protocol_instance = protocol_instance
   124         self._session_index = None
   136         self._session_index = None
       
   137         self.closed = False
   125 
   138 
   126     @property
   139     @property
   127     def is_watchdog_session(self):
   140     def is_watchdog_session(self):
   128         return self.protocol_instance.has_watchdog
   141         return self.protocol_instance.has_watchdog
   129 
   142 
   133 
   146 
   134     @session_index.setter
   147     @session_index.setter
   135     def session_index(self, value):
   148     def session_index(self, value):
   136         self._session_index = value
   149         self._session_index = value
   137 
   150 
       
   151     def reset(self):
       
   152         return svghmi_reset(self.session_index)
       
   153 
   138     def close(self):
   154     def close(self):
       
   155         if self.closed: return
   139         self.protocol_instance.sendClose(WebSocketProtocol.CLOSE_STATUS_CODE_NORMAL)
   156         self.protocol_instance.sendClose(WebSocketProtocol.CLOSE_STATUS_CODE_NORMAL)
       
   157 
       
   158     def notify_closed(self):
       
   159         self.closed = True
       
   160 
       
   161     def kill(self):
       
   162         self.close()
       
   163         self.reset()
   140 
   164 
   141     def onMessage(self, msg):
   165     def onMessage(self, msg):
   142         # pass message to the C side recieve_message()
   166         # pass message to the C side recieve_message()
       
   167         if self.closed: return
   143         return svghmi_recv_dispatch(self.session_index, len(msg), msg)
   168         return svghmi_recv_dispatch(self.session_index, len(msg), msg)
   144 
   169 
   145     def sendMessage(self, msg):
   170     def sendMessage(self, msg):
       
   171         if self.closed: return
   146         self.protocol_instance.sendMessage(msg, True)
   172         self.protocol_instance.sendMessage(msg, True)
   147         return 0
   173         return 0
   148 
   174 
   149 class Watchdog(object):
   175 class Watchdog(object):
   150     def __init__(self, initial_timeout, interval, callback):
   176     def __init__(self, initial_timeout, interval, callback):
   197 
   223 
   198     def onOpen(self):
   224     def onOpen(self):
   199         global svghmi_session_manager
   225         global svghmi_session_manager
   200         assert(self._hmi_session is None)
   226         assert(self._hmi_session is None)
   201         self._hmi_session = HMISession(self)
   227         self._hmi_session = HMISession(self)
   202         svghmi_session_manager.register(self._hmi_session)
   228         registered = svghmi_session_manager.register(self._hmi_session)
   203 
   229 
   204     def onClose(self, wasClean, code, reason):
   230     def onClose(self, wasClean, code, reason):
   205         global svghmi_session_manager
   231         global svghmi_session_manager
       
   232         self._hmi_session.notify_closed()
   206         svghmi_session_manager.unregister(self._hmi_session)
   233         svghmi_session_manager.unregister(self._hmi_session)
   207         self._hmi_session = None
   234         self._hmi_session = None
   208 
   235 
   209     def onMessage(self, msg, isBinary):
   236     def onMessage(self, msg, isBinary):
   210         global svghmi_watchdog
   237         global svghmi_watchdog
   226     size = ctypes.c_uint32()
   253     size = ctypes.c_uint32()
   227     ptr = ctypes.c_void_p()
   254     ptr = ctypes.c_void_p()
   228     res = 0
   255     res = 0
   229     finished = False
   256     finished = False
   230     while not(finished):
   257     while not(finished):
       
   258         svghmi_wait()
   231         for svghmi_session in svghmi_session_manager.iter_sessions():
   259         for svghmi_session in svghmi_session_manager.iter_sessions():
       
   260             # TODO make svghmi_send_collect waiting only once per
       
   261             # svghmi_session_manager.iter_sessions cycle
   232             res = svghmi_send_collect(
   262             res = svghmi_send_collect(
   233                 svghmi_session.session_index,
   263                 svghmi_session.session_index,
   234                 ctypes.byref(size), ctypes.byref(ptr))
   264                 ctypes.byref(size), ctypes.byref(ptr))
   235             if res == 0:
   265             if res == 0:
   236                 svghmi_session.sendMessage(
   266                 svghmi_session.sendMessage(
   237                     ctypes.string_at(ptr.value,size.value))
   267                     ctypes.string_at(ptr.value,size.value))
   238             elif res == errno.ENODATA:
   268             elif res == errno.ENODATA:
   239                 # this happens when there is no data after wakeup
   269                 # this happens when there is no data after wakeup
   240                 # because of hmi data refresh period longer than 
   270                 # because of hmi data refresh period longer than
   241                 # PLC common ticktime
   271                 # PLC common ticktime
   242                 pass 
   272                 pass
   243             else:
   273             else:
   244                 # this happens when finishing
   274                 # this happens when finishing
   245                 finished = True
   275                 finished = True
   246                 break
   276                 break
   247 
   277