Modifying LPCBeremiz to launch silently a frame and show or hide it on demand.
authorlaurent
Wed, 02 Jun 2010 16:35:00 +0200
changeset 539 6ff2c1d34640
parent 538 ad05f27222cd
child 540 bacc1314fee6
child 541 4d9ca788205e
Modifying LPCBeremiz to launch silently a frame and show or hide it on demand.
Adding support for transferring LPC programs.
Beremiz.py
LPCBeremiz.py
--- a/Beremiz.py	Wed Jun 02 10:08:58 2010 +0200
+++ b/Beremiz.py	Wed Jun 02 16:35:00 2010 +0200
@@ -468,6 +468,8 @@
             self.local_runtime.kill(gently=False)
             # clear temp dir
             shutil.rmtree(self.local_runtime_tmpdir)
+            
+            self.local_runtime = None
 
     def OnOpenWidgetInspector(self, evt):
         # Activate the widget inspection tool
--- a/LPCBeremiz.py	Wed Jun 02 10:08:58 2010 +0200
+++ b/LPCBeremiz.py	Wed Jun 02 16:35:00 2010 +0200
@@ -41,7 +41,7 @@
     else:
         projectOpen = None
         buildpath = None
-
+    
 class PseudoLocale:
     LocaleDirs = []
     Domains = []
@@ -367,6 +367,8 @@
             elif os.path.isfile(srcpath):
                 shutil.copy2(srcpath, dstpath)
 
+[SIMULATION_MODE, TRANSFER_MODE] = range(2)
+
 class LPCPluginsRoot(PluginsRoot):
 
     PluginMethods = [
@@ -384,10 +386,6 @@
          "shown" : False,
          "tooltip" : _("Stop Running PLC"),
          "method" : "_Stop"},
-        {"bitmap" : opjimg("Build"),
-         "name" : _("Build"),
-         "tooltip" : _("Build project into build folder"),
-         "method" : "_build"},
         {"bitmap" : opjimg("Transfer"),
          "name" : _("Transfer"),
          "shown" : False,
@@ -400,31 +398,33 @@
         
         self.PlugChildsTypes += [("LPCBus", LPCBus, "LPC bus")]
 
-        self.OnlineMode = 0
-        self.OnlinePath = None
-        
-        self.BuildSimulation = False
+        self.OnlineMode = "OFF"
+        self.LPCConnector = False
+        
+        self.CurrentMode = None
+        self.previous_mode = None
+        
         self.SimulationBuildPath = None
-
-        self.previous_simulating = False
-
+        
+        self.AbortTransferTimer = None
+        
     def GetProjectName(self):
         return self.Project.getname()
 
     def GetDefaultTargetName(self):
-        if self.BuildSimulation:
+        if self.CurrentMode == SIMULATION_MODE:
             return PluginsRoot.GetDefaultTargetName(self)
         else:
             return "LPC"
 
     def GetTarget(self):
         target = PluginsRoot.GetTarget(self)
-        if not self.BuildSimulation:
+        if self.CurrentMode != SIMULATION_MODE:
             target.getcontent()["value"].setBuildPath(self.BuildPath)
         return target
     
     def _getBuildPath(self):
-        if self.BuildSimulation:
+        if self.CurrentMode == SIMULATION_MODE:
             if self.SimulationBuildPath is None:
                 self.SimulationBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
             return self.SimulationBuildPath
@@ -440,54 +440,72 @@
         return self.Project.setname(name)
 
     def SetOnlineMode(self, mode, path=None):
-        if self.OnlineMode != mode:
-            self.OnlineMode = mode
-            self.KillDebugThread()
-            
-            if self.OnlineMode != 0:
-                if self._connector is None:
-                    uri = "LPC://%s" % path
-                    try:
-                        self._connector = connectors.ConnectorFactory(uri, self)
-                    except Exception, msg:
-                        self.logger.write_error(_("Exception while connecting %s!\n")%uri)
-                        self.logger.write_error(traceback.format_exc())
-
-                    # Did connection success ?
-                    if self._connector is None:
-                        # Oups.
-                        self.logger.write_error(_("Connection failed to %s!\n")%uri)
-                
-                if self._connector is not None:
-                
-                    if self.OnlineMode == 1:
-                        self.CompareLocalAndRemotePLC()
-                    
-                        # Init with actual PLC status and print it
-                        self.UpdateMethodsFromPLCStatus()
-                        if self.previous_plcstate is not None:
-                            status = _(self.previous_plcstate)
-                        else:
-                            status = ""
-                        self.logger.write(_("PLC is %s\n")%status)
-                        
-                        # Start the status Timer
-                        self.StatusTimer.Start(milliseconds=500, oneShot=False)
-                        
-                        if self.previous_plcstate=="Started":
-                            if self.DebugAvailable() and self.GetIECProgramsAndVariables():
-                                self.logger.write(_("Debug connect matching running PLC\n"))
-                                self._connect_debug()
-                            else:
-                                self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n"))
+        if self.OnlineMode != mode.upper():
+            self.OnlineMode = mode.upper()
+            
+            if self.OnlineMode != "OFF":
+                uri = "LPC://%s" % path
+                try:
+                    self.LPCConnector = connectors.ConnectorFactory(uri, self)
+                except Exception, msg:
+                    self.logger.write_error(_("Exception while connecting %s!\n")%uri)
+                    self.logger.write_error(traceback.format_exc())
+
+                # Did connection success ?
+                if self.LPCConnector is None:
+                    # Oups.
+                    self.logger.write_error(_("Connection failed to %s!\n")%uri)
                 
             else:
-                self._connector = None
+                self.LPCConnector = None
+            
+            self.ApplyOnlineMode()
+
+    def ApplyOnlineMode(self):
+        if self.CurrentMode != SIMULATION_MODE:
+            self.KillDebugThread()
+            
+            self._connector = self.LPCConnector
+            
+            # Init with actual PLC status and print it
+            self.UpdateMethodsFromPLCStatus()
+                
+            if self.LPCConnector is not None and self.OnlineMode == "APPLICATION":
+                
+                self.CompareLocalAndRemotePLC()
+                            
+                if self.previous_plcstate is not None:
+                    status = _(self.previous_plcstate)
+                else:
+                    status = ""
+                self.logger.write(_("PLC is %s\n")%status)
+                
+                if not self.StatusTimer.IsRunning():
+                    # Start the status Timer
+                    self.StatusTimer.Start(milliseconds=500, oneShot=False)
+                
+                if self.previous_plcstate=="Started":
+                    if self.DebugAvailable() and self.GetIECProgramsAndVariables():
+                        self.logger.write(_("Debug connect matching running PLC\n"))
+                        self._connect_debug()
+                    else:
+                        self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n"))
+            
+            elif self.StatusTimer.IsRunning():
                 self.StatusTimer.Stop()
+            
+            if self.CurrentMode == TRANSFER_MODE:
                 
-            self.OnlinePath = path
-            self.UpdateMethodsFromPLCStatus()
-
+                if self.OnlineMode == "BOOTLOADER":
+                    self.BeginTransfer()
+                
+                elif self.OnlineMode == "APPLICATION":
+                    self.CurrentMode = None
+                    self.AbortTransferTimer.Stop()
+                    self.AbortTransferTimer = None
+                    
+                    self.logger.write(_("PLC transferred successfully\n"))
+    
     # Update a PLCOpenEditor Pou variable name
     def UpdateProjectVariableName(self, old_name, new_name):
         self.Project.updateElementName(old_name, new_name)
@@ -548,7 +566,10 @@
         if self.PlugTestModified():
             self.SaveProject()
         
-        self.RefreshPluginsBlockLists()
+        if wx.GetApp() is None:
+            self.RefreshPluginsBlockLists()
+        else:
+            wx.CallAfter(self.RefreshPluginsBlockLists)
 
         return None
 
@@ -556,46 +577,38 @@
     def UpdateMethodsFromPLCStatus(self):
         # Get PLC state : Running or Stopped
         # TODO : use explicit status instead of boolean
-        simulating = False
-        if self.OnlineMode == 0:
-            if self._connector is not None:
-                simulating = self._connector.GetPLCstatus() == "Started"
+        if self.OnlineMode == "OFF":
             status = "Disconnected"
-        elif self.OnlineMode == 2:
-            if self._connector is not None:
-                simulating = self._connector.GetPLCstatus() == "Started"
+        elif self.OnlineMode == "BOOTLOADER":
             status = "Connected"
         else:
             if self._connector is not None:
                 status = self._connector.GetPLCstatus()
             else:
                 status = "Disconnected"
-        if self.previous_plcstate != status or self.previous_simulating != simulating:
+        if self.previous_plcstate != status or self.previous_mode != self.CurrentMode:
+            simulating = self.CurrentMode == SIMULATION_MODE
             for args in {
                      "Started" :     [("_Simulate", False),
                                       ("_Run", False),
                                       ("_Stop", True),
-                                      ("_build", False),
                                       ("_Transfer", False)],
-                     "Stopped" :     [("_Simulate", False),
+                     "Stopped" :     [("_Simulate", True),
                                       ("_Run", True),
                                       ("_Stop", False),
-                                      ("_build", False),
                                       ("_Transfer", False)],
                      "Connected" :   [("_Simulate", not simulating),
                                       ("_Run", False),
                                       ("_Stop", simulating),
-                                      ("_build", False),
                                       ("_Transfer", True)],
                      "Disconnected" :[("_Simulate", not simulating),
                                       ("_Run", False),
                                       ("_Stop", simulating),
-                                      ("_build", True),
                                       ("_Transfer", False)],
                    }.get(status,[]):
                 self.ShowMethod(*args)
             self.previous_plcstate = status
-            self.previous_simulating = simulating
+            self.previous_mode = self.CurrentMode
             return True
         return False
 
@@ -619,6 +632,8 @@
         """
         Method called by user to Simulate PLC
         """
+        self.CurrentMode = SIMULATION_MODE
+        
         uri = "LOCAL://"
         try:
             self._connector = connectors.ConnectorFactory(uri, self)
@@ -630,11 +645,9 @@
         if self._connector is None:
             # Oups.
             self.logger.write_error(_("Connection failed to %s!\n")%uri)
+            self.StopSimulation()
             return False
         
-        self.BuildSimulation = True
-
-
         buildpath = self._getBuildPath()
         
         # Eventually create build dir
@@ -647,7 +660,7 @@
          # If IEC code gen fail, bail out.
         if not IECGenRes:
             self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
-            self.BuildSimulation = False
+            self.StopSimulation()
             return False
 
         # Reset variable and program list that are parsed from
@@ -694,26 +707,26 @@
             except Exception, exc:
                 self.logger.write_error(name+_(" generation failed !\n"))
                 self.logger.write_error(traceback.format_exc())
-                self.BuildSimulation = False
+                self.StopSimulation()
                 return False
         
         # Get simulation builder
         builder = self.GetBuilder()
         if builder is None:
             self.logger.write_error(_("Fatal : cannot get builder.\n"))
-            self.BuildSimulation = False
+            self.StopSimulation()
             return False
 
         # Build
         try:
             if not builder.build() :
                 self.logger.write_error(_("C Build failed.\n"))
-                self.BuildSimulation = False
+                self.StopSimulation()
                 return False
         except Exception, exc:
             self.logger.write_error(_("C Build crashed !\n"))
             self.logger.write_error(traceback.format_exc())
-            self.BuildSimulation = False
+            self.StopSimulation()
             return False
 
         data = builder.GetBinaryCode()
@@ -727,16 +740,59 @@
                 self.logger.write(_("Transfer completed successfully.\n"))
             else:
                 self.logger.write_error(_("Transfer failed\n"))
-                self.BuildSimulation = False
+                self.StopSimulation()
                 return False
         
         self._Run()
                 
-        self.BuildSimulation = False
-
-        # Start the status Timer
-        self.StatusTimer.Start(milliseconds=500, oneShot=False)
-        
+        if not self.StatusTimer.IsRunning():
+            # Start the status Timer
+            self.StatusTimer.Start(milliseconds=500, oneShot=False)
+    
+    def StopSimulation(self):
+        self.CurrentMode = None
+        self.ApplyOnlineMode()
+    
+    def _Stop(self):
+        PluginsRoot._Stop(self)
+        
+        if self.CurrentMode == SIMULATION_MODE:
+            self.StopSimulation()
+
+    def _Transfer(self):
+        if self.CurrentMode is None and self.OnlineMode != "OFF":
+            self.CurrentMode = TRANSFER_MODE
+            
+            PluginsRoot._build(self)
+            
+            ID_ABORTTRANSFERTIMER = wx.NewId()
+            self.AbortTransferTimer = wx.Timer(self.AppFrame, ID_ABORTTRANSFERTIMER)
+            self.AppFrame.Bind(wx.EVT_TIMER, self.AbortTransfer, self.AbortTransferTimer)  
+            
+            if self.OnlineMode == "BOOTLOADER":
+                self.BeginTransfer()
+            
+            else:
+                self.logger.write(_("Resetting PLC\n"))
+                
+                self.LPCConnector.ResetPLC()
+                self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
+    
+    def BeginTransfer(self):
+        self.logger.write(_("Start PLC transfer\n"))
+        
+        self.AbortTransferTimer.Stop()
+        PluginsRoot._Transfer(self)
+        self.AbortTransferTimer.Start(milliseconds=5000, oneShot=True)
+    
+    def AbortTransfer(self, event):
+        self.logger.write(_("Transfer failed\n"))
+        
+        self.CurrentMode = None
+        self.AbortTransferTimer.Stop()
+        self.AbortTransferTimer = None
+        event.Skip()
+
 #-------------------------------------------------------------------------------
 #                              LPCBeremiz Class
 #-------------------------------------------------------------------------------
@@ -795,7 +851,9 @@
 
     def OnCloseFrame(self, event):
         global frame
-        frame = None
+        
+        frame.Hide()
+        
         self.PluginRoot.ResetAppFrame(lpcberemiz_cmd.Log)
         if self.PluginRoot.OnlineMode == 0:
             self.PluginRoot._connector = None
@@ -806,7 +864,7 @@
         print "Closed"
         sys.stdout.flush()
         
-        event.Skip()
+        event.Veto()
 
     def ShowProperties(self):
         old_values = self.Controler.GetProjectProperties()
@@ -996,14 +1054,9 @@
 frame = None
 app = None
 
-def GetApp():
-    global app
-    return app
-wx.GetApp = GetApp
-
-def BeremizStartProc(plugin_root):
+def MainLoopProc(plugin_root):
     global frame, app
-
+    
     app = wx.PySimpleApp()
     app.SetAppName('beremiz')
     wx.InitAllImageHandlers()
@@ -1025,17 +1078,11 @@
     
     # Install a exception handle for bug reports
     AddExceptHook(os.getcwd(),__version__)
-
+    
     frame = LPCBeremiz(None, plugin_root=plugin_root, debug=True)
-    plugin_root.SetAppFrame(frame, frame.Log)
-    frame.Show()
-    frame.Raise()
     
     app.MainLoop()
-
-    frame = None
-    app = None
-
+    
 class StdoutPseudoFile:
     """ Base class for file like objects to facilitate StdOut for the Shell."""
     def write(self, s, style = None):
@@ -1074,6 +1121,8 @@
                     print "Error: Invalid project directory", result
             else:
                 print "Error: No such file or directory"
+            beremiz_thread=Thread(target=MainLoopProc, args=[self.PluginRoot])
+            beremiz_thread.start()
             
         def RestartTimer(self):
             if self.RefreshTimer is not None:
@@ -1082,7 +1131,9 @@
             self.RefreshTimer.start()
         
         def Exit(self):
+            global frame, app
             self.Close()
+            app.ExitMainLoop()
             return True
         
         def do_EOF(self, line):
@@ -1090,9 +1141,9 @@
         
         def Show(self):
             global frame
-            if frame is None:
-                beremiz_thread=Thread(target=BeremizStartProc, args=[self.PluginRoot])
-                beremiz_thread.start()
+            if frame is not None:
+                self.PluginRoot.SetAppFrame(frame, frame.Log)
+                wx.CallAfter(frame.Show)
         
         def Refresh(self):
             global frame
@@ -1106,13 +1157,10 @@
             
             self.PluginRoot.ResetAppFrame(self.Log)
             if frame is not None:
-                wx.CallAfter(frame.Close)
+                wx.CallAfter(frame.Hide)
         
         def Compile(self):
-            if wx.GetApp() is None:
-                self.PluginRoot._build()
-            else:
-                wx.CallAfter(self.PluginRoot._build)
+            wx.CallAfter(self.PluginRoot._build)
         
         def SetProjectProperties(self, projectname, productname, productversion, companyname):
             properties = self.PluginRoot.GetProjectProperties()
@@ -1124,7 +1172,7 @@
             self.RestartTimer()
         
         def SetOnlineMode(self, mode, path=None):
-            self.PluginRoot.SetOnlineMode(mode, path)
+            wx.CallAfter(self.PluginRoot.SetOnlineMode, mode, path)
             self.RestartTimer()
         
         def AddBus(self, iec_channel, name, icon=None):
@@ -1156,7 +1204,13 @@
             for child in self.PluginRoot.IterChilds():
                 if child != bus and child.BaseParams.getIEC_Channel() == new_iec_channel:
                     return "Error: A bus with IEC_channel %d already exists" % new_iec_channel
-            self.PluginRoot.UpdateProjectVariableLocation(str(old_iec_channel), str(new_iec_channel))
+            if wx.GetApp() is None:
+                self.PluginRoot.UpdateProjectVariableLocation(str(old_iec_channel), 
+                                                              str(new_iec_channel))
+            else:
+                wx.CallAfter(self.PluginRoot.UpdateProjectVariableLocation,
+                             str(old_iec_channel), 
+                             str(new_iec_channel))
             bus.BaseParams.setIEC_Channel(new_iec_channel)
             self.RestartTimer()