ProjectController.py
changeset 1475 de4ee16f7c6c
parent 1451 94e620cbd9de
child 1484 d5efbb20927e
equal deleted inserted replaced
1474:28e9d479aa65 1475:de4ee16f7c6c
    11 from types import ListType
    11 from types import ListType
    12 from threading import Timer, Lock, Thread
    12 from threading import Timer, Lock, Thread
    13 from time import localtime
    13 from time import localtime
    14 from datetime import datetime
    14 from datetime import datetime
    15 from weakref import WeakKeyDictionary
    15 from weakref import WeakKeyDictionary
       
    16 from itertools import izip
    16 
    17 
    17 import targets
    18 import targets
    18 import connectors
    19 import connectors
    19 from util.misc import CheckPathPerm, GetClassImporter
    20 from util.misc import CheckPathPerm, GetClassImporter
    20 from util.MiniTextControler import MiniTextControler
    21 from util.MiniTextControler import MiniTextControler
    26 from editors.DebugViewer import DebugViewer, REFRESH_PERIOD
    27 from editors.DebugViewer import DebugViewer, REFRESH_PERIOD
    27 from dialogs import DiscoveryDialog
    28 from dialogs import DiscoveryDialog
    28 from PLCControler import PLCControler
    29 from PLCControler import PLCControler
    29 from plcopen.structures import IEC_KEYWORDS
    30 from plcopen.structures import IEC_KEYWORDS
    30 from targets.typemapping import DebugTypesSize, LogLevelsCount, LogLevels
    31 from targets.typemapping import DebugTypesSize, LogLevelsCount, LogLevels
       
    32 from targets.typemapping import UnpackDebugBuffer
    31 from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage
    33 from ConfigTreeNode import ConfigTreeNode, XSDSchemaErrorMessage
    32 
    34 
    33 base_folder = os.path.split(sys.path[0])[0]
    35 base_folder = os.path.split(os.path.dirname(os.path.realpath(__file__)))[0]
    34 
    36 
    35 MATIEC_ERROR_MODEL = re.compile(".*\.st:(\d+)-(\d+)\.\.(\d+)-(\d+): (?:error)|(?:warning) : (.*)$")
    37 MATIEC_ERROR_MODEL = re.compile(".*\.st:(\d+)-(\d+)\.\.(\d+)-(\d+): (?:error)|(?:warning) : (.*)$")
    36 
       
    37 DEBUG_RETRIES_WARN = 3
       
    38 DEBUG_RETRIES_REREGISTER = 4
       
    39 
    38 
    40 ITEM_CONFNODE = 25
    39 ITEM_CONFNODE = 25
    41 
    40 
    42 def ExtractChildrenTypesFromCatalog(catalog):
    41 def ExtractChildrenTypesFromCatalog(catalog):
    43     children_types = []
    42     children_types = []
   607         return True
   606         return True
   608 
   607 
   609     def _Compile_ST_to_SoftPLC(self):
   608     def _Compile_ST_to_SoftPLC(self):
   610         self.logger.write(_("Compiling IEC Program into C code...\n"))
   609         self.logger.write(_("Compiling IEC Program into C code...\n"))
   611         buildpath = self._getBuildPath()
   610         buildpath = self._getBuildPath()
   612 
   611         buildcmd = "\"%s\" -f -l -p -I \"%s\" -T \"%s\" \"%s\""%(
   613         # Now compile IEC code into many C files
       
   614         # files are listed to stdout, and errors to stderr.
       
   615         status, result, err_result = ProcessLogger(
       
   616                self.logger,
       
   617                "\"%s\" -f -l -p -I \"%s\" -T \"%s\" \"%s\""%(
       
   618                          self.iec2c_path,
   612                          self.iec2c_path,
   619                          self.ieclib_path,
   613                          self.ieclib_path,
   620                          buildpath,
   614                          buildpath,
   621                          self._getIECcodepath()),
   615                          self._getIECcodepath())
   622                no_stdout=True, no_stderr=True).spin()
   616 
       
   617         try:
       
   618             # Invoke compiler. Output files are listed to stdout, errors to stderr
       
   619             status, result, err_result = ProcessLogger(self.logger, buildcmd,
       
   620                 no_stdout=True, no_stderr=True).spin()
       
   621         except Exception,e:
       
   622             self.logger.write_error(buildcmd + "\n")
       
   623             self.logger.write_error(repr(e) + "\n")
       
   624             return False
       
   625 
   623         if status:
   626         if status:
   624             # Failed !
   627             # Failed !
   625 
   628 
   626             # parse iec2c's error message. if it contains a line number,
   629             # parse iec2c's error message. if it contains a line number,
   627             # then print those lines from the generated IEC file.
   630             # then print those lines from the generated IEC file.
   730         Reset variable and program list that are parsed from
   733         Reset variable and program list that are parsed from
   731         CSV file generated by IEC2C compiler.
   734         CSV file generated by IEC2C compiler.
   732         """
   735         """
   733         self._ProgramList = None
   736         self._ProgramList = None
   734         self._VariablesList = None
   737         self._VariablesList = None
       
   738         self._DbgVariablesList = None
   735         self._IECPathToIdx = {}
   739         self._IECPathToIdx = {}
   736         self._Ticktime = 0
   740         self._Ticktime = 0
   737         self.TracedIECPath = []
   741         self.TracedIECPath = []
       
   742         self.TracedIECTypes = []
   738 
   743 
   739     def GetIECProgramsAndVariables(self):
   744     def GetIECProgramsAndVariables(self):
   740         """
   745         """
   741         Parse CSV-like file  VARIABLES.csv resulting from IEC2C compiler.
   746         Parse CSV-like file  VARIABLES.csv resulting from IEC2C compiler.
   742         Each section is marked with a line staring with '//'
   747         Each section is marked with a line staring with '//'
   748                 # describes CSV columns
   753                 # describes CSV columns
   749                 ProgramsListAttributeName = ["num", "C_path", "type"]
   754                 ProgramsListAttributeName = ["num", "C_path", "type"]
   750                 VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
   755                 VariablesListAttributeName = ["num", "vartype", "IEC_path", "C_path", "type"]
   751                 self._ProgramList = []
   756                 self._ProgramList = []
   752                 self._VariablesList = []
   757                 self._VariablesList = []
       
   758                 self._DbgVariablesList = []
   753                 self._IECPathToIdx = {}
   759                 self._IECPathToIdx = {}
   754 
   760 
   755                 # Separate sections
   761                 # Separate sections
   756                 ListGroup = []
   762                 ListGroup = []
   757                 for line in open(csvfile,'r').xreadlines():
   763                 for line in open(csvfile,'r').xreadlines():
   772                     # Push this dictionnary into result.
   778                     # Push this dictionnary into result.
   773                     self._ProgramList.append(attrs)
   779                     self._ProgramList.append(attrs)
   774 
   780 
   775                 # second section contains all variables
   781                 # second section contains all variables
   776                 config_FBs = {}
   782                 config_FBs = {}
       
   783                 Idx = 0
   777                 for line in ListGroup[1]:
   784                 for line in ListGroup[1]:
   778                     # Split and Maps each field to dictionnary entries
   785                     # Split and Maps each field to dictionnary entries
   779                     attrs = dict(zip(VariablesListAttributeName,line.strip().split(';')))
   786                     attrs = dict(zip(VariablesListAttributeName,line.strip().split(';')))
   780                     # Truncate "C_path" to remove conf an ressources names
   787                     # Truncate "C_path" to remove conf an ressources names
   781                     parts = attrs["C_path"].split(".",2)
   788                     parts = attrs["C_path"].split(".",2)
   788                             attrs["C_path"] = '__'.join(parts[1:])
   795                             attrs["C_path"] = '__'.join(parts[1:])
   789                     else:
   796                     else:
   790                         attrs["C_path"] = '__'.join(parts)
   797                         attrs["C_path"] = '__'.join(parts)
   791                         if attrs["vartype"] == "FB":
   798                         if attrs["vartype"] == "FB":
   792                             config_FBs[tuple(parts)] = attrs["C_path"]
   799                             config_FBs[tuple(parts)] = attrs["C_path"]
   793                     # Push this dictionnary into result.
   800                     if attrs["vartype"] != "FB":
       
   801                         # Push this dictionnary into result.
       
   802                         self._DbgVariablesList.append(attrs)
       
   803                         # Fill in IEC<->C translation dicts
       
   804                         IEC_path=attrs["IEC_path"]
       
   805                         self._IECPathToIdx[IEC_path]=(Idx, attrs["type"])
       
   806                         # Ignores numbers given in CSV file
       
   807                         # Idx=int(attrs["num"])
       
   808                         # Count variables only, ignore FBs
       
   809                         Idx+=1
   794                     self._VariablesList.append(attrs)
   810                     self._VariablesList.append(attrs)
   795                     # Fill in IEC<->C translation dicts
       
   796                     IEC_path=attrs["IEC_path"]
       
   797                     Idx=int(attrs["num"])
       
   798                     self._IECPathToIdx[IEC_path]=(Idx, attrs["type"])
       
   799 
   811 
   800                 # third section contains ticktime
   812                 # third section contains ticktime
   801                 if len(ListGroup) > 2:
   813                 if len(ListGroup) > 2:
   802                     self._Ticktime = int(ListGroup[2][0])
   814                     self._Ticktime = int(ListGroup[2][0])
   803 
   815 
   814         Generate trace/debug code out of PLC variable list
   826         Generate trace/debug code out of PLC variable list
   815         """
   827         """
   816         self.GetIECProgramsAndVariables()
   828         self.GetIECProgramsAndVariables()
   817 
   829 
   818         # prepare debug code
   830         # prepare debug code
   819         debug_code = targets.GetCode("plc_debug") % {
   831         variable_decl_array = []
   820            "buffer_size": reduce(lambda x, y: x + y, [DebugTypesSize.get(v["type"], 0) for v in self._VariablesList], 0),
   832         bofs = 0
       
   833         for v in self._DbgVariablesList :
       
   834             sz = DebugTypesSize.get(v["type"], 0)
       
   835             variable_decl_array += [
       
   836                 "{&(%(C_path)s), "%v+
       
   837                 {"EXT":"%(type)s_P_ENUM",
       
   838                  "IN":"%(type)s_P_ENUM",
       
   839                  "MEM":"%(type)s_O_ENUM",
       
   840                  "OUT":"%(type)s_O_ENUM",
       
   841                  "VAR":"%(type)s_ENUM"}[v["vartype"]]%v +
       
   842                  "}"]
       
   843             bofs += sz
       
   844         debug_code = targets.GetCode("plc_debug.c") % {
       
   845            "buffer_size":bofs,
   821            "programs_declarations":
   846            "programs_declarations":
   822                "\n".join(["extern %(type)s %(C_path)s;"%p for p in self._ProgramList]),
   847                "\n".join(["extern %(type)s %(C_path)s;"%p for p in self._ProgramList]),
   823            "extern_variables_declarations":"\n".join([
   848            "extern_variables_declarations":"\n".join([
   824               {"EXT":"extern __IEC_%(type)s_p %(C_path)s;",
   849               {"EXT":"extern __IEC_%(type)s_p %(C_path)s;",
   825                "IN":"extern __IEC_%(type)s_p %(C_path)s;",
   850                "IN":"extern __IEC_%(type)s_p %(C_path)s;",
   826                "MEM":"extern __IEC_%(type)s_p %(C_path)s;",
   851                "MEM":"extern __IEC_%(type)s_p %(C_path)s;",
   827                "OUT":"extern __IEC_%(type)s_p %(C_path)s;",
   852                "OUT":"extern __IEC_%(type)s_p %(C_path)s;",
   828                "VAR":"extern __IEC_%(type)s_t %(C_path)s;",
   853                "VAR":"extern __IEC_%(type)s_t %(C_path)s;",
   829                "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v
   854                "FB":"extern %(type)s %(C_path)s;"}[v["vartype"]]%v
   830                for v in self._VariablesList if v["C_path"].find('.')<0]),
   855                for v in self._VariablesList if v["C_path"].find('.')<0]),
   831            "for_each_variable_do_code":"\n".join([
   856            "variable_decl_array": ",\n".join(variable_decl_array)
   832                {"EXT":"    (*fp)((void*)&(%(C_path)s),%(type)s_P_ENUM);\n",
   857            }
   833                 "IN":"    (*fp)((void*)&(%(C_path)s),%(type)s_P_ENUM);\n",
       
   834                 "MEM":"    (*fp)((void*)&(%(C_path)s),%(type)s_O_ENUM);\n",
       
   835                 "OUT":"    (*fp)((void*)&(%(C_path)s),%(type)s_O_ENUM);\n",
       
   836                 "VAR":"    (*fp)((void*)&(%(C_path)s),%(type)s_ENUM);\n"}[v["vartype"]]%v
       
   837                 for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ]),
       
   838            "find_variable_case_code":"\n".join([
       
   839                "    case %(num)s:\n"%v+
       
   840                "        *varp = (void*)&(%(C_path)s);\n"%v+
       
   841                {"EXT":"        return %(type)s_P_ENUM;\n",
       
   842                 "IN":"        return %(type)s_P_ENUM;\n",
       
   843                 "MEM":"        return %(type)s_O_ENUM;\n",
       
   844                 "OUT":"        return %(type)s_O_ENUM;\n",
       
   845                 "VAR":"        return %(type)s_ENUM;\n"}[v["vartype"]]%v
       
   846                 for v in self._VariablesList if v["vartype"] != "FB" and v["type"] in DebugTypesSize ])}
       
   847 
   858 
   848         return debug_code
   859         return debug_code
   849 
   860 
   850     def Generate_plc_main(self):
   861     def Generate_plc_main(self):
   851         """
   862         """
   857         locstrs = map(lambda x:"_".join(map(str,x)),
   868         locstrs = map(lambda x:"_".join(map(str,x)),
   858            [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
   869            [loc for loc,Cfiles,DoCalls in self.LocationCFilesAndCFLAGS if loc and DoCalls])
   859 
   870 
   860         # Generate main, based on template
   871         # Generate main, based on template
   861         if not self.BeremizRoot.getDisable_Extensions():
   872         if not self.BeremizRoot.getDisable_Extensions():
   862             plc_main_code = targets.GetCode("plc_main_head") % {
   873             plc_main_code = targets.GetCode("plc_main_head.c") % {
   863                 "calls_prototypes":"\n".join([(
   874                 "calls_prototypes":"\n".join([(
   864                       "int __init_%(s)s(int argc,char **argv);\n"+
   875                       "int __init_%(s)s(int argc,char **argv);\n"+
   865                       "void __cleanup_%(s)s(void);\n"+
   876                       "void __cleanup_%(s)s(void);\n"+
   866                       "void __retrieve_%(s)s(void);\n"+
   877                       "void __retrieve_%(s)s(void);\n"+
   867                       "void __publish_%(s)s(void);")%{'s':locstr} for locstr in locstrs]),
   878                       "void __publish_%(s)s(void);")%{'s':locstr} for locstr in locstrs]),
   877                 "cleanup_calls":"\n    ".join([
   888                 "cleanup_calls":"\n    ".join([
   878                       "if(init_level >= %d) "%i+
   889                       "if(init_level >= %d) "%i+
   879                       "__cleanup_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
   890                       "__cleanup_%s();"%locstrs[i-1] for i in xrange(len(locstrs), 0, -1)])
   880                 }
   891                 }
   881         else:
   892         else:
   882             plc_main_code = targets.GetCode("plc_main_head") % {
   893             plc_main_code = targets.GetCode("plc_main_head.c") % {
   883                 "calls_prototypes":"\n",
   894                 "calls_prototypes":"\n",
   884                 "retrieve_calls":"\n",
   895                 "retrieve_calls":"\n",
   885                 "publish_calls":"\n",
   896                 "publish_calls":"\n",
   886                 "init_calls":"\n",
   897                 "init_calls":"\n",
   887                 "cleanup_calls":"\n"
   898                 "cleanup_calls":"\n"
   888                 }
   899                 }
   889         plc_main_code += targets.GetTargetCode(self.GetTarget().getcontent().getLocalTag())
   900         plc_main_code += targets.GetTargetCode(self.GetTarget().getcontent().getLocalTag())
   890         plc_main_code += targets.GetCode("plc_main_tail")
   901         plc_main_code += targets.GetCode("plc_main_tail.c")
   891         return plc_main_code
   902         return plc_main_code
   892 
   903 
   893 
   904 
   894     def _Build(self):
   905     def _Build(self):
   895         """
   906         """
   973             self.logger.write_error(_("Runtime library extensions C code generation failed !\n"))
   984             self.logger.write_error(_("Runtime library extensions C code generation failed !\n"))
   974             self.logger.write_error(traceback.format_exc())
   985             self.logger.write_error(traceback.format_exc())
   975             self.ResetBuildMD5()
   986             self.ResetBuildMD5()
   976             return False
   987             return False
   977 
   988 
   978         self.LocationCFilesAndCFLAGS =  CTNLocationCFilesAndCFLAGS + LibCFilesAndCFLAGS
   989         self.LocationCFilesAndCFLAGS =  LibCFilesAndCFLAGS + CTNLocationCFilesAndCFLAGS
   979         self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS
   990         self.LDFLAGS = CTNLDFLAGS + LibLDFLAGS
   980         ExtraFiles = CTNExtraFiles + LibExtraFiles
   991         ExtraFiles = CTNExtraFiles + LibExtraFiles
   981 
   992 
   982         # Get temporary directory path
   993         # Get temporary directory path
   983         extrafilespath = self._getExtraFilesPath()
   994         extrafilespath = self._getExtraFilesPath()
  1204     def PullPLCStatusProc(self, event):
  1215     def PullPLCStatusProc(self, event):
  1205         self.UpdateMethodsFromPLCStatus()
  1216         self.UpdateMethodsFromPLCStatus()
  1206 
  1217 
  1207     def SnapshotAndResetDebugValuesBuffers(self):
  1218     def SnapshotAndResetDebugValuesBuffers(self):
  1208         buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
  1219         buffers, self.DebugValuesBuffers = (self.DebugValuesBuffers,
  1209             [list() for iec_path in self.TracedIECPath])
  1220             [list() for n in xrange(len(self.TracedIECPath))])
  1210         ticks, self.DebugTicks = self.DebugTicks, []
  1221         ticks, self.DebugTicks = self.DebugTicks, []
  1211         return ticks, buffers
  1222         return ticks, buffers
  1212 
  1223 
  1213     def RegisterDebugVarToConnector(self):
  1224     def RegisterDebugVarToConnector(self):
  1214         self.DebugTimer=None
  1225         self.DebugTimer=None
  1215         Idxs = []
  1226         Idxs = []
  1216         self.TracedIECPath = []
  1227         self.TracedIECPath = []
       
  1228         self.TracedIECTypes = []
  1217         if self._connector is not None:
  1229         if self._connector is not None:
  1218             self.IECdebug_lock.acquire()
  1230             self.IECdebug_lock.acquire()
  1219             IECPathsToPop = []
  1231             IECPathsToPop = []
  1220             for IECPath,data_tuple in self.IECdebug_datas.iteritems():
  1232             for IECPath,data_tuple in self.IECdebug_datas.iteritems():
  1221                 WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1233                 WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1236             for IECPathToPop in IECPathsToPop:
  1248             for IECPathToPop in IECPathsToPop:
  1237                 self.IECdebug_datas.pop(IECPathToPop)
  1249                 self.IECdebug_datas.pop(IECPathToPop)
  1238 
  1250 
  1239             if Idxs:
  1251             if Idxs:
  1240                 Idxs.sort()
  1252                 Idxs.sort()
  1241                 self.TracedIECPath = zip(*Idxs)[3]
  1253                 IdxsT = zip(*Idxs)
  1242                 self._connector.SetTraceVariablesList(zip(*zip(*Idxs)[0:3]))
  1254                 self.TracedIECPath = IdxsT[3]
       
  1255                 self.TracedIECTypes = IdxsT[1]
       
  1256                 self._connector.SetTraceVariablesList(zip(*IdxsT[0:3]))
  1243             else:
  1257             else:
  1244                 self.TracedIECPath = []
  1258                 self.TracedIECPath = []
  1245                 self._connector.SetTraceVariablesList([])
  1259                 self._connector.SetTraceVariablesList([])
  1246             self.SnapshotAndResetDebugValuesBuffers()
  1260             self.SnapshotAndResetDebugValuesBuffers()
  1247             self.IECdebug_lock.release()
  1261             self.IECdebug_lock.release()
  1265 
  1279 
  1266     def GetDebugIECVariableType(self, IECPath):
  1280     def GetDebugIECVariableType(self, IECPath):
  1267         Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
  1281         Idx, IEC_Type = self._IECPathToIdx.get(IECPath,(None,None))
  1268         return IEC_Type
  1282         return IEC_Type
  1269 
  1283 
  1270     def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False, *args, **kwargs):
  1284     def SubscribeDebugIECVariable(self, IECPath, callableobj, buffer_list=False):
  1271         """
  1285         """
  1272         Dispatching use a dictionnary linking IEC variable paths
  1286         Dispatching use a dictionnary linking IEC variable paths
  1273         to a WeakKeyDictionary linking
  1287         to a WeakKeyDictionary linking
  1274         weakly referenced callables to optionnal args
  1288         weakly referenced callables
  1275         """
  1289         """
  1276         if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath):
  1290         if IECPath != "__tick__" and not self._IECPathToIdx.has_key(IECPath):
  1277             return None
  1291             return None
  1278 
  1292 
  1279         self.IECdebug_lock.acquire()
  1293         self.IECdebug_lock.acquire()
  1288                     buffer_list]                # Forced value
  1302                     buffer_list]                # Forced value
  1289             self.IECdebug_datas[IECPath] = IECdebug_data
  1303             self.IECdebug_datas[IECPath] = IECdebug_data
  1290         else:
  1304         else:
  1291             IECdebug_data[4] |= buffer_list
  1305             IECdebug_data[4] |= buffer_list
  1292 
  1306 
  1293         IECdebug_data[0][callableobj]=(buffer_list, args, kwargs)
  1307         IECdebug_data[0][callableobj]=buffer_list
  1294 
  1308 
  1295         self.IECdebug_lock.release()
  1309         self.IECdebug_lock.release()
  1296 
  1310 
  1297         self.ReArmDebugRegisterTimer()
  1311         self.ReArmDebugRegisterTimer()
  1298 
  1312 
  1306             if len(IECdebug_data[0]) == 0:
  1320             if len(IECdebug_data[0]) == 0:
  1307                 self.IECdebug_datas.pop(IECPath)
  1321                 self.IECdebug_datas.pop(IECPath)
  1308             else:
  1322             else:
  1309                 IECdebug_data[4] = reduce(
  1323                 IECdebug_data[4] = reduce(
  1310                     lambda x, y: x|y,
  1324                     lambda x, y: x|y,
  1311                     [buffer_list for buffer_list,args,kwargs
  1325                     IECdebug_data[0].itervalues(),
  1312                      in IECdebug_data[0].itervalues()],
       
  1313                     False)
  1326                     False)
  1314         self.IECdebug_lock.release()
  1327         self.IECdebug_lock.release()
  1315 
  1328 
  1316         self.ReArmDebugRegisterTimer()
  1329         self.ReArmDebugRegisterTimer()
  1317 
  1330 
  1355     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1368     def CallWeakcallables(self, IECPath, function_name, *cargs):
  1356         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1369         data_tuple = self.IECdebug_datas.get(IECPath, None)
  1357         if data_tuple is not None:
  1370         if data_tuple is not None:
  1358             WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1371             WeakCallableDict, data_log, status, fvalue, buffer_list = data_tuple
  1359             #data_log.append((debug_tick, value))
  1372             #data_log.append((debug_tick, value))
  1360             for weakcallable,(buffer_list,args,kwargs) in WeakCallableDict.iteritems():
  1373             for weakcallable,buffer_list in WeakCallableDict.iteritems():
  1361                 function = getattr(weakcallable, function_name, None)
  1374                 function = getattr(weakcallable, function_name, None)
  1362                 if function is not None:
  1375                 if function is not None:
  1363                     if buffer_list:
  1376                     if buffer_list:
  1364                         function(*(cargs + args), **kwargs)
  1377                         function(*cargs)
  1365                     else:
  1378                     else:
  1366                         function(*(tuple([lst[-1] for lst in cargs]) + args), **kwargs)
  1379                         function(*tuple([lst[-1] for lst in cargs]))
  1367 
  1380 
  1368     def GetTicktime(self):
  1381     def GetTicktime(self):
  1369         return self._Ticktime
  1382         return self._Ticktime
  1370 
  1383 
  1371     def RemoteExec(self, script, **kwargs):
  1384     def RemoteExec(self, script, **kwargs):
  1378         This thread waid PLC debug data, and dispatch them to subscribers
  1391         This thread waid PLC debug data, and dispatch them to subscribers
  1379         """
  1392         """
  1380         self.debug_break = False
  1393         self.debug_break = False
  1381         debug_getvar_retry = 0
  1394         debug_getvar_retry = 0
  1382         while (not self.debug_break) and (self._connector is not None):
  1395         while (not self.debug_break) and (self._connector is not None):
  1383             Trace = self._connector.GetTraceVariables()
  1396             plc_status, Traces = self._connector.GetTraceVariables()
  1384             if(Trace):
       
  1385                 plc_status, debug_tick, debug_vars = Trace
       
  1386             else:
       
  1387                 plc_status = None
       
  1388             debug_getvar_retry += 1
  1397             debug_getvar_retry += 1
  1389             #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
  1398             #print [dict.keys() for IECPath, (dict, log, status, fvalue) in self.IECdebug_datas.items()]
  1390             if plc_status == "Started":
  1399             if plc_status == "Started" :
  1391                 self.IECdebug_lock.acquire()
  1400                 if len(Traces) > 0:
  1392                 if (debug_tick is not None and
  1401                     Failed = False
  1393                     len(debug_vars) == len(self.DebugValuesBuffers) and
  1402                     self.IECdebug_lock.acquire()
  1394                     len(debug_vars) == len(self.TracedIECPath)):
  1403                     for debug_tick, debug_buff in Traces :
  1395                     if debug_getvar_retry > DEBUG_RETRIES_WARN:
  1404                         debug_vars = UnpackDebugBuffer(debug_buff, self.TracedIECTypes)
  1396                         self.logger.write(_("... debugger recovered\n"))
  1405                         if (debug_vars is not None and
  1397                     debug_getvar_retry = 0
  1406                             len(debug_vars) == len(self.TracedIECPath)):
  1398                     for IECPath, values_buffer, value in zip(self.TracedIECPath, self.DebugValuesBuffers, debug_vars):
  1407                             for IECPath, values_buffer, value in izip(
  1399                         IECdebug_data = self.IECdebug_datas.get(IECPath, None)
  1408                                     self.TracedIECPath,
  1400                         if IECdebug_data is not None and value is not None:
  1409                                     self.DebugValuesBuffers,
  1401                             forced = IECdebug_data[2:4] == ["Forced", value]
  1410                                     debug_vars):
  1402                             if not IECdebug_data[4] and len(values_buffer) > 0:
  1411                                 IECdebug_data = self.IECdebug_datas.get(IECPath, None) #FIXME get
  1403                                 values_buffer[-1] = (value, forced)
  1412                                 if IECdebug_data is not None and value is not None:
  1404                             else:
  1413                                     forced = IECdebug_data[2:4] == ["Forced", value]
  1405                                 values_buffer.append((value, forced))
  1414                                     if not IECdebug_data[4] and len(values_buffer) > 0:
  1406                     self.DebugTicks.append(debug_tick)
  1415                                         values_buffer[-1] = (value, forced)
  1407                 self.IECdebug_lock.release()
  1416                                     else:
  1408                 if debug_getvar_retry == DEBUG_RETRIES_WARN:
  1417                                         values_buffer.append((value, forced))
  1409                     self.logger.write(_("Waiting debugger to recover...\n"))
  1418                             self.DebugTicks.append(debug_tick)
  1410                 if debug_getvar_retry == DEBUG_RETRIES_REREGISTER:
  1419                             debug_getvar_retry = 0
  1411                     # re-register debug registry to PLC
  1420                     self.IECdebug_lock.release()
  1412                     wx.CallAfter(self.RegisterDebugVarToConnector)
  1421 
  1413                 if debug_getvar_retry != 0:
  1422                 if debug_getvar_retry != 0:
  1414                     # Be patient, tollerate PLC to come up before debugging
  1423                     # Be patient, tollerate PLC to come with fresh samples
  1415                     time.sleep(0.1)
  1424                     time.sleep(0.1)
  1416             else:
  1425             else:
  1417                 self.debug_break = True
  1426                 self.debug_break = True
  1418         self.logger.write(_("Debugger disabled\n"))
  1427         self.logger.write(_("Debugger disabled\n"))
  1419         self.DebugThread = None
  1428         self.DebugThread = None
  1424         self.IECdebug_lock.acquire()
  1433         self.IECdebug_lock.acquire()
  1425         debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
  1434         debug_ticks, buffers = self.SnapshotAndResetDebugValuesBuffers()
  1426         self.IECdebug_lock.release()
  1435         self.IECdebug_lock.release()
  1427         start_time = time.time()
  1436         start_time = time.time()
  1428         if len(self.TracedIECPath) == len(buffers):
  1437         if len(self.TracedIECPath) == len(buffers):
  1429             for IECPath, values in zip(self.TracedIECPath, buffers):
  1438             for IECPath, values in izip(self.TracedIECPath, buffers):
  1430                 if len(values) > 0:
  1439                 if len(values) > 0:
  1431                     self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
  1440                     self.CallWeakcallables(IECPath, "NewValues", debug_ticks, values)
  1432             if len(debug_ticks) > 0:
  1441             if len(debug_ticks) > 0:
  1433                 self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
  1442                 self.CallWeakcallables("__tick__", "NewDataAvailable", debug_ticks)
  1434 
  1443