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 """ |
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() |
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 |