33 FD_DCG(
"Iec61131stCodeGenerator(" <<
this <<
")::Iec61131stCodeGenerator()");
39 FD_DCG(
"Iec61131stCodeGenerator(" <<
this <<
")::~Iec61131stCodeGenerator()");
45 FD_DCG(
"Iec61131stCodeGenerator::Clear()");
60 FD_DCG(
"Iec61131stCodeGenerator::DoReadTargetConfiguration()");
65 if(rTr.ExistsBegin(
"IecDeclarePhysical")) {
66 rTr.ReadBegin(
"IecDeclarePhysical",token);
68 rTr.ReadEnd(
"IecDeclarePhysical");
71 if(rTr.ExistsBegin(
"IncludeCyclic"))
73 if(rTr.ExistsBegin(
"IecTimeOperators")) {
74 rTr.ReadBegin(
"IecTimeOperators",token);
76 rTr.ReadEnd(
"IecTimeOperators");
82 FD_DCG(
"Iec61131stCodeGenerator::DoWriteTargetConfiguration()");
87 token.SetEmpty(
"IecDeclarePhysical");
93 token.SetEmpty(
"IecTimeOperators");
118 FCG_VERB1(
"Iec61131stCodeGenerator::Compile(): prefer compiled bitmasks over bit-address maths");
123 FCG_VERB1(
"Iec61131stCodeGenerator::Compile(): using array for state as return value datatype");
134 Comment(
"************************************************");
135 Comment(
"CodeGenerator: Target IEC 61131 Structured Text ");
136 Comment(
"************************************************");
149 Comment(
"************************************************");
150 Comment(
"CodeGenerator: Generated Code Ends Here ");
151 Comment(
"************************************************");
158 Comment(
"************************************************");
159 Comment(
"* function block to host cyclic code *");
160 Comment(
"************************************************");
191 Output() <<
"VAR_EXTERNAL";
209 Comment(
"************************************************");
210 Comment(
"* end of cyclic function block *");
212 Output() <<
"END_FUNCTION_BLOCK";
221 Comment(
"************************************************");
222 Comment(
"* function to host the event name loopup table *");
223 Comment(
"************************************************");
225 Output() <<
"FUNCTION " <<
mPrefix <<
"event_lookup_f" <<
" : STRING";
233 Output() <<
"VAR CONSTANT";
240 Output() <<
"END_FUNCTION";
245 Comment(
"************************************************");
246 Comment(
"* function to host state name loopup tables *");
247 Comment(
"************************************************");
249 Output() <<
"FUNCTION " <<
mPrefix <<
"state_lookup_f" <<
" : STRING";
259 Output() <<
"VAR CONSTANT";
266 Output() <<
"CASE GID OF";
268 for(
size_t gid=0; gid<
Size(); ++gid) {
270 Output() << ToStringInteger(gid) <<
": " 271 <<
mPrefix <<
"state_lookup_f" <<
" := " <<
mPrefix <<
"state_lookup_" << ToStringInteger(gid) <<
"[IDX]" <<
";";
276 Output() <<
"IF LEN(" <<
mPrefix <<
"state_lookup_f) = 0 THEN";
282 Output() <<
"END_FUNCTION";
291 FD_DCG(
"Iec61131stCodeGenerator(" <<
this <<
")::StateReset()");
306 Comment(
"elapsed time since last invokation");
321 std::string lineaddr= lit->second.mAddress;
322 if(lineaddr.size()<1)
continue;
323 if(lineaddr.at(0)==
'%') iocnt++;
327 if(!ait->second.mSetClr)
continue;
328 std::string actaddr= ait->second.mAddress;
329 if(actaddr.size()<1)
continue;
330 if(actaddr.at(0)==
'%') ++iocnt;
337 Comment(
"import physical i/o addresses");
340 std::string lineaddr= lit->second.mAddress;
341 if(lineaddr.size()<1)
continue;
342 if(lineaddr.at(0)==
'%') {
343 Output() <<
"AT " << lineaddr <<
" : BOOL;";
349 if(!ait->second.mSetClr)
continue;
350 std::string actaddr= ait->second.mAddress;
351 if(actaddr.size()<1)
continue;
352 if(actaddr.at(0)==
'%') {
353 Output() <<
"AT " << actaddr <<
" : BOOL;";
366 std::string lineaddr= lit->second.mAddress;
367 if(lineaddr.size()<1)
continue;
368 if(lineaddr.at(0)!=
'%') iocnt++;
372 if(!ait->second.mSetClr)
continue;
373 std::string actaddr= ait->second.mAddress;
374 if(actaddr.size()<1)
continue;
375 if(actaddr.at(0)!=
'%') ++iocnt;
381 Comment(
"import i/o variables and addresses");
384 std::string lineaddr= lit->second.mAddress;
385 if(lineaddr.size()<1)
continue;
386 if(lineaddr.at(0)!=
'%') {
393 if(!ait->second.mSetClr)
continue;
394 std::string actaddr= ait->second.mAddress;
395 if(actaddr.size()<1)
continue;
396 if(actaddr.at(0)!=
'%') {
408 Comment(
"************************************************");
409 Comment(
"* extra cyclic code from configuration *");
413 Comment(
"* end of extra code from configuration *");
414 Comment(
"************************************************");
440 Comment(
"************************************************");
441 Comment(
"* update timer states *");
448 AA cnt(
"timer_" + tit->second.mAddress +
"_cnt");
449 AA run(
"timer_" + tit->second.mAddress +
"_run");
485 Comment(
"iec timer to simulate system time");
495 Comment(
"do reset/track systime");
496 Output() <<
"IF " <<
mPrefix <<
"exec_event = -1 " <<
" THEN" << std::endl;
497 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=false);" << std::endl;
498 Output() <<
" " <<
mPrefix <<
"systime_recent := TIME#0ms;" << std::endl;
499 Output() <<
"END_IF;" << std::endl;
500 Output() <<
mPrefix <<
"systime_ton(IN:=true, PT:=TIME#2h, ET=>" <<
mPrefix <<
"systime_now);" << std::endl;
506 Output() <<
"IF " <<
mPrefix <<
"systime_now < TIME#1h THEN" << std::endl;
508 Output() <<
"ELSE" << std::endl;
509 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=false, PT:=TIME#2h);" << std::endl;
510 Output() <<
" " <<
mPrefix <<
"systime_ton(IN:=true, PT:=TIME#2h);" << std::endl;
511 Output() <<
" " <<
mPrefix <<
"systime_recent := TIME#0ms;" << std::endl;
512 Output() <<
"END_IF;" << std::endl;
535 Output() <<
"(* " << text <<
" *)";
544 if((ltype !=
mIntegerType) && (ltype !=
mWordType) && (ltype !=
"BOOL") && (ltype !=
"STRING") && (ltype !=
"TIME") && (ltype !=
"TON"))
545 FCG_ERR(
"Iec61131stCodeGenerator::VariableDeclare(): unsupported type [" << ltype <<
"]");
546 Output() << laddr <<
" : " << ltype <<
";";
551 if((ltype !=
mIntegerType) && (ltype !=
mWordType) && (ltype !=
"BOOL") && (ltype !=
"STRING") && (ltype !=
"TIME"))
552 FCG_ERR(
"Iec61131stCodeGenerator::VariableDeclare(): unsupported type [" << ltype <<
"]");
553 Output() << laddr <<
" : " << ltype <<
" := " << lval <<
";";
561 if(address==
"reset") res=
"RESET";
562 if(address==
"status") res=
"STATUS";
564 if(address==
"recent_event") res=
"RECENT_EVENT";
565 if(address.find(
"pending_events")==0)
566 if(address!=
"pending_events_t")
567 res=
"PENDING_EVENTS"+address.substr(14);
568 if(address.find(
"enabled_events")==0)
569 if(address!=
"enabled_events_t")
570 res=
"ENABLED_EVENTS"+address.substr(14);
573 if(address.find(
"parallel_state")==0)
574 if(address!=
"parallel_state_t")
575 res=
"PARALLEL_STATE"+address.substr(14);
578 if(res==
"") res=
mPrefix+address;
631 return AX(
"SHL( IN:=" +
WordConstant(1) +
" , N:=" + expression +
" )" );
641 std::string res(ToStringInteger(val));
645 FCG_ERR(
"Iec61131stCodeGenerator: unsupported integer data type");
788 std::stringstream sstr;
789 sstr <<
mWordType <<
"#16#" << std::setbase(16) << std::setfill(
'0');
790 if(
mWordType ==
"BYTE") sstr << std::setw(2) << (val & 0xff);
791 else if(
mWordType ==
"WORD") sstr << std::setw(4) << (val & 0xffff);
792 else if(
mWordType ==
"DWORD") sstr << std::setw(8) << (val & 0xffffffff);
793 else if(
mWordType ==
"LWORD") sstr << std::setw(16) << (val & 0xffffffffffffffff);
794 else FCG_ERR(
"Iec61131stCodeGenerator: unsupported word data type");
808 if(val) valstr=
"true";
else valstr=
"false";
815 if(val) valstr=
"true";
else valstr=
"false";
839 std::stringstream strstr;
841 if(val.size()<25) newline=25;
845 if(vit==val.size())
break;
848 if(vit==val.size())
break;
852 strstr << std::endl <<
" ";
857 return AX(strstr.str());
863 FCG_ERR(
"Iec61131stCodeGenerator::Cintarray(): ignoring empty const vector");
867 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): const vector exceeds address range");
882 return AA(address +
"[" + ToStringInteger(index) +
"]");
898 std::stringstream strstr;
900 if(val.size()<11) newline=15;
904 if(vit==val.size())
break;
907 if(vit==val.size())
break;
911 strstr << std::endl <<
" ";
916 return AX(strstr.str());
922 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): ignoring empty const vector");
926 FCG_ERR(
"Iec61131stCodeGenerator::Cwordarray(): const vector exceeds addres range");
941 return AA(address +
"[" + ToStringInteger(index) +
"]");
958 for(std::size_t i=0; i<val.length(); ++i) {
963 if(c==
'\'') { res.append(
"$'");
continue; }
965 if(c==
'$') { res.append(
"$$");
continue; }
967 if((c>=0x20) && (c<0x7f)) { res.append(1,c);
continue; };
969 FCG_ERR(
"EmbeddedcCodeGenerator: non-printable ascii or other encoding unsupported [" << val <<
"]");
977 std::stringstream strstr;
984 strstr <<
"[ " << std::endl;
988 if(vit==val.size())
break;
991 if(vit==val.size())
break;
1000 return AX(strstr.str());
1007 FCG_ERR(
"Iec61131stCodeGenerator::Cstrarray(): ignoring empty const vector");
1011 FCG_ERR(
"Iec61131stCodeGenerator::Cstrarray(): const vector exceeds addres range");
1016 for(
size_t i=0; i<val.size(); ++i)
1017 if(val[i].size()>len) len=val[i].size();
1019 Output() <<
TargetAddress(address) <<
" : ARRAY[" << offset <<
".." << val.size()+offset-1 <<
"] OF STRING[" << ToStringInteger(len) <<
"] := ";
1030 return AA(address +
"[" + ToStringInteger(index) +
"]");
1046 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): ignoring empty const vector");
1050 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): const vector exceeds addres range");
1066 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): ignoring empty const vector");
1070 FCG_ERR(
"Iec61131stCodeGenerator::Intarray(): const vector exceeds addres range");
1079 return AA(address +
"[" + ToStringInteger(index) +
"]");
1096 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): ignoring empty const vector");
1100 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): const vector exceeds addres range");
1116 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): ignoring empty const vector");
1120 FCG_ERR(
"Iec61131stCodeGenerator::Wordarray(): const vector exceeds addres range");
1129 return AA(address +
"[" + ToStringInteger(index) +
"]");
1154 Output() <<
"IF " << expression <<
" THEN";
1161 Output() <<
"IF NOT " << expression <<
" THEN";
1184 Output() <<
"ELSIF " << expression <<
" THEN";
1214 FCG_VERB0(
"CodeGenerator: WARNING: inconsistent empty range of switch-cases");
1233 FCG_VERB0(
"CodeGenerator: WARNING: inconsistent empty range of switch-cases");
1238 int from=*vals.begin();
1239 int to= *(--vals.end());
1240 if(to+1-from== (
int) vals.size()) {
1245 std::set< int >::const_iterator vit=vals.begin();
1246 for(; vit!=vals.end(); ++ vit) {
1247 if(vit!=vals.begin())
Output() <<
", ";
1273 Output() <<
"WHILE true DO";
1280 Output() <<
"IF " << expression <<
" THEN EXIT; END_IF;";
1287 Output() <<
"END_WHILE;";
1323 std::string res(
"TIME#" + ToStringInteger(val) +
"ms");
1330 Output() << address <<
" := true;" ;
1334 Output() << address <<
" := false;" ;
1338 Output() << expression <<
";";
1342 Iec61131stCodeGenerator::IECVariableType Iec61131stCodeGenerator::CurrentVariableType(
void) {
1343 return mCurrentVariableType;
1346 void Iec61131stCodeGenerator::CurrentVariableType(
const IECVariableType & type) {
1347 mCurrentVariableType = type;
#define FAUDES_REGISTERCODEGENERATOR(ftype, ctype)
Class registration macro.
virtual void CintarrayDeclare(const AA &address, int offset, const std::vector< int > &val)
generate code: conditionals
virtual void CwordarrayDeclare(const AA &address, int offset, const std::vector< word_t > &val)
generate code: conditionals
virtual void DoGenerateCyclicCode(void)
cut-and-paste template for code snippet assembly
Idx Size(void) const
Number of generators.
virtual AX IntarrayConstant(const std::vector< int > &val)
generate code: conditionals
virtual void IfElseIfTrue(const AX &expression)
generate code: conditionals
virtual void SwitchCase(const AA &address, int val)
generate code: conditionals
virtual void FunctionReturn(void)
generate code: conditionals
virtual void DeclareImportPhysicalIo(void)
generate code: conditionals
virtual void LoopBegin(void)
generate code: conditionals
virtual void DeclareStatus(void)
Declare "status".
virtual AA CwordarrayAccess(const AA &address, int index)
generate code: conditionals
Abstract expression; see also Absstract_Addresses.
LineIterator LinesEnd()
Access to line records by iterator.
virtual AX IntegerRemainder(const AX &expression, int val)
generate code: conditionals
virtual void DeclareRecentEvent(void)
Declare "recent_event".
virtual void LiteralCyclic(void)
generate code: conditionals
virtual bool HasCstrarray(void)
generate code: conditionals
virtual void IfWord(const AX &expression)
generate code: conditionals
virtual bool HasMultiCase(void)
generate code: conditionals
virtual std::ostream & Output(void)
Output stream.
virtual void TimerStop(const AA &address)
generate code: conditionals
virtual void Comment(const std::string &text)
Target comments (see EmbeddedcCodeGenerator for consistent reimplementation pattern) ...
virtual void DoGenerateResetCode(void)
cut-and-paste template for code snippet assembly
virtual AA CintarrayAccess(const AA &address, int index)
generate code: conditionals
Code-generator for target IEC 61131-3 ST.
virtual AX WordIsBitSet(const AA &address, int idx)
generate code: conditionals
Implementation of primitives by IEC 61131 ST.
int mWordSize
compressed boolean capacity of target type word
virtual void IfElse(void)
generate code: conditionals
virtual void LineFeed(int lines=1)
LineFeed (convenience support for derived classes)
virtual void BooleanDeclare(const AA &address)
generate code: conditionals
virtual std::string TargetAddress(const AA &address)
abstract address conversion
virtual AA WordarrayAccess(const AA &address, int index)
generate code: conditionals
virtual bool HasCwordarray(void)
generate code: conditionals
virtual AX StringConstant(const std::string &val)
generate code: conditionals
std::string mLiteralCyclic
option: extra cyclic code
virtual void DoGenerateLookups(void)
code generation hook (lookup functions)
virtual void IfTrue(const AX &expression)
generate code: conditionals
virtual AX IntegerConstant(int val)
generate code: conditionals
virtual void IfEnd(void)
generate code: conditionals
virtual void WordAnd(const AA &address, word_t val)
generate code: conditionals
virtual AX IntegerQuotient(const AX &expression, int val)
generate code: conditionals
virtual AA IntarrayAccess(const AA &address, int index)
generate code: conditionals
virtual void DeclareSmallCarray(void)
Declare bit-mask loop-ups.
virtual void RunActionExe(const AX &expression)
generate code: conditionals
virtual AX StrarrayConstant(const std::vector< std::string > &val)
generate code: conditionals
virtual void DeclareAux(void)
Declare variables local to the provided snippets, e.g. helpers for bit-mask computation.
virtual void DeclareLargeCarray(void)
Declare compiled transition relations.
virtual void WordDeclare(const AA &address)
generate code: conditionals
virtual void DeclareImportSymbolicIo(void)
generate code: conditionals
virtual void WordarrayDeclare(const AA &address, int offset, int len)
generate code: conditionals
virtual void DeclareReset(void)
Declare "reset".
virtual void SwitchBreak(void)
generate code: conditionals
Iec61131stCodeGenerator(void)
Constructor.
virtual void DeclareTimers(void)
generate code: conditionals
virtual bool HasIntmaths(void)
generate code: conditionals
std::map< std::string, TimerConfiguration >::iterator TimerIterator
Access to timer records by iterator.
bool mArrayForState
code option: use int arrays to represent that overall state
virtual AX IntegerIsGreater(const AA &address, int val)
generate code: conditionals
virtual void TimerDeclare(const AA &address, const std::string &val)
generate code: conditionals
void DoGenerate(void)
code generation hook (overall)
virtual void IndentInc()
Indentation (convenience support for derived classes)
bool mArrayForBitmasks
code option: use const array to represent bit-masks
virtual void ResetState(void)
generate code: conditionals
std::string mStateUpdateHook
code option: state change hook
virtual void WordNand(const AA &address, const AX &expression)
generate code: conditionals
virtual void ResetState(void)
Reset state.
virtual AX WordarrayConstant(const std::vector< word_t > &val)
generate code: conditionals
virtual void InsertExecHooks(void)
generate code: conditionals
virtual void WordAssign(const AA &address, word_t val)
generate code: conditionals
virtual void IntegerAssign(const AA &address, int val)
generate code: conditionals
virtual void VariableDeclare(const std::string &laddr, const std::string <ype)
generate code: conditionals
virtual void DoReadTargetConfiguration(TokenReader &rTr)
re-implement token i/o for extra configuration
virtual void RunActionClr(const std::string &address)
generate code: conditionals
virtual void IntarrayDeclare(const AA &address, int offset, int len)
generate code: conditionals
static std::string VersionString(void)
Version (refers to macro COMPILEDES_VERSION, defined in cgp_codegenerator.h)
std::string mIntegerType
target data type for integer
virtual AX BooleanIsEq(const AA &op1, const AA &op2)
generate code: conditionals
virtual void DoCompile(void)
virtual hook to extend compiled data
virtual void DeclareStateNameLookup(void)
Declare symbolic name lookup tables.
virtual void LiteralAppend(void)
Cosmetic: append literally from configuration.
virtual void DeclareParallelState(void)
Declare "parallel_state".
virtual void WordOr(const AA &address, word_t val)
generate code: conditionals
virtual void BooleanAssign(const AA &address, int val)
generate code: conditionals
virtual const std::string & Name(void) const
Get objects's name (reimplementing base faudes::Type)
int mIntegerSize
compressed boolean capacity of target type integer
virtual AX WordConstant(word_t val)
generate code: conditionals
std::map< std::string, ActionAddress >::iterator ActionAddressIterator
Access to action record by iterator.
virtual AX WordIsMaskSet(const AA &address, word_t mask)
generate code: conditionals
virtual void DoGenerateFunction(void)
code generation hook (function block)
std::string mWordType
target data type for word
virtual void LoopBreak(const AX &expression)
generate code: conditionals
virtual void DeclareLoopState(void)
Declare loop state, i.e. line levels, loop flag.
bool mEventNameLookup
code option: event name lookup
std::string mIecDeclarePhysical
option: formal declaration of io lines
virtual void DeclarePendingEvents(void)
Declare "pending_events" and "enabled_events".
virtual void SwitchBegin(const AA &address)
generate code: conditionals
virtual void DeclareTimers(void)
Use target implementation to declare timers, typically "timer_run_*" and "timer_cnt_*".
virtual void Clear(void)
Clear all data.
virtual int CountImportSymbolicIo(void)
generate code: conditionals
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
re-implement token i/o for extra configuration
virtual AX WordIsBitClr(const AA &address, int idx)
generate code: conditionals
unsigned long word_t
Code-generator internal data type of target words.
ActionAddressIterator ActionAddressesBegin()
Access to action addresses by iterator.
virtual AX WordIsEq(const AA &address, word_t val)
generate code: conditionals
virtual AX BooleanIsNotEq(const AA &op1, const AA &op2)
generate code: conditionals
virtual void DeclareEventNameLookup(void)
Declare symbolic name lookup tables.
virtual AX TimerIsElapsed(const AA &address)
generate code: conditionals
virtual void RunActionSet(const std::string &address)
generate code: conditionals
virtual void Clear(void)
Clear all data.
virtual ~Iec61131stCodeGenerator(void)
Explicit destructor.
std::string mEventExecutionHook
code option: event exec hook
Abstract address; see also Absstract_Addresses.
virtual bool HasCintarray(void)
generate code: conditionals
virtual int CountImportPhysicalIo(void)
generate code: conditionals
virtual AX IntegerIsEq(const AA &address, int val)
generate code: conditionals
virtual bool HasWordarray(void)
generate code: conditionals
bool mStateNameLookup
code option: state name lookup
virtual AX IntegerIsNotEq(const AA &address, int val)
generate code: conditionals
virtual AX TimeConstant(int val)
generate code: conditionals
ActionAddressIterator ActionAddressesEnd()
Access to action addresses by iterator.
std::string mPrefix
universal prefix (pseudo name space)
virtual AX IntegerBitmask(const AX &expression)
generate code: conditionals
virtual void IndentDec()
Indentation (convenience support for derived classes)
virtual void CstrarrayDeclare(const AA &address, int offset, const std::vector< std::string > &val)
generate code: conditionals
virtual void TimerStart(const AA &address)
generate code: conditionals
virtual void IntegerIncrement(const AA &address, int val)
generate code: conditionals
virtual void DeclareSystime(void)
generate code: conditionals
std::map< std::string, LineAddress >::iterator LineIterator
Access to line records by iterator.
virtual void SwitchEnd(void)
generate code: conditionals
TimerIterator TimersBegin()
Access to timer records by iterator.
bool mHasIecTimeOperators
option: overloaded operators for time maths
virtual void UpdateSystime(void)
generate code: conditionals
virtual void DoReadTargetConfiguration(TokenReader &rTr)
File i/o.
virtual void DecrementTimers(void)
code snippet
std::map< std::string, bitarray_rec > mBitarrays
Record of all declared bit-arrays.
virtual bool HasIntarray(void)
generate code: conditionals
void DoCompile(void)
add my preferences to DoCompile
virtual void TimerReset(const AA &address, const std::string &val)
generate code: conditionals
LineIterator LinesBegin()
Access to line records by iterator.
virtual void IntegerDeclare(const AA &address)
generate code: conditionals
virtual void Comment(const std::string &text)
generate code: conditionals
virtual void LiteralPrepend(void)
Cosmetic: prepend literally from configuration data.
virtual AX WordIsNotEq(const AA &address, word_t val)
generate code: conditionals
virtual void IfFalse(const AX &expression)
generate code: conditionals
virtual void DoWriteTargetConfiguration(TokenWriter &rTw) const
File i/o.
bool mMuteComments
mute comments
virtual void LoopEnd(void)
generate code: conditionals
virtual void SwitchCases(const AA &address, int from, int to)
generate code: conditionals
virtual AA CstrarrayAccess(const AA &address, int index)
generate code: conditionals
bool mBitAddressArithmetic
code option: compute bit and word address on target
std::vector< bool > mHasStateNames
record per generator whether there is a lookup table
virtual AX TargetExpression(const AA &address)
abstract address conversion
virtual AX IntegerIsLess(const AA &address, int val)
generate code: conditionals
Execution semantics in terms of code primitives.
TimerIterator TimersEnd()
Access to timer records by iterator.