Author |
|
jeffw_00 Super User
Joined: June 30 2007
Online Status: Offline Posts: 929
|
Posted: January 24 2008 at 21:13 | IP Logged
|
|
|
Hi - Setting Macro Jump Limit to a finite value seems like a good thing to do. I have it set to 500. I have a macro that loops 200 times and stops (it's for testing). I run the macro monday, run it again tuesday, and then on wednesday. On wednesday it stops 1/2 way through because it hit the limit.
(the loop is implemented with a Jump, Test, and Increment).
Does this mean that PH keeps a count for all my macros and at some point in the year, all of them with "loops" will time out? What does this Limit really check? Am I better off leaving it blank (or setting it to a really high number?)
Thanks
/j
|
Back to Top |
|
|
dhoward Admin Group
Joined: June 29 2001 Location: United States
Online Status: Offline Posts: 4447
|
Posted: January 26 2008 at 23:33 | IP Logged
|
|
|
PowerHome provides 3 parameters to try and keep bad code from causing the system to lock up. They are all on the Script page in the Setup section of the PowerHome Explorer. Macro Jump limit is one of these along with Global Variable maximum substitutions and Maximum number of recursive calls. Setting these parameters to a value above 0 is generally a good thing to do. The particular value depends a great deal on what a person is doing and their particular coding style. I'll detail the way these parameters work below along with an example of code they're trying to prevent. Keep in mind that setting any of these parameters to 0 effectively turns that particular checking off.
Macro Jump Limit: This parameter is designed to catch infinite loops within a macro. When a macro is first executed, a counter is initialized and set to 0. Everytime the macro executes a "Jump" command or a "Goto Label" command, this counter is incremented. The counter is unique to each macro and is destroyed when the macro terminates. You would typically set this to a value higher than the total number of jumps or loops that you expect to do in the macro. What it sounds like is happening in your case is that you have a macro that is executed, loops 200 times (the counter will now be at 200). If the macro then terminates and is restarted later, then no problem. Since you ran 200 times on Monday, 200 times on Tuesday, and 100 times on Wednesday, then your macro never terminated. What Im guessing you're doing is a "Wait" command. When a macro waits, it's variables are stored...including the jump counter. Now if you're sure that your code does not have any infinite loops, then you would be safe in just turning the Macro Jump Limit check off by setting it to 0. This is the default setting. You could then turn it on only when you suspect a problem and PowerHome is hanging.
This setting will catch infinite loops within a macro. A common mistake people make when first creating loops, is creating a loop without a way to exit. They may thing they have an exit created, but due to a code error or a condition they don't expect, the macro loops indefinately and PowerHome is effectively hung. A sampe infinite loop is:
10 Set System [LOCAL1] 1
20 ...
30 ...
40 Set System [LOCAL1] "[LOCAL1]" + 1
50 Jump if([LOCAL1] > 10,1, - 4)
The error above is in line 40. [LOCAL1] never really changes because it was cast as a string with a numeric 1 added to it. The result is an error so [LOCAL1] will never be greater than 10.
Maximum Number of Recursive calls: This parameter is again tied to macros and is designed to catch not infinite loops within a macro, but infinite recursion between multiple macros. Every time a macro is called, a GLOBAL recursion counter is incremented. If a Sub Macro is called, the counter is also incremented. Everytime a macro terminates, the counter is decremented. This parameter has nothing to do with the number of times a macro waits, loops, or jumps. It is only modified (incremented) when a macro or submacro is first launched (not resumed) and decremented when a submacro or macro terminates.
An example of infinite recursion is:
Macro "ABC"
10 Set System [LOCAL1] 123
20 Macro DEF
Macro "DEF"
10 Set System [TEMP2] 456
20 Macro ABC
The part that is a problem here is that when Macro ABC is executed, it will run and then call macro DEF in line 20. Macro DEF will then launch (macro ABC did not terminate...it's waiting for macro DEF to finish and return). Macro DEF eventually gets to line 20 when in turn calls macro ABC and the cycle continues ad infinitum and PowerHome is locked. Maxiumum recursion will catch this situation and terminate the macro.
Global Variable Maximum Substitutions: This parameter is not dependent upon macros and is designed to catch another possible way of sending PH into vapor lock. When a Global Variable is evaluated (or a formula containing a global variable is evaluated) a global variable substitution is performed (this applies to system variables as well). This substitution continues until no more variables require substitution in which case the formula evaluation is actually performed. Everytime a substitution process is performed, two counters are initialized. A counter for global variables, and a counter for system variables. With each actual substitution, the appropriate counter is incremented. When substitution is complete, the counters are destroyed and evaluation is performed. An example of an infinite loop using variables is below:
{TEST} contains the string "[LOCAL1] + 1"
[LOCAL1] contains the string "[LOCAL2] + [LOCAL3]"
[LOCAL2] contains the string "{TEST}"
[LOCAL3] contains 5
If you have a formula that contains {TEST}, then it will loop indefinately in variable substitution and PowerHome will be hung. If the formula is:
"The answer is: " + {TEST}
then the first substitution will yield a new formula of:
"The answer is: " + [LOCAL1] + 1
followed by:
"The answer is: " + [LOCAL2] + [LOCAL3] + 1
followed by:
"The answer is: " + {TEST} + 5 + 1
which will repeat forever.
Sorry to be so long winded, but I havent documented this functionality in quite some time and figured this was a good excuse to do so.
Hope this helps,
Dave.
|
Back to Top |
|
|
jeffw_00 Super User
Joined: June 30 2007
Online Status: Offline Posts: 929
|
Posted: January 27 2008 at 11:53 | IP Logged
|
|
|
Thanks Dave - very helpful indeed. However, what concerned me was that the macro terminated and was manually re-started each day. I've seen this at other times. Where I ran a "loop 200 times" macro a few times in an evening, each time killing it and restarting it manually, and by the 3rd time it dies by itself in the middle due to the Macro Jump Limit. It's not a big deal, but I would contend there's a way to terminate a macro without clearing the counter.
thanks
/j
|
Back to Top |
|
|
dhoward Admin Group
Joined: June 29 2001 Location: United States
Online Status: Offline Posts: 4447
|
Posted: January 29 2008 at 22:45 | IP Logged
|
|
|
Jeff,
I tried to duplicate this and was unsuccessful . I set my macro jump limit to 500, reinitialized, and created a new test macro. The macro was very simple:
10 Set System [LOCAL1] 1
20 Set System [LOCAL1] [LOCAL1] + 1
30 Jump if([LOCAL1] = 200,1, - 1)
I executed it 5 times in a row and had no errors. I changed the 200 in line 30, reran, and indeed got the macro jump limit exceeded error.
Can you post the relevant parts (or all parts) of the macro that is giving you problems? It's possible that something else is triggering the problem. Also, the key may be in the method that the macro is being called. Let me know what is triggering the playback of the macro as there may be something that is causing the variable to not reset. The method I used to test was to just right-click the macro (after I created it) and select "Play" from the popup.
Thanks,
Dave.
|
Back to Top |
|
|
jeffw_00 Super User
Joined: June 30 2007
Online Status: Offline Posts: 929
|
Posted: January 30 2008 at 21:57 | IP Logged
|
|
|
Hi Dave - it's not worth much of your time. here's the macro. you can see that it runs 200 times and stops. Problem is. when I start it again, the macro jump count doesn't seem to get reset. But again, doesn't bother me.
The macro is started by the Play (right-click) option within powerhome. I use this to test modules by cycling them 200 times.
/j
insert into macroheader values ('SEND_INSTEON_TEST','Generic INSTEON Sender',0,0,1);
insert into macrodetail values ('SEND_INSTEON_TEST',1,10,'TESTVAR',NULL,'0',1,'');
insert into macrodetail values ('SEND_INSTEON_TEST',2,15,'[LOCAL1]',NULL,'"BDRM3SOUNDI"',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',3,15,'[LOCAL2]',NULL,'0',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',4,15,'[LOCAL3]',NULL,'0',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',5,15,'[LOCAL4]',NULL,'0',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',6,15,'[LOCAL5]',NULL,'0',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',7,38,'',0,'ph_addtoglobal("TESTVAR",1)' ,0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',8,16,'',NULL,'if({TESTVAR}>200,999,1 )',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',9,15,'[LOCAL2]',NULL,'if([LOCAL2]=1,0,1)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',10,31,'',NULL,'5',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',11,37,'',NULL,'[LOCAL1] is the id of the device. [LOCAL2] is the desired state (1=on, 0=off). [LOCAL3] is 1 if the source was a trigger, 0 if a timed event (we try harder on timed events) [LOCAL9] and [LOCAL10] used internally',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',12,36,'',NULL,'"CALLED WITH: " + ph_getvar_s(1,1) + " | " + ph_getvar_n(1,2) + " | " + ph_getvar_n(1,3) ',1,'');
insert into macrodetail values ('SEND_INSTEON_TEST',13,37,'',NULL,'First - see if the device is already in the desired state, if it is, we''re done. Otherwise, send it a command, and wait 5 seconds',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',14,37,'',NULL,'Next 3 lines check current module status, set [LOCAL10] as follows: 0=off, 1=on, 2=can''t contact module, 3 = bad module name, and exit if module status is at desired state. This 3-line code block is repeated 4 more times in this macro',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',15,38,'',0,'if([LOCAL2] = 0, ph_insteon( "[LOCAL1]", ifastoff, 0), ph_insteon( "[LOCAL1]", ifaston, 0))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',16,31,'',NULL,'5',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',17,37,'',NULL,'Now see if we succeeded, if not, try again',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',18,38,'',0,'ph_setvar_a(1,9,ph_getinste onlevelrt("[LOCAL1]"))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',19,38,'',0,'ph_setvar_a(1,10,if([LOCAL9]=0,0,if([LOCAL9]>0,1,if([LOCAL9]= -2 ,2, 3))))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',20,16,'',NULL,'if([LOCAL10]=(ph_getvar_n(1,2)), -13 ,1)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',21,36,'',NULL,'"INSTEON RETRY: Device " + ph_getvar_s(1,1) + ", Desired State " + ph_getvar_n(1,2) + ", Trigger " + ph_getvar_n(1,3) + ", Returned Status " + ph_getvar_n(1,10)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',22,38,'',0,'ph_macroparm("SENDEMAIL","I NSTEON RETRY: Device [LOCAL1], Desired State [LOCAL2], Trigger [LOCAL3], Error Type [LOCAL10]",0,0,0,0)',1,'');
insert into macrodetail values ('SEND_INSTEON_TEST',23,38,'',0,'if([LOCAL2] = 0, ph_insteon( "[LOCAL1]", ifastoff, 0), ph_insteon( "[LOCAL1]", ifaston, 0))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',24,31,'',NULL,'5',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',25,38,'',0,'ph_setvar_a(1,9,ph_getinste onlevelrt("[LOCAL1]"))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',26,38,'',0,'ph_setvar_a(1,10,if([LOCAL9]=0,0,if([LOCAL9]>0,1,if([LOCAL9]= -2 ,2, 3))))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',27,16,'',NULL,'if([LOCAL10]=(ph_getvar_n(1,2)), -20 ,1)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',28,37,'',NULL,'If we still haven''t succeeded, but it was a trigger, one more try and then we''re done, otherwise wait 60 sec and try again',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',29,16,'',NULL,'if((ph_getvar_n(1,3)) = 1,3,1)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',30,31,'',NULL,'20',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',31,38,'',0,'ph_setvar_a(1,9,ph_getinste onlevelrt("[LOCAL1]"))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',32,38,'',0,'ph_setvar_a(1,10,if([LOCAL9]=0,0,if([LOCAL9]>0,1,if([LOCAL9]= -2 ,2, 3))))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',33,16,'',NULL,'if([LOCAL10]=(ph_getvar_n(1,2)), -26 ,1)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',34,36,'',NULL,'"INSTEON RETRY: Device " + ph_getvar_s(1,1) + ", Desired State " + ph_getvar_n(1,2) + ", Trigger " + ph_getvar_n(1,3) + ", Returned Status " + ph_getvar_n(1,10)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',35,38,'',0,'ph_macroparm("SENDEMAIL","I NSTEON RETRY: Device [LOCAL1], Desired State [LOCAL2], Trigger [LOCAL3], Error Type [LOCAL10]",0,0,0,0)',1,'');
insert into macrodetail values ('SEND_INSTEON_TEST',36,38,'',0,'if([LOCAL2] = 0, ph_insteon( "[LOCAL1]", ifastoff, 0), ph_insteon( "[LOCAL1]", ifaston, 0))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',37,31,'',NULL,'5',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',38,38,'',0,'ph_setvar_a(1,9,ph_getinste onlevelrt("[LOCAL1]"))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',39,38,'',0,'ph_setvar_a(1,10,if([LOCAL9]=0,0,if([LOCAL9]>0,1,if([LOCAL9]= -2 ,2, 3))))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',40,16,'',NULL,'if([LOCAL10]=(ph_getvar_n(1,2)), -33 ,1)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',41,37,'',NULL,'No more retries - log the error.',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',42,38,'',0,'ph_addtoglobal("IERROR",1)' ,0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',43,38,'',0,'ph_setccobjtext ( "MAIN", "IERROR_BUTTON", "{IERROR} INSTEON ERROR(S)" ) ',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',44,38,'',0,'ph_setccobjfcolor("MAIN","I ERROR_BUTTON",rgb(255,0,0))',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',45,16,'',NULL,'if({IERROR} > 12,999,1)',0,'');
insert into macrodetail values ('SEND_INSTEON_TEST',46,38,'',0,'ph_macroparm("SENDEMAIL","I NSTEON ERROR (count = {IERROR} ), Device [LOCAL1], Desired State [LOCAL2], Trigger [LOCAL3], Returned Status [LOCAL10]",0,0,0,0)',1,'');
Edited by jeffw_00 - January 30 2008 at 21:58
|
Back to Top |
|
|
|
|