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 |