ProjectController.py
changeset 1740 b789b695b5c6
parent 1739 ec153828ded2
child 1741 dd94b9a68c61
equal deleted inserted replaced
1739:ec153828ded2 1740:b789b695b5c6
    68 ITEM_CONFNODE = 25
    68 ITEM_CONFNODE = 25
    69 
    69 
    70 
    70 
    71 def ExtractChildrenTypesFromCatalog(catalog):
    71 def ExtractChildrenTypesFromCatalog(catalog):
    72     children_types = []
    72     children_types = []
    73     for n,d,h,c in catalog:
    73     for n, d, h, c in catalog:
    74         if isinstance(c, ListType):
    74         if isinstance(c, ListType):
    75             children_types.extend(ExtractChildrenTypesFromCatalog(c))
    75             children_types.extend(ExtractChildrenTypesFromCatalog(c))
    76         else:
    76         else:
    77             children_types.append((n, GetClassImporter(c), d))
    77             children_types.append((n, GetClassImporter(c), d))
    78     return children_types
    78     return children_types
    79 
    79 
    80 
    80 
    81 def ExtractMenuItemsFromCatalog(catalog):
    81 def ExtractMenuItemsFromCatalog(catalog):
    82     menu_items = []
    82     menu_items = []
    83     for n,d,h,c in catalog:
    83     for n, d, h, c in catalog:
    84         if isinstance(c, ListType):
    84         if isinstance(c, ListType):
    85             children = ExtractMenuItemsFromCatalog(c)
    85             children = ExtractMenuItemsFromCatalog(c)
    86         else:
    86         else:
    87             children = []
    87             children = []
    88         menu_items.append((n, d, h, children))
    88         menu_items.append((n, d, h, children))
   111     def findCmd(self):
   111     def findCmd(self):
   112         cmd="iec2c"+(".exe" if wx.Platform == '__WXMSW__' else "")
   112         cmd="iec2c"+(".exe" if wx.Platform == '__WXMSW__' else "")
   113         paths=[
   113         paths=[
   114             os.path.join(base_folder, "matiec")
   114             os.path.join(base_folder, "matiec")
   115         ]
   115         ]
   116         path = self.findObject(paths, lambda p:os.path.isfile(os.path.join(p, cmd)))
   116         path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, cmd)))
   117 
   117 
   118         # otherwise use iec2c from PATH
   118         # otherwise use iec2c from PATH
   119         if path is not None:
   119         if path is not None:
   120             cmd=os.path.join(path, cmd)
   120             cmd=os.path.join(path, cmd)
   121 
   121 
   124     def findLibPath(self):
   124     def findLibPath(self):
   125         paths=[
   125         paths=[
   126             os.path.join(base_folder, "matiec", "lib"),
   126             os.path.join(base_folder, "matiec", "lib"),
   127             "/usr/lib/matiec"
   127             "/usr/lib/matiec"
   128         ]
   128         ]
   129         path = self.findObject(paths, lambda p:os.path.isfile(os.path.join(p, "ieclib.txt")))
   129         path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, "ieclib.txt")))
   130         return path
   130         return path
   131 
   131 
   132     def findLibCPath(self):
   132     def findLibCPath(self):
   133         path=None
   133         path=None
   134         paths=[
   134         paths=[
   135             os.path.join(self.ieclib_path, "C"),
   135             os.path.join(self.ieclib_path, "C"),
   136             self.ieclib_path]
   136             self.ieclib_path]
   137         path = self.findObject(paths, lambda p:os.path.isfile(os.path.join(p, "iec_types.h")))
   137         path = self.findObject(paths, lambda p: os.path.isfile(os.path.join(p, "iec_types.h")))
   138         return path
   138         return path
   139 
   139 
   140     def findSupportedOptions(self):
   140     def findSupportedOptions(self):
   141         buildcmd = "\"%s\" -h" % (self.getCmd())
   141         buildcmd = "\"%s\" -h" % (self.getCmd())
   142         options =["-f", "-l", "-p"]
   142         options =["-f", "-l", "-p"]
   144         buildopt = ""
   144         buildopt = ""
   145         try:
   145         try:
   146             # Invoke compiler. Output files are listed to stdout, errors to stderr
   146             # Invoke compiler. Output files are listed to stdout, errors to stderr
   147             status, result, err_result = ProcessLogger(None, buildcmd,
   147             status, result, err_result = ProcessLogger(None, buildcmd,
   148                 no_stdout=True, no_stderr=True).spin()
   148                 no_stdout=True, no_stderr=True).spin()
   149         except Exception,e:
   149         except Exception, e:
   150             return buildopt
   150             return buildopt
   151 
   151 
   152         for opt in options:
   152         for opt in options:
   153             if opt in result:
   153             if opt in result:
   154                 buildopt = buildopt + " " + opt
   154                 buildopt = buildopt + " " + opt
   205             <xsd:element name="Libraries" minOccurs="0">
   205             <xsd:element name="Libraries" minOccurs="0">
   206               <xsd:complexType>
   206               <xsd:complexType>
   207               """+"\n".join(['<xsd:attribute name='+
   207               """+"\n".join(['<xsd:attribute name='+
   208                              '"Enable_'+ libname + '_Library" '+
   208                              '"Enable_'+ libname + '_Library" '+
   209                              'type="xsd:boolean" use="optional" default="true"/>'
   209                              'type="xsd:boolean" use="optional" default="true"/>'
   210                              for libname,lib in features.libraries])+"""
   210                              for libname, lib in features.libraries])+"""
   211               </xsd:complexType>
   211               </xsd:complexType>
   212             </xsd:element>""") if len(features.libraries)>0 else '') + """
   212             </xsd:element>""") if len(features.libraries)>0 else '') + """
   213           </xsd:sequence>
   213           </xsd:sequence>
   214           <xsd:attribute name="URI_location" type="xsd:string" use="optional" default=""/>
   214           <xsd:attribute name="URI_location" type="xsd:string" use="optional" default=""/>
   215           <xsd:attribute name="Disable_Extensions" type="xsd:boolean" use="optional" default="false"/>
   215           <xsd:attribute name="Disable_Extensions" type="xsd:boolean" use="optional" default="false"/>
   260         self.KillDebugThread()
   260         self.KillDebugThread()
   261 
   261 
   262     def LoadLibraries(self):
   262     def LoadLibraries(self):
   263         self.Libraries = []
   263         self.Libraries = []
   264         TypeStack=[]
   264         TypeStack=[]
   265         for libname,clsname in features.libraries:
   265         for libname, clsname in features.libraries:
   266             if self.BeremizRoot.Libraries is None or getattr(self.BeremizRoot.Libraries, "Enable_"+libname+"_Library"):
   266             if self.BeremizRoot.Libraries is None or getattr(self.BeremizRoot.Libraries, "Enable_"+libname+"_Library"):
   267                 Lib = GetClassImporter(clsname)()(self, libname, TypeStack)
   267                 Lib = GetClassImporter(clsname)()(self, libname, TypeStack)
   268                 TypeStack.append(Lib.GetTypes())
   268                 TypeStack.append(Lib.GetTypes())
   269                 self.Libraries.append(Lib)
   269                 self.Libraries.append(Lib)
   270 
   270 
   567     def GetLibrariesSTCode(self):
   567     def GetLibrariesSTCode(self):
   568         return "\n".join([ lib.GetSTCode() for lib in self.Libraries ])
   568         return "\n".join([ lib.GetSTCode() for lib in self.Libraries ])
   569 
   569 
   570     def GetLibrariesCCode(self, buildpath):
   570     def GetLibrariesCCode(self, buildpath):
   571         if len(self.Libraries)==0:
   571         if len(self.Libraries)==0:
   572             return [],[],()
   572             return [], [], ()
   573         self.GetIECProgramsAndVariables()
   573         self.GetIECProgramsAndVariables()
   574         LibIECCflags = '"-I%s" -Wno-unused-function' % os.path.abspath(self.GetIECLibPath())
   574         LibIECCflags = '"-I%s" -Wno-unused-function' % os.path.abspath(self.GetIECLibPath())
   575         LocatedCCodeAndFlags=[]
   575         LocatedCCodeAndFlags=[]
   576         Extras=[]
   576         Extras=[]
   577         for lib in self.Libraries:
   577         for lib in self.Libraries:
   578             res=lib.Generate_C(buildpath,self._VariablesList,LibIECCflags)
   578             res=lib.Generate_C(buildpath, self._VariablesList, LibIECCflags)
   579             LocatedCCodeAndFlags.append(res[:2])
   579             LocatedCCodeAndFlags.append(res[:2])
   580             if len(res)>2:
   580             if len(res)>2:
   581                 Extras.extend(res[2:])
   581                 Extras.extend(res[2:])
   582         return map(list,zip(*LocatedCCodeAndFlags))+[tuple(Extras)]
   582         return map(list, zip(*LocatedCCodeAndFlags))+[tuple(Extras)]
   583 
   583 
   584     # Update PLCOpenEditor ConfNode Block types from loaded confnodes
   584     # Update PLCOpenEditor ConfNode Block types from loaded confnodes
   585     def RefreshConfNodesBlockLists(self):
   585     def RefreshConfNodesBlockLists(self):
   586         if getattr(self, "Children", None) is not None:
   586         if getattr(self, "Children", None) is not None:
   587             self.ClearConfNodeTypes()
   587             self.ClearConfNodeTypes()
   666         # define name for IEC raw code file
   666         # define name for IEC raw code file
   667         return os.path.join(self.CTNPath(), "raw_plc.st")
   667         return os.path.join(self.CTNPath(), "raw_plc.st")
   668 
   668 
   669     def GetLocations(self):
   669     def GetLocations(self):
   670         locations = []
   670         locations = []
   671         filepath = os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h")
   671         filepath = os.path.join(self._getBuildPath(), "LOCATED_VARIABLES.h")
   672         if os.path.isfile(filepath):
   672         if os.path.isfile(filepath):
   673             # IEC2C compiler generate a list of located variables : LOCATED_VARIABLES.h
   673             # IEC2C compiler generate a list of located variables : LOCATED_VARIABLES.h
   674             location_file = open(os.path.join(self._getBuildPath(),"LOCATED_VARIABLES.h"))
   674             location_file = open(os.path.join(self._getBuildPath(), "LOCATED_VARIABLES.h"))
   675             # each line of LOCATED_VARIABLES.h declares a located variable
   675             # each line of LOCATED_VARIABLES.h declares a located variable
   676             lines = [line.strip() for line in location_file.readlines()]
   676             lines = [line.strip() for line in location_file.readlines()]
   677             # This regular expression parses the lines genereated by IEC2C
   677             # This regular expression parses the lines genereated by IEC2C
   678             LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWDL]))?,(?P<LOC>[,0-9]*)\)")
   678             LOCATED_MODEL = re.compile("__LOCATED_VAR\((?P<IEC_TYPE>[A-Z]*),(?P<NAME>[_A-Za-z0-9]*),(?P<DIR>[QMI])(?:,(?P<SIZE>[XBWDL]))?,(?P<LOC>[,0-9]*)\)")
   679             for line in lines:
   679             for line in lines:
   681                 result = LOCATED_MODEL.match(line)
   681                 result = LOCATED_MODEL.match(line)
   682                 if result:
   682                 if result:
   683                     # Get the resulting dict
   683                     # Get the resulting dict
   684                     resdict = result.groupdict()
   684                     resdict = result.groupdict()
   685                     # rewrite string for variadic location as a tuple of integers
   685                     # rewrite string for variadic location as a tuple of integers
   686                     resdict['LOC'] = tuple(map(int,resdict['LOC'].split(',')))
   686                     resdict['LOC'] = tuple(map(int, resdict['LOC'].split(',')))
   687                     # set located size to 'X' if not given
   687                     # set located size to 'X' if not given
   688                     if not resdict['SIZE']:
   688                     if not resdict['SIZE']:
   689                         resdict['SIZE'] = 'X'
   689                         resdict['SIZE'] = 'X'
   690                     # finally store into located variable list
   690                     # finally store into located variable list
   691                     locations.append(resdict)
   691                     locations.append(resdict)
   750 
   750 
   751         try:
   751         try:
   752             # Invoke compiler. Output files are listed to stdout, errors to stderr
   752             # Invoke compiler. Output files are listed to stdout, errors to stderr
   753             status, result, err_result = ProcessLogger(self.logger, buildcmd,
   753             status, result, err_result = ProcessLogger(self.logger, buildcmd,
   754                 no_stdout=True, no_stderr=True).spin()
   754                 no_stdout=True, no_stderr=True).spin()
   755         except Exception,e:
   755         except Exception, e:
   756             self.logger.write_error(buildcmd + "\n")
   756             self.logger.write_error(buildcmd + "\n")
   757             self.logger.write_error(repr(e) + "\n")
   757             self.logger.write_error(repr(e) + "\n")
   758             return False
   758             return False
   759 
   759 
   760         if status:
   760         if status:
   795         C_files.remove("POUS.c")
   795         C_files.remove("POUS.c")
   796         if not C_files:
   796         if not C_files:
   797             self.logger.write_error(_("Error : At least one configuration and one resource must be declared in PLC !\n"))
   797             self.logger.write_error(_("Error : At least one configuration and one resource must be declared in PLC !\n"))
   798             return False
   798             return False
   799         # transform those base names to full names with path
   799         # transform those base names to full names with path
   800         C_files = map(lambda filename:os.path.join(buildpath, filename), C_files)
   800         C_files = map(lambda filename: os.path.join(buildpath, filename), C_files)
   801 
   801 
   802         # prepend beremiz include to configuration header
   802         # prepend beremiz include to configuration header
   803         H_files = [ fname for fname in result.splitlines() if fname[-2:]==".h" or fname[-2:]==".H" ]
   803         H_files = [ fname for fname in result.splitlines() if fname[-2:]==".h" or fname[-2:]==".H" ]
   804         H_files.remove("LOCATED_VARIABLES.h")
   804         H_files.remove("LOCATED_VARIABLES.h")
   805         H_files = map(lambda filename:os.path.join(buildpath, filename), H_files)
   805         H_files = map(lambda filename: os.path.join(buildpath, filename), H_files)
   806         for H_file in H_files:
   806         for H_file in H_files:
   807             with file(H_file, 'r') as original: data = original.read()
   807             with file(H_file, 'r') as original: data = original.read()
   808             with file(H_file, 'w') as modified: modified.write('#include "beremiz.h"\n' + data)
   808             with file(H_file, 'w') as modified: modified.write('#include "beremiz.h"\n' + data)
   809 
   809 
   810         self.logger.write(_("Extracting Located Variables...\n"))
   810         self.logger.write(_("Extracting Located Variables...\n"))
   823         # Get target, module and class name
   823         # Get target, module and class name
   824         targetname = self.GetTarget().getcontent().getLocalTag()
   824         targetname = self.GetTarget().getcontent().getLocalTag()
   825         targetclass = targets.GetBuilder(targetname)
   825         targetclass = targets.GetBuilder(targetname)
   826 
   826 
   827         # if target already
   827         # if target already
   828         if self._builder is None or not isinstance(self._builder,targetclass):
   828         if self._builder is None or not isinstance(self._builder, targetclass):
   829             # Get classname instance
   829             # Get classname instance
   830             self._builder = targetclass(self)
   830             self._builder = targetclass(self)
   831         return self._builder
   831         return self._builder
   832 
   832 
   833     def ResetBuildMD5(self):
   833     def ResetBuildMD5(self):
   881         Each section is marked with a line staring with '//'
   881         Each section is marked with a line staring with '//'
   882         list of all variables used in various POUs
   882         list of all variables used in various POUs
   883         """
   883         """
   884         if self._ProgramList is None or self._VariablesList is None:
   884         if self._ProgramList is None or self._VariablesList is None:
   885             try:
   885             try:
   886                 csvfile = os.path.join(self._getBuildPath(),"VARIABLES.csv")
   886                 csvfile = os.path.join(self._getBuildPath(), "VARIABLES.csv")
   887                 # describes CSV columns
   887                 # describes CSV columns
   888                 ProgramsListAttributeName = ["num", "C_path", "type"]
   888                 ProgramsListAttributeName = ["num", "C_path", "type"]
   889                 VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
   889                 VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
   890                 self._ProgramList = []
   890                 self._ProgramList = []
   891                 self._VariablesList = []
   891                 self._VariablesList = []
   892                 self._DbgVariablesList = []
   892                 self._DbgVariablesList = []
   893                 self._IECPathToIdx = {}
   893                 self._IECPathToIdx = {}
   894 
   894 
   895                 # Separate sections
   895                 # Separate sections
   896                 ListGroup = []
   896                 ListGroup = []
   897                 for line in open(csvfile,'r').xreadlines():
   897                 for line in open(csvfile, 'r').xreadlines():
   898                     strippedline = line.strip()
   898                     strippedline = line.strip()
   899                     if strippedline.startswith("//"):
   899                     if strippedline.startswith("//"):
   900                         # Start new section
   900                         # Start new section
   901                         ListGroup.append([])
   901                         ListGroup.append([])
   902                     elif len(strippedline) > 0 and len(ListGroup) > 0:
   902                     elif len(strippedline) > 0 and len(ListGroup) > 0:
   904                         ListGroup[-1].append(strippedline)
   904                         ListGroup[-1].append(strippedline)
   905 
   905 
   906                 # first section contains programs
   906                 # first section contains programs
   907                 for line in ListGroup[0]:
   907                 for line in ListGroup[0]:
   908                     # Split and Maps each field to dictionnary entries
   908                     # Split and Maps each field to dictionnary entries
   909                     attrs = dict(zip(ProgramsListAttributeName,line.strip().split(';')))
   909                     attrs = dict(zip(ProgramsListAttributeName, line.strip().split(';')))
   910                     # Truncate "C_path" to remove conf an resources names
   910                     # Truncate "C_path" to remove conf an resources names
   911                     attrs["C_path"] = '__'.join(attrs["C_path"].split(".",2)[1:])
   911                     attrs["C_path"] = '__'.join(attrs["C_path"].split(".", 2)[1:])
   912                     # Push this dictionnary into result.
   912                     # Push this dictionnary into result.
   913                     self._ProgramList.append(attrs)
   913                     self._ProgramList.append(attrs)
   914 
   914 
   915                 # second section contains all variables
   915                 # second section contains all variables
   916                 config_FBs = {}
   916                 config_FBs = {}
   917                 Idx = 0
   917                 Idx = 0
   918                 for line in ListGroup[1]:
   918                 for line in ListGroup[1]:
   919                     # Split and Maps each field to dictionnary entries
   919                     # Split and Maps each field to dictionnary entries
   920                     attrs = dict(zip(VariablesListAttributeName,line.strip().split(';')))
   920                     attrs = dict(zip(VariablesListAttributeName, line.strip().split(';')))
   921                     # Truncate "C_path" to remove conf an resources names
   921                     # Truncate "C_path" to remove conf an resources names
   922                     parts = attrs["C_path"].split(".",2)
   922                     parts = attrs["C_path"].split(".", 2)
   923                     if len(parts) > 2:
   923                     if len(parts) > 2:
   924                         config_FB = config_FBs.get(tuple(parts[:2]))
   924                         config_FB = config_FBs.get(tuple(parts[:2]))
   925                         if config_FB:
   925                         if config_FB:
   926                             parts = [config_FB] + parts[2:]
   926                             parts = [config_FB] + parts[2:]
   927                             attrs["C_path"] = '.'.join(parts)
   927                             attrs["C_path"] = '.'.join(parts)
   945 
   945 
   946                 # third section contains ticktime
   946                 # third section contains ticktime
   947                 if len(ListGroup) > 2:
   947                 if len(ListGroup) > 2:
   948                     self._Ticktime = int(ListGroup[2][0])
   948                     self._Ticktime = int(ListGroup[2][0])
   949 
   949 
   950             except Exception,e:
   950             except Exception, e:
   951                 self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
   951                 self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
   952                 self.logger.write_error(traceback.format_exc())
   952                 self.logger.write_error(traceback.format_exc())
   953                 self.ResetIECProgramsAndVariables()
   953                 self.ResetIECProgramsAndVariables()
   954                 return False
   954                 return False
   955 
   955 
   966         bofs = 0
   966         bofs = 0
   967         for v in self._DbgVariablesList:
   967         for v in self._DbgVariablesList:
   968             sz = DebugTypesSize.get(v["type"], 0)
   968             sz = DebugTypesSize.get(v["type"], 0)
   969             variable_decl_array += [
   969             variable_decl_array += [
   970                 "{&(%(C_path)s), " % v+
   970                 "{&(%(C_path)s), " % v+
   971                 {"EXT":"%(type)s_P_ENUM",
   971                 {
   972                  "IN":"%(type)s_P_ENUM",
   972                     "EXT": "%(type)s_P_ENUM",
   973                  "MEM":"%(type)s_O_ENUM",
   973                     "IN":  "%(type)s_P_ENUM",
   974                  "OUT":"%(type)s_O_ENUM",
   974                     "MEM": "%(type)s_O_ENUM",
   975                  "VAR":"%(type)s_ENUM"}[v["vartype"]] % v +
   975                     "OUT": "%(type)s_O_ENUM",
   976                  "}"]
   976                     "VAR": "%(type)s_ENUM"
       
   977                 }[v["vartype"]] % v +
       
   978                 "}"]
   977             bofs += sz
   979             bofs += sz
   978         debug_code = targets.GetCode("plc_debug.c") % {
   980         debug_code = targets.GetCode("plc_debug.c") % {
   979            "buffer_size":bofs,
   981            "buffer_size": bofs,
   980            "programs_declarations":
   982            "programs_declarations":
   981                "\n".join(["extern %(type)s %(C_path)s;" % p for p in self._ProgramList]),
   983                "\n".join(["extern %(type)s %(C_path)s;" % p for p in self._ProgramList]),
   982            "extern_variables_declarations":"\n".join([
   984            "extern_variables_declarations": "\n".join([
   983               {"EXT":"extern __IEC_%(type)s_p %(C_path)s;",
   985               {
   984                "IN":"extern __IEC_%(type)s_p %(C_path)s;",
   986                   "EXT": "extern __IEC_%(type)s_p %(C_path)s;",
   985                "MEM":"extern __IEC_%(type)s_p %(C_path)s;",
   987                   "IN":  "extern __IEC_%(type)s_p %(C_path)s;",
   986                "OUT":"extern __IEC_%(type)s_p %(C_path)s;",
   988                   "MEM": "extern __IEC_%(type)s_p %(C_path)s;",
   987                "VAR":"extern __IEC_%(type)s_t %(C_path)s;",
   989                   "OUT": "extern __IEC_%(type)s_p %(C_path)s;",
   988                "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]] % v
   990                   "VAR": "extern __IEC_%(type)s_t %(C_path)s;",
       
   991                   "FB":  "extern       %(type)s   %(C_path)s;"
       
   992               }[v["vartype"]] % v
   989                for v in self._VariablesList if v["C_path"].find('.')<0]),
   993                for v in self._VariablesList if v["C_path"].find('.')<0]),
   990            "variable_decl_array": ",\n".join(variable_decl_array)
   994            "variable_decl_array": ",\n".join(variable_decl_array)
   991            }
   995            }
   992 
   996 
   993         return debug_code
   997         return debug_code
   997         Use confnodes layout given in LocationCFilesAndCFLAGS to
  1001         Use confnodes layout given in LocationCFilesAndCFLAGS to
   998         generate glue code that dispatch calls to all confnodes
  1002         generate glue code that dispatch calls to all confnodes
   999         """
  1003         """
  1000         # filter location that are related to code that will be called
  1004         # filter location that are related to code that will be called
  1001         # in retreive, publish, init, cleanup
  1005         # in retreive, publish, init, cleanup
  1002         locstrs = map(lambda x:"_".join(map(str,x)),
  1006         locstrs = map(lambda x: "_".join(map(str, x)),
  1003            [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
  1007            [loc for loc, Cfiles, DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
  1004 
  1008 
  1005         # Generate main, based on template
  1009         # Generate main, based on template
  1006         if not self.BeremizRoot.getDisable_Extensions():
  1010         if not self.BeremizRoot.getDisable_Extensions():
  1007             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1011             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1008                 "calls_prototypes":"\n".join([(
  1012                 "calls_prototypes": "\n".join([(
  1009                       "int __init_%(s)s(int argc,char **argv);\n"+
  1013                       "int __init_%(s)s(int argc,char **argv);\n"+
  1010                       "void __cleanup_%(s)s(void);\n"+
  1014                       "void __cleanup_%(s)s(void);\n"+
  1011                       "void __retrieve_%(s)s(void);\n"+
  1015                       "void __retrieve_%(s)s(void);\n"+
  1012                       "void __publish_%(s)s(void);") % {'s':locstr} for locstr in locstrs]),
  1016                       "void __publish_%(s)s(void);") % {'s': locstr} for locstr in locstrs]),
  1013                 "retrieve_calls":"\n    ".join([
  1017                 "retrieve_calls": "\n    ".join([
  1014                       "__retrieve_%s();" % locstr for locstr in locstrs]),
  1018                       "__retrieve_%s();" % locstr for locstr in locstrs]),
  1015                 "publish_calls":"\n    ".join([  #Call publish in reverse order
  1019                 "publish_calls": "\n    ".join([  # Call publish in reverse order
  1016                       "__publish_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
  1020                       "__publish_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
  1017                 "init_calls":"\n    ".join([
  1021                 "init_calls": "\n    ".join([
  1018                       "init_level=%d; " % (i+1)+
  1022                       "init_level=%d; " % (i+1)+
  1019                       "if((res = __init_%s(argc,argv))){" % locstr +
  1023                       "if((res = __init_%s(argc,argv))){" % locstr +
  1020                       #"printf(\"%s\"); "%locstr + #for debug
  1024                       #"printf(\"%s\"); "%locstr + #for debug
  1021                       "return res;}" for i,locstr in enumerate(locstrs)]),
  1025                       "return res;}" for i, locstr in enumerate(locstrs)]),
  1022                 "cleanup_calls":"\n    ".join([
  1026                 "cleanup_calls": "\n    ".join([
  1023                       "if(init_level >= %d) " % i+
  1027                       "if(init_level >= %d) " % i+
  1024                       "__cleanup_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
  1028                       "__cleanup_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
  1025                 }
  1029                 }
  1026         else:
  1030         else:
  1027             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1031             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1028                 "calls_prototypes":"\n",
  1032                 "calls_prototypes": "\n",
  1029                 "retrieve_calls":"\n",
  1033                 "retrieve_calls":   "\n",
  1030                 "publish_calls":"\n",
  1034                 "publish_calls":    "\n",
  1031                 "init_calls":"\n",
  1035                 "init_calls":       "\n",
  1032                 "cleanup_calls":"\n"
  1036                 "cleanup_calls":    "\n"
  1033                 }
  1037             }
  1034         plc_main_code += targets.GetTargetCode(self.GetTarget().getcontent().getLocalTag())
  1038         plc_main_code += targets.GetTargetCode(self.GetTarget().getcontent().getLocalTag())
  1035         plc_main_code += targets.GetCode("plc_main_tail.c")
  1039         plc_main_code += targets.GetCode("plc_main_tail.c")
  1036         return plc_main_code
  1040         return plc_main_code
  1037 
  1041 
  1038 
  1042 
  1128         if os.path.exists(extrafilespath):
  1132         if os.path.exists(extrafilespath):
  1129             shutil.rmtree(extrafilespath)
  1133             shutil.rmtree(extrafilespath)
  1130         # Recreate directory
  1134         # Recreate directory
  1131         os.mkdir(extrafilespath)
  1135         os.mkdir(extrafilespath)
  1132         # Then write the files
  1136         # Then write the files
  1133         for fname,fobject in ExtraFiles:
  1137         for fname, fobject in ExtraFiles:
  1134             fpath = os.path.join(extrafilespath,fname)
  1138             fpath = os.path.join(extrafilespath, fname)
  1135             open(fpath, "wb").write(fobject.read())
  1139             open(fpath, "wb").write(fobject.read())
  1136         # Now we can forget ExtraFiles (will close files object)
  1140         # Now we can forget ExtraFiles (will close files object)
  1137         del ExtraFiles
  1141         del ExtraFiles
  1138 
  1142 
  1139         # Header file for extensions
  1143         # Header file for extensions
  1140         open(os.path.join(buildpath,"beremiz.h"), "w").write(targets.GetHeader())
  1144         open(os.path.join(buildpath, "beremiz.h"), "w").write(targets.GetHeader())
  1141 
  1145 
  1142         # Template based part of C code generation
  1146         # Template based part of C code generation
  1143         # files are stacked at the beginning, as files of confnode tree root
  1147         # files are stacked at the beginning, as files of confnode tree root
  1144         for generator, filename, name in [
  1148         for generator, filename, name in [
  1145            # debugger code
  1149            # debugger code
  1146            (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
  1150            (self.Generate_plc_debugger, "plc_debugger.c", "Debugger"),
  1147            # init/cleanup/retrieve/publish, run and align code
  1151            # init/cleanup/retrieve/publish, run and align code
  1148            (self.Generate_plc_main,"plc_main.c","Common runtime")]:
  1152            (self.Generate_plc_main, "plc_main.c", "Common runtime")]:
  1149             try:
  1153             try:
  1150                 # Do generate
  1154                 # Do generate
  1151                 code = generator()
  1155                 code = generator()
  1152                 if code is None:
  1156                 if code is None:
  1153                      raise
  1157                      raise
  1154                 code_path = os.path.join(buildpath,filename)
  1158                 code_path = os.path.join(buildpath, filename)
  1155                 open(code_path, "w").write(code)
  1159                 open(code_path, "w").write(code)
  1156                 # Insert this file as first file to be compiled at root confnode
  1160                 # Insert this file as first file to be compiled at root confnode
  1157                 self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS))
  1161                 self.LocationCFilesAndCFLAGS[0][1].insert(0, (code_path, self.plcCFLAGS))
  1158             except Exception, exc:
  1162             except Exception, exc:
  1159                 self.logger.write_error(name+_(" generation failed !\n"))
  1163                 self.logger.write_error(name+_(" generation failed !\n"))
  1160                 self.logger.write_error(traceback.format_exc())
  1164                 self.logger.write_error(traceback.format_exc())
  1161                 self.ResetBuildMD5()
  1165                 self.ResetBuildMD5()
  1162                 return False
  1166                 return False
  1334         if status is None:
  1338         if status is None:
  1335             self._SetConnector(None, False)
  1339             self._SetConnector(None, False)
  1336             status = "Disconnected"
  1340             status = "Disconnected"
  1337         if(self.previous_plcstate != status):
  1341         if(self.previous_plcstate != status):
  1338             for args in {
  1342             for args in {
  1339                      "Started":     [("_Run", False),
  1343                     "Started":      [("_Run", False),
  1340                                      ("_Stop", True)],
  1344                                      ("_Stop", True)],
  1341                      "Stopped":     [("_Run", True),
  1345                     "Stopped":      [("_Run", True),
  1342                                      ("_Stop", False)],
  1346                                      ("_Stop", False)],
  1343                      "Empty":       [("_Run", False),
  1347                     "Empty":        [("_Run", False),
  1344                                      ("_Stop", False)],
  1348                                      ("_Stop", False)],
  1345                      "Broken":      [],
  1349                     "Broken":       [],
  1346                      "Disconnected":[("_Run", False),
  1350                     "Disconnected": [("_Run", False),
  1347                                      ("_Stop", False),
  1351                                      ("_Stop", False),
  1348                                      ("_Transfer", False),
  1352                                      ("_Transfer", False),
  1349                                      ("_Connect", True),
  1353                                      ("_Connect", True),
  1350                                      ("_Disconnect", False)],
  1354                                      ("_Disconnect", False)],
  1351                    }.get(status,[]):
  1355             }.get(status, []):
  1352                 self.ShowMethod(*args)
  1356                 self.ShowMethod(*args)
  1353             self.previous_plcstate = status
  1357             self.previous_plcstate = status
  1354             if self.AppFrame is not None:
  1358             if self.AppFrame is not None:
  1355                 updated = True
  1359                 updated = True
  1356                 self.AppFrame.RefreshStatusToolBar()
  1360                 self.AppFrame.RefreshStatusToolBar()
  1400         self.TracedIECPath = []
  1404         self.TracedIECPath = []
  1401         self.TracedIECTypes = []
  1405         self.TracedIECTypes = []
  1402         if self._connector is not None:
  1406         if self._connector is not None:
  1403             self.IECdebug_lock.acquire()
  1407             self.IECdebug_lock.acquire()
  1404             IECPathsToPop = []
  1408             IECPathsToPop = []
  1405             for IECPath,data_tuple in self.IECdebug_datas.iteritems():
  1409             for IECPath, data_tuple in self.IECdebug_datas.iteritems():
  1406                 WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1410                 WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1407                 if len(WeakCallableDict) == 0:
  1411                 if len(WeakCallableDict) == 0:
  1408                     # Callable Dict is empty.
  1412                     # Callable Dict is empty.
  1409                     # This variable is not needed anymore!
  1413                     # This variable is not needed anymore!
  1410                     IECPathsToPop.append(IECPath)
  1414                     IECPathsToPop.append(IECPath)
  1411                 elif IECPath != "__tick__":
  1415                 elif IECPath != "__tick__":
  1412                     # Convert
  1416                     # Convert
  1413                     Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
  1417                     Idx, IEC_Type = self._IECPathToIdx.get(IECPath, (None, None))
  1414                     if Idx is not None:
  1418                     if Idx is not None:
  1415                         if IEC_Type in DebugTypesSize:
  1419                         if IEC_Type in DebugTypesSize:
  1416                             Idxs.append((Idx, IEC_Type, fvalue, IECPath))
  1420                             Idxs.append((Idx, IEC_Type, fvalue, IECPath))
  1417                         else:
  1421                         else:
  1418                             self.logger.write_warning(_("Debug: Unsupported type to debug '%s'\n") % IEC_Type)
  1422                             self.logger.write_warning(_("Debug: Unsupported type to debug '%s'\n") % IEC_Type)
  1444         # If an output location var is forced it's leads to segmentation fault in runtime
  1448         # If an output location var is forced it's leads to segmentation fault in runtime
  1445         # Links between PLC located variables and real variables are not ready
  1449         # Links between PLC located variables and real variables are not ready
  1446         if self.IsPLCStarted():
  1450         if self.IsPLCStarted():
  1447             # Timer to prevent rapid-fire when registering many variables
  1451             # Timer to prevent rapid-fire when registering many variables
  1448             # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
  1452             # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
  1449             self.DebugTimer=Timer(0.5,wx.CallAfter,args = [self.RegisterDebugVarToConnector])
  1453             self.DebugTimer=Timer(0.5, wx.CallAfter, args = [self.RegisterDebugVarToConnector])
  1450             # Rearm anti-rapid-fire timer
  1454             # Rearm anti-rapid-fire timer
  1451             self.DebugTimer.start()
  1455             self.DebugTimer.start()
  1452 
  1456 
  1453     def GetDebugIECVariableType(self, IECPath):
  1457     def GetDebugIECVariableType(self, IECPath):
  1454         Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
  1458         Idx, IEC_Type = self._IECPathToIdx.get(IECPath, (None, None))
  1455         return IEC_Type
  1459         return IEC_Type
  1456 
  1460 
  1457     def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False):
  1461     def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False):
  1458         """
  1462         """
  1459         Dispatching use a dictionnary linking IEC variable paths
  1463         Dispatching use a dictionnary linking IEC variable paths
  1487 
  1491 
  1488     def UnsubscribeDebugIECVariable(self, IECPath, callableobj):
  1492     def UnsubscribeDebugIECVariable(self, IECPath, callableobj):
  1489         self.IECdebug_lock.acquire()
  1493         self.IECdebug_lock.acquire()
  1490         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1494         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1491         if IECdebug_data is not None:
  1495         if IECdebug_data is not None:
  1492             IECdebug_data[0].pop(callableobj,None)
  1496             IECdebug_data[0].pop(callableobj, None)
  1493             if len(IECdebug_data[0]) == 0:
  1497             if len(IECdebug_data[0]) == 0:
  1494                 self.IECdebug_datas.pop(IECPath)
  1498                 self.IECdebug_datas.pop(IECPath)
  1495             else:
  1499             else:
  1496                 IECdebug_data[4] = reduce(
  1500                 IECdebug_data[4] = reduce(
  1497                     lambda x, y: x|y,
  1501                     lambda x, y: x|y,
  1541     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1545     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1542         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1546         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1543         if data_tuple is not None:
  1547         if data_tuple is not None:
  1544             WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1548             WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1545             #data_log.append((debug_tick, value))
  1549             #data_log.append((debug_tick, value))
  1546             for weakcallable,buffer_list in WeakCallableDict.iteritems():
  1550             for weakcallable, buffer_list in WeakCallableDict.iteritems():
  1547                 function = getattr(weakcallable, function_name, None)
  1551                 function = getattr(weakcallable, function_name, None)
  1548                 if function is not None:
  1552                 if function is not None:
  1549                     if buffer_list:
  1553                     if buffer_list:
  1550                         function(*cargs)
  1554                         function(*cargs)
  1551                     else:
  1555                     else:
  1754             else:
  1758             else:
  1755                 status = ""
  1759                 status = ""
  1756 
  1760 
  1757             #self.logger.write(_("PLC is %s\n")%status)
  1761             #self.logger.write(_("PLC is %s\n")%status)
  1758 
  1762 
  1759             if self.previous_plcstate in ["Started","Stopped"]:
  1763             if self.previous_plcstate in ["Started", "Stopped"]:
  1760                 if self.DebugAvailable() and self.GetIECProgramsAndVariables():
  1764                 if self.DebugAvailable() and self.GetIECProgramsAndVariables():
  1761                     self.logger.write(_("Debugger ready\n"))
  1765                     self.logger.write(_("Debugger ready\n"))
  1762                     self._connect_debug()
  1766                     self._connect_debug()
  1763                 else:
  1767                 else:
  1764                     self.logger.write_warning(_("Debug does not match PLC - stop/transfert/start to re-enable\n"))
  1768                     self.logger.write_warning(_("Debug does not match PLC - stop/transfert/start to re-enable\n"))