137 def unicode_translation(message): |
154 def unicode_translation(message): |
138 return wx.GetTranslation(message).encode("utf-8") |
155 return wx.GetTranslation(message).encode("utf-8") |
139 |
156 |
140 if __name__ == '__main__': |
157 if __name__ == '__main__': |
141 __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation |
158 __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation |
142 |
159 |
143 defaulticon = wx.Image(Bpath("images", "brz.png")) |
160 defaulticon = wx.Image(Bpath("images", "brz.png")) |
144 starticon = wx.Image(Bpath("images", "icoplay24.png")) |
161 starticon = wx.Image(Bpath("images", "icoplay24.png")) |
145 stopicon = wx.Image(Bpath("images", "icostop24.png")) |
162 stopicon = wx.Image(Bpath("images", "icostop24.png")) |
146 |
163 |
147 class ParamsEntryDialog(wx.TextEntryDialog): |
164 class ParamsEntryDialog(wx.TextEntryDialog): |
148 if wx.VERSION < (2, 6, 0): |
165 if wx.VERSION < (2, 6, 0): |
149 def Bind(self, event, function, id = None): |
166 def Bind(self, event, function, id = None): |
150 if id is not None: |
167 if id is not None: |
151 event(self, id, function) |
168 event(self, id, function) |
152 else: |
169 else: |
153 event(self, function) |
170 event(self, function) |
154 |
171 |
155 |
172 |
156 def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", |
173 def __init__(self, parent, message, caption = "Please enter text", defaultValue = "", |
157 style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): |
174 style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition): |
158 wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) |
175 wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos) |
159 |
176 |
160 self.Tests = [] |
177 self.Tests = [] |
161 if wx.VERSION >= (2, 8, 0): |
178 if wx.VERSION >= (2, 8, 0): |
162 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) |
179 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetAffirmativeId()) |
163 elif wx.VERSION >= (2, 6, 0): |
180 elif wx.VERSION >= (2, 6, 0): |
164 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId()) |
181 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId()) |
165 else: |
182 else: |
166 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) |
183 self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) |
167 |
184 |
168 def OnOK(self, event): |
185 def OnOK(self, event): |
169 value = self.GetValue() |
186 value = self.GetValue() |
170 texts = {"value" : value} |
187 texts = {"value" : value} |
171 for function, message in self.Tests: |
188 for function, message in self.Tests: |
172 if not function(value): |
189 if not function(value): |
174 message.ShowModal() |
191 message.ShowModal() |
175 message.Destroy() |
192 message.Destroy() |
176 return |
193 return |
177 self.EndModal(wx.ID_OK) |
194 self.EndModal(wx.ID_OK) |
178 event.Skip() |
195 event.Skip() |
179 |
196 |
180 def GetValue(self): |
197 def GetValue(self): |
181 return self.GetSizer().GetItem(1).GetWindow().GetValue() |
198 return self.GetSizer().GetItem(1).GetWindow().GetValue() |
182 |
199 |
183 def SetTests(self, tests): |
200 def SetTests(self, tests): |
184 self.Tests = tests |
201 self.Tests = tests |
185 |
202 |
186 class BeremizTaskBarIcon(wx.TaskBarIcon): |
203 class BeremizTaskBarIcon(wx.TaskBarIcon): |
187 TBMENU_START = wx.NewId() |
204 TBMENU_START = wx.NewId() |
188 TBMENU_STOP = wx.NewId() |
205 TBMENU_STOP = wx.NewId() |
189 TBMENU_CHANGE_NAME = wx.NewId() |
206 TBMENU_CHANGE_NAME = wx.NewId() |
190 TBMENU_CHANGE_PORT = wx.NewId() |
207 TBMENU_CHANGE_PORT = wx.NewId() |
191 TBMENU_CHANGE_INTERFACE = wx.NewId() |
208 TBMENU_CHANGE_INTERFACE = wx.NewId() |
192 TBMENU_LIVE_SHELL = wx.NewId() |
209 TBMENU_LIVE_SHELL = wx.NewId() |
193 TBMENU_WXINSPECTOR = wx.NewId() |
210 TBMENU_WXINSPECTOR = wx.NewId() |
194 TBMENU_CHANGE_WD = wx.NewId() |
211 TBMENU_CHANGE_WD = wx.NewId() |
195 TBMENU_QUIT = wx.NewId() |
212 TBMENU_QUIT = wx.NewId() |
196 |
213 |
197 def __init__(self, pyroserver, level): |
214 def __init__(self, pyroserver, level): |
198 wx.TaskBarIcon.__init__(self) |
215 wx.TaskBarIcon.__init__(self) |
199 self.pyroserver = pyroserver |
216 self.pyroserver = pyroserver |
200 # Set the image |
217 # Set the image |
201 self.UpdateIcon(None) |
218 self.UpdateIcon(None) |
202 self.level = level |
219 self.level = level |
203 |
220 |
204 # bind some events |
221 # bind some events |
205 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START) |
222 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START) |
206 self.Bind(wx.EVT_MENU, self.OnTaskBarStopPLC, id=self.TBMENU_STOP) |
223 self.Bind(wx.EVT_MENU, self.OnTaskBarStopPLC, id=self.TBMENU_STOP) |
207 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME) |
224 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME) |
208 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeInterface, id=self.TBMENU_CHANGE_INTERFACE) |
225 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeInterface, id=self.TBMENU_CHANGE_INTERFACE) |
209 self.Bind(wx.EVT_MENU, self.OnTaskBarLiveShell, id=self.TBMENU_LIVE_SHELL) |
226 self.Bind(wx.EVT_MENU, self.OnTaskBarLiveShell, id=self.TBMENU_LIVE_SHELL) |
210 self.Bind(wx.EVT_MENU, self.OnTaskBarWXInspector, id=self.TBMENU_WXINSPECTOR) |
227 self.Bind(wx.EVT_MENU, self.OnTaskBarWXInspector, id=self.TBMENU_WXINSPECTOR) |
211 self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT) |
228 self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT) |
212 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD) |
229 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD) |
213 self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT) |
230 self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT) |
214 |
231 |
215 def CreatePopupMenu(self): |
232 def CreatePopupMenu(self): |
216 """ |
233 """ |
217 This method is called by the base class when it needs to popup |
234 This method is called by the base class when it needs to popup |
218 the menu for the default EVT_RIGHT_DOWN event. Just create |
235 the menu for the default EVT_RIGHT_DOWN event. Just create |
219 the menu how you want it and return it from this function, |
236 the menu how you want it and return it from this function, |
245 elif "wxGTK" in wx.PlatformInfo: |
262 elif "wxGTK" in wx.PlatformInfo: |
246 img = img.Scale(22, 22) |
263 img = img.Scale(22, 22) |
247 # wxMac can be any size upto 128x128, so leave the source img alone.... |
264 # wxMac can be any size upto 128x128, so leave the source img alone.... |
248 icon = wx.IconFromBitmap(img.ConvertToBitmap() ) |
265 icon = wx.IconFromBitmap(img.ConvertToBitmap() ) |
249 return icon |
266 return icon |
250 |
267 |
251 def OnTaskBarStartPLC(self, evt): |
268 def OnTaskBarStartPLC(self, evt): |
252 if self.pyroserver.plcobj is not None: |
269 if self.pyroserver.plcobj is not None: |
253 self.pyroserver.plcobj.StartPLC() |
270 self.pyroserver.plcobj.StartPLC() |
254 |
271 |
255 def OnTaskBarStopPLC(self, evt): |
272 def OnTaskBarStopPLC(self, evt): |
256 if self.pyroserver.plcobj is not None: |
273 if self.pyroserver.plcobj is not None: |
257 Thread(target=self.pyroserver.plcobj.StopPLC).start() |
274 Thread(target=self.pyroserver.plcobj.StopPLC).start() |
258 |
275 |
259 def OnTaskBarChangeInterface(self, evt): |
276 def OnTaskBarChangeInterface(self, evt): |
260 dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=self.pyroserver.ip_addr) |
277 dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=self.pyroserver.ip_addr) |
261 dlg.SetTests([(re.compile('\d{1,3}(?:\.\d{1,3}){3}$').match, _("IP is not valid!")), |
278 dlg.SetTests([(re.compile('\d{1,3}(?:\.\d{1,3}){3}$').match, _("IP is not valid!")), |
262 ( lambda x :len([x for x in x.split(".") if 0 <= int(x) <= 255]) == 4, _("IP is not valid!")) |
279 ( lambda x :len([x for x in x.split(".") if 0 <= int(x) <= 255]) == 4, _("IP is not valid!")) |
263 ]) |
280 ]) |
264 if dlg.ShowModal() == wx.ID_OK: |
281 if dlg.ShowModal() == wx.ID_OK: |
265 self.pyroserver.ip_addr = dlg.GetValue() |
282 self.pyroserver.ip_addr = dlg.GetValue() |
266 self.pyroserver.Stop() |
283 self.pyroserver.Stop() |
267 |
284 |
268 def OnTaskBarChangePort(self, evt): |
285 def OnTaskBarChangePort(self, evt): |
269 dlg = ParamsEntryDialog(None, _("Enter a port number "), defaultValue=str(self.pyroserver.port)) |
286 dlg = ParamsEntryDialog(None, _("Enter a port number "), defaultValue=str(self.pyroserver.port)) |
270 dlg.SetTests([(UnicodeType.isdigit, _("Port number must be an integer!")), (lambda port : 0 <= int(port) <= 65535 , _("Port number must be 0 <= port <= 65535!"))]) |
287 dlg.SetTests([(UnicodeType.isdigit, _("Port number must be an integer!")), (lambda port : 0 <= int(port) <= 65535 , _("Port number must be 0 <= port <= 65535!"))]) |
271 if dlg.ShowModal() == wx.ID_OK: |
288 if dlg.ShowModal() == wx.ID_OK: |
272 self.pyroserver.port = int(dlg.GetValue()) |
289 self.pyroserver.port = int(dlg.GetValue()) |
273 self.pyroserver.Stop() |
290 self.pyroserver.Stop() |
274 |
291 |
275 def OnTaskBarChangeWorkingDir(self, evt): |
292 def OnTaskBarChangeWorkingDir(self, evt): |
276 dlg = wx.DirDialog(None, _("Choose a working directory "), self.pyroserver.workdir, wx.DD_NEW_DIR_BUTTON) |
293 dlg = wx.DirDialog(None, _("Choose a working directory "), self.pyroserver.workdir, wx.DD_NEW_DIR_BUTTON) |
277 if dlg.ShowModal() == wx.ID_OK: |
294 if dlg.ShowModal() == wx.ID_OK: |
278 self.pyroserver.workdir = dlg.GetPath() |
295 self.pyroserver.workdir = dlg.GetPath() |
279 self.pyroserver.Stop() |
296 self.pyroserver.Stop() |
280 |
297 |
281 def OnTaskBarChangeName(self, evt): |
298 def OnTaskBarChangeName(self, evt): |
282 dlg = ParamsEntryDialog(None, _("Enter a name "), defaultValue=self.pyroserver.name) |
299 dlg = ParamsEntryDialog(None, _("Enter a name "), defaultValue=self.pyroserver.name) |
283 dlg.SetTests([(lambda name : len(name) is not 0 , _("Name must not be null!"))]) |
300 dlg.SetTests([(lambda name : len(name) is not 0 , _("Name must not be null!"))]) |
284 if dlg.ShowModal() == wx.ID_OK: |
301 if dlg.ShowModal() == wx.ID_OK: |
285 self.pyroserver.name = dlg.GetValue() |
302 self.pyroserver.name = dlg.GetValue() |
286 self.pyroserver.Restart() |
303 self.pyroserver.Restart() |
287 |
304 |
288 def _LiveShellLocals(self): |
305 def _LiveShellLocals(self): |
289 if self.pyroserver.plcobj is not None: |
306 if self.pyroserver.plcobj is not None: |
290 return {"locals":self.pyroserver.plcobj.python_runtime_vars} |
307 return {"locals":self.pyroserver.plcobj.python_runtime_vars} |
291 else: |
308 else: |
292 return {} |
309 return {} |
293 |
310 |
294 def OnTaskBarLiveShell(self, evt): |
311 def OnTaskBarLiveShell(self, evt): |
295 from wx import py |
312 from wx import py |
296 frame = py.crust.CrustFrame(**self._LiveShellLocals()) |
313 frame = py.crust.CrustFrame(**self._LiveShellLocals()) |
297 frame.Show() |
314 frame.Show() |
298 |
315 |
299 def OnTaskBarWXInspector(self, evt): |
316 def OnTaskBarWXInspector(self, evt): |
300 # Activate the widget inspection tool |
317 # Activate the widget inspection tool |
301 from wx.lib.inspection import InspectionTool |
318 from wx.lib.inspection import InspectionTool |
302 if not InspectionTool().initialized: |
319 if not InspectionTool().initialized: |
303 InspectionTool().Init(**self._LiveShellLocals()) |
320 InspectionTool().Init(**self._LiveShellLocals()) |
304 |
321 |
305 wnd = wx.GetApp() |
322 wnd = wx.GetApp() |
306 InspectionTool().Show(wnd, True) |
323 InspectionTool().Show(wnd, True) |
307 |
324 |
308 def OnTaskBarQuit(self, evt): |
325 def OnTaskBarQuit(self, evt): |
309 if wx.Platform == '__WXMSW__': |
326 if wx.Platform == '__WXMSW__': |
310 Thread(target=self.pyroserver.Quit).start() |
327 Thread(target=self.pyroserver.Quit).start() |
311 self.RemoveIcon() |
328 self.RemoveIcon() |
312 wx.CallAfter(wx.GetApp().ExitMainLoop) |
329 wx.CallAfter(wx.GetApp().ExitMainLoop) |
313 |
330 |
314 def UpdateIcon(self, plcstatus): |
331 def UpdateIcon(self, plcstatus): |
315 if plcstatus is "Started" : |
332 if plcstatus is "Started" : |
316 currenticon = self.MakeIcon(starticon) |
333 currenticon = self.MakeIcon(starticon) |
317 elif plcstatus is "Stopped": |
334 elif plcstatus is "Stopped": |
318 currenticon = self.MakeIcon(stopicon) |
335 currenticon = self.MakeIcon(stopicon) |
363 self.Stop() |
383 self.Stop() |
364 |
384 |
365 def Start(self): |
385 def Start(self): |
366 pyro.initServer() |
386 pyro.initServer() |
367 self.daemon=pyro.Daemon(host=self.ip_addr, port=self.port) |
387 self.daemon=pyro.Daemon(host=self.ip_addr, port=self.port) |
368 self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, self.statuschange, self.evaluator, self.website) |
388 self.plcobj = PLCObject(self.workdir, self.daemon, self.argv, |
|
389 self.statuschange, self.evaluator, |
|
390 self.pyruntimevars) |
369 uri = self.daemon.connect(self.plcobj,"PLCObject") |
391 uri = self.daemon.connect(self.plcobj,"PLCObject") |
370 |
392 |
371 print "Pyro port :",self.port |
393 print "Pyro port :",self.port |
372 print "Pyro object's uri :",uri |
394 print "Pyro object's uri :",uri |
373 print "Current working directory :",self.workdir |
395 print "Current working directory :",self.workdir |
374 |
396 |
375 # Configure and publish service |
397 # Configure and publish service |
376 # Not publish service if localhost in address params |
398 # Not publish service if localhost in address params |
377 if (self.servicename is not None and |
399 if (self.servicename is not None and |
378 self.ip_addr is not None and |
400 self.ip_addr is not None and |
379 self.ip_addr != "localhost" and |
401 self.ip_addr != "localhost" and |
380 self.ip_addr != "127.0.0.1"): |
402 self.ip_addr != "127.0.0.1"): |
381 print "Publishing service on local network" |
403 print "Publishing service on local network" |
382 self.servicepublisher = ServicePublisher.ServicePublisher() |
404 self.servicepublisher = ServicePublisher.ServicePublisher() |
383 self.servicepublisher.RegisterService(self.servicename, self.ip_addr, self.port) |
405 self.servicepublisher.RegisterService(self.servicename, self.ip_addr, self.port) |
384 |
406 |
385 if self.autostart and self.plcobj.GetPLCstatus()[0] != "Empty": |
407 if self.autostart : |
386 self.plcobj.StartPLC() |
408 self.plcobj.AutoLoad() |
387 |
409 if self.plcobj.GetPLCstatus()[0] != "Empty": |
|
410 self.plcobj.StartPLC() |
|
411 |
388 sys.stdout.flush() |
412 sys.stdout.flush() |
389 |
413 |
390 self.daemon.requestLoop() |
414 self.daemon.requestLoop() |
391 |
415 |
392 def Stop(self): |
416 def Stop(self): |
393 if self.plcobj is not None: |
417 if self.plcobj is not None: |
394 self.plcobj.StopPLC() |
418 self.plcobj.StopPLC() |
395 if self.servicepublisher is not None: |
419 if self.servicepublisher is not None: |
396 self.servicepublisher.UnRegisterService() |
420 self.servicepublisher.UnRegisterService() |
404 try: |
428 try: |
405 from threading import Thread, currentThread |
429 from threading import Thread, currentThread |
406 if havewx: |
430 if havewx: |
407 from twisted.internet import wxreactor |
431 from twisted.internet import wxreactor |
408 wxreactor.install() |
432 wxreactor.install() |
409 from twisted.internet import reactor, task |
433 from twisted.internet import reactor |
410 from twisted.python import log, util |
434 |
411 from nevow import rend, appserver, inevow, tags, loaders, athena |
|
412 from nevow.page import renderer |
|
413 |
|
414 havetwisted = True |
435 havetwisted = True |
415 except: |
436 except: |
416 print "Twisted unavailable !" |
437 print "Twisted unavailable." |
417 havetwisted = False |
438 havetwisted = False |
418 |
439 |
|
440 pyruntimevars = {} |
|
441 statuschange = [] |
|
442 |
419 if havetwisted: |
443 if havetwisted: |
420 |
444 |
421 xhtml_header = '''<?xml version="1.0" encoding="utf-8"?> |
|
422 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" |
|
423 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> |
|
424 ''' |
|
425 |
|
426 class PLCHMI(athena.LiveElement): |
|
427 |
|
428 initialised = False |
|
429 |
|
430 def HMIinitialised(self, result): |
|
431 self.initialised = True |
|
432 |
|
433 def HMIinitialisation(self): |
|
434 self.HMIinitialised(None) |
|
435 |
|
436 class DefaultPLCStartedHMI(PLCHMI): |
|
437 docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ |
|
438 tags.h1["PLC IS NOW STARTED"], |
|
439 ]) |
|
440 |
|
441 class PLCStoppedHMI(PLCHMI): |
|
442 docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ |
|
443 tags.h1["PLC IS STOPPED"], |
|
444 ]) |
|
445 |
|
446 class MainPage(athena.LiveElement): |
|
447 jsClass = u"WebInterface.PLC" |
|
448 docFactory = loaders.stan(tags.div(render=tags.directive('liveElement'))[ |
|
449 tags.div(id='content')[ |
|
450 tags.div(render = tags.directive('PLCElement')), |
|
451 ]]) |
|
452 |
|
453 def __init__(self, *a, **kw): |
|
454 athena.LiveElement.__init__(self, *a, **kw) |
|
455 self.pcl_state = False |
|
456 self.HMI = None |
|
457 self.resetPLCStartedHMI() |
|
458 |
|
459 def setPLCState(self, state): |
|
460 self.pcl_state = state |
|
461 if self.HMI is not None: |
|
462 self.callRemote('updateHMI') |
|
463 |
|
464 def setPLCStartedHMI(self, hmi): |
|
465 self.PLCStartedHMIClass = hmi |
|
466 |
|
467 def resetPLCStartedHMI(self): |
|
468 self.PLCStartedHMIClass = DefaultPLCStartedHMI |
|
469 |
|
470 def getHMI(self): |
|
471 return self.HMI |
|
472 |
|
473 def HMIexec(self, function, *args, **kwargs): |
|
474 if self.HMI is not None: |
|
475 getattr(self.HMI, function, lambda:None)(*args, **kwargs) |
|
476 athena.expose(HMIexec) |
|
477 |
|
478 def resetHMI(self): |
|
479 self.HMI = None |
|
480 |
|
481 def PLCElement(self, ctx, data): |
|
482 return self.getPLCElement() |
|
483 renderer(PLCElement) |
|
484 |
|
485 def getPLCElement(self): |
|
486 self.detachFragmentChildren() |
|
487 if self.pcl_state: |
|
488 f = self.PLCStartedHMIClass() |
|
489 else: |
|
490 f = PLCStoppedHMI() |
|
491 f.setFragmentParent(self) |
|
492 self.HMI = f |
|
493 return f |
|
494 athena.expose(getPLCElement) |
|
495 |
|
496 def detachFragmentChildren(self): |
|
497 for child in self.liveFragmentChildren[:]: |
|
498 child.detach() |
|
499 |
|
500 class WebInterface(athena.LivePage): |
|
501 |
|
502 docFactory = loaders.stan([tags.raw(xhtml_header), |
|
503 tags.html(xmlns="http://www.w3.org/1999/xhtml")[ |
|
504 tags.head(render=tags.directive('liveglue')), |
|
505 tags.body[ |
|
506 tags.div[ |
|
507 tags.div( render = tags.directive( "MainPage" )) |
|
508 ]]]]) |
|
509 MainPage = MainPage() |
|
510 PLCHMI = PLCHMI |
|
511 |
|
512 def __init__(self, plcState=False, *a, **kw): |
|
513 super(WebInterface, self).__init__(*a, **kw) |
|
514 self.jsModules.mapping[u'WebInterface'] = util.sibpath(__file__, os.path.join('runtime', 'webinterface.js')) |
|
515 self.plcState = plcState |
|
516 self.MainPage.setPLCState(plcState) |
|
517 |
|
518 def getHMI(self): |
|
519 return self.MainPage.getHMI() |
|
520 |
|
521 def LoadHMI(self, hmi, jsmodules): |
|
522 for name, path in jsmodules.iteritems(): |
|
523 self.jsModules.mapping[name] = os.path.join(WorkingDir, path) |
|
524 self.MainPage.setPLCStartedHMI(hmi) |
|
525 |
|
526 def UnLoadHMI(self): |
|
527 self.MainPage.resetPLCStartedHMI() |
|
528 |
|
529 def PLCStarted(self): |
|
530 self.plcState = True |
|
531 self.MainPage.setPLCState(True) |
|
532 |
|
533 def PLCStopped(self): |
|
534 self.plcState = False |
|
535 self.MainPage.setPLCState(False) |
|
536 |
|
537 def renderHTTP(self, ctx): |
|
538 """ |
|
539 Force content type to fit with SVG |
|
540 """ |
|
541 req = inevow.IRequest(ctx) |
|
542 req.setHeader('Content-type', 'application/xhtml+xml') |
|
543 return super(WebInterface, self).renderHTTP(ctx) |
|
544 |
|
545 def render_MainPage(self, ctx, data): |
|
546 f = self.MainPage |
|
547 f.setFragmentParent(self) |
|
548 return ctx.tag[f] |
|
549 |
|
550 def child_(self, ctx): |
|
551 self.MainPage.detachFragmentChildren() |
|
552 return WebInterface(plcState=self.plcState) |
|
553 |
|
554 def beforeRender(self, ctx): |
|
555 d = self.notifyOnDisconnect() |
|
556 d.addErrback(self.disconnected) |
|
557 |
|
558 def disconnected(self, reason): |
|
559 self.MainPage.resetHMI() |
|
560 #print reason |
|
561 #print "We will be called back when the client disconnects" |
|
562 |
|
563 if havewx: |
445 if havewx: |
564 reactor.registerWxApp(app) |
446 reactor.registerWxApp(app) |
565 website = WebInterface() |
|
566 site = appserver.NevowSite(website) |
|
567 |
|
568 website_port = 8009 |
|
569 listening = False |
|
570 while not listening: |
|
571 try: |
|
572 reactor.listenTCP(website_port, site) |
|
573 listening = True |
|
574 except: |
|
575 website_port += 1 |
|
576 print "Http interface port :",website_port |
|
577 else: |
|
578 website = None |
|
579 |
447 |
580 if havewx: |
448 if havewx: |
581 from threading import Semaphore |
449 from threading import Semaphore |
582 wx_eval_lock = Semaphore(0) |
450 wx_eval_lock = Semaphore(0) |
583 main_thread = currentThread() |
451 main_thread = currentThread() |
584 |
452 |
585 def statuschange(status): |
453 def statuschangeTskBar(status): |
586 wx.CallAfter(taskbar_instance.UpdateIcon,status) |
454 wx.CallAfter(taskbar_instance.UpdateIcon,status) |
587 |
455 |
|
456 statuschange.append(statuschangeTskBar) |
|
457 |
588 def wx_evaluator(obj, *args, **kwargs): |
458 def wx_evaluator(obj, *args, **kwargs): |
589 tocall,args,kwargs = obj.call |
459 tocall,args,kwargs = obj.call |
590 obj.res = default_evaluator(tocall, *args, **kwargs) |
460 obj.res = default_evaluator(tocall, *args, **kwargs) |
591 wx_eval_lock.release() |
461 wx_eval_lock.release() |
592 |
462 |
593 def evaluator(tocall, *args, **kwargs): |
463 def evaluator(tocall, *args, **kwargs): |
594 global main_thread |
464 global main_thread |
595 if(main_thread == currentThread()): |
465 if(main_thread == currentThread()): |
596 # avoid dead lock if called from the wx mainloop |
466 # avoid dead lock if called from the wx mainloop |
597 return default_evaluator(tocall, *args, **kwargs) |
467 return default_evaluator(tocall, *args, **kwargs) |
598 else: |
468 else: |
599 o=type('',(object,),dict(call=(tocall, args, kwargs), res=None)) |
469 o=type('',(object,),dict(call=(tocall, args, kwargs), res=None)) |
600 wx.CallAfter(wx_evaluator,o) |
470 wx.CallAfter(wx_evaluator,o) |
601 wx_eval_lock.acquire() |
471 wx_eval_lock.acquire() |
602 return o.res |
472 return o.res |
603 |
473 |
604 pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, statuschange, evaluator, website) |
474 pyroserver = Server(servicename, given_ip, port, |
|
475 WorkingDir, argv, autostart, |
|
476 statuschange, evaluator, pyruntimevars) |
|
477 |
605 taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx) |
478 taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx) |
606 else: |
479 else: |
607 pyroserver = Server(servicename, given_ip, port, WorkingDir, argv, autostart, website=website) |
480 pyroserver = Server(servicename, given_ip, port, |
|
481 WorkingDir, argv, autostart, |
|
482 statuschange, pyruntimevars=pyruntimevars) |
|
483 |
608 |
484 |
609 # Exception hooks s |
485 # Exception hooks s |
610 import threading, traceback |
486 import threading, traceback |
611 def LogException(*exp): |
487 def LogException(*exp): |
612 if pyroserver.plcobj is not None: |
488 if pyroserver.plcobj is not None: |