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