Jump to content

Failed State Variable Assignment

Recommended Posts

I’ve implemented a state machine that is triggered when the target state becomes different than the current state.  Everything is working fine but I had to add a ‘wait 1 second’ statement in order to get it to work.  Perhaps someone can explain why the ‘wait’ is needed or what I’ve done wrong to require it (waving my newbie flag here).


The machine has states 0, 1, 2, and 3.  The user may request any state at any time (by keypad entry) but the machine is constrained to only change one state at a time in either ascending or descending order until the user’s requested state is attained.  The end purpose of the state machine is to turn our sound system equipment on/off in proper sequence to prevent damage to our loudspeakers.  State 0 represents all equipment off, state 3 is all equipment on, and states 1 and 2 represent useful and allowable interim states.


Based on the user’s requested state, I compute each interim target state value as an integer variable and then assign it to a state variable in order to trigger the state machine handlers. 


01  UpdateState - [iD 000A][Parent 0006]
02  If
03          $s.CurrentState is not $i.RequestedState
04  Then
05          $i.DeltaState = $i.RequestedState
06          $i.DeltaState -= $s.CurrentState
07          $i.TargetState = $s.CurrentState
08          Run Program 'UpdateStateTargetNeg' (If)
09          Run Program 'UpdateStateTargetPos' (If)
10          Wait 1 second
11          $s.TargetState = $i.TargetState


The purpose of lines 05 - 09 is to compute the next interim target state.  The target state must always be one more or one less that the current state, depending on whether the user requested an ascending or descending transition of states.  Lines 05 and 06 compute the requested state change as deltaState = (requestedState – currentState).  For example if the current state is 0 and the user requests state 3 the delta is +3 (ascending).  If the current state is 2 and the user requests state 0 the delta is -2 (descending).  In line 07 the target state is initialized to the current state so that lines 08 or 09 can add or subtract 1 in accordance with the direction of change.  The subprograms of lines 08 and 09 are trivial:


UpdateStateTargetNeg - [iD 000B][Parent 0006]
        $i.DeltaState < 0
        $i.TargetState -= 1


UpdateStateTargetPos - [iD 000C][Parent 0006]
        $i.DeltaState > 0
        $i.TargetState += 1


Here is where the problem occurs.  Without the ‘wait 1 second’ statement (line 10 above) the state variable s.TargetState does not change (line 11).  It retains the initialized value of s.CurrentState.  There is no event so the transition handler is never triggered, and the state machine gets stuck even though all of the integer variables have the expected values.  With the ‘wait’ everything works like I would expect.  Please help me understand this confusing behavior.


I’ve read through the forum, especially posts by ‘oberkc’ who explains the sequence of triggering from state variable change (http://forum.universal-devices.com/topic/21381-state-variable-change-not-triggering-program/?hl=%2Bstate+%2Bvariable+%2Bevent&do=findComment&comment=207990 and other posts.  None of them quite explain what I am experiencing.


Below is a representative state transition handler for state 0 (all audio equipment off) going to state 1 (audio mixing console on).  It is triggered by the change in s.TargetState.


S00S01 - [iD 0008][Parent 0006]
        $s.TargetState is $i.STATE_CONSOLE
    And $i.DeltaState > 0    // the change is ascending
        Set 'ControlRoom / Console Outlet Top' On
        Set Scene ‘ControlRoom / Keypad LED E' On    // indicator for state 1
        Set Scene 'ControlRoom / Keypad LED G' Off    // indicator for state 0
        $s.CurrentState = $i.STATE_CONSOLE

Please send help in the form of wisdom. 


Link to comment

08          Run Program 'UpdateStateTargetNeg' (If)
09          Run Program 'UpdateStateTargetPos' (If)
10          Wait 1 second


LInes 08 and 09 tell the ISY engine to put these programs on the list for execuion when possible. 

Line 10 tells the ISY engine to allow other programs to run or 1 second and then get back here.


Without the Wait 1 second no voluntary surrender of processing engine attention is given.

 (doesn't give up it's time slice)




BTW:This appears that most of the process could be put into one program without so many variables. I don't see  posted what is calling your programs to cause each step towards  $i.RequestedState. IOW:What is causing the "stepping" to competion, rather than just one step?

Link to comment

Then and Else clauses are atomic.


This means they all happen as a single indivisible entity, just like in the old days when we thought the atom was a single indivisible thing.


So, basically, your running of the other two programs (lines 8 and 9) did not happen before line 10 happened.  


Adding a "wait" . . . "splits the atom".  The wait creates to atomic elements out of your then clause allowing the other two programs to execute and then come back to this program.


Also note, a "repeat" also "splits the atom".

Link to comment

What's your ISY's firmware version?


Michel, sorry I left that out.  We're at v.4.5.4.


larryllix and apostolakisl, thank you for taking the time to absorb my lengthy post.  Thank you for a clear explanation of the subtlety of the Run command and the atomic nature of Then/Else clauses.  As a newbie I just assumed that Run acted like a stacked subroutine in a procedural language.  Now that I understand the sequence of execution I will attempt to rewrite the code to eliminate the Wait statement.


BTW:This appears that most of the process could be put into one program without so many variables. I don't see posted what is calling your programs to cause each step towards $i.RequestedState. IOW:What is causing the "stepping" to competion, rather than just one step?


larryllix, perhaps my design could be simpler but I couldn't find a simpler solution given the two constraints:

  • the state machine transitions must be monotonic (e.g. 0 to 1, 1 to 2, etc.) and not random (e.g. 1 to 3) while
  • the user request buttons can be randomly selected (e.g. requesting 0 to 3 is acceptable since the logic must preserve the step-wise sequence)

I neglected to describe the request mechanism since it wasn't my problem but I will describe it now.  The 'main'  behavior of my system is handled by the program 'UpdateState' as listed in my original post.  There are two ways UpdateState is triggered: 1) a new request is made, or 2) the current state changes but is still different from the requested state.  For new requests, the user has 4 buttons which each trigger a request handler, for example:


01  RequestConsole - [iD 000F][Parent 0006]

02  If

03          Control 'ControlRoom / KeypadF' is switched On

04  Then

05          $i.RequestedState  = $i.STATE_CONSOLE

06          Run Program 'UpdateState' (Then Path)


Note that line 06 above calls UpdateState which will run the Then path provided the requested state is different from the current state.  The other way UpdateState is triggered is by change of the state variable $s.CurrentState.  The state transition handlers (one example listed in my original post) update the current state as their final action, thereby potentially re-triggering UpdateState until at last the current state matches the requested state.  That is the mechanism that causes automatic stepping and is the reason I have three important variables: requested state, current state, and target state.  At each iteration, the new interim target state is computed and the current state becomes the target state until finally they both catch up to the requested state.


Regards and thank you for your contributions to a marvelous forum.


Link to comment


This topic is now archived and is closed to further replies.

  • Create New...