LPCBeremiz.py
changeset 492 0852c4682179
parent 487 1df4a28d3586
child 494 9e4263099427
equal deleted inserted replaced
491:28afed8b1af5 492:0852c4682179
    60 
    60 
    61 if __name__ == '__main__':
    61 if __name__ == '__main__':
    62     __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
    62     __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
    63 
    63 
    64 from Beremiz import *
    64 from Beremiz import *
    65 from plugger import PluginsRoot, PlugTemplate, opjimg
    65 from plugger import PluginsRoot, PlugTemplate, opjimg, connectors
    66 from plcopen.structures import LOCATIONDATATYPES
    66 from plcopen.structures import LOCATIONDATATYPES
    67 from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP,\
    67 from PLCControler import LOCATION_PLUGIN, LOCATION_MODULE, LOCATION_GROUP,\
    68                          LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    68                          LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    69 from PLCOpenEditor import IDEFrame
    69 from PLCOpenEditor import IDEFrame
    70 
    70 
   353                 shutil.copy2(srcpath, dstpath)
   353                 shutil.copy2(srcpath, dstpath)
   354 
   354 
   355 class LPCPluginsRoot(PluginsRoot):
   355 class LPCPluginsRoot(PluginsRoot):
   356 
   356 
   357     PluginMethods = [
   357     PluginMethods = [
   358         {"bitmap" : opjimg("Build"),
   358         {"bitmap" : opjimg("Debug"),
   359          "name" : _("Build"),
   359          "name" : _("Simulate"),
   360          "tooltip" : _("Build project into build folder"),
   360          "tooltip" : _("Simulate PLC"),
   361          "method" : "_build"},
   361          "method" : "_Simulate"},
   362         {"bitmap" : opjimg("Run"),
   362         {"bitmap" : opjimg("Run"),
   363          "name" : _("Run"),
   363          "name" : _("Run"),
   364          "shown" : False,
   364          "shown" : False,
   365          "tooltip" : _("Start PLC"),
   365          "tooltip" : _("Start PLC"),
   366          "method" : "_Run"},
   366          "method" : "_Run"},
   367         {"bitmap" : opjimg("Stop"),
   367         {"bitmap" : opjimg("Stop"),
   368          "name" : _("Stop"),
   368          "name" : _("Stop"),
   369          "shown" : False,
   369          "shown" : False,
   370          "tooltip" : _("Stop Running PLC"),
   370          "tooltip" : _("Stop Running PLC"),
   371          "method" : "_Stop"},
   371          "method" : "_Stop"},
       
   372         {"bitmap" : opjimg("Build"),
       
   373          "name" : _("Build"),
       
   374          "tooltip" : _("Build project into build folder"),
       
   375          "method" : "_build"},
   372         {"bitmap" : opjimg("Transfer"),
   376         {"bitmap" : opjimg("Transfer"),
   373          "name" : _("Transfer"),
   377          "name" : _("Transfer"),
   374          "shown" : False,
   378          "shown" : False,
   375          "tooltip" : _("Transfer PLC"),
   379          "tooltip" : _("Transfer PLC"),
   376          "method" : "_Transfer"},
   380          "method" : "_Transfer"},
   381         
   385         
   382         self.PlugChildsTypes += [("LPCBus", LPCBus, "LPC bus")]
   386         self.PlugChildsTypes += [("LPCBus", LPCBus, "LPC bus")]
   383 
   387 
   384         self.OnlineMode = 0
   388         self.OnlineMode = 0
   385         self.OnlinePath = None
   389         self.OnlinePath = None
       
   390         
       
   391         self.BuildSimulation = False
       
   392         self.SimulationBuildPath = None
       
   393 
       
   394         self.previous_simulating = False
   386 
   395 
   387     def GetProjectName(self):
   396     def GetProjectName(self):
   388         return self.Project.getname()
   397         return self.Project.getname()
   389 
   398 
   390     def GetDefaultTarget(self):
   399     def GetDefaultTarget(self):
   391         target = self.Classes["BeremizRoot_TargetType"]()
   400         target = self.Classes["BeremizRoot_TargetType"]()
   392         target_value = self.Classes["TargetType_LPC"]()
   401         if self.BuildSimulation:
   393         target_value.setBuildPath(self.BuildPath)
   402             if wx.Platform == '__WXMSW__':
   394         target.setcontent({"name": "Makefile", "value": target_value})
   403                 target_name = "Win32"
       
   404             else:
       
   405                 target_name = "Linux"
       
   406             target_value = self.Classes["TargetType_%s"%target_name]()
       
   407         else:
       
   408             target_name = "LPC"
       
   409             target_value = self.Classes["TargetType_LPC"]()
       
   410             target_value.setBuildPath(self.BuildPath)
       
   411         target.setcontent({"name": target_name, "value": target_value})
   395         return target
   412         return target
   396      
   413     
       
   414     def _getBuildPath(self):
       
   415         if self.BuildSimulation:
       
   416             if self.SimulationBuildPath is None:
       
   417                 self.SimulationBuildPath = os.path.join(tempfile.mkdtemp(), os.path.basename(self.ProjectPath), "build")
       
   418             return self.SimulationBuildPath
       
   419         else:
       
   420             PluginsRoot._getBuildPath(self)
       
   421     
   397     def SetProjectName(self, name):
   422     def SetProjectName(self, name):
   398         return self.Project.setname(name)
   423         return self.Project.setname(name)
   399 
   424 
   400     def SetOnlineMode(self, mode, path=None):
   425     def SetOnlineMode(self, mode, path=None):
   401         self.OnlineMode = mode
   426         if self.OnlineMode != mode:
   402         self.OnlinePath = path
   427             self.OnlineMode = mode
   403         self.UpdateMethodsFromPLCStatus()
   428             if self.OnLineMode != 0:
       
   429                 if self._connector is None:
       
   430                     uri = "LPC://%s" % path
       
   431                     try:
       
   432                         self._connector = connectors.ConnectorFactory(uri, self)
       
   433                     except Exception, msg:
       
   434                         self.logger.write_error(_("Exception while connecting %s!\n")%uri)
       
   435                         self.logger.write_error(traceback.format_exc())
       
   436 
       
   437                     # Did connection success ?
       
   438                     if self._connector is None:
       
   439                         # Oups.
       
   440                         self.logger.write_error(_("Connection failed to %s!\n")%uri)
       
   441                 
       
   442                 if self._connector is not None:
       
   443                 
       
   444                     if self.OnLineMode == 1:
       
   445                         self.CompareLocalAndRemotePLC()
       
   446                     
       
   447                         # Init with actual PLC status and print it
       
   448                         self.UpdateMethodsFromPLCStatus()
       
   449                         if self.previous_plcstate is not None:
       
   450                             status = _(self.previous_plcstate)
       
   451                         else:
       
   452                             status = ""
       
   453                         self.logger.write(_("PLC is %s\n")%status)
       
   454                         
       
   455                         # Start the status Timer
       
   456                         self.StatusTimer.Start(milliseconds=500, oneShot=False)
       
   457                         
       
   458                         if self.previous_plcstate=="Started":
       
   459                             if self.DebugAvailable() and self.GetIECProgramsAndVariables():
       
   460                                 self.logger.write(_("Debug connect matching running PLC\n"))
       
   461                                 self._connect_debug()
       
   462                             else:
       
   463                                 self.logger.write_warning(_("Debug do not match PLC - stop/transfert/start to re-enable\n"))
       
   464                 
       
   465             else:
       
   466                 self._connector = None
       
   467                 self.StatusTimer.Stop()
       
   468                 
       
   469             self.OnlinePath = path
       
   470             self.UpdateMethodsFromPLCStatus()
   404 
   471 
   405     # Update a PLCOpenEditor Pou variable name
   472     # Update a PLCOpenEditor Pou variable name
   406     def UpdateProjectVariableName(self, old_name, new_name):
   473     def UpdateProjectVariableName(self, old_name, new_name):
   407         self.Project.updateElementName(old_name, new_name)
   474         self.Project.updateElementName(old_name, new_name)
   408         self.BufferProject()
   475         self.BufferProject()
   448             #Load and init all the childs
   515             #Load and init all the childs
   449             self.LoadChilds()
   516             self.LoadChilds()
   450         self.RefreshPluginsBlockLists()
   517         self.RefreshPluginsBlockLists()
   451 
   518 
   452         return None
   519         return None
   453         
       
   454     def SaveProject(self):
       
   455         self.SaveXMLFile(self.ProjectPath)
       
   456 
   520 
   457     ############# Real PLC object access #############
   521     ############# Real PLC object access #############
   458     def UpdateMethodsFromPLCStatus(self):
   522     def UpdateMethodsFromPLCStatus(self):
   459         # Get PLC state : Running or Stopped
   523         # Get PLC state : Running or Stopped
   460         # TODO : use explicit status instead of boolean
   524         # TODO : use explicit status instead of boolean
       
   525         simulating = False
   461         if self.OnlineMode == 0:
   526         if self.OnlineMode == 0:
       
   527             if self._connector is not None:
       
   528                 simulating = self._connector.GetPLCstatus() == "Started"
   462             status = "Disconnected"
   529             status = "Disconnected"
   463         elif self.OnlineMode == 1:
   530         elif self.OnlineMode == 1:
       
   531             if self._connector is not None:
       
   532                 simulating = self._connector.GetPLCstatus() == "Started"
   464             status = "Connected"
   533             status = "Connected"
   465         elif self._connector is not None:
       
   466             status = self._connector.GetPLCstatus()
       
   467         else:
   534         else:
   468             status = "Disconnected"
   535             if self._connector is not None:
   469         if(self.previous_plcstate != status):
   536                 status = self._connector.GetPLCstatus()
       
   537             else:
       
   538                 status = "Disconnected"
       
   539         if self.previous_plcstate != status or self.previous_simulating != simulating:
   470             for args in {
   540             for args in {
   471                      "Started" :     [("_build", False),
   541                      "Started" :     [("_Simulate", False),
   472                                       ("_Run", False),
   542                                       ("_Run", False),
   473                                       ("_Stop", True),
   543                                       ("_Stop", True),
       
   544                                       ("_build", False),
   474                                       ("_Transfer", False)],
   545                                       ("_Transfer", False)],
   475                      "Stopped" :     [("_build", False),
   546                      "Stopped" :     [("_Simulate", False),
   476                                       ("_Run", True),
   547                                       ("_Run", True),
   477                                       ("_Stop", False),
   548                                       ("_Stop", False),
       
   549                                       ("_build", False),
   478                                       ("_Transfer", False)],
   550                                       ("_Transfer", False)],
   479                      "Connected" :   [("_build", False),
   551                      "Connected" :   [("_Simulate", not simulating),
   480                                       ("_Run", False),
   552                                       ("_Run", False),
   481                                       ("_Stop", False),
   553                                       ("_Stop", simulating),
       
   554                                       ("_build", False),
   482                                       ("_Transfer", True)],
   555                                       ("_Transfer", True)],
   483                      "Disconnected" :[("_build", True),
   556                      "Disconnected" :[("_Simulate", not simulating),
   484                                       ("_Run", False),
   557                                       ("_Run", False),
   485                                       ("_Stop", False),
   558                                       ("_Stop", simulating),
       
   559                                       ("_build", True),
   486                                       ("_Transfer", False)],
   560                                       ("_Transfer", False)],
   487                    }.get(status,[]):
   561                    }.get(status,[]):
   488                 self.ShowMethod(*args)
   562                 self.ShowMethod(*args)
   489             self.previous_plcstate = status
   563             self.previous_plcstate = status
       
   564             self.previous_simulating = simulating
   490             return True
   565             return True
   491         return False
   566         return False
   492 
   567 
       
   568     def Generate_plc_declare_locations(self):
       
   569         """
       
   570         Declare used locations in order to simulatePLC in a black box
       
   571         """
       
   572         return """#include "iec_types_all.h"
       
   573 
       
   574 #define __LOCATED_VAR(type, name, ...) \
       
   575 type beremiz_##name;\
       
   576 type *name = &beremiz_##name;
       
   577 
       
   578 #include "LOCATED_VARIABLES.h"
       
   579 
       
   580 #undef __LOCATED_VAR
       
   581 
       
   582 """
       
   583 
       
   584     def _Simulate(self):
       
   585         """
       
   586         Method called by user to Simulate PLC
       
   587         """
       
   588         uri = "LOCAL://"
       
   589         try:
       
   590             self._connector = connectors.ConnectorFactory(uri, self)
       
   591         except Exception, msg:
       
   592             self.logger.write_error(_("Exception while connecting %s!\n")%uri)
       
   593             self.logger.write_error(traceback.format_exc())
       
   594 
       
   595         # Did connection success ?
       
   596         if self._connector is None:
       
   597             # Oups.
       
   598             self.logger.write_error(_("Connection failed to %s!\n")%uri)
       
   599             return False
       
   600         
       
   601         self.BuildSimulation = True
       
   602 
       
   603 
       
   604         buildpath = self._getBuildPath()
       
   605         
       
   606         # Eventually create build dir
       
   607         if not os.path.exists(buildpath):
       
   608             os.makedirs(buildpath)
       
   609         
       
   610         # Generate SoftPLC IEC code
       
   611         IECGenRes = self._Generate_SoftPLC()
       
   612         
       
   613          # If IEC code gen fail, bail out.
       
   614         if not IECGenRes:
       
   615             self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
       
   616             self.BuildSimulation = False
       
   617             return False
       
   618 
       
   619         # Reset variable and program list that are parsed from
       
   620         # CSV file generated by IEC2C compiler.
       
   621         self.ResetIECProgramsAndVariables()
       
   622         
       
   623         gen_result = self.PlugGenerate_C(buildpath, self.PLCGeneratedLocatedVars)
       
   624         PlugCFilesAndCFLAGS, PlugLDFLAGS, DoCalls = gen_result[:3]
       
   625         # if some files have been generated put them in the list with their location
       
   626         if PlugCFilesAndCFLAGS:
       
   627             self.LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), PlugCFilesAndCFLAGS, DoCalls)]
       
   628         else:
       
   629             self.LocationCFilesAndCFLAGS = []
       
   630 
       
   631         # plugin asks for some LDFLAGS
       
   632         if PlugLDFLAGS:
       
   633             # LDFLAGS can be either string
       
   634             if type(PlugLDFLAGS)==type(str()):
       
   635                 self.LDFLAGS=[PlugLDFLAGS]
       
   636             #or list of strings
       
   637             elif type(PlugLDFLAGS)==type(list()):
       
   638                 self.LDFLAGS=PlugLDFLAGS[:]
       
   639         else:
       
   640             self.LDFLAGS=[]
       
   641         
       
   642         # Template based part of C code generation
       
   643         # files are stacked at the beginning, as files of plugin tree root
       
   644         for generator, filename, name in [
       
   645            # debugger code
       
   646            (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
       
   647            # init/cleanup/retrieve/publish, run and align code
       
   648            (self.Generate_plc_common_main,"plc_common_main.c","Common runtime"),
       
   649            # declare located variables for simulate in a black box
       
   650            (self.Generate_plc_declare_locations,"plc_declare_locations.c","Declare Locations")]:
       
   651             try:
       
   652                 # Do generate
       
   653                 code = generator()
       
   654                 if code is None:
       
   655                      raise
       
   656                 code_path = os.path.join(buildpath,filename)
       
   657                 open(code_path, "w").write(code)
       
   658                 # Insert this file as first file to be compiled at root plugin
       
   659                 self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS))
       
   660             except Exception, exc:
       
   661                 self.logger.write_error(name+_(" generation failed !\n"))
       
   662                 self.logger.write_error(traceback.format_exc())
       
   663                 self.BuildSimulation = False
       
   664                 return False
       
   665         
       
   666         # Get simulation builder
       
   667         builder = self.GetBuilder()
       
   668         if builder is None:
       
   669             self.logger.write_error(_("Fatal : cannot get builder.\n"))
       
   670             self.BuildSimulation = False
       
   671             return False
       
   672 
       
   673         # Build
       
   674         try:
       
   675             if not builder.build() :
       
   676                 self.logger.write_error(_("C Build failed.\n"))
       
   677                 self.BuildSimulation = False
       
   678                 return False
       
   679         except Exception, exc:
       
   680             self.logger.write_error(_("C Build crashed !\n"))
       
   681             self.logger.write_error(traceback.format_exc())
       
   682             self.BuildSimulation = False
       
   683             return False
       
   684 
       
   685         data = builder.GetBinaryCode()
       
   686         if data is not None :
       
   687             if self._connector.NewPLC(builder.GetBinaryCodeMD5(), data, []):
       
   688                 if self.AppFrame is not None:
       
   689                     self.AppFrame.CloseDebugTabs()
       
   690                     self.AppFrame.RefreshInstancesTree()
       
   691                 self.UnsubscribeAllDebugIECVariable()
       
   692                 self.ProgramTransferred()
       
   693                 self.logger.write(_("Transfer completed successfully.\n"))
       
   694             else:
       
   695                 self.logger.write_error(_("Transfer failed\n"))
       
   696                 self.BuildSimulation = False
       
   697                 return False
       
   698         
       
   699         self._Run()
       
   700                 
       
   701         self.BuildSimulation = False
       
   702 
       
   703         # Start the status Timer
       
   704         self.StatusTimer.Start(milliseconds=500, oneShot=False)
       
   705         
   493 #-------------------------------------------------------------------------------
   706 #-------------------------------------------------------------------------------
   494 #                              LPCBeremiz Class
   707 #                              LPCBeremiz Class
   495 #-------------------------------------------------------------------------------
   708 #-------------------------------------------------------------------------------
   496 
   709 
   497 class LPCBeremiz(Beremiz):
   710 class LPCBeremiz(Beremiz):
   548 
   761 
   549     def OnCloseFrame(self, event):
   762     def OnCloseFrame(self, event):
   550         global frame, lpcberemiz_cmd
   763         global frame, lpcberemiz_cmd
   551         frame = None
   764         frame = None
   552         self.PluginRoot.ResetAppFrame(lpcberemiz_cmd.Log)
   765         self.PluginRoot.ResetAppFrame(lpcberemiz_cmd.Log)
   553         
   766         if self.PluginRoot.OnlineMode == 0:
       
   767             self.PluginRoot._connector = None
       
   768         
       
   769         self.PluginRoot.KillDebugThread()
   554         self.KillLocalRuntime()
   770         self.KillLocalRuntime()
   555         
   771         
   556         event.Skip()
   772         event.Skip()
   557 
   773 
   558     def RefreshFileMenu(self):
   774     def RefreshFileMenu(self):
   752     __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
   968     __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
   753     
   969     
   754     # Install a exception handle for bug reports
   970     # Install a exception handle for bug reports
   755     AddExceptHook(os.getcwd(),__version__)
   971     AddExceptHook(os.getcwd(),__version__)
   756 
   972 
   757     frame = LPCBeremiz(None, plugin_root=plugin_root, debug=False)
   973     frame = LPCBeremiz(None, plugin_root=plugin_root, debug=True)
   758     plugin_root.SetAppFrame(frame, frame.Log)
   974     plugin_root.SetAppFrame(frame, frame.Log)
   759     frame.Show()
   975     frame.Show()
   760     frame.Raise()
   976     frame.Raise()
   761     
   977     
   762     app.MainLoop()
   978     app.MainLoop()