Home AMX User Forum NetLinx Studio
Options

Feedback problem I haven't seen before ...

I have been using device arrays for panel feedback for a long time, and have not had any real issues with it. My typical procedure is to iterate through the array with a FOR loop, and send the feedback as appropriate. But, it seems to not be working anymore, and I can't for the life of me figure out why. Here's a snippet from the code that is plaguing me:
DEFINE_FUNCTION fnUpdateDisplay()
{
    STACK_VAR CHAR nPanelCount 
    STACK_VAR CHAR nCount 
    STACK_VAR CHAR nSubCount 

    FOR(nPanelCount = 1 ; nPanelCount <= nNumPanels; nPanelCount ++)
    {
	IF(bActive[nPanelCount] && (dvPanels[nPanelCount].NUMBER < 32000))
	{
	    // Input Gains
	    FOR(nCount = 1; nCount <= nSwitchSize[2]; nCount ++) 
	    {
		IF(nLastGain[nCount] <> nGains[nCount])
		{
		    SEND_COMMAND dvPanels[nPanelCount], "'^TXT-', ITOA(nCount),',0,', FTOA(nGains[nCount]), ' dB'" ;
		    nLastGain[nCount] = nGains[nCount] ;
		}
		[dvPanels[nPanelCount], nButtons[nCount]] = (nCurrentInput == nCount) ;
	    }
        }
    }
}

The routine is called in a timeline that fires every half second. There is more to it, but I clipped it for brevity's sake; just what is above is enough to screw up.

The deal is, if only one panel is active (as set in the bActive array), it works fine. But if more than one flag is set in that array, the feedback on the ^TXT command never happens. The button on/off feedback is fine. What is making me crazy is that with device notifications turned on, I can clearly see the command going out to the panel, but the panel isn't reflecting it. I don't know if I have a case of brain fog here,or if there is something very fishy going on, but this has the potential of wrecking a lot of my projects if it is some new change due to a firmware or NS update. I use routines like this in pretty much every project that has more than one panel.

I keep getting the idea that I'm sending too many ^TXT commands too quickly because of the FOR loop ... but, like I said, I'm tracking it with device notifications, and I can see clearly that not much is going out at all, and the exact command I expect is also going out. It just does nothing, like it's being eaten before it gets to the panel. So now I'm following the hunch that it's something fairly obvious and I am just missing it by virtue of being too close to it for too long, and hopefully one of you folks will see something I'm missing ...

Comments

  • Options
    jjamesjjames Posts: 2,908
    Just curious - what firmware revs are you running?

    I've been noticing weird things with ^TXT lately as well.
  • Options
    ericmedleyericmedley Posts: 4,177
    Is this a case of having channels above 255? If so you have to send the set the number of channels in code at the online of the device. (even if it's a real device)

    I've been burned by this coountless times.
    e
  • Options
    jjamesjjames Posts: 2,908
    ericmedley wrote: »
    If so you have to send the set the number of channels in code at the online of the device. (even if it's a real device)

    As in SET_VIRTUAL_CHANNEL_COUNT?
  • Options
    ericmedleyericmedley Posts: 4,177
    jjames wrote: »
    As in SET_VIRTUAL_CHANNEL_COUNT?

    yes, I've had to do this on AxLink devices before. Also, touch panels where I get above 255 channels. I have yet to find a rhyme or reason to it. I just know that sometimes when feedback isn't working I send the command to the device and all is well.
  • Options
    Spire_JeffSpire_Jeff Posts: 1,917
    Have you stepped through the code with debug to make sure that it is actually getting to the send_command? I don't see anything obvious sticking out in the code posted.

    Are all of the variable arrays one dimensional? I have had problems where I was testing a 2 dimensional array with just the first dimension being used in the comparison (ie if(bActive[x]) instead of if(bActive[nCurrentWhatever][x]) ).

    Jeff
  • Options
    DHawthorneDHawthorne Posts: 4,584
    This particular module has it's own port on the panels. Feedback channels are 1-64. The panel arrays are one-dimensional. And, as I stated, I can see the command going to the panel in Device Notifications. It just isn't acting on it.

    The master is an NI-4100, firmware 3.50.430
    Panels are mixed; I have some 5200's, at firmware 2.66.21, some R4's at 3.01.05, and some 500's at 2.3.22.

    The code snippet above is acting up on the 500's for sure; I haven't tested on the others (job isn't complete, they don't all exist yet), but for this module, the R4's are not active. However, I had the exact same problem in a different module in another project going to R4's. In that case, I did a quick-and-dirty trick of getting rid of the FOR loop and sending to the entire array instead of indexing it. That worked, but I don't want to make a habit of it, that can be a lot of feedback statements all at once.
  • Options
    ericmedleyericmedley Posts: 4,177
    DHawthorne wrote: »
    I can see the command going to the panel in Device Notifications.

    I know. I've still seen it misbehave even though diganostics showed it worked.
  • Options
    DHawthorneDHawthorne Posts: 4,584
    jjames wrote: »
    As in SET_VIRTUAL_CHANNEL_COUNT?

    It works if I am only sending to one panel. Same exact code, with more than one active, it doesn't. I would think a virtual channel issue wouldn't work ever ...
  • Options
    ericmedleyericmedley Posts: 4,177
    DHawthorne wrote: »
    It works if I am only sending to one panel. Same exact code, with more than one active, it doesn't. I would think a virtual channel issue wouldn't work ever ...

    I don't think it's a virtual channel issue. I think it must have something to do with how the master sets up its internal allocation of RAM to deal with channel feedback. The command doesn't care if you put it on a virtual device or not. Like I said, I've actually had to do it on an Axlink device to get channel 254 to work. 1-253 worked fine without it but not 254. Once I put in the set_virutal... it worked. take it out it stops.

    I'm not saying it makes sense. I'm just reporting what worked.
  • Options
    DHawthorneDHawthorne Posts: 4,584
    ericmedley wrote: »
    I don't think it's a virtual channel issue. I think it must have something to do with how the master sets up its internal allocation of RAM to deal with channel feedback. The command doesn't care if you put it on a virtual device or not. Like I said, I've actually had to do it on an Axlink device to get channel 254 to work. 1-253 worked fine without it but not 254. Once I put in the set_virutal... it worked. take it out it stops.

    I'm not saying it makes sense. I'm just reporting what worked.

    I'll give it a shot, though all my channels are under 100 right now, let alone 255. Maybe because it's port 22 ...
  • Options
    DHawthorneDHawthorne Posts: 4,584
    No joy ... but I have to take back a previous statement, adamant as I was about it ... the command is NOT going out from the master. The first panel in the FOR loop gets it, anything past that does not. Been staring at things too long, and apparently, I was focusing on the port number, not the device number.

    So I guess I'm flooding the message queue too quickly. I'm certain this has worked just fine for me in the past. I have a wrenching gut feeling when I consider all the old projects which might now be broken because of this ...
  • Options
    DHawthorneDHawthorne Posts: 4,584
    I'm spinning my wheels now ... the message queue idea doesn't really pan out, since if I remove the bActive test and send to the entire dang array instead of a single indexed panel each pass of the loop, I can watch the dozens of messages go out just fine. It's got to be sending them faster to the entire array than what a FOR loop can generate. But I also might be bypassing some internal buffering by doing that. And the entire array thing just won't work if I have to send different data out depending on the panel stat (like in this case, what zone it is controlling).

    I'm just going to have to revisit this when I'm fresh ... starting to goof things up simply by virtue of staring at it too long.
  • Options
    Spire_JeffSpire_Jeff Posts: 1,917
    Have you gone into debug and followed the execution to find out if the program is seeing/interpreting things as you did when you coded? I have found a few bugs this way (mainly the number of dimensions being used :) ) In the least, stepping through with debug should slow down the outgoing messages to the point that if it all works in debug, you have some evidence pointing to the message queue getting perplexed.

    Jeff
  • Options
    BigsquatchBigsquatch Posts: 216
    Sounds like there is a problem in either your if statement or with the array.

    It's a pain to do it but I've always been able to solve similar problems by adding in my own debug code that spits out diagnostic messages at each step of the way.

    To get you started:
    DEFINE_FUNCTION fnUpdateDisplay()
    {
        STACK_VAR CHAR nPanelCount 
        STACK_VAR CHAR nCount 
        STACK_VAR CHAR nSubCount 
    
        FOR(nPanelCount = 1 ; nPanelCount <= nNumPanels; nPanelCount ++)
        {
    
    
    send_string 0, "'-->Loop count 1: evaluating bActive[',ITOA(nPanelCount),'] 
          && (dvPanels[nPanelCount].NUMBER < 32000))'"
    
    
    	IF(bActive[nPanelCount] && (dvPanels[nPanelCount].NUMBER < 32000))
    	{
    
    
    send_string 0, "'bActive[',ITOA(nPanelCount),'] = ',
       ITOA(bActive[nPanelCount]),' dvPanels[nPanelCount].NUMBER =    
    ',ITOA(dvPanels[nPanelCount].NUMBER),' evaluated as true'"
    
    
    	    // Input Gains
    	    FOR(nCount = 1; nCount <= nSwitchSize[2]; nCount ++) 
    	    {
    		IF(nLastGain[nCount] <> nGains[nCount])
    		{
    		    SEND_COMMAND dvPanels[nPanelCount], "'^TXT-', ITOA(nCount),',0,', FTOA(nGains[nCount]), ' dB'" ;
    		    nLastGain[nCount] = nGains[nCount] ;
    		}
    		[dvPanels[nPanelCount], nButtons[nCount]] = (nCurrentInput == nCount) ;
    	    }
    
    
    else
    {
    send_string 0, "'bActive[',ITOA(nPanelCount),'] = ',ITOA(bActive[nPanelCount]),' 
    dvPanels[nPanelCount].NUMBER = ',ITOA(dvPanels[nPanelCount].NUMBER),
    ' evaluated as false'"
    }
    
    
            }
        }
    }
    

    Code not tested so you might have to fix some string expressions.
  • Options
    a_riot42a_riot42 Posts: 1,624
    DHawthorne wrote: »
    That worked, but I don't want to make a habit of it, that can be a lot of feedback statements all at once.

    If it worked, I would suggest making a habit of it. Nested for loops are very inefficient, and hog the processor, and there's usually a more efficient way anyway. If you have 20 panels and a 64 IO switch, those loops will run 1280 times, potentially sending that many commands. I would imagine that would bog down the command queue. If you are running this twice a second, that seems like an awful lot of processing to simply update volume text fields. Perhaps that is why with one panel it works, but beyond that it just can't do it.
    Paul
  • Options
    truetrue Posts: 307
    Profile it.

    The amount of instructions taken for the loop and incrementing an iterator is fairly small. Conditions for checking to continue the loop are also small and may be more "efficient" than sending to a dev array. Maybe not as "efficient" machine-wise as writing 1200 statements, and I haven't profiled sending to a dev array so I don't know of "efficiency" there, but writing a loop is certainly more "efficient" than trying to maintain those 1200 lines when one will do and is usually the same or only slightly more difficult than sending to a dev array.

    The decision of whether to iterate through devices or send to an array of them depends on application, though.

    ("efficiency" is mentioned a lot on these boards, but I rarely see concrete numbers backing it up. We're not running at 1 MIPS.)
  • Options
    a_riot42a_riot42 Posts: 1,624
    true wrote: »
    Maybe not as "efficient" machine-wise as writing 1200 statements, and I haven't profiled sending to a dev array so I don't know of "efficiency" there, but writing a loop is certainly more "efficient" than trying to maintain those 1200 lines when one will do and is usually the same or only slightly more difficult than sending to a dev array.

    The problem isn't with the for loop processing, its with sending thousands of ^TXT commands to a touch panel every second. It doesn't really matter how efficient the code is if you are doing that, as you will encounter problems and can even lockup a touch panel if you aren't careful.
    Paul
  • Options
    DHawthorneDHawthorne Posts: 4,584
    a_riot42 wrote: »
    The problem isn't with the for loop processing, its with sending thousands of ^TXT commands to a touch panel every second. It doesn't really matter how efficient the code is if you are doing that, as you will encounter problems and can even lockup a touch panel if you aren't careful.
    Paul

    Exactly, and since this has a lot of R4's in the mix, I'm trying to keep commands to the controllers to a minimum.
  • Options
    DHawthorneDHawthorne Posts: 4,584
    Well, there's nothing like a fresh look. But at least I'm somewhat consoled none of you guys picked it up either :) ... was a very brain dead mistake.

    I'm sending the ^TXT commands based on whether the text value to be sent has changed, then storing it to another variable which I later compare against to detect future changes. But I'm doing it inside the loop! So, naturally, second pass of the panel loop, it thinks it hasn't changed, because my compare value now matches; ergo only the first panel in the loop actually gets it. Duh. Easiest solution was to move the panel loop to inside the input loop, and now she works as expected.
    DEFINE_FUNCTION fnUpdateDisplay( )
    {
        LOCAL_VAR CHAR nPanelCount 
        LOCAL_VAR CHAR nCount 
        LOCAL_VAR CHAR nSubCount 
    
        IF(bActive[nPanelCount] && (dvPanels[nPanelCount].NUMBER < 32000))
        {
    	// Light input button
    	FOR(nPanelCount = 1 ; nPanelCount <= nNumPanels; nPanelCount ++)
    	    FOR(nCount = 1; nCount <= nSwitchSize[2]; nCount ++)
                    [dvPanels[nPanelCount], nButtons[nCount]] = (nCurrentInput == nCount) ;
    	
    	// Input Gains
    	FOR(nCount = 1; nCount <= nSwitchSize[2]; nCount ++)
    	{
    	    IF(nLastGain[nCount] <> nGains[nCount])
    	    {
    		FOR(nPanelCount = 1 ; nPanelCount <= nNumPanels; nPanelCount ++)
    		    SEND_COMMAND dvPanels[nPanelCount], "'^TXT-', ITOA(nCount),',0,', FTOA(nGains[nCount]), ' dB'" ;
    		nLastGain[nCount] = nGains[nCount] ;
    	    }
    	}
        }
    }
    

    A few more loops in there than I like, but I'll take another look at it later and clean that up if I can.

    I just hate it when you look, and look, and look, but still miss something obvious.
  • Options
    It's like a "Where's Waldo" puzzle! I see it now!
    Glad you caught it Dave.

    -John
  • Options
    a_riot42a_riot42 Posts: 1,624
    Are you sure that was the problem? I am not seeing what you mean.

    EDIT: I see what you mean. But now you have 2 nested for loops! That will tie up your processor on job with many touch panels. You could bum that down to one for loop.

    Paul
  • Options
    DHawthorneDHawthorne Posts: 4,584
    a_riot42 wrote: »
    Are you sure that was the problem? I am not seeing what you mean.

    EDIT: I see what you mean. But now you have 2 nested for loops! That will tie up your processor on job with many touch panels. You could bum that down to one for loop.

    Paul

    I do it all the time, and there doesn't seem to be much of a hit. Since the actual operations in the loops are fairly simple, it blows through them very quickly. That is also why inside the loop there are comparisons made before anything goes out to the panel. Comparisons are fairly cheap, processor wise, where sending commands to a panel brings in the message queue and device responses. I'm more interested in minimizing that than minimizing memory operations.

    Another reason is flexibility - the size of those loops can vary with the size of the installation, very easily.
Sign In or Register to comment.