plugger.py
changeset 203 cb9901076a21
parent 202 cd81a7a6e55c
child 204 f572ab819769
equal deleted inserted replaced
202:cd81a7a6e55c 203:cb9901076a21
    68         pass
    68         pass
    69 
    69 
    70     def BufferProject(self):
    70     def BufferProject(self):
    71         pass
    71         pass
    72 
    72 
       
    73 # helper func to get path to images
       
    74 def opjimg(imgname):
       
    75     return os.path.join("images",imgname)
       
    76 
    73 class PlugTemplate:
    77 class PlugTemplate:
    74     """
    78     """
    75     This class is the one that define plugins.
    79     This class is the one that define plugins.
    76     """
    80     """
    77 
    81 
    98         self._AddParamsMembers()
   102         self._AddParamsMembers()
    99         self.PluggedChilds = {}
   103         self.PluggedChilds = {}
   100         # copy PluginMethods so that it can be later customized
   104         # copy PluginMethods so that it can be later customized
   101         self.PluginMethods = [dic.copy() for dic in self.PluginMethods]
   105         self.PluginMethods = [dic.copy() for dic in self.PluginMethods]
   102 
   106 
   103     def IsGUIPlugin(self):
       
   104         return False
       
   105 
       
   106     def PluginBaseXmlFilePath(self, PlugName=None):
   107     def PluginBaseXmlFilePath(self, PlugName=None):
   107         return os.path.join(self.PlugPath(PlugName), "baseplugin.xml")
   108         return os.path.join(self.PlugPath(PlugName), "baseplugin.xml")
   108     
   109     
   109     def PluginXmlFilePath(self, PlugName=None):
   110     def PluginXmlFilePath(self, PlugName=None):
   110         return os.path.join(self.PlugPath(PlugName), "plugin.xml")
   111         return os.path.join(self.PlugPath(PlugName), "plugin.xml")
   111 
   112 
   112     def PlugPath(self,PlugName=None):
   113     def PlugPath(self,PlugName=None):
   113         if not PlugName:
   114         if not PlugName:
   114             PlugName = self.BaseParams.getName()
   115             PlugName = self.BaseParams.getName()
   115         return os.path.join(self.PlugParent.PlugPath(), PlugName + NameTypeSeparator + self.PlugType)
   116         return os.path.join(self.PlugParent.PlugPath(),
       
   117                             PlugName + NameTypeSeparator + self.PlugType)
   116     
   118     
   117     def PlugTestModified(self):
   119     def PlugTestModified(self):
   118         return self.ChangesToSave
   120         return self.ChangesToSave
   119 
   121 
   120     def ProjectTestModified(self):
   122     def ProjectTestModified(self):
   147                 params.append(self.MandatoryParams[1].getElementInfos(self.MandatoryParams[0]))
   149                 params.append(self.MandatoryParams[1].getElementInfos(self.MandatoryParams[0]))
   148             if self.PlugParams:
   150             if self.PlugParams:
   149                 params.append(self.PlugParams[1].getElementInfos(self.PlugParams[0]))
   151                 params.append(self.PlugParams[1].getElementInfos(self.PlugParams[0]))
   150             return params
   152             return params
   151         
   153         
   152     def SetParamsAttribute(self, path, value, logger):
   154     def SetParamsAttribute(self, path, value):
   153         self.ChangesToSave = True
   155         self.ChangesToSave = True
   154         # Filter IEC_Channel and Name, that have specific behavior
   156         # Filter IEC_Channel and Name, that have specific behavior
   155         if path == "BaseParams.IEC_Channel":
   157         if path == "BaseParams.IEC_Channel":
   156             return self.FindNewIEC_Channel(value,logger), True
   158             return self.FindNewIEC_Channel(value), True
   157         elif path == "BaseParams.Name":
   159         elif path == "BaseParams.Name":
   158             res = self.FindNewName(value,logger)
   160             res = self.FindNewName(value)
   159             self.PlugRequestSave()
   161             self.PlugRequestSave()
   160             return res, True
   162             return res, True
   161         
   163         
   162         parts = path.split(".", 1)
   164         parts = path.split(".", 1)
   163         if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
   165         if self.MandatoryParams and parts[0] == self.MandatoryParams[0]:
   203     
   205     
   204     def PlugImport(self, src_PlugPath):
   206     def PlugImport(self, src_PlugPath):
   205         shutil.copytree(src_PlugPath, self.PlugPath)
   207         shutil.copytree(src_PlugPath, self.PlugPath)
   206         return True
   208         return True
   207 
   209 
   208     def PlugGenerate_C(self, buildpath, locations, logger):
   210     def PlugGenerate_C(self, buildpath, locations):
   209         """
   211         """
   210         Generate C code
   212         Generate C code
   211         @param locations: List of complete variables locations \
   213         @param locations: List of complete variables locations \
   212             [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
   214             [{"IEC_TYPE" : the IEC type (i.e. "INT", "STRING", ...)
   213             "NAME" : name of the variable (generally "__IW0_1_2" style)
   215             "NAME" : name of the variable (generally "__IW0_1_2" style)
   215             "SIZE" : size "X", "B", "W", "D", "L"
   217             "SIZE" : size "X", "B", "W", "D", "L"
   216             "LOC" : tuple of interger for IEC location (0,1,2,...)
   218             "LOC" : tuple of interger for IEC location (0,1,2,...)
   217             }, ...]
   219             }, ...]
   218         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   220         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
   219         """
   221         """
   220         logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n")
   222         self.logger.write_warning(".".join(map(lambda x:str(x), self.GetCurrentLocation())) + " -> Nothing to do\n")
   221         return [],"",False
   223         return [],"",False
   222     
   224     
   223     def _Generate_C(self, buildpath, locations, logger):
   225     def _Generate_C(self, buildpath, locations):
   224         # Generate plugins [(Cfiles, CFLAGS)], LDFLAGS
   226         # Generate plugins [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files
   225         PlugCFilesAndCFLAGS, PlugLDFLAGS, DoCalls = self.PlugGenerate_C(buildpath, locations, logger)
   227         # extra_files = [(fname,fobject), ...]
       
   228         gen_result = self.PlugGenerate_C(buildpath, locations)
       
   229         PlugCFilesAndCFLAGS, PlugLDFLAGS, DoCalls = gen_result[:3]
       
   230         extra_files = gen_result[3:]
   226         # if some files heve been generated put them in the list with their location
   231         # if some files heve been generated put them in the list with their location
   227         if PlugCFilesAndCFLAGS:
   232         if PlugCFilesAndCFLAGS:
   228             LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), PlugCFilesAndCFLAGS, DoCalls)]
   233             LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), PlugCFilesAndCFLAGS, DoCalls)]
   229         else:
   234         else:
   230             LocationCFilesAndCFLAGS = []
   235             LocationCFilesAndCFLAGS = []
   243         # recurse through all childs, and stack their results
   248         # recurse through all childs, and stack their results
   244         for PlugChild in self.IECSortedChilds():
   249         for PlugChild in self.IECSortedChilds():
   245             new_location = PlugChild.GetCurrentLocation()
   250             new_location = PlugChild.GetCurrentLocation()
   246             # How deep are we in the tree ?
   251             # How deep are we in the tree ?
   247             depth=len(new_location)
   252             depth=len(new_location)
   248             _LocationCFilesAndCFLAGS, _LDFLAGS = \
   253             _LocationCFilesAndCFLAGS, _LDFLAGS, _extra_files = \
   249                 PlugChild._Generate_C(
   254                 PlugChild._Generate_C(
   250                     #keep the same path
   255                     #keep the same path
   251                     buildpath,
   256                     buildpath,
   252                     # filter locations that start with current IEC location
   257                     # filter locations that start with current IEC location
   253                     [loc for loc in locations if loc["LOC"][0:depth] == new_location ],
   258                     [loc for loc in locations if loc["LOC"][0:depth] == new_location ])
   254                     #propagete logger
       
   255                     logger)
       
   256             # stack the result
   259             # stack the result
   257             LocationCFilesAndCFLAGS += _LocationCFilesAndCFLAGS
   260             LocationCFilesAndCFLAGS += _LocationCFilesAndCFLAGS
   258             LDFLAGS += _LDFLAGS
   261             LDFLAGS += _LDFLAGS
   259         
   262             extra_files += _extra_files
   260         return LocationCFilesAndCFLAGS,LDFLAGS
   263         
       
   264         return LocationCFilesAndCFLAGS, LDFLAGS, extra_files
   261 
   265 
   262     def BlockTypesFactory(self):
   266     def BlockTypesFactory(self):
   263         return []
   267         return []
   264 
   268 
   265     def STLibraryFactory(self):
   269     def STLibraryFactory(self):
   341         if wx.VERSION < (2, 8, 0):
   345         if wx.VERSION < (2, 8, 0):
   342             return {"name" : "%d-%s"%(self.BaseParams.getIEC_Channel(),self.BaseParams.getName()), "type" : self.BaseParams.getName(), "values" : childs}
   346             return {"name" : "%d-%s"%(self.BaseParams.getIEC_Channel(),self.BaseParams.getName()), "type" : self.BaseParams.getName(), "values" : childs}
   343         else:
   347         else:
   344             return {"name" : self.BaseParams.getName(), "channel" : self.BaseParams.getIEC_Channel(), "enabled" : self.BaseParams.getEnabled(), "parent" : len(self.PlugChildsTypes) > 0, "type" : self.BaseParams.getName(), "values" : childs}
   348             return {"name" : self.BaseParams.getName(), "channel" : self.BaseParams.getIEC_Channel(), "enabled" : self.BaseParams.getEnabled(), "parent" : len(self.PlugChildsTypes) > 0, "type" : self.BaseParams.getName(), "values" : childs}
   345     
   349     
   346     def FindNewName(self, DesiredName, logger):
   350     def FindNewName(self, DesiredName):
   347         """
   351         """
   348         Changes Name to DesiredName if available, Name-N if not.
   352         Changes Name to DesiredName if available, Name-N if not.
   349         @param DesiredName: The desired Name (string)
   353         @param DesiredName: The desired Name (string)
   350         """
   354         """
   351         # Get Current Name
   355         # Get Current Name
   374         # Rename plugin dir if exist
   378         # Rename plugin dir if exist
   375         if not dontexist:
   379         if not dontexist:
   376             shutil.move(oldname, self.PlugPath())
   380             shutil.move(oldname, self.PlugPath())
   377         # warn user he has two left hands
   381         # warn user he has two left hands
   378         if DesiredName != res:
   382         if DesiredName != res:
   379             logger.write_warning("A child names \"%s\" already exist -> \"%s\"\n"%(DesiredName,res))
   383             self.logger.write_warning("A child names \"%s\" already exist -> \"%s\"\n"%(DesiredName,res))
   380         return res
   384         return res
   381 
   385 
   382     def FindNewIEC_Channel(self, DesiredChannel, logger):
   386     def FindNewIEC_Channel(self, DesiredChannel):
   383         """
   387         """
   384         Changes IEC Channel number to DesiredChannel if available, nearest available if not.
   388         Changes IEC Channel number to DesiredChannel if available, nearest available if not.
   385         @param DesiredChannel: The desired IEC channel (int)
   389         @param DesiredChannel: The desired IEC channel (int)
   386         """
   390         """
   387         # Get Current IEC channel
   391         # Get Current IEC channel
   399         res = DesiredChannel
   403         res = DesiredChannel
   400         while res in AllChannels: # While channel not free
   404         while res in AllChannels: # While channel not free
   401             if res < CurrentChannel: # Want to go down ?
   405             if res < CurrentChannel: # Want to go down ?
   402                 res -=  1 # Test for n-1
   406                 res -=  1 # Test for n-1
   403                 if res < 0 :
   407                 if res < 0 :
   404                     if logger :
   408                     self.logger.write_warning("Cannot find lower free IEC channel than %d\n"%CurrentChannel)
   405                         logger.write_warning("Cannot find lower free IEC channel than %d\n"%CurrentChannel)
       
   406                     return CurrentChannel # Can't go bellow 0, do nothing
   409                     return CurrentChannel # Can't go bellow 0, do nothing
   407             else : # Want to go up ?
   410             else : # Want to go up ?
   408                 res +=  1 # Test for n-1
   411                 res +=  1 # Test for n-1
   409         # Finally set IEC Channel
   412         # Finally set IEC Channel
   410         self.BaseParams.setIEC_Channel(res)
   413         self.BaseParams.setIEC_Channel(res)
   411         if logger and DesiredChannel != res:
   414         if DesiredChannel != res:
   412             logger.write_warning("A child with IEC channel %d already exist -> %d\n"%(DesiredChannel,res))
   415             self.logger.write_warning("A child with IEC channel %d already exist -> %d\n"%(DesiredChannel,res))
   413         return res
   416         return res
   414 
   417 
   415     def OnPlugClose(self):
   418     def OnPlugClose(self):
   416         return True
   419         return True
   417 
   420 
   431         # Fetch the plugin
   434         # Fetch the plugin
   432         #PlugInstance = self.GetChildByName(PlugName)
   435         #PlugInstance = self.GetChildByName(PlugName)
   433         # Ask to his parent to remove it
   436         # Ask to his parent to remove it
   434         self.PlugParent._doRemoveChild(self)
   437         self.PlugParent._doRemoveChild(self)
   435 
   438 
   436     def PlugAddChild(self, PlugName, PlugType, logger):
   439     def PlugAddChild(self, PlugName, PlugType):
   437         """
   440         """
   438         Create the plugins that may be added as child to this node self
   441         Create the plugins that may be added as child to this node self
   439         @param PlugType: string desining the plugin class name (get name from PlugChildsTypes)
   442         @param PlugType: string desining the plugin class name (get name from PlugChildsTypes)
   440         @param PlugName: string for the name of the plugin instance
   443         @param PlugName: string for the name of the plugin instance
   441         """
   444         """
   467             before PlugClass.__init__, and to do the file related stuff.
   470             before PlugClass.__init__, and to do the file related stuff.
   468             """
   471             """
   469             def __init__(_self):
   472             def __init__(_self):
   470                 # self is the parent
   473                 # self is the parent
   471                 _self.PlugParent = self
   474                 _self.PlugParent = self
       
   475                 # self is the parent
       
   476                 _self.logger = self.logger
   472                 # Keep track of the plugin type name
   477                 # Keep track of the plugin type name
   473                 _self.PlugType = PlugType
   478                 _self.PlugType = PlugType
   474                 # remind the help string, for more fancy display
   479                 # remind the help string, for more fancy display
   475                 _self.PlugHelp = PlugHelp
   480                 _self.PlugHelp = PlugHelp
   476                 # Call the base plugin template init - change XSD into class members
   481                 # Call the base plugin template init - change XSD into class members
   477                 PlugTemplate.__init__(_self)
   482                 PlugTemplate.__init__(_self)
   478                 # check name is unique
   483                 # check name is unique
   479                 NewPlugName = _self.FindNewName(PlugName, logger)
   484                 NewPlugName = _self.FindNewName(PlugName)
   480                 # If dir have already be made, and file exist
   485                 # If dir have already be made, and file exist
   481                 if os.path.isdir(_self.PlugPath(NewPlugName)): #and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
   486                 if os.path.isdir(_self.PlugPath(NewPlugName)): #and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
   482                     #Load the plugin.xml file into parameters members
   487                     #Load the plugin.xml file into parameters members
   483                     _self.LoadXMLParams(logger, NewPlugName)
   488                     _self.LoadXMLParams(NewPlugName)
   484                     # Basic check. Better to fail immediately.
   489                     # Basic check. Better to fail immediately.
   485                     if (_self.BaseParams.getName() != NewPlugName):
   490                     if (_self.BaseParams.getName() != NewPlugName):
   486                         raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(NewPlugName, _self.BaseParams.getName())
   491                         raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(NewPlugName, _self.BaseParams.getName())
   487 
   492 
   488                     # Now, self.PlugPath() should be OK
   493                     # Now, self.PlugPath() should be OK
   489                     
   494                     
   490                     # Check that IEC_Channel is not already in use.
   495                     # Check that IEC_Channel is not already in use.
   491                     _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel(),logger)
   496                     _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel())
   492                     # Call the plugin real __init__
   497                     # Call the plugin real __init__
   493                     if getattr(PlugClass, "__init__", None):
   498                     if getattr(PlugClass, "__init__", None):
   494                         PlugClass.__init__(_self)
   499                         PlugClass.__init__(_self)
   495                     #Load and init all the childs
   500                     #Load and init all the childs
   496                     _self.LoadChilds(logger)
   501                     _self.LoadChilds()
   497                     #just loaded, nothing to saved
   502                     #just loaded, nothing to saved
   498                     _self.ChangesToSave = False
   503                     _self.ChangesToSave = False
   499                 else:
   504                 else:
   500                     # If plugin do not have corresponding file/dirs - they will be created on Save
   505                     # If plugin do not have corresponding file/dirs - they will be created on Save
   501                     os.mkdir(_self.PlugPath())
   506                     os.mkdir(_self.PlugPath())
   517         PluggedChildsWithSameClass.append(newPluginOpj)
   522         PluggedChildsWithSameClass.append(newPluginOpj)
   518         
   523         
   519         return newPluginOpj
   524         return newPluginOpj
   520             
   525             
   521 
   526 
   522     def LoadXMLParams(self, logger, PlugName = None):
   527     def LoadXMLParams(self, PlugName = None):
   523         methode_name = os.path.join(self.PlugPath(PlugName), "methods.py")
   528         methode_name = os.path.join(self.PlugPath(PlugName), "methods.py")
   524         if os.path.isfile(methode_name):
   529         if os.path.isfile(methode_name):
   525             execfile(methode_name)
   530             execfile(methode_name)
   526 
   531 
   527         # Get the base xml tree
   532         # Get the base xml tree
   528         if self.MandatoryParams:
   533         if self.MandatoryParams:
   529             #try:
   534             try:
   530                 basexmlfile = open(self.PluginBaseXmlFilePath(PlugName), 'r')
   535                 basexmlfile = open(self.PluginBaseXmlFilePath(PlugName), 'r')
   531                 basetree = minidom.parse(basexmlfile)
   536                 basetree = minidom.parse(basexmlfile)
   532                 self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0])
   537                 self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0])
   533                 basexmlfile.close()
   538                 basexmlfile.close()
   534             #except Exception, e:
   539             except Exception, exc:
   535             #    logger.write_error("Couldn't load plugin base parameters %s :\n %s" % (PlugName, str(e)))
   540                 self.logger.write_error("Couldn't load plugin base parameters %s :\n %s" % (PlugName, str(exc)))
   536                 
   541                 self.logger.write_error(traceback.format_exc())
   537         
   542         
   538         # Get the xml tree
   543         # Get the xml tree
   539         if self.PlugParams:
   544         if self.PlugParams:
   540             #try:
   545             try:
   541                 xmlfile = open(self.PluginXmlFilePath(PlugName), 'r')
   546                 xmlfile = open(self.PluginXmlFilePath(PlugName), 'r')
   542                 tree = minidom.parse(xmlfile)
   547                 tree = minidom.parse(xmlfile)
   543                 self.PlugParams[1].loadXMLTree(tree.childNodes[0])
   548                 self.PlugParams[1].loadXMLTree(tree.childNodes[0])
   544                 xmlfile.close()
   549                 xmlfile.close()
   545             #except Exception, e:
   550             except Exception, exc:
   546             #    logger.write_error("Couldn't load plugin parameters %s :\n %s" % (PlugName, str(e)))
   551                 self.logger.write_error("Couldn't load plugin parameters %s :\n %s" % (PlugName, str(exc)))
   547         
   552                 self.logger.write_error(traceback.format_exc())
   548     def LoadChilds(self, logger):
   553         
       
   554     def LoadChilds(self):
   549         # Iterate over all PlugName@PlugType in plugin directory, and try to open them
   555         # Iterate over all PlugName@PlugType in plugin directory, and try to open them
   550         for PlugDir in os.listdir(self.PlugPath()):
   556         for PlugDir in os.listdir(self.PlugPath()):
   551             if os.path.isdir(os.path.join(self.PlugPath(), PlugDir)) and \
   557             if os.path.isdir(os.path.join(self.PlugPath(), PlugDir)) and \
   552                PlugDir.count(NameTypeSeparator) == 1:
   558                PlugDir.count(NameTypeSeparator) == 1:
   553                 pname, ptype = PlugDir.split(NameTypeSeparator)
   559                 pname, ptype = PlugDir.split(NameTypeSeparator)
   554                 #try:
   560                 try:
   555                 self.PlugAddChild(pname, ptype, logger)
   561                     self.PlugAddChild(pname, ptype)
   556                 #except Exception, e:
   562                 except Exception, exc:
   557                 #    logger.write_error("Could not add child \"%s\", type %s :\n%s\n"%(pname, ptype, str(e)))
   563                     self.logger.write_error("Could not add child \"%s\", type %s :\n%s\n"%(pname, ptype, str(exc)))
       
   564                     self.logger.write_error(traceback.format_exc())
   558 
   565 
   559     def EnableMethod(self, method, value):
   566     def EnableMethod(self, method, value):
   560         for d in self.PluginMethods:
   567         for d in self.PluginMethods:
   561             if d["method"]==method:
   568             if d["method"]==method:
   562                 d["enabled"]=value
   569                 d["enabled"]=value
       
   570                 return True
       
   571         return False
       
   572 
       
   573     def ShowMethod(self, method, value):
       
   574         for d in self.PluginMethods:
       
   575             if d["method"]==method:
       
   576                 d["shown"]=value
   563                 return True
   577                 return True
   564         return False
   578         return False
   565 
   579 
   566 def _GetClassFunction(name):
   580 def _GetClassFunction(name):
   567     def GetRootClass():
   581     def GetRootClass():
   584 
   598 
   585 iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+exe_ext)
   599 iec2c_path = os.path.join(base_folder, "matiec", "iec2c"+exe_ext)
   586 ieclib_path = os.path.join(base_folder, "matiec", "lib")
   600 ieclib_path = os.path.join(base_folder, "matiec", "lib")
   587 
   601 
   588 # import for project creation timestamping
   602 # import for project creation timestamping
       
   603 from threading import Timer
   589 from time import localtime
   604 from time import localtime
   590 from datetime import datetime
   605 from datetime import datetime
   591 # import necessary stuff from PLCOpenEditor
   606 # import necessary stuff from PLCOpenEditor
   592 from PLCControler import PLCControler
   607 from PLCControler import PLCControler
   593 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
   608 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
   594 from TextViewer import TextViewer
   609 from TextViewer import TextViewer
   595 from plcopen.structures import IEC_KEYWORDS
   610 from plcopen.structures import IEC_KEYWORDS, TypeHierarchy_list
       
   611 
       
   612 # Construct debugger natively supported types
       
   613 DebugTypes = [t for t in zip(*TypeHierarchy_list)[0] if not t.startswith("ANY")] + \
       
   614     ["STEP","TRANSITION","ACTION"]
       
   615 
   596 import runtime
   616 import runtime
   597 import re
   617 import re
       
   618 import targets
       
   619 import connectors
       
   620 from discovery import DiscoveryDialog
   598 
   621 
   599 class PluginsRoot(PlugTemplate, PLCControler):
   622 class PluginsRoot(PlugTemplate, PLCControler):
   600     """
   623     """
   601     This class define Root object of the plugin tree. 
   624     This class define Root object of the plugin tree. 
   602     It is responsible of :
   625     It is responsible of :
   617         <xsd:complexType>
   640         <xsd:complexType>
   618           <xsd:sequence>
   641           <xsd:sequence>
   619             <xsd:element name="TargetType">
   642             <xsd:element name="TargetType">
   620               <xsd:complexType>
   643               <xsd:complexType>
   621                 <xsd:choice>
   644                 <xsd:choice>
   622                   <xsd:element name="Win32">
   645                 """+targets.targetchoices+"""
   623                     <xsd:complexType>
       
   624                       <xsd:attribute name="Priority" type="xsd:integer" use="required"/>
       
   625                     </xsd:complexType>
       
   626                   </xsd:element>
       
   627                   <xsd:element name="Linux">
       
   628                     <xsd:complexType>
       
   629                       <xsd:attribute name="Nice" type="xsd:integer" use="required"/>
       
   630                     </xsd:complexType>
       
   631                   </xsd:element>
       
   632                   <xsd:element name="Xenomai">
       
   633                     <xsd:complexType>
       
   634                       <xsd:attribute name="xeno_config" type="xsd:string" use="optional" default="/usr/xenomai/"/>
       
   635                       <xsd:attribute name="Priority" type="xsd:integer" use="required"/>
       
   636                     </xsd:complexType>
       
   637                   </xsd:element>
       
   638                   <xsd:element name="RTAI">
       
   639                     <xsd:complexType>
       
   640                       <xsd:attribute name="rtai_config" type="xsd:string" use="required"/>
       
   641                       <xsd:attribute name="Priority" type="xsd:integer" use="required"/>
       
   642                     </xsd:complexType>
       
   643                   </xsd:element>
       
   644                   <xsd:element name="Library">
       
   645                     <xsd:complexType>
       
   646                       <xsd:attribute name="Dynamic" type="xsd:boolean" use="optional" default="true"/>
       
   647                     </xsd:complexType>
       
   648                   </xsd:element>
       
   649                 </xsd:choice>
       
   650               </xsd:complexType>
       
   651             </xsd:element>
       
   652             <xsd:element name="Connection">
       
   653               <xsd:complexType>
       
   654                 <xsd:choice>
       
   655                   <xsd:element name="Local"/>
       
   656                   <xsd:element name="TCP_IP">
       
   657                     <xsd:complexType>
       
   658                       <xsd:attribute name="Host" type="xsd:string" use="required"/>
       
   659                     </xsd:complexType>
       
   660                   </xsd:element>
       
   661                 </xsd:choice>
   646                 </xsd:choice>
   662               </xsd:complexType>
   647               </xsd:complexType>
   663             </xsd:element>
   648             </xsd:element>
   664           </xsd:sequence>
   649           </xsd:sequence>
   665           <xsd:attribute name="Compiler" type="xsd:string" use="optional" default="gcc"/>
       
   666           <xsd:attribute name="CFLAGS" type="xsd:string" use="required"/>
       
   667           <xsd:attribute name="Linker" type="xsd:string" use="optional" default="ld"/>
       
   668           <xsd:attribute name="LDFLAGS" type="xsd:string" use="required"/>
       
   669           <xsd:attribute name="Sync_Align_Ratio" use="optional" default="50">
       
   670             <xsd:simpleType>
       
   671                 <xsd:restriction base="xsd:integer">
       
   672                     <xsd:minInclusive value="1"/>
       
   673                     <xsd:maxInclusive value="99"/>
       
   674                 </xsd:restriction>
       
   675             </xsd:simpleType>
       
   676           </xsd:attribute>
       
   677         </xsd:complexType>
   650         </xsd:complexType>
   678       </xsd:element>
   651       </xsd:element>
   679     </xsd:schema>
   652     </xsd:schema>
   680     """
   653     """
   681 
   654 
   682     def __init__(self, frame):
   655     def __init__(self, frame, logger):
   683         PLCControler.__init__(self)
   656         PLCControler.__init__(self)
   684         
   657         
   685         self.MandatoryParams = None
   658         self.MandatoryParams = None
   686         self.AppFrame = frame
   659         self.AppFrame = frame
   687         
   660         self.logger = logger
   688         """
   661         self._builder = None
   689         This method are not called here... but in NewProject and OpenProject
   662         self._connector = None
   690         self._AddParamsMembers()
   663         
   691         self.PluggedChilds = {}
   664         # Setup debug information
   692         """
   665         self.IECdebug_callables = {}
       
   666         # Timer to prevent rapid-fire when registering many variables
       
   667         self.DebugTimer=Timer(0.5,self.RegisterDebugVarToConnector)
       
   668         self.ResetIECProgramsAndVariables()
       
   669 
       
   670         
       
   671         #This method are not called here... but in NewProject and OpenProject
       
   672         #self._AddParamsMembers()
       
   673         #self.PluggedChilds = {}
       
   674 
   693         # In both new or load scenario, no need to save
   675         # In both new or load scenario, no need to save
   694         self.ChangesToSave = False        
   676         self.ChangesToSave = False        
   695         # root have no parent
   677         # root have no parent
   696         self.PlugParent = None
   678         self.PlugParent = None
   697         # Keep track of the plugin type name
   679         # Keep track of the plugin type name
   767         self.RefreshPluginsBlockLists()
   749         self.RefreshPluginsBlockLists()
   768         # this will create files base XML files
   750         # this will create files base XML files
   769         self.SaveProject()
   751         self.SaveProject()
   770         return None
   752         return None
   771         
   753         
   772     def LoadProject(self, ProjectPath, logger):
   754     def LoadProject(self, ProjectPath):
   773         """
   755         """
   774         Load a project contained in a folder
   756         Load a project contained in a folder
   775         @param ProjectPath: path of the project folder
   757         @param ProjectPath: path of the project folder
   776         """
   758         """
   777         if os.path.basename(ProjectPath) == "":
   759         if os.path.basename(ProjectPath) == "":
   778             ProjectPath = os.path.dirname(ProjectPath)
   760             ProjectPath = os.path.dirname(ProjectPath)
   779         # Verify that project contains a PLCOpen program
   761 		# Verify that project contains a PLCOpen program
   780         plc_file = os.path.join(ProjectPath, "plc.xml")
   762         plc_file = os.path.join(ProjectPath, "plc.xml")
   781         if not os.path.isfile(plc_file):
   763         if not os.path.isfile(plc_file):
   782             return "Folder choosen doesn't contain a program. It's not a valid project!"
   764             return "Folder choosen doesn't contain a program. It's not a valid project!"
   783         # Load PLCOpen file
   765         # Load PLCOpen file
   784         result = self.OpenXMLFile(plc_file)
   766         result = self.OpenXMLFile(plc_file)
   790         # Keep track of the root plugin (i.e. project path)
   772         # Keep track of the root plugin (i.e. project path)
   791         self.ProjectPath = ProjectPath
   773         self.ProjectPath = ProjectPath
   792         # If dir have already be made, and file exist
   774         # If dir have already be made, and file exist
   793         if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()):
   775         if os.path.isdir(self.PlugPath()) and os.path.isfile(self.PluginXmlFilePath()):
   794             #Load the plugin.xml file into parameters members
   776             #Load the plugin.xml file into parameters members
   795             result = self.LoadXMLParams(logger)
   777             result = self.LoadXMLParams()
   796             if result:
   778             if result:
   797                 return result
   779                 return result
   798             #Load and init all the childs
   780             #Load and init all the childs
   799             self.LoadChilds(logger)
   781             self.LoadChilds()
   800         self.RefreshPluginsBlockLists()
   782         self.RefreshPluginsBlockLists()
       
   783         
       
   784         if os.path.exists(self._getBuildPath()):
       
   785             self.EnableMethod("_Clean", True)
       
   786 
       
   787         if os.path.isfile(self._getIECrawcodepath()):
       
   788             self.ShowMethod("_showIECcode", True)
       
   789 
   801         return None
   790         return None
   802     
   791     
   803     def SaveProject(self):
   792     def SaveProject(self):
   804         if not self.SaveXMLFile():
   793         if not self.SaveXMLFile():
   805             self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
   794             self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml'))
   825         return self.ProjectPath
   814         return self.ProjectPath
   826     
   815     
   827     def PluginXmlFilePath(self, PlugName=None):
   816     def PluginXmlFilePath(self, PlugName=None):
   828         return os.path.join(self.PlugPath(PlugName), "beremiz.xml")
   817         return os.path.join(self.PlugPath(PlugName), "beremiz.xml")
   829 
   818 
   830     def PlugGenerate_C(self, buildpath, locations, logger):
       
   831         """
       
   832         Generate C code
       
   833         @param locations: List of complete variables locations \
       
   834             [(IEC_loc, IEC_Direction, IEC_Type, Name)]\
       
   835             ex: [((0,0,4,5),'I','STRING','__IX_0_0_4_5'),...]
       
   836         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
       
   837         """
       
   838         return [(C_file_name, self.CFLAGS) for C_file_name in self.PLCGeneratedCFiles ] , "", False
       
   839     
       
   840     def _getBuildPath(self):
   819     def _getBuildPath(self):
   841         return os.path.join(self.ProjectPath, "build")
   820         return os.path.join(self.ProjectPath, "build")
   842     
   821     
       
   822     def _getExtraFilesPath(self):
       
   823         return os.path.join(self._getBuildPath(), "extra_files")
       
   824 
   843     def _getIECcodepath(self):
   825     def _getIECcodepath(self):
   844         # define name for IEC code file
   826         # define name for IEC code file
   845         return os.path.join(self._getBuildPath(), "plc.st")
   827         return os.path.join(self._getBuildPath(), "plc.st")
   846     
   828     
   847     def _getIECgeneratedcodepath(self):
   829     def _getIECgeneratedcodepath(self):
   848         # define name for IEC generated code file
   830         # define name for IEC generated code file
   849         return os.path.join(self._getBuildPath(), "generated_plc.st")
   831         return os.path.join(self._getBuildPath(), "generated_plc.st")
   850     
   832     
   851     def _getIECrawcodepath(self):
   833     def _getIECrawcodepath(self):
   852         # define name for IEC raw code file
   834         # define name for IEC raw code file
   853         return os.path.join(self._getBuildPath(), "raw_plc.st")
   835         return os.path.join(self.PlugPath(), "raw_plc.st")
   854     
   836     
   855     def GetLocations(self):
   837     def GetLocations(self):
   856         locations = []
   838         locations = []
   857         filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")
   839         filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")
   858         if os.path.isfile(filepath):
   840         if os.path.isfile(filepath):
   875                         resdict['SIZE'] = 'X'
   857                         resdict['SIZE'] = 'X'
   876                     # finally store into located variable list
   858                     # finally store into located variable list
   877                     locations.append(resdict)
   859                     locations.append(resdict)
   878         return locations
   860         return locations
   879         
   861         
   880     def _Generate_SoftPLC(self, logger):
   862     def _Generate_SoftPLC(self):
   881         """
   863         """
   882         Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C
   864         Generate SoftPLC ST/IL/SFC code out of PLCOpenEditor controller, and compile it with IEC2C
   883         @param buildpath: path where files should be created
   865         @param buildpath: path where files should be created
   884         @param logger: the log pseudo file
       
   885         """
   866         """
   886 
   867 
   887         # Update PLCOpenEditor Plugin Block types before generate ST code
   868         # Update PLCOpenEditor Plugin Block types before generate ST code
   888         self.RefreshPluginsBlockLists()
   869         self.RefreshPluginsBlockLists()
   889         
   870         
   890         logger.write("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")
   871         self.logger.write("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")
   891         buildpath = self._getBuildPath()
   872         buildpath = self._getBuildPath()
   892         # ask PLCOpenEditor controller to write ST/IL/SFC code file
   873         # ask PLCOpenEditor controller to write ST/IL/SFC code file
   893         result = self.GenerateProgram(self._getIECgeneratedcodepath())
   874         result = self.GenerateProgram(self._getIECgeneratedcodepath())
   894         if result is not None:
   875         if result is not None:
   895             # Failed !
   876             # Failed !
   896             logger.write_error("Error in ST/IL/SFC code generator :\n%s\n"%result)
   877             self.logger.write_error("Error in ST/IL/SFC code generator :\n%s\n"%result)
   897             return False
   878             return False
   898         plc_file = open(self._getIECcodepath(), "w")
   879         plc_file = open(self._getIECcodepath(), "w")
   899         if os.path.isfile(self._getIECrawcodepath()):
   880         if os.path.isfile(self._getIECrawcodepath()):
   900             plc_file.write(open(self._getIECrawcodepath(), "r").read())
   881             plc_file.write(open(self._getIECrawcodepath(), "r").read())
   901             plc_file.write("\n")
   882             plc_file.write("\n")
   902         plc_file.write(open(self._getIECgeneratedcodepath(), "r").read())
   883         plc_file.write(open(self._getIECgeneratedcodepath(), "r").read())
   903         plc_file.close()
   884         plc_file.close()
   904         logger.write("Compiling IEC Program in to C code...\n")
   885         self.logger.write("Compiling IEC Program in to C code...\n")
   905         # Now compile IEC code into many C files
   886         # Now compile IEC code into many C files
   906         # files are listed to stdout, and errors to stderr. 
   887         # files are listed to stdout, and errors to stderr. 
   907         status, result, err_result = ProcessLogger(
   888         status, result, err_result = ProcessLogger(
   908                logger,
   889                self.logger,
   909                "\"%s\" -f \"%s\" -I \"%s\" \"%s\""%(
   890                "\"%s\" -f \"%s\" -I \"%s\" \"%s\""%(
   910                          iec2c_path,
   891                          iec2c_path,
   911                          self._getIECcodepath(),
   892                          self._getIECcodepath(),
   912                          ieclib_path, buildpath),
   893                          ieclib_path, buildpath),
   913                no_stdout=True).spin()
   894                no_stdout=True).spin()
   914         if status:
   895         if status:
   915             # Failed !
   896             # Failed !
   916             logger.write_error("Error : IEC to C compiler returned %d\n"%status)
   897             self.logger.write_error("Error : IEC to C compiler returned %d\n"%status)
   917             return False
   898             return False
   918         # Now extract C files of stdout
   899         # Now extract C files of stdout
   919         C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ]
   900         C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ]
   920         # remove those that are not to be compiled because included by others
   901         # remove those that are not to be compiled because included by others
   921         C_files.remove("POUS.c")
   902         C_files.remove("POUS.c")
   922         if not C_files:
   903         if not C_files:
   923             logger.write_error("Error : At least one configuration and one ressource must be declared in PLC !\n")
   904             self.logger.write_error("Error : At least one configuration and one ressource must be declared in PLC !\n")
   924             return False
   905             return False
   925         # transform those base names to full names with path
   906         # transform those base names to full names with path
   926         C_files = map(lambda filename:os.path.join(buildpath, filename), C_files)
   907         C_files = map(lambda filename:os.path.join(buildpath, filename), C_files)
   927         logger.write("Extracting Located Variables...\n")
   908         self.logger.write("Extracting Located Variables...\n")
   928         # Keep track of generated located variables for later use by self._Generate_C
   909         # Keep track of generated located variables for later use by self._Generate_C
   929         self.PLCGeneratedLocatedVars = self.GetLocations()
   910         self.PLCGeneratedLocatedVars = self.GetLocations()
   930         # Keep track of generated C files for later use by self.PlugGenerate_C
   911         # Keep track of generated C files for later use by self.PlugGenerate_C
   931         self.PLCGeneratedCFiles = C_files
   912         self.PLCGeneratedCFiles = C_files
   932         # compute CFLAGS for plc
   913         # compute CFLAGS for plc
   933         self.CFLAGS = "\"-I"+ieclib_path+"\""
   914         self.plcCFLAGS = "\"-I"+ieclib_path+"\""
   934         return True
   915         return True
   935 
   916 
   936     def _build(self, logger):
   917     def GetBuilder(self):
       
   918         """
       
   919         Return a Builder (compile C code into machine code)
       
   920         """
       
   921         # Get target, module and class name
       
   922         targetname = self.BeremizRoot.getTargetType().getcontent()["name"]
       
   923         modulename = "targets." + targetname
       
   924         classname = targetname + "_target"
       
   925 
       
   926         # Get module reference
       
   927         try :
       
   928             targetmodule = getattr(__import__(modulename), targetname)
       
   929 
       
   930         except Exception, msg:
       
   931             self.logger.write_error("Can't find module for target %s!\n"%targetname)
       
   932             self.logger.write_error(str(msg))
       
   933             return None
       
   934         
       
   935         # Get target class
       
   936         targetclass = getattr(targetmodule, classname)
       
   937 
       
   938         # if target already 
       
   939         if self._builder is None or not isinstance(self._builder,targetclass):
       
   940             # Get classname instance
       
   941             self._builder = targetclass(self)
       
   942         return self._builder
       
   943 
       
   944     def GetLastBuildMD5(self):
       
   945         builder=self.GetBuilder()
       
   946         if builder is not None:
       
   947             return builder.GetBinaryCodeMD5()
       
   948         else:
       
   949             return None
       
   950 
       
   951     #######################################################################
       
   952     #
       
   953     #                C CODE GENERATION METHODS
       
   954     #
       
   955     #######################################################################
       
   956     
       
   957     def PlugGenerate_C(self, buildpath, locations):
       
   958         """
       
   959         Return C code generated by iec2c compiler 
       
   960         when _generate_softPLC have been called
       
   961         @param locations: ignored
       
   962         @return: [(C_file_name, CFLAGS),...] , LDFLAGS_TO_APPEND
       
   963         """
       
   964         return [(C_file_name, self.plcCFLAGS) for C_file_name in self.PLCGeneratedCFiles ] , "-lrt", False
       
   965     
       
   966     def ResetIECProgramsAndVariables(self):
       
   967         """
       
   968         Reset variable and program list that are parsed from
       
   969         CSV file generated by IEC2C compiler.
       
   970         """
       
   971         self._ProgramList = None
       
   972         self._VariablesList = None
       
   973         self._IECPathToIdx = None
       
   974         self._IdxToIECPath = None
       
   975         
       
   976     def GetIECProgramsAndVariables(self):
       
   977         """
       
   978         Parse CSV-like file  VARIABLES.csv resulting from IEC2C compiler.
       
   979         Each section is marked with a line staring with '//'
       
   980         list of all variables used in various POUs
       
   981         """
       
   982         if self._ProgramList is None or self._VariablesList is None:
       
   983             try:
       
   984                 csvfile = os.path.join(self._getBuildPath(),"VARIABLES.csv")
       
   985                 # describes CSV columns
       
   986                 ProgramsListAttributeName = ["num", "C_path", "type"]
       
   987                 VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
       
   988                 self._ProgramList = []
       
   989                 self._VariablesList = []
       
   990                 self._IECPathToIdx = {}
       
   991                 self._IdxToIECPath = {}
       
   992                 
       
   993                 # Separate sections
       
   994                 ListGroup = []
       
   995                 for line in open(csvfile,'r').xreadlines():
       
   996                     strippedline = line.strip()
       
   997                     if strippedline.startswith("//"):
       
   998                         # Start new section
       
   999                         ListGroup.append([])
       
  1000                     elif len(strippedline) > 0 and len(ListGroup) > 0:
       
  1001                         # append to this section
       
  1002                         ListGroup[-1].append(strippedline)
       
  1003         
       
  1004                 # first section contains programs
       
  1005                 for line in ListGroup[0]:
       
  1006                     # Split and Maps each field to dictionnary entries
       
  1007                     attrs = dict(zip(ProgramsListAttributeName,line.strip().split(';')))
       
  1008                     # Truncate "C_path" to remove conf an ressources names
       
  1009                     attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:])
       
  1010                     # Push this dictionnary into result.
       
  1011                     self._ProgramList.append(attrs)
       
  1012         
       
  1013                 # second section contains all variables
       
  1014                 for line in ListGroup[1]:
       
  1015                     # Split and Maps each field to dictionnary entries
       
  1016                     attrs = dict(zip(VariablesListAttributeName,line.strip().split(';')))
       
  1017                     # Truncate "C_path" to remove conf an ressources names
       
  1018                     attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:])
       
  1019                     # Push this dictionnary into result.
       
  1020                     self._VariablesList.append(attrs)
       
  1021                     # Fill in IEC<->C translation dicts
       
  1022                     IEC_path=attrs["IEC_path"]
       
  1023                     Idx=int(attrs["num"])
       
  1024                     self._IECPathToIdx[IEC_path]=Idx
       
  1025                     self._IdxToIECPath[Idx]=IEC_path
       
  1026             except Exception,e:
       
  1027                 self.logger.write_error("Cannot open/parse VARIABLES.csv!\n")
       
  1028                 self.logger.write_error(traceback.format_exc())
       
  1029                 self.ResetIECProgramsAndVariables()
       
  1030                 return False
       
  1031 
       
  1032         return True
       
  1033 
       
  1034     def Generate_plc_debugger(self):
       
  1035         """
       
  1036         Generate trace/debug code out of PLC variable list
       
  1037         """
       
  1038         self.GetIECProgramsAndVariables()
       
  1039 
       
  1040         # prepare debug code
       
  1041         debug_code = runtime.code("plc_debug") % {
       
  1042            "programs_declarations":
       
  1043                "\n".join(["extern %(type)s %(C_path)s;"%p for p in self._ProgramList]),
       
  1044            "extern_variables_declarations":"\n".join([
       
  1045               {"PT":"extern %(type)s *%(C_path)s;",
       
  1046                "VAR":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v 
       
  1047                for v in self._VariablesList if v["C_path"].find('.')<0]),
       
  1048            "subscription_table_count":
       
  1049                len(self._VariablesList),
       
  1050            "variables_pointer_type_table_count":
       
  1051                len(self._VariablesList),
       
  1052            "variables_pointer_type_table_initializer":"\n".join([
       
  1053                {"PT":"    variable_table[%(num)s].ptrvalue = (void*)(%(C_path)s);\n",
       
  1054                 "VAR":"    variable_table[%(num)s].ptrvalue = (void*)(&%(C_path)s);\n"}[v["vartype"]]%v + 
       
  1055                 "    variable_table[%(num)s].type = %(type)s_ENUM;\n"%v
       
  1056                 for v in self._VariablesList if v["type"] in DebugTypes ])}
       
  1057         
       
  1058         return debug_code
       
  1059 
       
  1060     def RegisterDebugVarToConnector(self):
       
  1061         Idxs = []
       
  1062         if self._connector is not None:
       
  1063             for IECPath,WeakCallableDict in self.IECdebug_callables:
       
  1064                 if len(WeakCallableDict) == 0:
       
  1065                     # Callable Dict is empty.
       
  1066                     # This variable is not needed anymore!
       
  1067                     self.IECdebug_callables.pop(IECPath)
       
  1068                 else:
       
  1069                     # Convert 
       
  1070                     Idx = self._IECPathToIdx.get(IECPath,None)
       
  1071                     if Idx is not None:
       
  1072                         Idxs.append(Idx)
       
  1073                     else:
       
  1074                         self.logger.write_warning("Debug : Unknown variable %s\n"%IECPath)
       
  1075             self._connector.TraceVariables(Idxs)
       
  1076         
       
  1077     def SubscribeDebugIECVariable(self, IECPath, callable, *args, **kwargs):
       
  1078         """
       
  1079         Dispatching use a dictionnary linking IEC variable paths
       
  1080         to a WeakKeyDictionary linking 
       
  1081         weakly referenced callables to optionnal args
       
  1082         """
       
  1083         # If no entry exist, create a new one with a fresh WeakKeyDictionary
       
  1084         self.IECdebug_callables.setdefault(
       
  1085                    IECPath, 
       
  1086                    WeakKeyDictionary())[callable]=(args, kwargs)
       
  1087         # Rearm anti-rapid-fire timer
       
  1088         self.DebugTimer.cancel()
       
  1089         self.DebugTimer.start()
       
  1090         
       
  1091     def Generate_plc_common_main(self):
       
  1092         """
       
  1093         Use plugins layout given in LocationCFilesAndCFLAGS to
       
  1094         generate glue code that dispatch calls to all plugins
       
  1095         """
       
  1096         # filter location that are related to code that will be called
       
  1097         # in retreive, publish, init, cleanup
       
  1098         locstrs = map(lambda x:"_".join(map(str,x)),
       
  1099            [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
       
  1100 
       
  1101         # Generate main, based on template
       
  1102         plc_main_code = runtime.code("plc_common_main") % {
       
  1103             "calls_prototypes":"\n".join([(
       
  1104                   "int __init_%(s)s(int argc,char **argv);\n"+
       
  1105                   "void __cleanup_%(s)s();\n"+
       
  1106                   "void __retrieve_%(s)s();\n"+
       
  1107                   "void __publish_%(s)s();")%{'s':locstr} for locstr in locstrs]),
       
  1108             "retrieve_calls":"\n    ".join([
       
  1109                   "__retrieve_%s();"%locstr for locstr in locstrs]),
       
  1110             "publish_calls":"\n    ".join([ #Call publish in reverse order
       
  1111                   "__publish_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
       
  1112             "init_calls":"\n    ".join([
       
  1113                   "init_level=%d; "%i+
       
  1114                   "if(res = __init_%s(argc,argv)){"%locstr +
       
  1115                   #"printf(\"%s\"); "%locstr + #for debug
       
  1116                   "return res;}" for i,locstr in enumerate(locstrs)]),
       
  1117             "cleanup_calls":"\n    ".join([
       
  1118                   "if(init_level >= %d) "%i+
       
  1119                   "__cleanup_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
       
  1120             }
       
  1121 
       
  1122         target_name = self.BeremizRoot.getTargetType().getcontent()["name"]
       
  1123         plc_main_code += runtime.code("plc_%s_main"%target_name)
       
  1124         
       
  1125         return plc_main_code
       
  1126 
       
  1127         
       
  1128     def _build(self):
   937         """
  1129         """
   938         Method called by user to (re)build SoftPLC and plugin tree
  1130         Method called by user to (re)build SoftPLC and plugin tree
   939         """
  1131         """
   940         if self.PLCEditor is not None:
  1132         if self.PLCEditor is not None:
   941             self.PLCEditor.ClearErrors()
  1133             self.PLCEditor.ClearErrors()
   943         buildpath = self._getBuildPath()
  1135         buildpath = self._getBuildPath()
   944 
  1136 
   945         # Eventually create build dir
  1137         # Eventually create build dir
   946         if not os.path.exists(buildpath):
  1138         if not os.path.exists(buildpath):
   947             os.mkdir(buildpath)
  1139             os.mkdir(buildpath)
   948         
  1140         # There is something to clean
   949         logger.flush()
       
   950         logger.write("Start build in %s\n" % buildpath)
       
   951 
       
   952         self.EnableMethod("_Clean", True)
  1141         self.EnableMethod("_Clean", True)
   953         self.EnableMethod("_showIECcode", True)
  1142 
   954         
  1143         self.logger.flush()
   955         # Generate SoftPLC code
  1144         self.logger.write("Start build in %s\n" % buildpath)
   956         if not self._Generate_SoftPLC(logger):
  1145 
   957             logger.write_error("SoftPLC code generation failed !\n")
  1146         # Generate SoftPLC IEC code
       
  1147         IECGenRes = self._Generate_SoftPLC()
       
  1148         self.ShowMethod("_showIECcode", True)
       
  1149 
       
  1150         # If IEC code gen fail, bail out.
       
  1151         if not IECGenRes:
       
  1152             self.logger.write_error("IEC-61131-3 code generation failed !\n")
   958             return False
  1153             return False
   959 
  1154 
   960 
  1155         # Reset variable and program list that are parsed from
   961         #logger.write("SoftPLC code generation successfull\n")
  1156         # CSV file generated by IEC2C compiler.
   962 
  1157         self.ResetIECProgramsAndVariables()
   963         logger.write("Generating plugins code ...\n")
       
   964         
  1158         
   965         # Generate C code and compilation params from plugin hierarchy
  1159         # Generate C code and compilation params from plugin hierarchy
       
  1160         self.logger.write("Generating plugins C code\n")
   966         try:
  1161         try:
   967             LocationCFilesAndCFLAGS,LDFLAGS = self._Generate_C(
  1162             self.LocationCFilesAndCFLAGS, self.LDFLAGS, ExtraFiles = self._Generate_C(
   968                 buildpath, 
  1163                 buildpath, 
   969                 self.PLCGeneratedLocatedVars,
  1164                 self.PLCGeneratedLocatedVars)
   970                 logger)
       
   971         except Exception, exc:
  1165         except Exception, exc:
   972             logger.write_error("Plugins code generation Failed !\n")
  1166             self.logger.write_error("Plugins code generation failed !\n")
   973             logger.write_error(traceback.format_exc())
  1167             self.logger.write_error(traceback.format_exc())
   974             return False
  1168             return False
   975 
  1169 
   976 
  1170         # Get temprary directory path
   977         #debug
  1171         extrafilespath = self._getExtraFilesPath()
   978         #import pprint
  1172         # Remove old directory
   979         #pp = pprint.PrettyPrinter(indent=4)
  1173         if os.path.exists(extrafilespath):
   980         #logger.write("LocationCFilesAndCFLAGS :\n"+pp.pformat(LocationCFilesAndCFLAGS)+"\n")
  1174             shutil.rmtree(extrafilespath)
   981         #logger.write("LDFLAGS :\n"+pp.pformat(LDFLAGS)+"\n")
  1175         # Recreate directory
   982         
  1176         os.mkdir(extrafilespath)
   983         # Generate main
  1177         # Then write the files
   984         locstrs = map(lambda x:"_".join(map(str,x)), [loc for loc,Cfiles,DoCalls in LocationCFilesAndCFLAGS if loc and DoCalls])
  1178         for fname,fobject in ExtraFiles:
   985         plc_main = runtime.code("plc_common_main") % {
  1179             print fname,fobject
   986             "calls_prototypes":"\n".join(
  1180             fpath = os.path.join(extrafilespath,fname)
   987                ["int __init_%(s)s(int argc,char **argv);\nvoid __cleanup_%(s)s();\nvoid __retrieve_%(s)s();\nvoid __publish_%(s)s();"%
  1181             open(fpath, "wb").write(fobject.read())
   988                 {'s':locstr} for locstr in locstrs]),
  1182         # Now we can forget ExtraFiles (will close files object)
   989             "retrieve_calls":"\n    ".join(["__retrieve_%(s)s();"%{'s':locstr} for locstr in locstrs]),
  1183         del ExtraFiles
   990             "publish_calls":"\n    ".join(["__publish_%(s)s();"%{'s':locstr} for locstr in locstrs]),
  1184 
   991             "init_calls":"\n    ".join(["init_level++; if(res = __init_%(s)s(argc,argv)) return res;"%{'s':locstr} for locstr in locstrs]),
  1185         # Template based part of C code generation
   992             "cleanup_calls":"\n    ".join(["if(init_level-- > 0) __cleanup_%(s)s();"%{'s':locstr} for locstr in locstrs]),
  1186         # files are stacked at the beginning, as files of plugin tree root
   993             "sync_align_ratio":self.BeremizRoot.getSync_Align_Ratio()}
  1187         for generator, filename, name in [
   994         target_name = self.BeremizRoot.TargetType.content["name"]
  1188            # debugger code
   995         plc_main += runtime.code("plc_%s_main"%target_name)
  1189            (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
   996 
  1190            # init/cleanup/retrieve/publish, run and align code
   997         main_path = os.path.join(buildpath, "main.c" )
  1191            (self.Generate_plc_common_main,"plc_common_main.c","Common runtime")]:
   998         f = open(main_path,'w')
  1192             try:
   999         f.write(plc_main)
  1193                 # Do generate
  1000         f.close()
  1194                 code = generator()
  1001         # First element is necessarely root
  1195                 code_path = os.path.join(buildpath,filename)
  1002         LocationCFilesAndCFLAGS[0][1].insert(0,(main_path, self.CFLAGS))
  1196                 open(code_path, "w").write(code)
  1003         
  1197                 # Insert this file as first file to be compiled at root plugin
  1004         # Compile the resulting code into object files.
  1198                 self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS))
  1005         compiler = self.BeremizRoot.getCompiler()
  1199             except Exception, exc:
  1006         _CFLAGS = self.BeremizRoot.getCFLAGS()
  1200                 self.logger.write_error(name+" generation failed !\n")
  1007         linker = self.BeremizRoot.getLinker()
  1201                 self.logger.write_error(traceback.format_exc())
  1008         _LDFLAGS = self.BeremizRoot.getLDFLAGS()
  1202                 return False
  1009         obns = []
  1203 
  1010         objs = []
  1204         self.logger.write("C code generated successfully.\n")
  1011         for Location, CFilesAndCFLAGS, DoCalls in LocationCFilesAndCFLAGS:
  1205 
  1012             if Location:
  1206         # Get current or fresh builder
  1013                 logger.write("Plugin : " + self.GetChildByIECLocation(Location).GetCurrentName() + " " + str(Location)+"\n")
  1207         builder = self.GetBuilder()
  1014             else:
  1208         if builder is None:
  1015                 logger.write("PLC :\n")
  1209             self.logger.write_error("Fatal : cannot get builder.\n")
  1016                 
       
  1017             for CFile, CFLAGS in CFilesAndCFLAGS:
       
  1018                 bn = os.path.basename(CFile)
       
  1019                 obn = os.path.splitext(bn)[0]+".o"
       
  1020                 obns.append(obn)
       
  1021                 logger.write("   [CC]  "+bn+" -> "+obn+"\n")
       
  1022                 objectfilename = os.path.splitext(CFile)[0]+".o"
       
  1023 
       
  1024                 status, result, err_result = ProcessLogger(
       
  1025                        logger,
       
  1026                        "\"%s\" -c \"%s\" -o \"%s\" %s %s"%
       
  1027                            (compiler, CFile, objectfilename, _CFLAGS, CFLAGS)
       
  1028                        ).spin()
       
  1029 
       
  1030                 if status != 0:
       
  1031                     logger.write_error("Build failed\n")
       
  1032                     return False
       
  1033                 objs.append(objectfilename)
       
  1034         # Link all the object files into one executable
       
  1035         logger.write("Linking :\n")
       
  1036         exe = self.GetProjectName()
       
  1037         if target_name == "Win32":
       
  1038             exe += ".exe"
       
  1039         exe_path = os.path.join(buildpath, exe)
       
  1040         logger.write("   [CC]  " + ' '.join(obns)+" -> " + exe + "\n")
       
  1041         status, result, err_result = ProcessLogger(
       
  1042                logger,
       
  1043                "\"%s\" \"%s\" -o \"%s\" %s"%
       
  1044                    (linker,
       
  1045                     '" "'.join(objs),
       
  1046                     exe_path,
       
  1047                     ' '.join(LDFLAGS+[_LDFLAGS]))
       
  1048                ).spin()
       
  1049         if status != 0:
       
  1050             logger.write_error("Build failed\n")
       
  1051             self.EnableMethod("_Run", False)
       
  1052             return False
  1210             return False
  1053         
  1211 
  1054         self.EnableMethod("_Run", True)
  1212         # Build
       
  1213         try:
       
  1214             if not builder.build() :
       
  1215                 self.logger.write_error("C Build failed.\n")
       
  1216                 return False
       
  1217         except Exception, exc:
       
  1218             self.logger.write_error("C Build crashed !\n")
       
  1219             self.logger.write_error(traceback.format_exc())
       
  1220             return False
       
  1221 
       
  1222         # Update GUI status about need for transfer
       
  1223         self.CompareLocalAndRemotePLC()
  1055         return True
  1224         return True
  1056     
  1225     
  1057     def ShowError(self, logger, from_location, to_location):
  1226     def ShowError(self, logger, from_location, to_location):
  1058         chunk_infos = self.GetChunkInfos(from_location, to_location)
  1227         chunk_infos = self.GetChunkInfos(from_location, to_location)
  1059         self._EditPLC(logger)
  1228         self._EditPLC(logger)
  1060         for infos, (start_row, start_col) in chunk_infos:
  1229         for infos, (start_row, start_col) in chunk_infos:
  1061             start = (from_location[0] - start_row, from_location[1] - start_col)
  1230             start = (from_location[0] - start_row, from_location[1] - start_col)
  1062             end = (to_location[0] - start_row, to_location[1] - start_col)
  1231             end = (to_location[0] - start_row, to_location[1] - start_col)
  1063             self.PLCEditor.ShowError(infos, start, end)
  1232             self.PLCEditor.ShowError(infos, start, end)
  1064             
  1233 
  1065     def _showIECcode(self, logger):
  1234     def _showIECcode(self):
  1066         plc_file = self._getIECcodepath()
  1235         plc_file = self._getIECcodepath()
  1067         new_dialog = wx.Frame(self.AppFrame)
  1236         new_dialog = wx.Frame(self.AppFrame)
  1068         ST_viewer = TextViewer(new_dialog, "", None, None)
  1237         ST_viewer = TextViewer(new_dialog, "", None, None)
  1069         #ST_viewer.Enable(False)
  1238         #ST_viewer.Enable(False)
  1070         ST_viewer.SetKeywords(IEC_KEYWORDS)
  1239         ST_viewer.SetKeywords(IEC_KEYWORDS)
  1074             text = '(* No IEC code have been generated at that time ! *)'
  1243             text = '(* No IEC code have been generated at that time ! *)'
  1075         ST_viewer.SetText(text = text)
  1244         ST_viewer.SetText(text = text)
  1076             
  1245             
  1077         new_dialog.Show()
  1246         new_dialog.Show()
  1078 
  1247 
  1079     def _editIECrawcode(self, logger):
  1248     def _editIECrawcode(self):
  1080         new_dialog = wx.Frame(self.AppFrame)
  1249         new_dialog = wx.Frame(self.AppFrame)
  1081         
       
  1082         buildpath = self._getBuildPath()
       
  1083         # Eventually create build dir
       
  1084         if not os.path.exists(buildpath):
       
  1085             os.mkdir(buildpath)
       
  1086         
  1250         
  1087         controler = MiniTextControler(self._getIECrawcodepath())
  1251         controler = MiniTextControler(self._getIECrawcodepath())
  1088         ST_viewer = TextViewer(new_dialog, "", None, controler)
  1252         ST_viewer = TextViewer(new_dialog, "", None, controler)
  1089         #ST_viewer.Enable(False)
  1253         #ST_viewer.Enable(False)
  1090         ST_viewer.SetKeywords(IEC_KEYWORDS)
  1254         ST_viewer.SetKeywords(IEC_KEYWORDS)
  1091         ST_viewer.RefreshView()
  1255         ST_viewer.RefreshView()
  1092             
  1256             
  1093         new_dialog.Show()
  1257         new_dialog.Show()
  1094 
  1258 
  1095     def _EditPLC(self, logger):
  1259     def _EditPLC(self):
  1096         if self.PLCEditor is None:
  1260         if self.PLCEditor is None:
  1097             self.RefreshPluginsBlockLists()
  1261             self.RefreshPluginsBlockLists()
  1098             def _onclose():
  1262             def _onclose():
  1099                 self.PLCEditor = None
  1263                 self.PLCEditor = None
  1100             def _onsave():
  1264             def _onsave():
  1106             self.PLCEditor.RefreshToolBar()
  1270             self.PLCEditor.RefreshToolBar()
  1107             self.PLCEditor._onclose = _onclose
  1271             self.PLCEditor._onclose = _onclose
  1108             self.PLCEditor._onsave = _onsave
  1272             self.PLCEditor._onsave = _onsave
  1109             self.PLCEditor.Show()
  1273             self.PLCEditor.Show()
  1110 
  1274 
  1111     def _Clean(self, logger):
  1275     def _Clean(self):
  1112         if os.path.isdir(os.path.join(self._getBuildPath())):
  1276         if os.path.isdir(os.path.join(self._getBuildPath())):
  1113             logger.write("Cleaning the build directory\n")
  1277             self.logger.write("Cleaning the build directory\n")
  1114             shutil.rmtree(os.path.join(self._getBuildPath()))
  1278             shutil.rmtree(os.path.join(self._getBuildPath()))
  1115         else:
  1279         else:
  1116             logger.write_error("Build directory already clean\n")
  1280             self.logger.write_error("Build directory already clean\n")
  1117         self.EnableMethod("_showIECcode", False)
  1281         self.ShowMethod("_showIECcode", False)
  1118         self.EnableMethod("_Clean", False)
  1282         self.EnableMethod("_Clean", False)
  1119         self.EnableMethod("_Run", False)
  1283         self.CompareLocalAndRemotePLC()
  1120     
  1284 
  1121     def _Run(self, logger):
  1285     ############# Real PLC object access #############
  1122         command_start_plc = os.path.join(self._getBuildPath(),self.GetProjectName() + exe_ext)
  1286     def UpdateMethodsFromPLCStatus(self):
  1123         if os.path.isfile(command_start_plc):
  1287         # Get PLC state : Running or Stopped
  1124             has_gui_plugin = False
  1288         # TODO : use explicit status instead of boolean
  1125             for PlugChild in self.IterChilds():
  1289         if self._connector is not None:
  1126                 has_gui_plugin |= PlugChild.IsGUIPlugin()
  1290             status = self._connector.GetPLCstatus()
  1127             logger.write("Starting PLC\n")
  1291             self.logger.write("PLC is %s\n"%status)
  1128             def this_plc_finish_callback(*args):
       
  1129                 if self.runningPLC is not None:
       
  1130                     self.runningPLC = None
       
  1131                     self.reset_finished()
       
  1132             self.runningPLC = ProcessLogger(
       
  1133                logger,
       
  1134                command_start_plc,
       
  1135                finish_callback = this_plc_finish_callback,
       
  1136                no_gui=wx.Platform != '__WXMSW__' or not has_gui_plugin)
       
  1137             self.EnableMethod("_Clean", False)
       
  1138             self.EnableMethod("_Run", False)
       
  1139             self.EnableMethod("_Stop", True)
       
  1140             self.EnableMethod("_build", False)
       
  1141         else:
  1292         else:
  1142             logger.write_error("%s doesn't exist\n" %command_start_plc)
  1293             status = "Disconnected"
  1143 
  1294         for args in {
  1144     def reset_finished(self):
  1295                "Started":[("_Run", False),
  1145         self.EnableMethod("_Clean", True)
  1296                           ("_Debug", False),
  1146         self.EnableMethod("_Run", True)
  1297                           ("_Stop", True)],
  1147         self.EnableMethod("_Stop", False)
  1298                "Stopped":[("_Run", True),
  1148         self.EnableMethod("_build", True)
  1299                           ("_Debug", True),
  1149 
  1300                           ("_Stop", False)],
  1150     def _Stop(self, logger):
  1301                "Empty":  [("_Run", False),
  1151         if self.runningPLC is not None:
  1302                           ("_Debug", False),
  1152             logger.write("Stopping PLC\n")
  1303                           ("_Stop", False)],
  1153             was_runningPLC = self.runningPLC 
  1304                "Dirty":  [("_Run", True),
  1154             self.runningPLC = None
  1305                           ("_Debug", True),
  1155             was_runningPLC.kill()
  1306                           ("_Stop", False)],
  1156             self.reset_finished()
  1307                "Disconnected":  [("_Run", False),
       
  1308                                  ("_Debug", False),
       
  1309                                  ("_Stop", False)],
       
  1310                }.get(status,[]):
       
  1311             self.ShowMethod(*args)
       
  1312         
       
  1313     def _Run(self):
       
  1314         """
       
  1315         Start PLC
       
  1316         """
       
  1317         if self._connector.StartPLC():
       
  1318             self.logger.write("Starting PLC\n")
       
  1319         else:
       
  1320             self.logger.write_error("Couldn't start PLC !\n")
       
  1321         self.UpdateMethodsFromPLCStatus()
       
  1322 
       
  1323     def _Debug(self): 
       
  1324         """
       
  1325         Start PLC (Debug Mode)
       
  1326         """
       
  1327         if self.GetIECProgramsAndVariables() and self._connector.StartPLC():
       
  1328             self.logger.write("Starting PLC (debug mode)\n")
       
  1329             # TODO : laucnch PLCOpenEditor in Debug Mode
       
  1330             self.logger.write_warning("Debug mode for PLCopenEditor not implemented\n")
       
  1331             self.logger.write_warning("Starting alternative test GUI\n")
       
  1332             # TODO : laucnch PLCOpenEditor in Debug Mode
       
  1333         else:
       
  1334             self.logger.write_error("Couldn't start PLC debug !\n")
       
  1335         self.UpdateMethodsFromPLCStatus()
       
  1336        
       
  1337     def _Stop(self):
       
  1338         """
       
  1339         Stop PLC
       
  1340         """
       
  1341         if self._connector.StopPLC():
       
  1342             self.logger.write("Stopping PLC\n")
       
  1343         else:
       
  1344             self.logger.write_error("Couldn't stop PLC !\n")
       
  1345         self.UpdateMethodsFromPLCStatus()
       
  1346 
       
  1347     def _Connect(self):
       
  1348         # don't accept re-connetion is already connected
       
  1349         if self._connector is not None:
       
  1350             self.logger.write_error("Already connected. Please disconnect\n")
       
  1351             return
       
  1352         
       
  1353         # Get connector uri
       
  1354         uri = self.\
       
  1355               BeremizRoot.\
       
  1356               getTargetType().\
       
  1357               getcontent()["value"].\
       
  1358               getConnection().\
       
  1359               getURI_location().\
       
  1360               strip()
       
  1361 
       
  1362         # if uri is empty launch discovery dialog
       
  1363         if uri == "":
       
  1364             # Launch Service Discovery dialog
       
  1365             dia = DiscoveryDialog(self.AppFrame)
       
  1366             dia.ShowModal()
       
  1367             uri = dia.GetResult()
       
  1368             # Nothing choosed or cancel button
       
  1369             if uri is None:
       
  1370                 return
       
  1371             else:
       
  1372                 self.\
       
  1373                 BeremizRoot.\
       
  1374                 getTargetType().\
       
  1375                 getcontent()["value"].\
       
  1376                 getConnection().\
       
  1377                 setURI_location(uri)
       
  1378        
       
  1379         # Get connector from uri
       
  1380         try:
       
  1381             self._connector = connectors.ConnectorFactory(uri, self)
       
  1382         except Exception, msg:
       
  1383             self.logger.write_error("Exception while connecting %s!\n"%uri)
       
  1384             self.logger.write_error(traceback.format_exc())
       
  1385 
       
  1386         # Did connection success ?
       
  1387         if self._connector is None:
       
  1388             # Oups.
       
  1389             self.logger.write_error("Connection failed to %s!\n"%uri)
       
  1390         else:
       
  1391             self.ShowMethod("_Connect", False)
       
  1392             self.ShowMethod("_Disconnect", True)
       
  1393             self.ShowMethod("_Transfer", True)
       
  1394 
       
  1395             self.CompareLocalAndRemotePLC()
       
  1396             self.UpdateMethodsFromPLCStatus()
       
  1397 
       
  1398     def CompareLocalAndRemotePLC(self):
       
  1399         if self._connector is None:
       
  1400             return
       
  1401         # We are now connected. Update button status
       
  1402         MD5 = self.GetLastBuildMD5()
       
  1403         # Check remote target PLC correspondance to that md5
       
  1404         if MD5 is not None:
       
  1405             if not self._connector.MatchMD5(MD5):
       
  1406                 self.logger.write_warning(
       
  1407                    "Latest build do not match with target, please transfer.\n")
       
  1408                 self.EnableMethod("_Transfer", True)
       
  1409             else:
       
  1410                 self.logger.write(
       
  1411                    "Latest build match target, no transfer needed.\n")
       
  1412                 self.EnableMethod("_Transfer", True)
       
  1413                 #self.EnableMethod("_Transfer", False)
       
  1414         else:
       
  1415             self.logger.write_warning(
       
  1416                 "Cannot compare latest build to target. Please build.\n")
       
  1417             self.EnableMethod("_Transfer", False)
       
  1418 
       
  1419 
       
  1420     def _Disconnect(self):
       
  1421         self._connector = None
       
  1422         self.ShowMethod("_Transfer", False)
       
  1423         self.ShowMethod("_Connect", True)
       
  1424         self.ShowMethod("_Disconnect", False)
       
  1425         self.UpdateMethodsFromPLCStatus()
       
  1426         
       
  1427     def _Transfer(self):
       
  1428         # Get the last build PLC's 
       
  1429         MD5 = self.GetLastBuildMD5()
       
  1430         
       
  1431         # Check if md5 file is empty : ask user to build PLC 
       
  1432         if MD5 is None :
       
  1433             self.logger.write_error("Failed : Must build before transfer.\n")
       
  1434             return False
       
  1435 
       
  1436         # Compare PLC project with PLC on target
       
  1437         if self._connector.MatchMD5(MD5):
       
  1438             self.logger.write(
       
  1439                 "Latest build already match current target. Transfering anyway...\n")
       
  1440 
       
  1441         # Get temprary directory path
       
  1442         extrafilespath = self._getExtraFilesPath()
       
  1443         extrafiles = [(name, open(os.path.join(extrafilespath, name), 
       
  1444                                   'rb').read()) \
       
  1445                       for name in os.listdir(extrafilespath) \
       
  1446                       if not name=="CVS"]
       
  1447 
       
  1448         for filename, unused in extrafiles:
       
  1449             print filename
       
  1450 
       
  1451         # Send PLC on target
       
  1452         builder = self.GetBuilder()
       
  1453         if builder is not None:
       
  1454             data = builder.GetBinaryCode()
       
  1455             if data is not None :
       
  1456                 if self._connector.NewPLC(MD5, data, extrafiles):
       
  1457                     self.logger.write("Transfer completed successfully.\n")
       
  1458                 else:
       
  1459                     self.logger.write_error("Transfer failed\n")
       
  1460             else:
       
  1461                 self.logger.write_error("No PLC to transfer (did build success ?)\n")
       
  1462         self.UpdateMethodsFromPLCStatus()
  1157 
  1463 
  1158     PluginMethods = [
  1464     PluginMethods = [
  1159         {"bitmap" : os.path.join("images", "editPLC"),
  1465         {"bitmap" : opjimg("editPLC"),
  1160          "name" : "Edit PLC",
  1466          "name" : "Edit PLC",
  1161          "tooltip" : "Edit PLC program with PLCOpenEditor",
  1467          "tooltip" : "Edit PLC program with PLCOpenEditor",
  1162          "method" : "_EditPLC"},
  1468          "method" : "_EditPLC"},
  1163         {"bitmap" : os.path.join("images", "Build"),
  1469         {"bitmap" : opjimg("Build"),
  1164          "name" : "Build",
  1470          "name" : "Build",
  1165          "tooltip" : "Build project into build folder",
  1471          "tooltip" : "Build project into build folder",
  1166          "method" : "_build"},
  1472          "method" : "_build"},
  1167         {"bitmap" : os.path.join("images", "Clean"),
  1473         {"bitmap" : opjimg("Clean"),
  1168          "name" : "Clean",
  1474          "name" : "Clean",
       
  1475          "enabled" : False,
  1169          "tooltip" : "Clean project build folder",
  1476          "tooltip" : "Clean project build folder",
  1170          "method" : "_Clean"},
  1477          "method" : "_Clean"},
  1171         {"bitmap" : os.path.join("images", "Run"),
  1478         {"bitmap" : opjimg("Run"),
  1172          "name" : "Run",
  1479          "name" : "Run",
  1173          "enabled" : False,
  1480          "shown" : False,
  1174          "tooltip" : "Run PLC from build folder",
  1481          "tooltip" : "Start PLC",
  1175          "method" : "_Run"},
  1482          "method" : "_Run"},
  1176         {"bitmap" : os.path.join("images", "Stop"),
  1483         {"bitmap" : opjimg("Debug"),
       
  1484          "name" : "Debug",
       
  1485          "shown" : False,
       
  1486          "tooltip" : "Start PLC (debug mode)",
       
  1487          "method" : "_Debug"},
       
  1488         {"bitmap" : opjimg("Stop"),
  1177          "name" : "Stop",
  1489          "name" : "Stop",
  1178          "enabled" : False,
  1490          "shown" : False,
  1179          "tooltip" : "Stop Running PLC",
  1491          "tooltip" : "Stop Running PLC",
  1180          "method" : "_Stop"},
  1492          "method" : "_Stop"},
  1181         {"bitmap" : os.path.join("images", "ShowIECcode"),
  1493         {"bitmap" : opjimg("Connect"),
       
  1494          "name" : "Connect",
       
  1495          "tooltip" : "Connect to the target PLC",
       
  1496          "method" : "_Connect"},
       
  1497         {"bitmap" : opjimg("Transfer"),
       
  1498          "name" : "Transfer",
       
  1499          "shown" : False,
       
  1500          "tooltip" : "Transfer PLC",
       
  1501          "method" : "_Transfer"},
       
  1502         {"bitmap" : opjimg("Disconnect"),
       
  1503          "name" : "Disconnect",
       
  1504          "shown" : False,
       
  1505          "tooltip" : "Disconnect from PLC",
       
  1506          "method" : "_Disconnect"},
       
  1507         {"bitmap" : opjimg("ShowIECcode"),
  1182          "name" : "Show code",
  1508          "name" : "Show code",
  1183          "enabled" : False,
  1509          "shown" : False,
  1184          "tooltip" : "Show IEC code generated by PLCGenerator",
  1510          "tooltip" : "Show IEC code generated by PLCGenerator",
  1185          "method" : "_showIECcode"},
  1511          "method" : "_showIECcode"},
  1186         {"bitmap" : os.path.join("images", "editIECrawcode"),
  1512         {"bitmap" : opjimg("editIECrawcode"),
  1187          "name" : "Append code",
  1513          "name" : "Append code",
  1188          "tooltip" : "Edit raw IEC code added to code generated by PLCGenerator",
  1514          "tooltip" : "Edit raw IEC code added to code generated by PLCGenerator",
  1189          "method" : "_editIECrawcode"}
  1515          "method" : "_editIECrawcode"},
  1190     ]
  1516     ]