plugger.py
changeset 20 d3cb5020997b
parent 19 73257cea38bd
child 22 9a0c535c3272
equal deleted inserted replaced
19:73257cea38bd 20:d3cb5020997b
     1 """
     1 """
     2 Base definitions for beremiz plugins
     2 Base definitions for beremiz plugins
     3 """
     3 """
     4 
     4 
     5 import os
     5 import os,sys
     6 import plugins
     6 import plugins
     7 import types
     7 import types
     8 import shutil
     8 import shutil
     9 from xml.dom import minidom
     9 from xml.dom import minidom
       
    10 
       
    11 #Quick hack to be able to find Beremiz IEC tools. Should be config params.
       
    12 base_folder = os.path.split(sys.path[0])[0]
       
    13 sys.path.append(os.path.join(base_folder, "plcopeneditor"))
       
    14 
    10 from xmlclass import GenerateClassesFromXSDstring
    15 from xmlclass import GenerateClassesFromXSDstring
    11 
       
    12 from PLCControler import PLCControler
       
    13 
    16 
    14 _BaseParamsClass = GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?>
    17 _BaseParamsClass = GenerateClassesFromXSDstring("""<?xml version="1.0" encoding="ISO-8859-1" ?>
    15         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    18         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    16           <xsd:element name="BaseParams">
    19           <xsd:element name="BaseParams">
    17             <xsd:complexType>
    20             <xsd:complexType>
    64     
    67     
    65     def PlugTestModified(self):
    68     def PlugTestModified(self):
    66         return False
    69         return False
    67         
    70         
    68     def OnPlugSave(self):
    71     def OnPlugSave(self):
       
    72         #Default, do nothing and return success
    69         return True
    73         return True
    70 
    74 
    71     def GetParamsAttributes(self, path = None):
    75     def GetParamsAttributes(self, path = None):
    72         if path:
    76         if path:
    73             parts = path.split(".", 1)
    77             parts = path.split(".", 1)
    96         if not os.path.isdir(plugpath):
   100         if not os.path.isdir(plugpath):
    97             # Create it
   101             # Create it
    98             os.mkdir(plugpath)
   102             os.mkdir(plugpath)
    99 
   103 
   100         # generate XML for base XML parameters controller of the plugin
   104         # generate XML for base XML parameters controller of the plugin
   101         basexmlfilepath = self.PluginBaseXmlFilePath()
   105         if self.MandatoryParams:
   102         if basexmlfilepath:
   106             BaseXMLFile = open(self.PluginBaseXmlFilePath(),'w')
   103             BaseXMLFile = open(basexmlfilepath,'w')
       
   104             BaseXMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
   107             BaseXMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
   105             BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0))
   108             BaseXMLFile.write(self.MandatoryParams[1].generateXMLText(self.MandatoryParams[0], 0))
   106             BaseXMLFile.close()
   109             BaseXMLFile.close()
   107         
   110         
   108         # generate XML for XML parameters controller of the plugin
   111         # generate XML for XML parameters controller of the plugin
   109         xmlfilepath = self.PluginXmlFilePath()
   112         if self.PlugParams:
   110         if xmlfilepath:
   113             XMLFile = open(self.PluginXmlFilePath(),'w')
   111             XMLFile = open(xmlfilepath,'w')
       
   112             XMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
   114             XMLFile.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
   113             XMLFile.write(self.PlugParams[1].generateXMLText(self.PlugParams[0], 0))
   115             XMLFile.write(self.PlugParams[1].generateXMLText(self.PlugParams[0], 0))
   114             XMLFile.close()
   116             XMLFile.close()
   115         
   117         
   116         # Call the plugin specific OnPlugSave method
   118         # Call the plugin specific OnPlugSave method
   290                 PlugTemplate.__init__(_self)
   292                 PlugTemplate.__init__(_self)
   291                 # If dir have already be made, and file exist
   293                 # If dir have already be made, and file exist
   292                 if os.path.isdir(_self.PlugPath(PlugName)) and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
   294                 if os.path.isdir(_self.PlugPath(PlugName)) and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
   293                     #Load the plugin.xml file into parameters members
   295                     #Load the plugin.xml file into parameters members
   294                     _self.LoadXMLParams(PlugName)
   296                     _self.LoadXMLParams(PlugName)
       
   297                     # Basic check. Better to fail immediately.
       
   298                     if (_self.BaseParams.getName() != PlugName):
       
   299                         raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(PlugName, _self.BaseParams.getName())
       
   300 
       
   301                     # Now, self.PlugPath() should be OK
       
   302                     
   295                     # Check that IEC_Channel is not already in use.
   303                     # Check that IEC_Channel is not already in use.
   296                     self.FindNewIEC_Channel(self.BaseParams.getIEC_Channel())
   304                     _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel())
   297                     # Call the plugin real __init__
   305                     # Call the plugin real __init__
   298                     if getattr(PlugClass, "__init__", None):
   306                     if getattr(PlugClass, "__init__", None):
   299                         PlugClass.__init__(_self)
   307                         PlugClass.__init__(_self)
   300                     #Load and init all the childs
   308                     #Load and init all the childs
   301                     _self.LoadChilds()
   309                     _self.LoadChilds()
   317         PluggedChildsWithSameClass.append(newPluginOpj)
   325         PluggedChildsWithSameClass.append(newPluginOpj)
   318         
   326         
   319         return newPluginOpj
   327         return newPluginOpj
   320             
   328             
   321 
   329 
   322     def LoadXMLParams(self, PlugName = None, test = True):
   330     def LoadXMLParams(self, PlugName = None):
   323         # Get the base xml tree
   331         # Get the base xml tree
   324         basexmlfilepath = self.PluginBaseXmlFilePath(PlugName)
   332         if self.MandatoryParams:
   325         if basexmlfilepath:
   333             basexmlfile = open(self.PluginBaseXmlFilePath(PlugName), 'r')
   326             basexmlfile = open(basexmlfilepath, 'r')
       
   327             basetree = minidom.parse(basexmlfile)
   334             basetree = minidom.parse(basexmlfile)
   328             self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0])
   335             self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0])
   329             basexmlfile.close()
   336             basexmlfile.close()
   330         
   337         
   331         # Get the xml tree
   338         # Get the xml tree
   332         xmlfilepath = self.PluginXmlFilePath(PlugName)
   339         if self.PlugParams:
   333         if xmlfilepath:
   340             xmlfile = open(self.PluginXmlFilePath(PlugName), 'r')
   334             xmlfile = open(xmlfilepath, 'r')
       
   335             tree = minidom.parse(xmlfile)
   341             tree = minidom.parse(xmlfile)
   336             self.PlugParams[1].loadXMLTree(tree.childNodes[0])
   342             self.PlugParams[1].loadXMLTree(tree.childNodes[0])
   337             xmlfile.close()
   343             xmlfile.close()
   338         
   344         
   339         if test:
       
   340             # Basic check. Better to fail immediately.
       
   341             if not PlugName:
       
   342                 PlugName = os.path.split(self.PlugPath())[1].split(NameTypeSeparator)[0]
       
   343             if (self.BaseParams.getName() != PlugName):
       
   344                 raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(PlugName, self.BaseParams.getName())
       
   345             # Now, self.PlugPath() should be OK
       
   346 
       
   347     def LoadChilds(self):
   345     def LoadChilds(self):
   348         # Iterate over all PlugName@PlugType in plugin directory, and try to open them
   346         # Iterate over all PlugName@PlugType in plugin directory, and try to open them
   349         for PlugDir in os.listdir(self.PlugPath()):
   347         for PlugDir in os.listdir(self.PlugPath()):
   350             if os.path.isdir(os.path.join(self.PlugPath(), PlugDir)) and \
   348             if os.path.isdir(os.path.join(self.PlugPath(), PlugDir)) and \
   351                PlugDir.count(NameTypeSeparator) == 1:
   349                PlugDir.count(NameTypeSeparator) == 1:
   357 def _GetClassFunction(name):
   355 def _GetClassFunction(name):
   358     def GetRootClass():
   356     def GetRootClass():
   359         return getattr(__import__("plugins." + name), name).RootClass
   357         return getattr(__import__("plugins." + name), name).RootClass
   360     return GetRootClass
   358     return GetRootClass
   361 
   359 
       
   360 
       
   361 ####################################################################################
       
   362 ####################################################################################
       
   363 ####################################################################################
       
   364 ###################################   ROOT    ######################################
       
   365 ####################################################################################
       
   366 ####################################################################################
       
   367 ####################################################################################
       
   368 
       
   369 iec2cc_path = os.path.join(base_folder, "matiec", "iec2cc")
       
   370 ieclib_path = os.path.join(base_folder, "matiec", "lib")
       
   371 
       
   372 # import for project creation timestamping
       
   373 from time import localtime
       
   374 from datetime import datetime
       
   375 # import necessary stuff from PLCOpenEditor
       
   376 from PLCControler import PLCControler
       
   377 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
       
   378 from TextViewer import TextViewer
       
   379 from plcopen.structures import IEC_KEYWORDS
       
   380 
   362 class PluginsRoot(PlugTemplate):
   381 class PluginsRoot(PlugTemplate):
       
   382     """
       
   383     This class define Root object of the plugin tree. 
       
   384     It is responsible of :
       
   385     - Managing project directory
       
   386     - Building project
       
   387     - Handling PLCOpenEditor controler and view
       
   388     - Loading user plugins and instanciante them as childs
       
   389     - ...
       
   390     
       
   391     """
   363 
   392 
   364     # For root object, available Childs Types are modules of the plugin packages.
   393     # For root object, available Childs Types are modules of the plugin packages.
   365     PlugChildsTypes = [(name, _GetClassFunction(name)) for name in plugins.__all__]
   394     PlugChildsTypes = [(name, _GetClassFunction(name)) for name in plugins.__all__]
   366 
   395 
   367     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   396     XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   416         </xsd:complexType>
   445         </xsd:complexType>
   417       </xsd:element>
   446       </xsd:element>
   418     </xsd:schema>
   447     </xsd:schema>
   419     """
   448     """
   420 
   449 
   421     def __init__(self):
   450     def __init__(self, frame):
   422         PlugTemplate.__init__(self)
   451 
       
   452         self.MandatoryParams = None
       
   453         self.AppFrame = frame
       
   454         
       
   455         """
       
   456         This method are not called here... but in NewProject and OpenProject
       
   457         self._AddParamsMembers()
       
   458         self.PluggedChilds = {}
       
   459         """
       
   460 
   423         # self is the parent
   461         # self is the parent
   424         self.PlugParent = None
   462         self.PlugParent = None
   425         # Keep track of the plugin type name
   463         # Keep track of the plugin type name
   426         self.PlugType = "Beremiz"
   464         self.PlugType = "Beremiz"
   427         
   465         
   428         self.ProjectPath = ""
   466         # After __init__ root plugin is not valid
       
   467         self.ProjectPath = None
   429         self.PLCManager = None
   468         self.PLCManager = None
       
   469         self.PLCEditor = None
   430     
   470     
   431     def HasProjectOpened(self):
   471     def HasProjectOpened(self):
   432         """
   472         """
   433         Return if a project is actually opened
   473         Return if a project is actually opened
   434         """
   474         """
   435         return self.ProjectPath != ""
   475         return self.ProjectPath != None
   436     
   476     
   437     def GetProjectPath(self):
   477     def GetProjectPath(self):
   438         return self.ProjectPath
   478         return self.ProjectPath
   439     
   479     
   440     def NewProject(self, ProjectPath, PLCParams):
   480     def GetPlugInfos(self):
       
   481         childs = []
       
   482         for child in self.IterChilds():
       
   483             childs.append(child.GetPlugInfos())
       
   484         return {"name" : os.path.split(self.ProjectPath)[1], "type" : None, "values" : childs}
       
   485     
       
   486     def NewProject(self, ProjectPath):
   441         """
   487         """
   442         Create a new project in an empty folder
   488         Create a new project in an empty folder
   443         @param ProjectPath: path of the folder where project have to be created
   489         @param ProjectPath: path of the folder where project have to be created
   444         @param PLCParams: properties of the PLCOpen program created
   490         @param PLCParams: properties of the PLCOpen program created
   445         """
   491         """
   446         # Verify that choosen folder is empty
   492         # Verify that choosen folder is empty
   447         if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0:
   493         if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0:
   448             return "Folder choosen isn't empty. You can't use it for a new project!"
   494             return "Folder choosen isn't empty. You can't use it for a new project!"
       
   495         
       
   496         dialog = ProjectDialog(self.AppFrame)
       
   497         if dialog.ShowModal() == wx.ID_OK:
       
   498             values = dialog.GetValues()
       
   499             values["creationDateTime"] = datetime(*localtime()[:6])
       
   500             dialog.Destroy()
       
   501         else:
       
   502             dialog.Destroy()
       
   503             return "Project not created"
       
   504         
   449         # Create Controler for PLCOpen program
   505         # Create Controler for PLCOpen program
   450         self.PLCManager = PLCControler()
   506         self.PLCManager = PLCControler()
   451         self.PLCManager.CreateNewProject(PLCParams.pop("projectName"))
   507         self.PLCManager.CreateNewProject(PLCParams.pop("projectName"))
   452         self.PLCManager.SetProjectProperties(properties = PLCParams)
   508         self.PLCManager.SetProjectProperties(properties = PLCParams)
   453         # Change XSD into class members
   509         # Change XSD into class members
   454         self._AddParamsMembers()
   510         self._AddParamsMembers()
   455         self.PluggedChilds = {}
   511         self.PluggedChilds = {}
   456         # No IEC channel, name, etc...
       
   457         self.MandatoryParams = []
       
   458         # Keep track of the root plugin (i.e. project path)
   512         # Keep track of the root plugin (i.e. project path)
   459         self.ProjectPath = ProjectPath
   513         self.ProjectPath = ProjectPath
   460         self.BaseParams.setName(os.path.split(ProjectPath)[1])
       
   461         return None
   514         return None
   462         
   515         
   463     def LoadProject(self, ProjectPath):
   516     def LoadProject(self, ProjectPath):
   464         """
   517         """
   465         Load a project contained in a folder
   518         Load a project contained in a folder
   476         if result:
   529         if result:
   477             return result
   530             return result
   478         # Change XSD into class members
   531         # Change XSD into class members
   479         self._AddParamsMembers()
   532         self._AddParamsMembers()
   480         self.PluggedChilds = {}
   533         self.PluggedChilds = {}
   481         # No IEC channel, name, etc...
       
   482         self.MandatoryParams = None
       
   483         # Keep track of the root plugin (i.e. project path)
   534         # Keep track of the root plugin (i.e. project path)
   484         self.ProjectPath = ProjectPath
   535         self.ProjectPath = ProjectPath
   485         # If dir have already be made, and file exist
   536         # If dir have already be made, and file exist
   486         if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()):
   537         if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()):
   487             #Load the plugin.xml file into parameters members
   538             #Load the plugin.xml file into parameters members
   488             result = self.LoadXMLParams(test = False)
   539             result = self.LoadXMLParams()
   489             if result:
   540             if result:
   490                 return result
   541                 return result
   491             #Load and init all the childs
   542             #Load and init all the childs
   492             self.LoadChilds()
   543             self.LoadChilds()
   493         self.BaseParams.setName(os.path.split(ProjectPath)[1])
       
   494         return None
   544         return None
   495     
   545     
   496     def SaveProject(self):
   546     def SaveProject(self):
   497         if not self.PLCManager.SaveXMLFile():
   547         if not self.PLCManager.SaveXMLFile():
   498             self.PLCManager.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
   548             self.PLCManager.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
   499         self.PlugRequestSave()
   549         self.PlugRequestSave()
   500     
   550     
   501     def PlugPath(self, PlugName=None):
   551     def PlugPath(self, PlugName=None):
   502         return self.ProjectPath
   552         return self.ProjectPath
   503     
       
   504     def PluginBaseXmlFilePath(self, PlugName=None):
       
   505         return None
       
   506     
   553     
   507     def PluginXmlFilePath(self, PlugName=None):
   554     def PluginXmlFilePath(self, PlugName=None):
   508         return os.path.join(self.PlugPath(PlugName), "beremiz.xml")
   555         return os.path.join(self.PlugPath(PlugName), "beremiz.xml")
   509 
   556 
   510     def PlugGenerate_C(self, buildpath, current_location, locations, logger):
   557     def PlugGenerate_C(self, buildpath, current_location, locations, logger):
   515             [(IEC_loc, IEC_Direction, IEC_Type, Name)]\
   562             [(IEC_loc, IEC_Direction, IEC_Type, Name)]\
   516             ex: [((0,0,4,5),'I','STRING','__IX_0_0_4_5'),...]
   563             ex: [((0,0,4,5),'I','STRING','__IX_0_0_4_5'),...]
   517         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   564         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   518         """
   565         """
   519         return [(C_file_name, "") for C_file_name in self.PLCGeneratedCFiles ] , ""
   566         return [(C_file_name, "") for C_file_name in self.PLCGeneratedCFiles ] , ""
   520         
   567     
   521     def _Generate_SoftPLC(self, buildpath, logger):
   568     def _getBuildPath(self):
   522 
   569         return os.path.join(self.ProjectPath, "build")
       
   570     
       
   571     def _getIECcodepath(self):
       
   572         # define name for IEC code file
       
   573         return os.path.join(self._getBuildPath(), "plc.st")
       
   574     
       
   575     def _Generate_SoftPLC(self, logger):
       
   576         """
       
   577         Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2CC
       
   578         @param buildpath: path where files should be created
       
   579         @param logger: the log pseudo file
       
   580         """
       
   581 
       
   582         logger.write("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")
       
   583         buildpath = self._getBuildPath()
       
   584         # define name for IEC code file
       
   585         plc_file = self._getIECcodepath()
       
   586         # ask PLCOpenEditor controller to write ST/IL/SFC code file
       
   587         result = self.PLCManager.GenerateProgram(plc_file)
       
   588         if not result:
       
   589             # Failed !
       
   590             logger.write_error("Error : ST/IL/SFC code generator returned %d"%result)
       
   591             return False
       
   592         logger.write("Compiling ST Program in to C Program...\n")
       
   593         # Now compile IEC code into many C files
       
   594         # files are listed to stdout, and errors to stderr. 
       
   595         status, result, err_result = logger.LogCommand("%s %s -I %s %s"%(iec2cc_path, plc_file, ieclib_path, self.TargetDir))
       
   596         if status:
       
   597             # Failed !
       
   598             logger.write_error("Error : IEC to C compiler returned %d"%status)
       
   599             return False
       
   600         # Now extract C files of stdout
       
   601         C_files = result.splitlines()
       
   602         # remove those that are not to be compiled because included by others
       
   603         C_files.remove("POUS.c")
       
   604         C_files.remove("LOCATED_VARIABLES.h")
       
   605         # transform those base names to full names with path
       
   606         C_files = map(lambda filename:os.path.join(self.TargetDir, filename), C_files)
       
   607         logger.write("Extracting Located Variables...\n")
       
   608         # IEC2CC compiler generate a list of located variables : LOCATED_VARIABLES.h
       
   609         location_file = open(os.path.join(buildpath,"LOCATED_VARIABLES.h"))
       
   610         locations = []
       
   611         # each line of LOCATED_VARIABLES.h declares a located variable
       
   612         lines = [line.strip() for line in location_file.readlines()]
       
   613         # This regular expression parses the lines genereated by IEC2CC
   523         LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWD]))?,(?P<LOC>[,0-9]*)\)")
   614         LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWD]))?,(?P<LOC>[,0-9]*)\)")
   524         
   615         for line in lines:
   525         if self.PLCManager:
   616             # If line match RE, 
   526             logger.write("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")
   617             result = LOCATED_MODEL.match(line)
   527             plc_file = os.path.join(self.TargetDir, "plc.st")
   618             if result:
   528             result = self.PLCManager.GenerateProgram(plc_file)
   619                 # Get the resulting dict
   529             if not result:
   620                 resdict = result.groupdict()
   530                 logger.write_error("Error : ST/IL/SFC code generator returned %d"%result)
   621                 # rewrite string for variadic location as a tuple of integers
   531                 return False
   622                 resdict['LOC'] = tuple(map(int,resdict['LOC'].split(',')))
   532             logger.write("Compiling ST Program in to C Program...\n")
   623                 # set located size to 'X' if not given 
   533             status, result, err_result = self.LogCommand("%s %s -I %s %s"%(iec2cc_path, plc_file, ieclib_path, self.TargetDir))
   624                 if not resdict['SIZE']:
   534             if status:
   625                     resdict['SIZE'] = 'X'
   535                 new_dialog = wx.Frame(None)
   626                 # finally store into located variable list
   536                 ST_viewer = TextViewer(new_dialog, None, None)
   627                 locations.append(resdict)
   537                 #ST_viewer.Enable(False)
   628         # Keep track of generated C files for later use by self.PlugGenerate_C
   538                 ST_viewer.SetKeywords(IEC_KEYWORDS)
       
   539                 ST_viewer.SetText(file(plc_file).read())
       
   540                 new_dialog.Show()
       
   541                 raise Exception, "Error : IEC to C compiler returned %d"%status
       
   542             C_files = result.splitlines()
       
   543             C_files.remove("POUS.c")
       
   544             C_files = map(lambda filename:os.path.join(self.TargetDir, filename), C_files)
       
   545             logger.write("Extracting Located Variables...\n")
       
   546             location_file = open(os.path.join(self.TargetDir,"LOCATED_VARIABLES.h"))
       
   547             locations = []
       
   548             lines = [line.strip() for line in location_file.readlines()]
       
   549             for line in lines:
       
   550                 result = LOCATED_MODEL.match(line)
       
   551                 if result:
       
   552                     resdict = result.groupdict()
       
   553                     # rewrite location as a tuple of integers
       
   554                     resdict['LOC'] = tuple(map(int,resdict['LOC'].split(',')))
       
   555                     if not resdict['SIZE']:
       
   556                         resdict['SIZE'] = 'X'
       
   557                     locations.append(resdict)
       
   558         self.PLCGeneratedCFiles = C_files
   629         self.PLCGeneratedCFiles = C_files
       
   630         # Keep track of generated located variables for later use by self._Generate_C
   559         self.PLCGeneratedLocatedVars = locations
   631         self.PLCGeneratedLocatedVars = locations
   560         return True
   632         return True
   561 
   633 
   562     def _build(self, logger):
   634     def _build(self, logger):
   563         buildpath = os.path.join(self.ProjectPath, "build")
   635         """
       
   636         Method called by user to (re)build SoftPLC and plugin tree
       
   637         """
       
   638         buildpath = self._getBuildPath()
       
   639 
       
   640         # Eventually create build dir
   564         if not os.path.exists(buildpath):
   641         if not os.path.exists(buildpath):
   565             os.mkdir(buildpath)
   642             os.mkdir(buildpath)
   566         
   643         
   567         logger.write("Start build in %s" % buildpath)
   644         logger.write("Start build in %s" % buildpath)
   568         
   645         
   569         if not self._Generate_SoftPLC(buildpath, logger):
   646         # Generate SoftPLC code
   570             logger.write("SoftPLC code generation failed !")
   647         if not self._Generate_SoftPLC(logger):
   571             return
   648             logger.write_error("SoftPLC code generation failed !")
   572     
   649             return False
       
   650 
   573         logger.write("SoftPLC code generation successfull")
   651         logger.write("SoftPLC code generation successfull")
   574         
   652         
       
   653         # Generate C code and compilation params from plugin hierarchy
   575         try:
   654         try:
   576             CFilesAndCFLAGS, LDFLAGS = self._Generate_C(
   655             CFilesAndCFLAGS, LDFLAGS = self._Generate_C(
   577                 buildpath, 
   656                 buildpath, 
   578                 (), 
   657                 (), 
   579                 self.PLCGeneratedLocatedVars,
   658                 self.PLCGeneratedLocatedVars,
   580                 logger)
   659                 logger)
   581         except Exception, msg:
   660         except Exception, msg:
   582             logger.write_error("Plugins code generation Failed !")
   661             logger.write_error("Plugins code generation Failed !")
   583             logger.write_error(str(msg))
   662             logger.write_error(str(msg))
   584             return
   663             return False
   585 
   664 
   586         logger.write_error("Plugins code generation successfull")
   665         logger.write_error("Plugins code generation successfull")
   587         
   666 
       
   667         # Compile the resulting code into object files.
   588         for CFile, CFLAG in CFilesAndCFLAGS:
   668         for CFile, CFLAG in CFilesAndCFLAGS:
   589             print CFile,CFLAG
   669             print CFile,CFLAG
   590         
   670         
   591         LDFLAGS
   671         # Link object files into something that can be executed on target
   592 
   672         print LDFLAGS
   593     PluginMethods = [("Build",_build), ("Clean",None), ("Run",None), ("EditPLC",None), ("Simulate",None)]
   673 
   594     
   674     def _showIECcode(self, logger):
       
   675         plc_file = self._getIECcodepath()
       
   676         new_dialog = wx.Frame(None)
       
   677         ST_viewer = TextViewer(new_dialog, None, None)
       
   678         #ST_viewer.Enable(False)
       
   679         ST_viewer.SetKeywords(IEC_KEYWORDS)
       
   680         try:
       
   681             text = file(plc_file).read()
       
   682         except:
       
   683             text = '(* No IEC code have been generated at that time ! *)'
       
   684         ST_viewer.SetText(text)
       
   685             
       
   686         new_dialog.Show()
       
   687 
       
   688     def _EditPLC(self, logger):
       
   689         if not self.PLCEditor:
       
   690             self.PLCEditor = PLCOpenEditor(self, self.PLCManager)
       
   691             self.PLCEditor.RefreshProjectTree()
       
   692             self.PLCEditor.RefreshFileMenu()
       
   693             self.PLCEditor.RefreshEditMenu()
       
   694             self.PLCEditor.RefreshToolBar()
       
   695             self.PLCEditor.Show()
       
   696 
       
   697     PluginMethods = [("Build",_build), ("Clean",None), ("Run",None), ("EditPLC",None), ("Show IEC code",_showIECcode)]
       
   698