240 TBMENU_LIVE_SHELL = wx.NewId() |
239 TBMENU_LIVE_SHELL = wx.NewId() |
241 TBMENU_WXINSPECTOR = wx.NewId() |
240 TBMENU_WXINSPECTOR = wx.NewId() |
242 TBMENU_CHANGE_WD = wx.NewId() |
241 TBMENU_CHANGE_WD = wx.NewId() |
243 TBMENU_QUIT = wx.NewId() |
242 TBMENU_QUIT = wx.NewId() |
244 |
243 |
245 def __init__(self, pyroserver, level): |
244 def __init__(self, pyroserver): |
246 wx.TaskBarIcon.__init__(self) |
245 wx.TaskBarIcon.__init__(self) |
247 self.pyroserver = pyroserver |
246 self.pyroserver = pyroserver |
248 # Set the image |
247 # Set the image |
249 self.UpdateIcon(None) |
248 self.UpdateIcon(None) |
250 self.level = level |
|
251 |
249 |
252 # bind some events |
250 # bind some events |
253 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START) |
251 self.Bind(wx.EVT_MENU, self.OnTaskBarStartPLC, id=self.TBMENU_START) |
254 self.Bind(wx.EVT_MENU, self.OnTaskBarStopPLC, id=self.TBMENU_STOP) |
252 self.Bind(wx.EVT_MENU, self.OnTaskBarStopPLC, id=self.TBMENU_STOP) |
255 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME) |
253 self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME) |
268 the base class takes care of the rest. |
266 the base class takes care of the rest. |
269 """ |
267 """ |
270 menu = wx.Menu() |
268 menu = wx.Menu() |
271 menu.Append(self.TBMENU_START, _("Start PLC")) |
269 menu.Append(self.TBMENU_START, _("Start PLC")) |
272 menu.Append(self.TBMENU_STOP, _("Stop PLC")) |
270 menu.Append(self.TBMENU_STOP, _("Stop PLC")) |
273 if self.level == 1: |
271 menu.AppendSeparator() |
274 menu.AppendSeparator() |
272 menu.Append(self.TBMENU_CHANGE_NAME, _("Change Name")) |
275 menu.Append(self.TBMENU_CHANGE_NAME, _("Change Name")) |
273 menu.Append(self.TBMENU_CHANGE_INTERFACE, _("Change IP of interface to bind")) |
276 menu.Append(self.TBMENU_CHANGE_INTERFACE, _("Change IP of interface to bind")) |
274 menu.Append(self.TBMENU_CHANGE_PORT, _("Change Port Number")) |
277 menu.Append(self.TBMENU_CHANGE_PORT, _("Change Port Number")) |
275 menu.Append(self.TBMENU_CHANGE_WD, _("Change working directory")) |
278 menu.Append(self.TBMENU_CHANGE_WD, _("Change working directory")) |
276 menu.AppendSeparator() |
279 menu.AppendSeparator() |
277 menu.Append(self.TBMENU_LIVE_SHELL, _("Launch a live Python shell")) |
280 menu.Append(self.TBMENU_LIVE_SHELL, _("Launch a live Python shell")) |
278 menu.Append(self.TBMENU_WXINSPECTOR, _("Launch WX GUI inspector")) |
281 menu.Append(self.TBMENU_WXINSPECTOR, _("Launch WX GUI inspector")) |
|
282 menu.AppendSeparator() |
279 menu.AppendSeparator() |
283 menu.Append(self.TBMENU_QUIT, _("Quit")) |
280 menu.Append(self.TBMENU_QUIT, _("Quit")) |
284 return menu |
281 return menu |
285 |
282 |
286 def MakeIcon(self, img): |
283 def MakeIcon(self, img): |
295 # wxMac can be any size upto 128x128, so leave the source img alone.... |
292 # wxMac can be any size upto 128x128, so leave the source img alone.... |
296 icon = wx.IconFromBitmap(img.ConvertToBitmap()) |
293 icon = wx.IconFromBitmap(img.ConvertToBitmap()) |
297 return icon |
294 return icon |
298 |
295 |
299 def OnTaskBarStartPLC(self, evt): |
296 def OnTaskBarStartPLC(self, evt): |
300 if self.pyroserver.plcobj is not None: |
297 runtime.GetPLCObjectSingleton().StartPLC() |
301 plcstatus = self.pyroserver.plcobj.GetPLCstatus()[0] |
|
302 if plcstatus is "Stopped": |
|
303 self.pyroserver.plcobj.StartPLC() |
|
304 else: |
|
305 print(_("PLC is empty or already started.")) |
|
306 |
298 |
307 def OnTaskBarStopPLC(self, evt): |
299 def OnTaskBarStopPLC(self, evt): |
308 if self.pyroserver.plcobj is not None: |
300 runtime.GetPLCObjectSingleton().StopPLC() |
309 if self.pyroserver.plcobj.GetPLCstatus()[0] == "Started": |
|
310 Thread(target=self.pyroserver.plcobj.StopPLC).start() |
|
311 else: |
|
312 print(_("PLC is not started.")) |
|
313 |
301 |
314 def OnTaskBarChangeInterface(self, evt): |
302 def OnTaskBarChangeInterface(self, evt): |
315 ip_addr = self.pyroserver.ip_addr |
303 ip_addr = self.pyroserver.ip_addr |
316 ip_addr = '' if ip_addr is None else ip_addr |
304 ip_addr = '' if ip_addr is None else ip_addr |
317 dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr) |
305 dlg = ParamsEntryDialog(None, _("Enter the IP of the interface to bind"), defaultValue=ip_addr) |
343 if dlg.ShowModal() == wx.ID_OK: |
331 if dlg.ShowModal() == wx.ID_OK: |
344 self.pyroserver.servicename = dlg.GetValue() |
332 self.pyroserver.servicename = dlg.GetValue() |
345 self.pyroserver.Restart() |
333 self.pyroserver.Restart() |
346 |
334 |
347 def _LiveShellLocals(self): |
335 def _LiveShellLocals(self): |
348 if self.pyroserver.plcobj is not None: |
336 return {"locals": runtime.GetPLCObjectSingleton().python_runtime_vars} |
349 return {"locals": self.pyroserver.plcobj.python_runtime_vars} |
|
350 else: |
|
351 return {} |
|
352 |
337 |
353 def OnTaskBarLiveShell(self, evt): |
338 def OnTaskBarLiveShell(self, evt): |
354 from wx import py |
339 from wx import py |
355 frame = py.crust.CrustFrame(**self._LiveShellLocals()) |
340 frame = py.crust.CrustFrame(**self._LiveShellLocals()) |
356 frame.Show() |
341 frame.Show() |
388 try: |
373 try: |
389 res = (tocall(*args, **kwargs), None) |
374 res = (tocall(*args, **kwargs), None) |
390 except Exception: |
375 except Exception: |
391 res = (None, sys.exc_info()) |
376 res = (None, sys.exc_info()) |
392 return res |
377 return res |
393 |
|
394 |
|
395 class Server(object): |
|
396 def __init__(self, servicename, ip_addr, port, |
|
397 workdir, argv, |
|
398 statuschange=None, evaluator=default_evaluator, |
|
399 pyruntimevars=None): |
|
400 self.continueloop = True |
|
401 self.daemon = None |
|
402 self.servicename = servicename |
|
403 self.ip_addr = ip_addr |
|
404 self.port = port |
|
405 self.workdir = workdir |
|
406 self.argv = argv |
|
407 self.servicepublisher = None |
|
408 self.statuschange = statuschange |
|
409 self.evaluator = evaluator |
|
410 self.pyruntimevars = pyruntimevars |
|
411 self.plcobj = PLCObject(self) |
|
412 |
|
413 def _to_be_published(self): |
|
414 return self.servicename is not None and \ |
|
415 self.ip_addr is not None and \ |
|
416 self.ip_addr != "localhost" and \ |
|
417 self.ip_addr != "127.0.0.1" |
|
418 |
|
419 def PrintServerInfo(self): |
|
420 print(_("Pyro port :"), self.port) |
|
421 |
|
422 # Beremiz IDE detects LOCAL:// runtime is ready by looking |
|
423 # for self.workdir in the daemon's stdout. |
|
424 print(_("Current working directory :"), self.workdir) |
|
425 |
|
426 if self._to_be_published(): |
|
427 print(_("Publishing service on local network")) |
|
428 |
|
429 sys.stdout.flush() |
|
430 |
|
431 def PyroLoop(self, when_ready): |
|
432 while self.continueloop: |
|
433 Pyro.config.PYRO_MULTITHREADED = 0 |
|
434 pyro.initServer() |
|
435 self.daemon = pyro.Daemon(host=self.ip_addr, port=self.port) |
|
436 |
|
437 # pyro never frees memory after connection close if no timeout set |
|
438 # taking too small timeout value may cause |
|
439 # unwanted diconnection when IDE is kept busy for long periods |
|
440 self.daemon.setTimeout(60) |
|
441 |
|
442 self.daemon.connect(self.plcobj, "PLCObject") |
|
443 |
|
444 if self._to_be_published(): |
|
445 self.servicepublisher = ServicePublisher.ServicePublisher() |
|
446 self.servicepublisher.RegisterService(self.servicename, self.ip_addr, self.port) |
|
447 |
|
448 when_ready() |
|
449 self.daemon.requestLoop() |
|
450 self.daemon.sock.close() |
|
451 |
|
452 def Restart(self): |
|
453 self._stop() |
|
454 |
|
455 def Quit(self): |
|
456 self.continueloop = False |
|
457 if self.plcobj is not None: |
|
458 self.plcobj.StopPLC() |
|
459 self.plcobj.UnLoadPLC() |
|
460 self._stop() |
|
461 |
|
462 def _stop(self): |
|
463 if self.plcobj is not None: |
|
464 self.plcobj.StopPLC() |
|
465 if self.servicepublisher is not None: |
|
466 self.servicepublisher.UnRegisterService() |
|
467 self.servicepublisher = None |
|
468 self.daemon.shutdown(True) |
|
469 |
|
470 def AutoLoad(self): |
|
471 self.plcobj.AutoLoad() |
|
472 if self.plcobj.GetPLCstatus()[0] == "Stopped": |
|
473 if autostart: |
|
474 self.plcobj.StartPLC() |
|
475 self.plcobj.StatusChange() |
|
476 |
|
477 |
378 |
478 if enabletwisted: |
379 if enabletwisted: |
479 import warnings |
380 import warnings |
480 with warnings.catch_warnings(): |
381 with warnings.catch_warnings(): |
481 warnings.simplefilter("ignore") |
382 warnings.simplefilter("ignore") |
520 # else: |
421 # else: |
521 o = type('', (object,), dict(call=(tocall, args, kwargs), res=None)) |
422 o = type('', (object,), dict(call=(tocall, args, kwargs), res=None)) |
522 wx.CallAfter(wx_evaluator, o) |
423 wx.CallAfter(wx_evaluator, o) |
523 wx_eval_lock.acquire() |
424 wx_eval_lock.acquire() |
524 return o.res |
425 return o.res |
525 |
|
526 pyroserver = Server(servicename, given_ip, port, |
|
527 WorkingDir, argv, |
|
528 statuschange, evaluator, pyruntimevars) |
|
529 |
|
530 taskbar_instance = BeremizTaskBarIcon(pyroserver, enablewx) |
|
531 else: |
426 else: |
532 pyroserver = Server(servicename, given_ip, port, |
427 evaluator = default_evaluator |
533 WorkingDir, argv, |
|
534 statuschange, pyruntimevars=pyruntimevars) |
|
535 |
|
536 |
428 |
537 # Exception hooks |
429 # Exception hooks |
538 |
|
539 |
|
540 def LogMessageAndException(msg, exp=None): |
|
541 if exp is None: |
|
542 exp = sys.exc_info() |
|
543 if pyroserver.plcobj is not None: |
|
544 pyroserver.plcobj.LogMessage(0, msg + '\n'.join(traceback.format_exception(*exp))) |
|
545 else: |
|
546 print(msg) |
|
547 traceback.print_exception(*exp) |
|
548 |
|
549 |
430 |
550 def LogException(*exp): |
431 def LogException(*exp): |
551 LogMessageAndException("", exp) |
432 LogMessageAndException("", exp) |
552 |
433 |
553 |
434 |
594 # Load extensions |
475 # Load extensions |
595 for extention_file, extension_folder in extensions: |
476 for extention_file, extension_folder in extensions: |
596 sys.path.append(extension_folder) |
477 sys.path.append(extension_folder) |
597 execfile(os.path.join(extension_folder, extention_file), locals()) |
478 execfile(os.path.join(extension_folder, extention_file), locals()) |
598 |
479 |
|
480 |
|
481 runtime.CreatePLCObjectSingleton( |
|
482 WorkingDir, argv, statuschange, evaluator, pyruntimevars) |
|
483 |
|
484 pyroserver = Server(servicename, given_ip, port) |
|
485 |
|
486 if havewx: |
|
487 taskbar_instance = BeremizTaskBarIcon(pyroserver) |
|
488 |
599 if havetwisted: |
489 if havetwisted: |
600 if webport is not None: |
490 if webport is not None: |
601 try: |
491 try: |
602 website = NS.RegisterWebsite(webport) |
492 website = NS.RegisterWebsite(webport) |
603 pyruntimevars["website"] = website |
493 pyruntimevars["website"] = website |
622 |
512 |
623 # Wait for pyro thread to be effective |
513 # Wait for pyro thread to be effective |
624 pyro_thread_started.acquire() |
514 pyro_thread_started.acquire() |
625 |
515 |
626 pyroserver.PrintServerInfo() |
516 pyroserver.PrintServerInfo() |
|
517 |
|
518 # Beremiz IDE detects LOCAL:// runtime is ready by looking |
|
519 # for self.workdir in the daemon's stdout. |
|
520 print(_("Current working directory :"), WorkingDir) |
|
521 |
627 |
522 |
628 if havetwisted or havewx: |
523 if havetwisted or havewx: |
629 ui_thread_started = Lock() |
524 ui_thread_started = Lock() |
630 ui_thread_started.acquire() |
525 ui_thread_started.acquire() |
631 if havetwisted: |
526 if havetwisted: |