Local Runtime (LOCAL://) now launched "on demand"
authoretisserant
Wed, 14 Jan 2009 16:41:14 +0100
changeset 290 3bd617ae7a05
parent 289 d17bd2f00a87
child 291 701c0601db02
Local Runtime (LOCAL://) now launched "on demand"
Added Graphical Python shell in Tray Icon menu
Fixed some missing __DEBUG variable assignement
More generic per target LDFLAGS and CFLAGS
Beremiz.py
Beremiz_service.py
connectors/__init__.py
plugger.py
runtime/PLCObject.py
targets/Linux/__init__.py
targets/Linux/plc_Linux_main.c
targets/Win32/__init__.py
targets/Win32/plc_Win32_main.c
targets/toolchain_gcc.py
--- a/Beremiz.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/Beremiz.py	Wed Jan 14 16:41:14 2009 +0100
@@ -416,18 +416,10 @@
         self._init_ctrls(parent)
         
         self.Log = LogPseudoFile(self.LogConsole)
-        
-        # create temporary directory for runtime working directory
-        self.local_runtime_tmpdir = tempfile.mkdtemp()
-        # choose an arbitrary random port for runtime
-        self.runtime_port = int(random.random() * 1000) + 61131
-        # launch local runtime
-        self.local_runtime = ProcessLogger(self.Log,
-                                           "\"%s\" \"%s\" -p %s -i localhost -x 0 %s"%(sys.executable,
-                                                       Bpath("Beremiz_service.py"),
-                                                       self.runtime_port,
-                                                       self.local_runtime_tmpdir),
-                                                       no_gui=False)
+
+        self.local_runtime = None
+        self.runtime_port = None
+        self.local_runtime_tmpdir = None
         
         # Add beremiz's icon in top left corner of the frame
         self.SetIcon(wx.Icon(Bpath( "images", "brz.ico"), wx.BITMAP_TYPE_ICO))
@@ -437,7 +429,7 @@
         self.PluginInfos = {}
         
         if projectOpen:
-            self.PluginRoot = PluginsRoot(self, self.Log, self.runtime_port)
+            self.PluginRoot = PluginsRoot(self, self.Log)
             self.PluginRoot.LoadProject(projectOpen, buildpath)
             self.RefreshAll()
         else:
@@ -445,6 +437,30 @@
         
         self.RefreshMainMenu()
 
+    def StartLocalRuntime(self, taskbaricon = True):
+        if self.local_runtime is None or self.local_runtime.finished:
+            # create temporary directory for runtime working directory
+            self.local_runtime_tmpdir = tempfile.mkdtemp()
+            # choose an arbitrary random port for runtime
+            self.runtime_port = int(random.random() * 1000) + 61131
+            # launch local runtime
+            self.local_runtime = ProcessLogger(self.Log,
+                                               "\"%s\" \"%s\" -p %s -i localhost %s %s"%(sys.executable,
+                                                           Bpath("Beremiz_service.py"),
+                                                           self.runtime_port,
+                                                           {False : "-x 0", True :"-x 1"}[taskbaricon],
+                                                           self.local_runtime_tmpdir),
+                                                           no_gui=False)
+            self.local_runtime.spin(timeout=500, keyword = "working", kill_it = False)
+        return self.runtime_port
+    
+    def KillLocalRuntime(self):
+        if self.local_runtime is not None:
+            # shutdown local runtime
+            self.local_runtime.kill(gently=False)
+            # clear temp dir
+            shutil.rmtree(self.local_runtime_tmpdir)
+
     def OnOpenWidgetInspector(self, evt):
         # Activate the widget inspection tool
         from wx.lib.inspection import InspectionTool
@@ -492,11 +508,8 @@
                     event.Veto()
                     return
 
-        # shutdown local runtime
-        self.local_runtime.kill(gently=False)
-        # clear temp dir
-        shutil.rmtree(self.local_runtime_tmpdir)
-
+        self.KillLocalRuntime()
+        
         event.Skip()
     
     def OnMoveWindow(self, event):
--- a/Beremiz_service.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/Beremiz_service.py	Wed Jan 14 16:41:14 2009 +0100
@@ -215,6 +215,7 @@
                     message.Destroy()
                     return
             self.EndModal(wx.ID_OK)
+            event.Skip()
         
         def GetValue(self):
             return self.GetSizer().GetItem(1).GetWindow().GetValue()
@@ -222,21 +223,24 @@
         def SetTests(self, tests):
             self.Tests = tests
             
-    class DemoTaskBarIcon(wx.TaskBarIcon):
+    class BeremizTaskBarIcon(wx.TaskBarIcon):
         TBMENU_CHANGE_NAME = wx.NewId()
         TBMENU_CHANGE_PORT = wx.NewId()
         TBMENU_CHANGE_INTERFACE = wx.NewId()
+        TBMENU_LIVE_SHELL = wx.NewId()
         TBMENU_CHANGE_WD = wx.NewId()
         TBMENU_QUIT = wx.NewId()
         
         def __init__(self, pyroserver):
             wx.TaskBarIcon.__init__(self)
+            self.pyroserver = pyroserver
             # Set the image
             self.UpdateIcon(None)
     
             # bind some events
             self.Bind(wx.EVT_MENU, self.OnTaskBarChangeName, id=self.TBMENU_CHANGE_NAME)
             self.Bind(wx.EVT_MENU, self.OnTaskBarChangeInterface, id=self.TBMENU_CHANGE_INTERFACE)
+            self.Bind(wx.EVT_MENU, self.OnTaskBarLiveShell, id=self.TBMENU_LIVE_SHELL)
             self.Bind(wx.EVT_MENU, self.OnTaskBarChangePort, id=self.TBMENU_CHANGE_PORT)
             self.Bind(wx.EVT_MENU, self.OnTaskBarChangeWorkingDir, id=self.TBMENU_CHANGE_WD)
             self.Bind(wx.EVT_MENU, self.OnTaskBarQuit, id=self.TBMENU_QUIT)
@@ -251,6 +255,7 @@
             menu = wx.Menu()
             menu.Append(self.TBMENU_CHANGE_NAME, "Change Name")
             menu.Append(self.TBMENU_CHANGE_INTERFACE, "Change IP of interface to bind")
+            menu.Append(self.TBMENU_LIVE_SHELL, "Launch a live Python shell")
             menu.Append(self.TBMENU_CHANGE_PORT, "Change Port Number")
             menu.AppendSeparator()
             menu.Append(self.TBMENU_CHANGE_WD, "Change working directory")
@@ -276,34 +281,47 @@
                            ( lambda ip :len([x for x in ip.split(".") if 0 <= int(x) <= 255]) == 4, "Ip is not valid!")
                            ])
             if dlg.ShowModal() == wx.ID_OK:
-                pyroserver.ip = dlg.GetValue()
-                pyroserver.Stop()
+                self.pyroserver.ip = dlg.GetValue()
+                self.pyroserver.Stop()
+            evt.Skip()
                 
         def OnTaskBarChangePort(self,evt):
             dlg = ParamsEntryDialog(None, "Enter a port number ", defaultValue=str(pyroserver.port))
             dlg.SetTests([(UnicodeType.isdigit, "Port number must be an integer!"), (lambda port : 0 <= int(port) <= 65535 , "Port number must be 0 <= port <= 65535!")])
             if dlg.ShowModal() == wx.ID_OK:
-                pyroserver.port = int(dlg.GetValue())
-                pyroserver.Stop()
-                
+                self.pyroserver.port = int(dlg.GetValue())
+                self.pyroserver.Stop()
+            evt.Skip()
         
         def OnTaskBarChangeWorkingDir(self,evt):
             dlg = wx.DirDialog(None, "Choose a working directory ", pyroserver.workdir, wx.DD_NEW_DIR_BUTTON)
             if dlg.ShowModal() == wx.ID_OK:
-                pyroserver.workdir = dlg.GetPath()
-                pyroserver.Stop()
+                self.pyroserver.workdir = dlg.GetPath()
+                self.pyroserver.Stop()
+            evt.Skip()
                 
         def OnTaskBarChangeName(self,evt):
             dlg = ParamsEntryDialog(None, "Enter a name ", defaultValue=pyroserver.name)
             dlg.SetTests([(lambda name : len(name) is not 0 , "Name must not be null!")])
             if dlg.ShowModal() == wx.ID_OK:
-                pyroserver.name = dlg.GetValue()
-                pyroserver.Restart()
-    
+                self.pyroserver.name = dlg.GetValue()
+                self.pyroserver.Restart()
+            evt.Skip()
+
+        def OnTaskBarLiveShell(self,evt):
+            if self.pyroserver.plcobj is not None and self.pyroserver.plcobj.python_threads_vars is not None:
+                from wx import py
+                frame = py.shell.ShellFrame(locals=self.pyroserver.plcobj.python_threads_vars)
+                frame.Show()
+            else:
+                wx.MessageBox("No runnning PLC","Error")
+            evt.Skip()
+
         def OnTaskBarQuit(self,evt):
             pyroserver.Quit()
             self.RemoveIcon()
             wx.GetApp().ExitMainLoop()
+            evt.Skip()
             
         def UpdateIcon(self, plcstatus):
             if plcstatus is "Started" :
@@ -376,7 +394,7 @@
 
 if havewx:
     app=wx.App(redirect=False)
-    taskbar_instance = DemoTaskBarIcon(pyroserver)
+    taskbar_instance = BeremizTaskBarIcon(pyroserver)
     def statuschange(status):
         wx.CallAfter(taskbar_instance.UpdateIcon,status)
     pyro_thread=Thread(target=pyroserver.Loop, args=[statuschange])
--- a/connectors/__init__.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/connectors/__init__.py	Wed Jan 14 16:41:14 2009 +0100
@@ -39,9 +39,12 @@
         factoryname = servicetype + "_connector_factory"
         return getattr(connectormodule, factoryname)(uri, pluginsroot)
     elif servicetype == "LOCAL":
+        #handle incompatibility with tray icon and svgui...
+        no_poisoned_plugin = pluginsroot.GetChildByType("svgui") is None
+        runtime_port = pluginsroot.AppFrame.StartLocalRuntime(taskbaricon = no_poisoned_plugin)
         import PYRO
         return PYRO.PYRO_connector_factory(
-                       "PYRO://127.0.0.1:"+str(pluginsroot.runtime_port), 
+                       "PYRO://127.0.0.1:"+str(runtime_port), 
                        pluginsroot)
     else :
         return None    
--- a/plugger.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/plugger.py	Wed Jan 14 16:41:14 2009 +0100
@@ -313,6 +313,12 @@
         else:
             return self
 
+    def GetChildByType(self, TypeName):
+        if TypeName:
+            return self._GetChildBySomething("PlugType", TypeName)
+        else:
+            return self
+
     def GetChildByIECLocation(self, Location):
         if Location:
             return self._GetChildBySomething("IEC_Channel", Location)
@@ -668,10 +674,9 @@
     </xsd:schema>
     """
 
-    def __init__(self, frame, logger, runtime_port):
+    def __init__(self, frame, logger):
         PLCControler.__init__(self)
 
-        self.runtime_port = runtime_port
         self.MandatoryParams = None
         self.AppFrame = frame
         self.logger = logger
--- a/runtime/PLCObject.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/runtime/PLCObject.py	Wed Jan 14 16:41:14 2009 +0100
@@ -51,6 +51,7 @@
         self._FreePLC()
         self.daemon = daemon
         self.statuschange = statuschange
+        self.python_threads_vars = None
         
         # Get the last transfered PLC if connector must be restart
         try:
@@ -174,28 +175,29 @@
 
     def PythonThreadProc(self):
         print "PythonThreadProc started"
-        my_globs = globals().copy()
+        self.python_threads_vars = globals().copy()
         pyfile = os.path.join(self.workingdir, "runtime.py")
         if os.path.exists(pyfile):
             # TODO handle exceptions in runtime.py
             # pyfile may redefine _runtime_cleanup
             # or even call _PythonThreadProc itself.
-            execfile(pyfile, my_globs)
+            execfile(pyfile, self.python_threads_vars)
         res,cmd = "None","None"
         while self.PLCStatus == "Started":
-            print "_PythonIterator(", res, ")",
+            #print "_PythonIterator(", res, ")",
             cmd = self._PythonIterator(res)
-            print " -> ", cmd
+            #print " -> ", cmd
             if cmd is None:
                 break
             try :
-                res = str(eval(cmd,my_globs))
+                res = str(eval(cmd,self.python_threads_vars))
             except Exception,e:
                 res = "#EXCEPTION : "+str(e)
                 print res
         print "PythonThreadProc interrupted"
-        if my_globs.get("_runtime_cleanup",None) is not None:
-            my_globs["_runtime_cleanup"]()
+        if self.python_threads_vars.get("_runtime_cleanup",None) is not None:
+            self.python_threads_vars["_runtime_cleanup"]()
+        self.python_threads_vars = None
         print "PythonThreadProc cleaned up"
     
     def StartPLC(self, debug=False):
--- a/targets/Linux/__init__.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/targets/Linux/__init__.py	Wed Jan 14 16:41:14 2009 +0100
@@ -2,4 +2,5 @@
 
 class Linux_target(toolchain_gcc):
     extension = ".so"
-    CustomLDFLAGS = ["-shared", "-lrt"]
+    def getBuilderLDFLAGS(self):
+        return toolchain_gcc.getBuilderLDFLAGS(self) + ["-shared", "-lrt"]
--- a/targets/Linux/plc_Linux_main.c	Fri Jan 09 17:08:31 2009 +0100
+++ b/targets/Linux/plc_Linux_main.c	Wed Jan 14 16:41:14 2009 +0100
@@ -141,12 +141,14 @@
 
 void suspendDebug(void)
 {
+    __DEBUG = 0;
     /* Prevent PLC to enter debug code */
     pthread_mutex_lock(&debug_mutex);
 }
 
 void resumeDebug(void)
 {
+    __DEBUG = 1;
     /* Let PLC enter debug code */
     pthread_mutex_unlock(&debug_mutex);
 }
--- a/targets/Win32/__init__.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/targets/Win32/__init__.py	Wed Jan 14 16:41:14 2009 +0100
@@ -2,7 +2,8 @@
 
 class Win32_target(toolchain_gcc):
     extension = ".dll"
-    CustomLDFLAGS = ["-shared",
+    def getBuilderLDFLAGS(self):
+        return toolchain_gcc.getBuilderLDFLAGS(self) + ["-shared",
                      "-Wl,--export-all-symbols",
                      "-Wl,--enable-auto-import",
                      "-Wl,--whole-archive",
--- a/targets/Win32/plc_Win32_main.c	Fri Jan 09 17:08:31 2009 +0100
+++ b/targets/Win32/plc_Win32_main.c	Wed Jan 14 16:41:14 2009 +0100
@@ -188,12 +188,14 @@
 
 void suspendDebug()
 {
+	__DEBUG = 0;
     /* Prevent PLC to enter debug code */
 	WaitForSingleObject(debug_sem, INFINITE);  
 }
 
 void resumeDebug()
 {
+	__DEBUG = 1;
     /* Let PLC enter debug code */
 	ReleaseSemaphore(debug_sem, 1, NULL);
 }
--- a/targets/toolchain_gcc.py	Fri Jan 09 17:08:31 2009 +0100
+++ b/targets/toolchain_gcc.py	Wed Jan 14 16:41:14 2009 +0100
@@ -19,6 +19,19 @@
         self.md5key = None
         self.srcmd5 = {}
 
+    def getBuilderLDFLAGS(self):
+        """
+        Returns list of builder specific CFLAGS
+        """
+        return [self.PuginsRootInstance.BeremizRoot.getTargetType().getcontent()["value"].getCFLAGS()]
+
+    def getBuilderCFLAGS(self):
+        """
+        Returns list of builder specific LDFLAGS
+        """
+        return self.PuginsRootInstance.LDFLAGS + \
+               [self.PuginsRootInstance.BeremizRoot.getTargetType().getcontent()["value"].getLDFLAGS()]
+
     def GetBinaryCode(self):
         try:
             return open(self.exe_path, "rb").read()
@@ -67,9 +80,9 @@
         # Retrieve toolchain user parameters
         toolchain_params = self.PuginsRootInstance.BeremizRoot.getTargetType().getcontent()["value"]
         self.compiler = toolchain_params.getCompiler()
-        self._CFLAGS = toolchain_params.getCFLAGS()
         self.linker = toolchain_params.getLinker()
-        self._LDFLAGS = toolchain_params.getLDFLAGS()
+
+        Builder_CFLAGS = ' '.join(self.getBuilderCFLAGS())
 
         ######### GENERATE OBJECT FILES ########################################
         obns = []
@@ -98,7 +111,7 @@
                     status, result, err_result = ProcessLogger(
                            self.logger,
                            "\"%s\" -c \"%s\" -o \"%s\" %s %s"%
-                               (self.compiler, CFile, objectfilename, self._CFLAGS, CFLAGS)
+                               (self.compiler, CFile, objectfilename, Builder_CFLAGS, CFLAGS)
                            ).spin()
 
                     if status :
@@ -117,7 +130,7 @@
             # Generate list .o files
             listobjstring = '"' + '"  "'.join(objs) + '"'
     
-            ALLldflags = ' '.join(self.CustomLDFLAGS+self.PuginsRootInstance.LDFLAGS+[self._LDFLAGS])
+            ALLldflags = ' '.join(self.getBuilderLDFLAGS())
     
             self.logger.write("   [CC]  " + ' '.join(obns)+" -> " + self.exe + "\n")