Home AMX User Forum AMX General Discussion

TP Button Feedback Statements?

I have often wondered what others are doing for button feedback statements on TPs. Some disagree with putting them in mainline (Define Program Block)
i.e.
Define Program
[dvTP,38]=[dvRELAY,1] //Simple statement for illustration purposes

What are you doing? This is just a curiosity thing :)

Comments

  • TurnipTruckTurnipTruck Posts: 1,485
    Tworhythms wrote: »
    I have often wondered what others are doing for button feedback statements on TPs. Some disagree with putting them in mainline (Define Program Block)
    i.e.
    Define Program
    [dvTP,38]=[dvRELAY,1] //Simple statement for illustration purposes

    What are you doing? This is just a curiosity thing :)

    I generally associate my button feedback with a state change from a device or from a module. When the state changes, the feedback goes with it and I also note the state change in a variable for refreshing feedback on UI online events. This method is best when using dev arrays for multiple TPs. I don't combine panels, so I would need a feedback statement for each button and each panel if using define program.

    It always seemed lame to put feedback in define program, but the Programmer III teacher does it that way! It's probably OK fo single panel systems.
  • chillchill Posts: 186
    I generally associate my button feedback with a state change from a device or from a module. When the state changes, the feedback goes with it and I also note the state change in a variable for refreshing feedback on UI online events. This method is best when using dev arrays for multiple TPs. I don't combine panels, so I would need a feedback statement for each button and each panel if using define program.

    It always seemed lame to put feedback in define program, but the Programmer III teacher does it that way! It's probably OK fo single panel systems.

    I used to to feedback in mainline, but things get pretty bogged down in a big system where you're trying to update thousands of buttons on every pass through mainline. For several years now I've been updating button feedback in a timeline that runs every 150 to 200 ms. This works very well; it's fast enough to appear instantaneous to the human eye, but slow enough to take a load off the processor. And yes, my feedback is real - the source select button doesn't light up until the switcher and display both claim to be on the appropriate input.
  • DHawthorneDHawthorne Posts: 4,584
    I generally associate my button feedback with a state change from a device or from a module. When the state changes, the feedback goes with it and I also note the state change in a variable for refreshing feedback on UI online events. This method is best when using dev arrays for multiple TPs. I don't combine panels, so I would need a feedback statement for each button and each panel if using define program.

    This is not necessary with button channels, the master already does this kind of tracking internally (except if it's a virtual device). Try it - turn on notifications, and put your feedback statement in mainline. You will see it only changes when the value you are comparing with changes. It is not necessary with levels either, only with feedback that relies on SEND_COMMANDs.

    That said, I always make a function or CALL for my feedback. If it's a small system and the feedback generates little traffic, I'll call it in mainline; if that generates too much master load, I'll put it in a timeline. Since it's already modularized into a function, the change is trivial. For modules, I'll go a step further and only call the feedback routine when something happens that might change the feedback, like a button press, incoming string, or a page change. I would use that method universally, but when you have a half dozen modules changing things outside the scope of the parent program, it can get messy, so I leave that to modules that are doing one thing alone.
  • TurnipTruckTurnipTruck Posts: 1,485
    DHawthorne wrote: »
    Try it - turn on notifications, and put your feedback statement in mainline. You will see it only changes when the value you are comparing with changes. It is not necessary with levels either, only with feedback that relies on SEND_COMMANDs.

    I've seen that and was quite suprised. No one at AMX has been able to explain exactly how that works.

    I've found that discrete feedback statements can be quite clumsy for multiple panels in dev arrays. I have not found a way to be able to say:

    [tparray,1]=feedback_flag

    Each TP must be be stated seperately.
  • jjamesjjames Posts: 2,908
    Could just loop through the DEV array rather than doing it discretely - but by saying that, I know I'll start a debate on what is more efficient.

    Here's my source feedback statement for my code:
    FOR (nLOOP=1;nLOOP<=LENGTH_ARRAY(dv_TP);nLOOP++)
    {
    	// Source feedback
    	FOR(nLOOP1 = 1;nLOOP1<=LENGTH_ARRAY(nSOURCE_BTNS);nLOOP1++)	// Loop btns
    		[dv_TP[nLOOP],nSOURCE_BTNS[nLOOP1]]=(nPOP_FB[nLOOP]==nLOOP1)// Turn on according to pop up feedback var
    }
    
  • DHawthorneDHawthorne Posts: 4,584
    I use a FOR loop like jjames describes, except that I have found that you can't reliably use LENGTH_ARRAY for an array passed to a module, so I generally set up a constant for array dimensions that I can use for capping the FOR loop as well.
  • Feedback idea update
    jjames wrote: »
    Could just loop through the DEV array rather than doing it discretely - but by saying that, I know I'll start a debate on what is more efficient.

    Here's my source feedback statement for my code:
    FOR (nLOOP=1;nLOOP<=LENGTH_ARRAY(dv_TP);nLOOP++)
    {
    	// Source feedback
    	FOR(nLOOP1 = 1;nLOOP1<=LENGTH_ARRAY(nSOURCE_BTNS);nLOOP1++)	// Loop btns
    		[dv_TP[nLOOP],nSOURCE_BTNS[nLOOP1]]=(nPOP_FB[nLOOP]==nLOOP1)// Turn on according to pop up feedback var
    }
    
    For all you code heads out there, I did some reasearch into this topic recently and might be able to shed some new light on the topic.

    Depending on the size of the compiled program, you can except the Define_Program section to loop anywhere from between 100 to +300 times per second. So at a minimum you can expect at least 100 loops per second no matter what is going on with the event queue.

    Those of you like myself who prefer to put your feedback statements in Define_Program can use this to your advantage. In Jay's example above we can make the program run more efficiently by letting the Define_Program section become your first "for loop."

    Revised concept below:
    Define_Program
    [color=green]// The variable nTP_Loop represents a counter for the number of touch panels in the program[/color]
    nTP_Loop++  [color=green]// Increment the nTP_Loop counter[/color]
    
    [color=green]// Check to make sure nTP_Loop counter is in the proper range[/color]
    IF(nTP_Loop<1 or nTP_Loop>LENGTH_ARRAY(dv_TP))
       nTP_Loop=1
    
    [color=green]// Source feedback - The variable nBTN_Loop represents a counter for the number of sources buttons.[/color]
    FOR(nBTN_Loop = 1;nBTN_Loop<=LENGTH_ARRAY(nSOURCE_BTNS);nBTN_Loop++)
      [color=green]// Turn on according to pop up feedback var[/color]
      [dv_TP[nTP_Loop],nSOURCE_BTNS[nBTN_Loop]] = (nPOP_FB[nTP_Loop]==nBTN_Loop)
    
  • TurnipTruckTurnipTruck Posts: 1,485
    Are there any proponents for feedback in define event? Am I all alone in the room?
  • jjamesjjames Posts: 2,908
    I like it!
    B_Clements wrote: »
    Those of you like myself who prefer to put your feedback statements in Define_Program can use this to your advantage. In Jay's example above we can make the program run more efficiently by letting the Define_Program section become your first "for loop."
    Hmm - interesting concept. I like it! It surely doess seem that it'd be more efficient - one less loop that runs through DEFINE_PROGRAM is good with me!

    I know I've run into some major problems before with having too many loops in DEFINE_PROGRAM, especially with lighting feedback. Restructuring my feedback portion somewhat fixed the problems I was experiencing to the point where the system wasn't too "laggy".
    Are there any proponents for feedback in define event? Am I all alone in the room?
    If you're talking about not having loops for feedback - yes, I'll use that as well in some portions for feedback. If I'm just doing a handful of buttons that need specific feedback (AM, FM, WX, repeat, random, etc.) I won't use a loop.

    There are times when I feel it's more appropriate to use "discrete" feedback rather than "looped" feedback, but more often I use the latter. There's no "wrong" way to do things if it's working, just more "efficient" or "easier" ways. But whatever works for you, then that's all that should matter. The fun of being a "code head", is that we're always trying to think of ways to improve on something that already works. :D
  • JeffJeff Posts: 374
    Let me first admit I haven't tried this, so I could be missing something obvious

    Instead of a timeline set to run every .2 seconds, why not use a wait?
    define_program
    
    wait 2
    {
        [dvTP,1]=var1
        [dvTP,2]=var2
        [dvTP,3]=var3
        [dvTP,4]=var4
        [dvTP,5]=var5
    }
    

    The wait wont recreate again until the first one is done, so it seems to me that this would severely decrease load in the define_program section of the code.

    Forgive me if I'm missing something obvious, I don't really remember all of how waits work, but this seems like so much less work than a timeline that I'd like to know why a timeline is considered better

    J
  • Feedback

    I've used all of them and I agree that it depends on the system size. Currently, I am using a combination of feedback in the button events as well as mainline. I also code source state and room state feedback in mainline not based off from the switchers and other components and here's why. In residential, I have found that when a switcher doesn't switch properly, you won't see your source material on screen. That's one perceived error for the client. If the touch panel isn't lighting up the button when the client pushes it too, that's two perceived errors. Actual quote from a client, "Hey! I pushed the button and the screen didn't change and the button won't push! Why is everything broken?" I know that this is a nebulous thing but it seems to work well so far. It's opposed to, "I pushed the button but the screen won't change!"

    In events, I will use a statement like TO[BUTTON.INPUT] for feedback on channels for simple receivers like cable or satellite. In commercial, I can imagine a different approach would be needed. I've also used waits in mainline to slow down the feedback sometimes when there are a lot of strings going back and forth with a lot of parsing. The theory is if I'm using a good amount of loops in parsing data, I really want to feeback only when neccessary. Seems to be that when a large amount of data is being parse and a lot of feedback needs to be updated, the system will take a larger performance hit. Seems to be anyways...

    I really liked the way Brian does his feedback and it seems really elegant so thx Brian!
  • DHawthorneDHawthorne Posts: 4,584
    Are there any proponents for feedback in define event? Am I all alone in the room?

    I do that inside modules where I can narrow down exactly what events will require a feedback change. It's not always feasible in a busy main program, where all you might have to work with is a variable change, and that is your only way of knowing something needs updating. Sometimes that is even the case in a device module, but it is more rare there. So, yes, I am a proponent of that, but I find it can't be used sometimes.
  • TonyAngeloTonyAngelo Posts: 315
    I also code source state and room state feedback in mainline not based off from the switchers and other components and here's why. In residential, I have found that when a switcher doesn't switch properly, you won't see your source material on screen. That's one perceived error for the client. If the touch panel isn't lighting up the button when the client pushes it too, that's two perceived errors. Actual quote from a client, "Hey! I pushed the button and the screen didn't change and the button won't push! Why is everything broken?" I know that this is a nebulous thing but it seems to work well so far. It's opposed to, "I pushed the button but the screen won't change!"

    I ran into this situation as well and it was determined (by my boss and the client) that the button should light up when pushed, so that the client knows they pushed it. In this case I added a text box that contains the current video/audio source and this updates based on switcher/avr feedback.
    Main.jpg 291.1K
  • DarksideDarkside Posts: 345
    TonyAngelo wrote: »
    I ran into this situation as well and it was determined (by my boss and the client) that the button should light up when pushed, so that the client knows they pushed it. In this case I added a text box that contains the current video/audio source and this updates based on switcher/avr feedback.
    ...and this is exactly why I create arrays for text that is to be sent to a panel button with the feedback rather than just using send_command on its own - if the G4 touch panel goes offline and you have sent some text to a button via send_command, when it returns online, it will not have that text in it any more.

    So, an online_event sends the the current value of cSourceSel to a button for example. Mainline looks after my button feedback.

    JJames and B_Clements' revised FOR loop system is very interesting - thanks for posting it guys
  • viningvining Posts: 4,368
    I also put feedback in many places and when I put it in DEFINE_PROGRAM I almost always put it behind a wait to keep it from running 100-300 x per second. So if it were me I would use Jays original version with a wait.
    DEFINE_PROGRAM
    
    WAIT 5
         {
         FOR (nLOOP=1;nLOOP<=LENGTH_ARRAY(dv_TP);nLOOP++)
    	  {
    	  // Source feedback
    	  FOR(nLOOP1 = 1;nLOOP1<=LENGTH_ARRAY(nSOURCE_BTNS);nLOOP1++)	// Loop btns
    	       [dv_TP[nLOOP],nSOURCE_BTNS[nLOOP1]]=(nPOP_FB[nLOOP]==nLOOP1)// Turn on according to pop up feedback var
    	  }
         }
    

    With a wait the processor checks the wait queue every 100ms to see if the wait time is up and checks the queue on every pass of the mainliine to see if the wait is in the queue or not which does use up processor power but it still much better then running the loop on every pass of the mainline unless you have alot of waits in the queue that the processor has to search through.

    The wait time depends on what type of feedback we're talking about but a wait of 2 or 5 is usually appropriate for what I do.
  • a_riot42a_riot42 Posts: 1,624
    I am in the non define_program boat. I tend to think of the program as a state machine. So certain states lead to other states, which lead to other states etc. in a predictable pattern. So every button is associated with a particular state, so that if that state is triggered (button pressed) then there is a feedback state that would go along with it. All feedback is done in functions that represent the current state and the button events only change state, they do not really do any processing.
    Paul
  • dchristodchristo Posts: 177
    B_Clements wrote: »
    Those of you like myself who prefer to put your feedback statements in Define_Program can use this to your advantage. In Jay's example above we can make the program run more efficiently by letting the Define_Program section become your first "for loop."

    That's a great idea, Brian.

    I'm in the Define_Program camp, although the majority of my systems have only of couple of TP's.

    --D
  • Wasting processing power?
    vining wrote: »
    I also put feedback in many places and when I put it in DEFINE_PROGRAM I almost always put it behind a wait to keep it from running 100-300 x per second. So if it were me I would use Jays original version with a wait.
    DEFINE_PROGRAM
    
    WAIT 5
         {
         FOR (nLOOP=1;nLOOP<=LENGTH_ARRAY(dv_TP);nLOOP++)
    	  {
    	  // Source feedback
    	  FOR(nLOOP1 = 1;nLOOP1<=LENGTH_ARRAY(nSOURCE_BTNS);nLOOP1++)	// Loop btns
    	       [dv_TP[nLOOP],nSOURCE_BTNS[nLOOP1]]=(nPOP_FB[nLOOP]==nLOOP1)// Turn on according to pop up feedback var
    	  }
         }
    

    With a wait the processor checks the wait queue every 100ms to see if the wait time is up and checks the queue on every pass of the mainliine to see if the wait is in the queue or not which does use up processor power but it still much better then running the loop on every pass of the mainline unless you have alot of waits in the queue that the processor has to search through.

    The wait time depends on what type of feedback we're talking about but a wait of 2 or 5 is usually appropriate for what I do.

    Vining, this is not a slam so please don't take it that way. I don't believe that is possible to "waste" processing power just like it not possible to save electricity. It is going to be there whether you use it or not. Efficiency is the key.

    Simple feedback evaluations are not very processor intensive as compared to calling a function or sending the feedback (via ethernet packet) to the panel. Once again, evaluating feedback and sending feedback are two entirely different things. It just so happens that the firmware can automatically determine whether feedback needs to be updated to the panel every pass through the Define_Program section. Sending text to panels that come online is a different story.

    Executing for-loops in Define_Program are a bit more processor intensive than single line feedback for every button. The trade-off with loops is much better scalabilty with a small reduction in efficiency. The real processor hog is input/output processing, with ethernet based events being first, followed closely by RS232 data events.

    One could argue that a 0.05 to 0.1 second repeating Timeline_Event for processing feedback might be the best approach. I have not done any benchmarking to determine which is better/faster, but this would require the double for-loop approach in Jay's example.
  • Thanks Dave
    dchristo wrote: »
    That's a great idea, Brian.
    I'm in the Define_Program camp, although the majority of my systems have only of couple of TP's.
    --D

    Thinking about this further, the stopping point would be 30-40 touch panels.
  • TonyAngeloTonyAngelo Posts: 315
    B_Clements wrote: »
    Simple feedback evaluations are not very processor intensive as compared to calling a function or sending the feedback (via ethernet packet) to the panel.

    This is what I usually do:
    DEFINE_FUNCTION fnFeedback(INTEGER nArgBtn, INTEGER nArgArray[], INTEGER nArgPanel)
    {
        OFF[vdvTP[nArgPanel],nArgArray] // turn off btns
        IF(nArgBtn)
        {
    	ON[vdvTP[nArgPanel],nArgArray[nArgBtn]] // turn on btn
        }
    }
    

    Are you saying that a FOR loop in Define_program would be more efficient?
  • jjamesjjames Posts: 2,908
    B_Clements wrote: »
    Thinking about this further, the stopping point would be 30-40 touch panels.
    Which is one reason why I'm a proponent to the looping - it's expandable. You can start it out with three touch panels, and a year down the road add fifteen touch panels and the feedback portion doesn't have to change.

    Though, in your experience Brian - would you have 30-40 touch panels running off of a single processor? I'm not saying it isn't possible, but keeping with the tone of efficiency - would you sooner move to a M2M layout then?
  • You can try
    TonyAngelo wrote: »
    This is what I usually do:
    DEFINE_FUNCTION fnFeedback(INTEGER nArgBtn, INTEGER nArgArray[], INTEGER nArgPanel)
    {
        OFF[vdvTP[nArgPanel],nArgArray] // turn off btns
        IF(nArgBtn)
        {
    	ON[vdvTP[nArgPanel],nArgArray[nArgBtn]] // turn on btn
        }
    }
    

    Are you saying that a FOR loop in Define_program would be more efficient?

    Unless the program is very large, you may not notice a speed difference.
  • Master to Master application
    jjames wrote: »
    Which is one reason why I'm a proponent to the looping - it's expandable. You can start it out with three touch panels, and a year down the road add fifteen touch panels and the feedback portion doesn't have to change.

    Though, in your experience Brian - would you have 30-40 touch panels running off of a single processor? I'm not saying it isn't possible, but keeping with the tone of efficiency - would you sooner move to a M2M layout then?

    Running that number of panels is not a problem at all. Off loading data processing for sub-systems would be the ideal M2M solution. For example, use separate NI-700 processors for lights, HVAC, media server, etc; all of which have the potential for a lot of data I/O. As we covered in previous threads, only update panels that are on the page needing the updates to reduce button and text feedback messages.
  • jjamesjjames Posts: 2,908
    B_Clements wrote: »
    Running that number of panels is not a problem at all. Off loading data processing for sub-systems would be the ideal M2M solution.
    Makes sense! Thanks. :D
  • viningvining Posts: 4,368
    B_Clements wrote:
    Vining, this is not a slam so please don't take it that way. I don't believe that is possible to "waste" processing power just like it not possible to save electricity.
    No offense taken. In the scale of the jobs I'm doing I not really concerned about memory usage or bogging down the processor but ideally I like to plan every job as if it's a mega system so that the day I get to do a mega system I'll have a clue of what to do and I won't have to start a new from scratch. It just seems that running the loop every pass all be it for a different TP each pass seems over kill for simple feedback even if for the most part it's just evaluating the need for feedback updates and not necassarily do any updating.
  • B_Clements wrote: »
    As we covered in previous threads, only update panels that are on the page needing the updates to reduce button and text feedback messages.

    I agree completely. R4's are in need of this even with the queing module. Request modules are an example of devices that chat a lot to a touch panel so I usually only send text feedback when that page showing said feedback is displayed. Some of my touch panel navigation buttons will pulse a variable where the feedback in mainline is conditional on the variable, expecially with text feedback. *sometimes* I don't mind if a structure is constantly updating looking for changes but a touch panel doesn't need to. In my earlier days, I've crippled the master in just sending text all of the time. So, not only does it help to put feedback statements in the event section opposed to mainline, it also helps to control the feedback, especially text IMHO. In fact, you told me that on the phone once Brian and ever since then, I've implemented it. So... Thx again!

    What I haven't figured out yet (and a topic for another thread), is how to get text off from a touch panel without setting up variable states or structures for comparision if text feedback needs to be updated. But I digress.
  • Text feedback?
    I In fact, you told me that on the phone once Brian and ever since then, I've implemented it. So... Thx again!

    What I haven't figured out yet (and a topic for another thread), is how to get text off from a touch panel without setting up variable states or structures for comparision if text feedback needs to be updated. But I digress.

    Brad, thanks for the kind words. :)

    And by all means, go ahead and start a new thread so we all can discuss how we manage text feedback. I'm game.

    Once again, thank you all for your continued contributions to the AMX forums.
  • a_riot42a_riot42 Posts: 1,624
    What I haven't figured out yet (and a topic for another thread), is how to get text off from a touch panel without setting up variable states or structures for comparision if text feedback needs to be updated. But I digress.

    What do you mean by get text off from a touch panel? You mean how to request from a touch panel what the text on a button is? Why would you need to, you sent it there correct? Maybe I misunderstand.
    Paul
  • Sorry I didn't jump in earlier, I have been away. Great ideas, everyone! I am a Define_Program with a FOR loop kind of guy (scalability in mind). I have worked on quite a few larger jobs using this method (6 master, 23 TPs, 18 zones of audio/video kind of system) and have always wondered if there was a more efficient way of handling these statements. My statements have worked with good results but it is the common "Coder Head" mentality to make it better :) Thx for the input! I always learn something new everyday I read your posts! Some people pick up the Financial Times and others read forums ;)
Sign In or Register to comment.