ProjectController.py
changeset 1742 92932cd370a4
parent 1741 dd94b9a68c61
child 1744 69dfdb26f600
equal deleted inserted replaced
1741:dd94b9a68c61 1742:92932cd370a4
    99         self.iec2c_buildopts = None
    99         self.iec2c_buildopts = None
   100         self.ieclib_path   = self.findLibPath()
   100         self.ieclib_path   = self.findLibPath()
   101         self.ieclib_c_path = self.findLibCPath()
   101         self.ieclib_c_path = self.findLibCPath()
   102 
   102 
   103     def findObject(self, paths, test):
   103     def findObject(self, paths, test):
   104         path=None
   104         path = None
   105         for p in paths:
   105         for p in paths:
   106             if test(p):
   106             if test(p):
   107                 path = p
   107                 path = p
   108                 break
   108                 break
   109         return path
   109         return path
   110 
   110 
   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 
   122         return cmd
   122         return cmd
   123 
   123 
   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"]
   143 
   143 
   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,
   202                 </xsd:choice>
   202                 </xsd:choice>
   203               </xsd:complexType>
   203               </xsd:complexType>
   204             </xsd:element>"""+(("""
   204             </xsd:element>"""+(("""
   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"/>
   216         </xsd:complexType>
   216         </xsd:complexType>
   217       </xsd:element>
   217       </xsd:element>
   232 
   232 
   233         # Setup debug information
   233         # Setup debug information
   234         self.IECdebug_datas = {}
   234         self.IECdebug_datas = {}
   235         self.IECdebug_lock = Lock()
   235         self.IECdebug_lock = Lock()
   236 
   236 
   237         self.DebugTimer=None
   237         self.DebugTimer = None
   238         self.ResetIECProgramsAndVariables()
   238         self.ResetIECProgramsAndVariables()
   239 
   239 
   240         # In both new or load scenario, no need to save
   240         # In both new or load scenario, no need to save
   241         self.ChangesToSave = False
   241         self.ChangesToSave = False
   242         # root have no parent
   242         # root have no parent
   259             self.DebugTimer.cancel()
   259             self.DebugTimer.cancel()
   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)
   566 
   566 
   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):
   786 
   786 
   787             self.logger.write_error(_("Error : IEC to C compiler returned %d\n") % status)
   787             self.logger.write_error(_("Error : IEC to C compiler returned %d\n") % status)
   788             return False
   788             return False
   789 
   789 
   790         # Now extract C files of stdout
   790         # Now extract C files of stdout
   791         C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ]
   791         C_files = [ fname for fname in result.splitlines() if fname[-2:] == ".c" or fname[-2:] == ".C" ]
   792         # remove those that are not to be compiled because included by others
   792         # remove those that are not to be compiled because included by others
   793         C_files.remove("POUS.c")
   793         C_files.remove("POUS.c")
   794         if not C_files:
   794         if not C_files:
   795             self.logger.write_error(_("Error : At least one configuration and one resource must be declared in PLC !\n"))
   795             self.logger.write_error(_("Error : At least one configuration and one resource must be declared in PLC !\n"))
   796             return False
   796             return False
   797         # transform those base names to full names with path
   797         # transform those base names to full names with path
   798         C_files = map(lambda filename: os.path.join(buildpath, filename), C_files)
   798         C_files = map(lambda filename: os.path.join(buildpath, filename), C_files)
   799 
   799 
   800         # prepend beremiz include to configuration header
   800         # prepend beremiz include to configuration header
   801         H_files = [ fname for fname in result.splitlines() if fname[-2:]==".h" or fname[-2:]==".H" ]
   801         H_files = [ fname for fname in result.splitlines() if fname[-2:] == ".h" or fname[-2:] == ".H" ]
   802         H_files.remove("LOCATED_VARIABLES.h")
   802         H_files.remove("LOCATED_VARIABLES.h")
   803         H_files = map(lambda filename: os.path.join(buildpath, filename), H_files)
   803         H_files = map(lambda filename: os.path.join(buildpath, filename), H_files)
   804         for H_file in H_files:
   804         for H_file in H_files:
   805             with file(H_file, 'r') as original: data = original.read()
   805             with file(H_file, 'r') as original: data = original.read()
   806             with file(H_file, 'w') as modified: modified.write('#include "beremiz.h"\n' + data)
   806             with file(H_file, 'w') as modified: modified.write('#include "beremiz.h"\n' + data)
   827             # Get classname instance
   827             # Get classname instance
   828             self._builder = targetclass(self)
   828             self._builder = targetclass(self)
   829         return self._builder
   829         return self._builder
   830 
   830 
   831     def ResetBuildMD5(self):
   831     def ResetBuildMD5(self):
   832         builder=self.GetBuilder()
   832         builder = self.GetBuilder()
   833         if builder is not None:
   833         if builder is not None:
   834             builder.ResetBinaryCodeMD5()
   834             builder.ResetBinaryCodeMD5()
   835         self.EnableMethod("_Transfer", False)
   835         self.EnableMethod("_Transfer", False)
   836 
   836 
   837     def GetLastBuildMD5(self):
   837     def GetLastBuildMD5(self):
   838         builder=self.GetBuilder()
   838         builder = self.GetBuilder()
   839         if builder is not None:
   839         if builder is not None:
   840             return builder.GetBinaryCodeMD5()
   840             return builder.GetBinaryCodeMD5()
   841         else:
   841         else:
   842             return None
   842             return None
   843 
   843 
   931                             config_FBs[tuple(parts)] = attrs["C_path"]
   931                             config_FBs[tuple(parts)] = attrs["C_path"]
   932                     if attrs["vartype"] != "FB" and attrs["type"] in DebugTypesSize:
   932                     if attrs["vartype"] != "FB" and attrs["type"] in DebugTypesSize:
   933                         # Push this dictionnary into result.
   933                         # Push this dictionnary into result.
   934                         self._DbgVariablesList.append(attrs)
   934                         self._DbgVariablesList.append(attrs)
   935                         # Fill in IEC<->C translation dicts
   935                         # Fill in IEC<->C translation dicts
   936                         IEC_path=attrs["IEC_path"]
   936                         IEC_path = attrs["IEC_path"]
   937                         self._IECPathToIdx[IEC_path]=(Idx, attrs["type"])
   937                         self._IECPathToIdx[IEC_path] = (Idx, attrs["type"])
   938                         # Ignores numbers given in CSV file
   938                         # Ignores numbers given in CSV file
   939                         # Idx=int(attrs["num"])
   939                         # Idx=int(attrs["num"])
   940                         # Count variables only, ignore FBs
   940                         # Count variables only, ignore FBs
   941                         Idx+=1
   941                         Idx += 1
   942                     self._VariablesList.append(attrs)
   942                     self._VariablesList.append(attrs)
   943 
   943 
   944                 # third section contains ticktime
   944                 # third section contains ticktime
   945                 if len(ListGroup) > 2:
   945                 if len(ListGroup) > 2:
   946                     self._Ticktime = int(ListGroup[2][0])
   946                     self._Ticktime = int(ListGroup[2][0])
   963         variable_decl_array = []
   963         variable_decl_array = []
   964         bofs = 0
   964         bofs = 0
   965         for v in self._DbgVariablesList:
   965         for v in self._DbgVariablesList:
   966             sz = DebugTypesSize.get(v["type"], 0)
   966             sz = DebugTypesSize.get(v["type"], 0)
   967             variable_decl_array += [
   967             variable_decl_array += [
   968                 "{&(%(C_path)s), " % v+
   968                 "{&(%(C_path)s), " % v +
   969                 {
   969                 {
   970                     "EXT": "%(type)s_P_ENUM",
   970                     "EXT": "%(type)s_P_ENUM",
   971                     "IN":  "%(type)s_P_ENUM",
   971                     "IN":  "%(type)s_P_ENUM",
   972                     "MEM": "%(type)s_O_ENUM",
   972                     "MEM": "%(type)s_O_ENUM",
   973                     "OUT": "%(type)s_O_ENUM",
   973                     "OUT": "%(type)s_O_ENUM",
   986                   "MEM": "extern __IEC_%(type)s_p %(C_path)s;",
   986                   "MEM": "extern __IEC_%(type)s_p %(C_path)s;",
   987                   "OUT": "extern __IEC_%(type)s_p %(C_path)s;",
   987                   "OUT": "extern __IEC_%(type)s_p %(C_path)s;",
   988                   "VAR": "extern __IEC_%(type)s_t %(C_path)s;",
   988                   "VAR": "extern __IEC_%(type)s_t %(C_path)s;",
   989                   "FB":  "extern       %(type)s   %(C_path)s;"
   989                   "FB":  "extern       %(type)s   %(C_path)s;"
   990               }[v["vartype"]] % v
   990               }[v["vartype"]] % v
   991                for v in self._VariablesList if v["C_path"].find('.')<0]),
   991                for v in self._VariablesList if v["C_path"].find('.') < 0]),
   992            "variable_decl_array": ",\n".join(variable_decl_array)
   992            "variable_decl_array": ",\n".join(variable_decl_array)
   993            }
   993            }
   994 
   994 
   995         return debug_code
   995         return debug_code
   996 
   996 
  1006 
  1006 
  1007         # Generate main, based on template
  1007         # Generate main, based on template
  1008         if not self.BeremizRoot.getDisable_Extensions():
  1008         if not self.BeremizRoot.getDisable_Extensions():
  1009             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1009             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1010                 "calls_prototypes": "\n".join([(
  1010                 "calls_prototypes": "\n".join([(
  1011                       "int __init_%(s)s(int argc,char **argv);\n"+
  1011                       "int __init_%(s)s(int argc,char **argv);\n" +
  1012                       "void __cleanup_%(s)s(void);\n"+
  1012                       "void __cleanup_%(s)s(void);\n" +
  1013                       "void __retrieve_%(s)s(void);\n"+
  1013                       "void __retrieve_%(s)s(void);\n" +
  1014                       "void __publish_%(s)s(void);") % {'s': locstr} for locstr in locstrs]),
  1014                       "void __publish_%(s)s(void);") % {'s': locstr} for locstr in locstrs]),
  1015                 "retrieve_calls": "\n    ".join([
  1015                 "retrieve_calls": "\n    ".join([
  1016                       "__retrieve_%s();" % locstr for locstr in locstrs]),
  1016                       "__retrieve_%s();" % locstr for locstr in locstrs]),
  1017                 "publish_calls": "\n    ".join([  # Call publish in reverse order
  1017                 "publish_calls": "\n    ".join([  # Call publish in reverse order
  1018                       "__publish_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
  1018                       "__publish_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)]),
  1019                 "init_calls": "\n    ".join([
  1019                 "init_calls": "\n    ".join([
  1020                       "init_level=%d; " % (i+1)+
  1020                       "init_level=%d; " % (i+1) +
  1021                       "if((res = __init_%s(argc,argv))){" % locstr +
  1021                       "if((res = __init_%s(argc,argv))){" % locstr +
  1022                       #"printf(\"%s\"); "%locstr + #for debug
  1022                       #"printf(\"%s\"); "%locstr + #for debug
  1023                       "return res;}" for i, locstr in enumerate(locstrs)]),
  1023                       "return res;}" for i, locstr in enumerate(locstrs)]),
  1024                 "cleanup_calls": "\n    ".join([
  1024                 "cleanup_calls": "\n    ".join([
  1025                       "if(init_level >= %d) " % i+
  1025                       "if(init_level >= %d) " % i +
  1026                       "__cleanup_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
  1026                       "__cleanup_%s();" % locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
  1027                 }
  1027                 }
  1028         else:
  1028         else:
  1029             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1029             plc_main_code = targets.GetCode("plc_main_head.c") % {
  1030                 "calls_prototypes": "\n",
  1030                 "calls_prototypes": "\n",
  1393             [list() for n in xrange(len(self.TracedIECPath))])
  1393             [list() for n in xrange(len(self.TracedIECPath))])
  1394         ticks, self.DebugTicks = self.DebugTicks, []
  1394         ticks, self.DebugTicks = self.DebugTicks, []
  1395         return ticks, buffers
  1395         return ticks, buffers
  1396 
  1396 
  1397     def RegisterDebugVarToConnector(self):
  1397     def RegisterDebugVarToConnector(self):
  1398         self.DebugTimer=None
  1398         self.DebugTimer = None
  1399         Idxs = []
  1399         Idxs = []
  1400         self.TracedIECPath = []
  1400         self.TracedIECPath = []
  1401         self.TracedIECTypes = []
  1401         self.TracedIECTypes = []
  1402         if self._connector is not None:
  1402         if self._connector is not None:
  1403             self.IECdebug_lock.acquire()
  1403             self.IECdebug_lock.acquire()
  1444         # If an output location var is forced it's leads to segmentation fault in runtime
  1444         # 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
  1445         # Links between PLC located variables and real variables are not ready
  1446         if self.IsPLCStarted():
  1446         if self.IsPLCStarted():
  1447             # Timer to prevent rapid-fire when registering many variables
  1447             # Timer to prevent rapid-fire when registering many variables
  1448             # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
  1448             # use wx.CallAfter use keep using same thread. TODO : use wx.Timer instead
  1449             self.DebugTimer=Timer(0.5, wx.CallAfter, args = [self.RegisterDebugVarToConnector])
  1449             self.DebugTimer = Timer(0.5, wx.CallAfter, args = [self.RegisterDebugVarToConnector])
  1450             # Rearm anti-rapid-fire timer
  1450             # Rearm anti-rapid-fire timer
  1451             self.DebugTimer.start()
  1451             self.DebugTimer.start()
  1452 
  1452 
  1453     def GetDebugIECVariableType(self, IECPath):
  1453     def GetDebugIECVariableType(self, IECPath):
  1454         Idx, IEC_Type = self._IECPathToIdx.get(IECPath, (None, None))
  1454         Idx, IEC_Type = self._IECPathToIdx.get(IECPath, (None, None))
  1475                     buffer_list]                # Forced value
  1475                     buffer_list]                # Forced value
  1476             self.IECdebug_datas[IECPath] = IECdebug_data
  1476             self.IECdebug_datas[IECPath] = IECdebug_data
  1477         else:
  1477         else:
  1478             IECdebug_data[4] |= buffer_list
  1478             IECdebug_data[4] |= buffer_list
  1479 
  1479 
  1480         IECdebug_data[0][callableobj]=buffer_list
  1480         IECdebug_data[0][callableobj] = buffer_list
  1481 
  1481 
  1482         self.IECdebug_lock.release()
  1482         self.IECdebug_lock.release()
  1483 
  1483 
  1484         self.ReArmDebugRegisterTimer()
  1484         self.ReArmDebugRegisterTimer()
  1485 
  1485 
  1906         },
  1906         },
  1907     ]
  1907     ]
  1908 
  1908 
  1909     def EnableMethod(self, method, value):
  1909     def EnableMethod(self, method, value):
  1910         for d in self.StatusMethods:
  1910         for d in self.StatusMethods:
  1911             if d["method"]==method:
  1911             if d["method"] == method:
  1912                 d["enabled"]=value
  1912                 d["enabled"] = value
  1913                 return True
  1913                 return True
  1914         return False
  1914         return False
  1915 
  1915 
  1916     def ShowMethod(self, method, value):
  1916     def ShowMethod(self, method, value):
  1917         for d in self.StatusMethods:
  1917         for d in self.StatusMethods:
  1918             if d["method"]==method:
  1918             if d["method"] == method:
  1919                 d["shown"]=value
  1919                 d["shown"] = value
  1920                 return True
  1920                 return True
  1921         return False
  1921         return False
  1922 
  1922 
  1923     def CallMethod(self, method):
  1923     def CallMethod(self, method):
  1924         for d in self.StatusMethods:
  1924         for d in self.StatusMethods:
  1925             if d["method"]==method and d.get("enabled", True) and d.get("shown", True):
  1925             if d["method"] == method and d.get("enabled", True) and d.get("shown", True):
  1926                 getattr(self, method)()
  1926                 getattr(self, method)()