Home NetLinx Studio

Feedback Best Practice Question

CT-DallasCT-Dallas Junior MemberPosts: 157
I am trying to code a feedback statement that would turn on a button channel for feedback to display the current video source in a selected zone.

-There is a structure element that tracks the current input in the zone
-There is an array that tracks what zone the touch panel is controlling (all panels can control all zones).
-The buttons in the nSourceSelectButtons array are mutually exclusive

In essence, I need to do this in a feedback statement:

IF (strAVzones[panelAVzone[1]].zoneInput]) //if the room is on
{
ON [dvPanel1,nSourceSelectButtons[strAVzones[panelAVzone[1]].zoneInput]]
}
ELSE ON[dvPanel1, nSourceSelectButtons[length_array(nSourceSelectButtons)]]//turn on the OFF button which should be the last one in the array


Would this just go in Define_Program? With 30+ panels, I want to do this the most efficient way and I do not think that define_program is the preferred method.

Any help is appreciated.

Thank you!

Comments

  • a_riot42a_riot42 AMX Wizard Posts: 1,619
    You don't need to do the if/else thing when you want to assign the result to a channel anyway. This should do what you want:

    [dvPanel1,nSourceSelectButtons[strAVzones[panelAVzone[1]].zoneInput]] = strAVzones[panelAVzone[1]].zoneInput]

    Don't use define_program if you want a snappy program.
    Paul
  • jazzwyldjazzwyld Registered User Posts: 199
    Instead

    So instead of DEFINE_PROGRAM do you just run a function after the feedback occurs?
  • DHawthorneDHawthorne Junior Member Posts: 4,584
    jazzwyld wrote: »
    So instead of DEFINE_PROGRAM do you just run a function after the feedback occurs?

    For a simple [device, channel] = value sort of feedback, it doesn't matter. Even in DEFINE_PROGRAM, it will only go out when it actually changes. However, overall feedback doesn't generally stay quite so simple, and may also require text updates, etc. So I like to put all my feedback in a function call. It really depends on the type of feedback how I will call that though. If it will only update after a button press, I call the function in the button events that apply. If it only has to update after something comes back from a device, I put it in the data event. If it could go either way, I'll put it right in DEFINE_PROGRAM or in a timeline of a half second or so, taking extreme care to only send feedback that has actually changed and is on display. It may not matter in a small to moderate system, but SEND_COMMAND type feedback can totally bog your project down if you are sending it out more than it needs to. The trick is in knowing when it needs to.
  • jazzwyldjazzwyld Registered User Posts: 199
    Good

    That's what I have been doing, just always good to bounce back an idea.
  • JohnMichnrJohnMichnr Junior Member Posts: 276
    DHawthorne wrote: »
    taking extreme care to only send feedback that has actually changed and is on display.

    So do you track which page the touchpanel is on to know if you can send feedback to that touchpanel?
  • jazzwyldjazzwyld Registered User Posts: 199
    Yes
    JohnMichnr wrote: »
    So do you track which page the touchpanel is on to know if you can send feedback to that touchpanel?

    Yes I do for my talkative modules. Iport, Radio, Kscape, ARQ, DVD... some of them I have written that in, but many of them have some form of that already in the module (ARQ, Iport, Kscape).
  • JohnMichnrJohnMichnr Junior Member Posts: 276
    jazzwyld wrote: »
    Yes I do for my talkative modules. Iport, Radio, Kscape, ARQ, DVD... some of them I have written that in, but many of them have some form of that already in the module (ARQ, Iport, Kscape).

    What method do you use for that? Page tracking? (TPAGEON)
  • jazzwyldjazzwyld Registered User Posts: 199
    Methodical Madness

    When the client presses the source button within my array of commands that happens when the source is pressed. I tell my module to turn on the communication for that touch panel. Are you asking for a sample?
  • JohnMichnrJohnMichnr Junior Member Posts: 276
    jazzwyld wrote: »
    When the client presses the source button within my array of commands that happens when the source is pressed. I tell my module to turn on the communication for that touch panel. Are you asking for a sample?

    Yeah I can see that for source - if you select a source on any panel then update the feedback for that source, on that panel.

    My brain fart is more generic stuff, like lighting and security systems.

    Example - page full of zone information for a secuity system - realtime status of motion dectectors, door locks,etc. If I navigate to that page on the touchpanel, then I should update the current status, and keep the realtime status showing on that page, butonce I've migrated off the page - stop updating. I guess I can trigger all of that from the button presses that get me to and from that page. I was just wondering if there was another way.
  • a_riot42a_riot42 AMX Wizard Posts: 1,619
    JohnMichnr wrote: »
    Yeah I can see that for source - if you select a source on any panel then update the feedback for that source, on that panel.

    My brain fart is more generic stuff, like lighting and security systems.

    Example - page full of zone information for a secuity system - realtime status of motion dectectors, door locks,etc. If I navigate to that page on the touchpanel, then I should update the current status, and keep the realtime status showing on that page, butonce I've migrated off the page - stop updating. I guess I can trigger all of that from the button presses that get me to and from that page. I was just wondering if there was another way.

    You can try setting up some logic based on page tracking ? la TPAGEON, but I wouldn't recommend it as I haven't yet seen the need and it requires a lot of slow text parsing code that would always need changing depending on the page/popup names for the project. To get to any security or lighting page/popup, the user has to hit a button, so it should be fairly obvious that that should be what triggers a change in feedback status.
    Paul
  • jazzwyldjazzwyld Registered User Posts: 199
    I agree

    the feedback many security systems give or lighting as well for that matter of fact.. is minimal especially when compared to the text that sources usually want to throw on the panel.
  • JohnMichnrJohnMichnr Junior Member Posts: 276
    Yeah I can see that the security system would be less than an Ipod or music server, but this system needs to show all the motion sensor status as people move around which is why I got to this point.

    So, excuss me if this is obvious, but I am not connecting the dots today.

    You have an array tracking what source each touchpanel is controlling. As each touchpanel selects a source you update teh feedback and continue to update the feedback based on that array selection. If multiple touchpanels are on the same source - do you go through a loop to send that data to all the touchpanels currently on that source?
  • jjamesjjames AMX Sustaining Engineer Posts: 2,901
    There's nothing wrong with having your feedback in DEFINE_PROGRAM. I do it all the time, and if it's a larger program or have a lot of feedback going on down there, add a WAIT 2 to the entire feedback section. The eye most likely isn't going to see a 2/10 of a second delay, and even if ya do - it's probably not going to be a big deal.

    I think there's been a lot of discussion regarding FOR loops in DEFINE_PROGRAM, but I use them something like this:
    DEFINE_PROGRAM
    WAIT 2
    {
    	FOR(nLOOP=1;nLOOP<=LENGTH_ARRAY(dv_TP);nLOOP++)
    	{
    		[dv_TP[nLOOP],231] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 1)
    		[dv_TP[nLOOP],232] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 2)
    		[dv_TP[nLOOP],233] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 3)
    		[dv_TP[nLOOP],234] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 4)
    		[dv_TP[nLOOP],235] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 5)
    	}                                                         
    }
    
  • a_riot42a_riot42 AMX Wizard Posts: 1,619
    jjames wrote: »
    DEFINE_PROGRAM
    WAIT 2
    {
    	FOR(nLOOP=1;nLOOP<=LENGTH_ARRAY(dv_TP);nLOOP++)
    	{
    		[dv_TP[nLOOP],231] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 1)
    		[dv_TP[nLOOP],232] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 2)
    		[dv_TP[nLOOP],233] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 3)
    		[dv_TP[nLOOP],234] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 4)
    		[dv_TP[nLOOP],235] = (nAV_ZONE_SOURCE[nPNL_ZONE[nLOOP]] == 5)
    	}                                                         
    }
    

    The brute force way will work too, although that's quite a bit of context switching to do to highlight some buttons that 99% of the time are static. Would this not do the same thing without the for loop?
    DEFINE_PROGRAM
    WAIT 2
    {
    		[dv_TP,231] = (nAV_ZONE_SOURCE[nPNL_ZONE[1]] == 1)
    		[dv_TP,232] = (nAV_ZONE_SOURCE[nPNL_ZONE[2]] == 2)
    		[dv_TP,233] = (nAV_ZONE_SOURCE[nPNL_ZONE[3]] == 3)
    		[dv_TP,234] = (nAV_ZONE_SOURCE[nPNL_ZONE[4]] == 4)
    		[dv_TP,235] = (nAV_ZONE_SOURCE[nPNL_ZONE[5]] == 5)
                                                             
    }
    
    Paul
  • jjamesjjames AMX Sustaining Engineer Posts: 2,901
    a_riot42 wrote: »
    Would this not do the same thing without the for loop?
    DEFINE_PROGRAM
    WAIT 2
    {
    		[dv_TP,231] = (nAV_ZONE_SOURCE[nPNL_ZONE[1]] == 1)
    		[dv_TP,232] = (nAV_ZONE_SOURCE[nPNL_ZONE[2]] == 2)
    		[dv_TP,233] = (nAV_ZONE_SOURCE[nPNL_ZONE[3]] == 3)
    		[dv_TP,234] = (nAV_ZONE_SOURCE[nPNL_ZONE[4]] == 4)
    		[dv_TP,235] = (nAV_ZONE_SOURCE[nPNL_ZONE[5]] == 5)
                                                             
    }
    
    No actually since in my code (and I should have been a bit more clear) dv_TP is a dev array of the touch panels. So with example above, the feedback would go for all panels. A more brute force way could be done yes, but "hard coding" many of these things means plenty of changes if one thing changes. Take for example, what I *really* do in code for feedback is:
    FOR(nLOOP=1;nLOOP<=LENGTH_ARRAY(dv_TP);nLOOP++)
    {
    	FOR(nLOOP2 = 1;nLOOP2<=LENGTH_ARRAY(nSRC_BTNS);nLOOP2++)
    	{
    		[dv_TP[nLOOP],nSRC_BTNS[nLOOP2]] = (nAV_ZONE_SOURCE[nPNL_AV[nLOOP]] == nLOOP2)
    	}
    }  
    
    where:
    * dv_TP is the dev array of panels
    * nSRC_BTNS is an integer array of source buttons
    * nAV_ZONE_SOURCE is an integer array to keep track of the source of the zone
    * nPNL_AV is an integer array the same size as dv_TP and holds which zone the panel is currently controlling

    Now, should anything change, either in definitions (i.e. nSRC_BTNS, dv_TP's length, etc.) or in variable (which zone the panel is controlling) my feedback code for these buttons will not need to be modified.

    Of course, this could be done in a timeline, or a function, but I'll keep skinning my cats this way for now. ;)
  • JohnMichnrJohnMichnr Junior Member Posts: 276
    jjames - I've user similar array layouts when I'm doing multiple room combining, funny I didn't think about that till now...

    But what I am wondering is what do you do if you are using send_commands instead of simple [dvTP,something]==(valuesomething=somethingelse)?

    I've got a bunch of buttons with 4 states for different conditions, in the past I woudl have just updated the touchpanel dev array when ever there was a state change and not carred if there was one touchpanel on the page or 20. But after reading a number of these thread I am beginning to realize that might be an issue.

    For one touchpanel it is not a problem to update based on the dev array and a place holder, how do you update multiple touchpanels on the same page - other than adding or removing panels from the dev array, or by doing a loop?
  • jjamesjjames AMX Sustaining Engineer Posts: 2,901
    If the button has several states, I usually make them multi-state bargraph and do a SEND_LEVEL the same exact way as I do the button feedback since a SEND_LEVEL is only issued / received / processed if the level has changed (at least that's how it was explained to me at one point, but I forget by whom.)

    All in all, I use a loop for nearly everything. If the system starts to get bogged down I throw in a WAIT of about 2 or 3 tenths of a second. Not sure if it answers your question, but I do use SEND_LEVELs in DEFINE_PROGRAM. I wonder if setting up a LEVEL_EVENT would be any better, that way you could only change the levels when needed instead of it being sent every pass of DEFINE_PROGRAM.

    Ideas anyone?
  • JohnMichnrJohnMichnr Junior Member Posts: 276
    jjames wrote: »
    I usually make them multi-state bargraph and do a SEND_LEVEL the same exact way as I do the button feedback since a SEND_LEVEL is only issued / received / processed if the level has changed (at least that's how it was explained to me at one point, but I forget by whom.)

    Ahh - I had not thought of that - I like that way of handeling it - for the same reason you mention above. And as long as you are using a dev array and not a virtual device, you don't have to worry about setting the virtual level count.
  • CT-DallasCT-Dallas Junior Member Posts: 157
    Thanks for the help guys. Unfortunatly for me, I need to keep the loop with conditionals because the .zoneinput = 0 when the zone is off.

    Without the conditional, I get do number errors in telnet when the structure value is 0 because it is looking for the 0 spot of the array.

    Oddly enough, I tried the code in define_program and still got the errors -- even with the conditional that .zoneinput needed to be greater than 0.

    I am going to throw it into a feedback timeline later today and see if the processor evaluates the statement differently.
  • CT-DallasCT-Dallas Junior Member Posts: 157
    geez!

    Have you ever found that you find your keys in the last place you look... oh so are the woes of our coding errors...

    right in the beginning strAVzones[panelAVzone[nLoopCounter]] <- I neglected to remember that panelAVzone[nLoopCounter] piece of the equation could be zero, hence the do number zero errors.

    So, after I rectify this and feel pretty good, I uploaded it and showed the client. Oops! Not what they were looking for. It seems as if I missed the point of the exercise. When they asked for functionality that would display what source is currently in use, I took that to mean, show what source is playing in the zone. If you change zones on the touch panel, you see what the other zone is using.... Not exactly what they wanted. In fact, they wanted something far more simple...

    If a source is in use, turn the button 'on' for all panels regardless of what they are watching so we know what other sources are available. This is a distributed video system and they find that they are constantly asking the other person in the house what source they are using so they can use a different source. If they have guests, they want to be able to say - look here and if it is not a different color, you can pick it.

    After showing them my take on it and hearing how it was not operating the way they wanted, the solution was far easier than the path I had originally taken. Way to complicate things Chris!
    Timeline_Event[TL_FEEDBACK] 
    {    
        (*audio source feedback - if a source is in use, show it on all touch panels*)
        (*reset source usage counters*)
        source1counter = 0
        source2counter = 0
        source3counter = 0
        source4counter = 0
        source5counter = 0
        source6counter = 0
        source7counter = 0
        
        FOR (nLoopCntr=1;nLoopCntr<=numberOfAVZones;nLoopCntr++)
        {
    	//as we search the zones, if any of the zones are on - then move to the next step and show what sources are in use
    	IF (strAVzones[nLoopCntr].zoneInput)
    	{
    	    SWITCH (strAVzones[nLoopCntr].zoneInput)
    	    {
    		case 1: 
    		{
    		    ON [dvGlobalTP,nSourceSelectButtons[1]]
    		    source1counter++ // add 1 to the source 1 counter
    		}
    		case 2: 
    		{
    		    ON [dvGlobalTP,nSourceSelectButtons[2]]
    		    source2counter++ // add 1 to the source 2 counter
    		}
    		case 3: 
    		{
    		    ON [dvGlobalTP,nSourceSelectButtons[3]]
    		    source3counter++ // add 1 to the source 3 counter
    		}
    		case 4: 
    		{
    		    ON [dvGlobalTP,nSourceSelectButtons[4]]
    		    source4counter++ // add 1 to the source 4 counter
    		}
    		case 5: 
    		{
    		    ON [dvGlobalTP,nSourceSelectButtons[5]]
    		    source5counter++ // add 1 to the source 5 counter
    		}
    		case 6: 
    		{
    		    ON [dvGlobalTP,nSourceSelectButtons[6]]
    		    source6counter++ // add 1 to the source 6 counter
    		}
    		case 7: 
    		{
    		    ON [dvGlobalTP,nSourceSelectButtons[7]]
    		    source7counter++ // add 1 to the source 7 counter
    		}//end case
    	    }//end switch
    	}//end if
        }//end for
        IF (!source1counter) //if after searching the zones, no one is using the source -- turn off the button
        {
    	OFF [dvGlobalTP,nSourceSelectButtons[1]]
        }
        IF (!source2counter) //if after searching the zones, no one is using the source -- turn off the button
        {
    	OFF [dvGlobalTP,nSourceSelectButtons[2]]
        }
        IF (!source3counter) //if after searching the zones, no one is using the source -- turn off the button
        {
    	OFF [dvGlobalTP,nSourceSelectButtons[3]]
        }
        IF (!source4counter) //if after searching the zones, no one is using the source -- turn off the button
        {
    	OFF [dvGlobalTP,nSourceSelectButtons[4]]
        }
        IF (!source5counter) //if after searching the zones, no one is using the source -- turn off the button
        {
    	OFF [dvGlobalTP,nSourceSelectButtons[5]]
        }
        IF (!source6counter) //if after searching the zones, no one is using the source -- turn off the button
        {
    	OFF [dvGlobalTP,nSourceSelectButtons[6]]
        }
        IF (!source7counter) //if after searching the zones, no one is using the source -- turn off the button
        {
    	OFF [dvGlobalTP,nSourceSelectButtons[7]]
        }//end if
    }//end timeline event
    
  • a_riot42a_riot42 AMX Wizard Posts: 1,619
    CT-Dallas wrote: »
    Have you ever found that you find your keys in the last place you look... oh so are the woes of our coding errors...

    You seem to have a lot of code to do something very simple, at least if I followed your code correctly. Are you sure there isn't a more concise and robust way of doing this?
    Paul
  • CT-DallasCT-Dallas Junior Member Posts: 157
    I'm all for it if there is a shorter way. Essentially, I need to:
    1) poll the .zoneinput section of the avzones array to see if a zone is on and what source it is using
    2) If they are in use, turn the button on
    3) If after searching all of the zones and the source is not in use - turn the feedback off.
  • a_riot42a_riot42 AMX Wizard Posts: 1,619
    CT-Dallas wrote: »
    I'm all for it if there is a shorter way. Essentially, I need to:
    1) poll the .zoneinput section of the avzones array to see if a zone is on and what source it is using
    2) If they are in use, turn the button on
    3) If after searching all of the zones and the source is not in use - turn the feedback off.

    I guess I don't understand the searching part. I think what I would do, is if a user hits a source button, just turn that channel on for all the touch panels. Then make the source channels all mutually exclusive so that when one gets turned on the other sources get turned off. Would this not work?

    Regarding the users request that they be able to see what sources are currently on, I usually give them a page or popup that allows them to select the room they want to control and on that page it indicates what sources are being used in which room so that at a glance the user can see what is going on in the whole house. Not the only way to do it, but in a shared environment it is pretty imperative that the users know if another source is being used so they don't get into having remote wars.
    Paul
  • CT-DallasCT-Dallas Junior Member Posts: 157
    Paul,
    The logic of the panel is to select the AV button from the main menu, and you are taken to a source selection/volume screen for the default zone of the panel. From there, if you pick a source - you are taken to a control screen for that source. Users can select a zones screen to control another zone in the system. From the zones screen, you can see if a zone is on, but not what source it is using. There are roughly 30 AV zones in the project and I could not fit all the data on one screen. After selecting the zone, you go back to the source selection/volume screen for the zone - you now control the selected zone and not the default zone for the panel.

    I originally had the buttons as mutually exclusives, and had them showing what was on in a particular zone. Meaning, if I select zone 1, I see what is playing in there, etc. However after seeing what that looked like, the homeowner decided that is not what they wanted. With as few button presses as possible, they wanted to be able to see what was in use and what was not.

    In this case, the problem with the mutually exclisive is if zone 1 is watching source 1, and then zone 10 selects source 4 - the mutually exclusive would then only show the last selected source.

    They want to be able to look at the source selection page and see what sources are currently in use anywhere in the house. In this example, button channels for source 1 and source 4 would be ON to indicate that somewhere in the system, those sources are in use.

    The reason I think I need to search for whether or not any of the zones are using a particular source is to ensure that if 1 zone is using it, the button stays lit. If no zones are using the source, turn it off.

    If a user in zone 4 is on source 1, and a user in zone 20 is on source 1 - then one turns it off, the button should stay lit because at least one zone is still using it.

    I guess the only reason I was avoiding triggering the ON state via the button press for source selection is that other actions trigger AV outside of the source selection buttons. I guess I could put these into a function that is called by the other triggers. The search for the OFF state could also go into the function as well. I presume that would free up system resources.
  • viningvining X Member Posts: 4,368
    What if you added another for loop and declared another constant for the number of inputs like this:
    Timeline_Event[TL_FEEDBACK] 
         
         { 
         STACK_VAR INTEGER nIputCntr ;
              
         FOR (nIputCntr=1;nIputCntr<=NumAV_Inputs;nIputCntr++)
    	  {
    	  STACK_VAR INTEGER nZoneCntr ;
    	  STACK_VAR INTEGER nInputActive ;
    	  
    	  FOR (nZoneCntr=1;nZoneCntr<=NumAV_Zones;nZoneCntr++)
    	       {
    	       IF (strAVzones[nZoneCntr].zoneInput == nIputCntr)
    		    {
    		    ON [dvGlobalTP,nSourceSelectButtons[nIputCntr]] ;
    		    nZoneCntr = nNumAV_Zones + 1 ;//exit after 1st match
    		    nInputActive = 1 ;
    		    }
    	       }
    	  if(!nInputActive)
    	       {
    	       OFF [dvGlobalTP,nSourceSelectButtons[nIputCntr]] ;
    	       }
    	  }
         }
    
    This isn't tested but it should do what you want and it's shorter. The end result would be the same, just another approach.
  • CT-DallasCT-Dallas Junior Member Posts: 157
    that looks pretty clean. I'll give it a shot.

    Thanks.
  • viningvining X Member Posts: 4,368
    If that code actually works you could then take it a step further and when ever any tp goes to the input page you check to see if the timeline is active and if not create it (start it). Create an array to track which tps are on page, set its corresponding index to 1 when on and 0 when off. When ever a tp goes off run a function to check the array to determine if any other tps are on page and when the function returns and no tps are on the input page you can then kill the timeline.

    You could also take that another step since you now know what tps are on page you can run your feedback through another for loop and just update the tps that are actually on the input page. However if you do that you'll need to also track and make adjusments to this tracking array when a panel falls offline and possible other unexpected events.

    You could also move your feedback into your events and make everything event driven. That's currently the practice I try to achieve but it requires a bit more work to do that. I still usually have a timeline to run polling (in needed) or to check Rx Buffer and Tx Queues and maybe some feedback or other crap. I would then stop & stop that timeline depending on whether any tps are on page.
Sign In or Register to comment.