Home AMX User Forum NetLinx Studio

NEC Projector Feedback and buffers

I'm trying to get the feedback to work on an NEC Projector. Trying to light the ON/OFF buttons on the control panel. Sometimes the remote control gets used to turn the projector on or off.
This is what I have. It does compile, but doesn't do anything.
It is being controlled as an actual device, not a virtual.


DEFINE_DEVICE
Projector = 5001:1:0

DEFINE_CONSTANT
(*Projector power status*)
PROS_ON = 1
PROS_OFF = 2

DEFINE_VARIABLE
PRO_Buffer[100]
PRO_Status

DEFINE_START
CREATE_BUFFER Projector,PRO_Buffer

DEFINE_PROGRAM
SEND_STRING Projector,”$00,$81,$00,$00,$00,$81” //Running Sense
WAIT 10

IF (PRO_Buffer =’ $81$01@$01$02$E5’)
PRO_Status = PROS_ON
[TP,9] = (PRO_Status = PROS_ON) //Turn on “ON” button

IF (PRO_Buffer =’ $81$01@$01$00$E3’)
PRO_Status = PROS_OFF
[TP,10] = (PRO_Status = PROS_OFF) //Turn on “OFF” button

CLEAR_BUFFER PRO_BUFFER

1)The response that I am supposed to get is $22$00$01$xx$00 CKS, the above responses are consistent when using "Control a Device"
2)I know they are Hex, but as far as the buffer and NetLinx is concerned they are just characters?
3)Should the whole thing go into a DATA_EVENT?
4)Most of the examples on the forum show using DATA.TEXT which is followed by a comment that you should NOT use DATA.TEXT on an actual device?
5)I could use FIND_STRING, but is it necessary?
6)I tried using single quotes inside of double quotes, but it won't compile.

Thanks

Comments

  • I've recently built a NEC Projector module as well and yours is probably similar. When you ask the projector for an update it returns a string of about 133 hex symbols (as a text string).

    I dump all that into a buffer and then execute a set of find_String commands once the buffer sees a checksum.

    I had the best luck running that through a function to convert to a hex array. Here is the function that I found on these forums.
    WHILE(LENGTH_ARRAY(cInString))
        {
    	cTempByte = GET_BUFFER_CHAR(cInString); //Grab one byte from the input
    	cStringRXCleanHex[nCounter] = FORMAT('$%02X,',cTempByte)
    	nCounter++
        }
    

    Now in the main define program I have this:
    	    ACTIVE (FIND_STRING(cStringRXCleanHex[2],"'BF'",1) AND FIND_STRING(cStringRXCleanHex[6],"'02'",1)) : //Projector Information Request Result
    	    {
    		nStatus[1] = atoi(cStringRXCleanHex[7]) // Processing Status
    		nStatus[7] = atoi(cStringRXCleanHex[8]) //Picture Status
    		nStatus[4] = atoi(cStringRXCleanHex[9]) //Input
    		nStatus[6] = atoi(cStringRXCleanHex[12]) //Picture Mute
    	    }
    

    I personally liked this method because I don't have to parse through each returned Hex in the string and instead just dump it into an array. No counting needed and the array ID lines up with the returned string.
  • ericmedleyericmedley Posts: 4,177
    Some code Best Practice for you.


    I would not put this kind of thing in Define_program. You'll see a lot of debate on the forum as to when to use Def_Prog (or even if at all - of which I am in that camp). But either way I'd not put anything processor intensive in Def_Program. the best practice is to limit it to feedback only, not string processing.

    You might want to look at using the Data_Event in Define_Event.
    define_event
    
    data_event[dvProj]{
      string:{
        If(find_string(MyBuffer,"$01,02'etc..",1)){
          Proj_power=1;
          }
        If(find_string(MyBuffer,"$99,$98,etc...",1)){
          Proj_power=0;
          }
          fn_Update_Proj_Power_fb() // make a function or call to update the TP button feedback
      }
    }
    
    

    This is just a simple example but you'll get the idea.
  • TUTechTUTech Posts: 70
    I would not put this kind of thing in Define_program. You'll see a lot of debate on the forum as to when to use Def_Prog (or even if at all - of which I am in that camp). But either way I'd not put anything processor intensive in Def_Program. the best practice is to limit it to feedback only, not string processing.

    Yes I noticed, a lot of debate!!

    I made a Data_Event. It worked, except the Send_String to send the Running Sense. I had to put it in the Define Programming. I also had to make the ON/OFF button mutually exclusive or else they would both turn on and stay on.
  • TUTechTUTech Posts: 70
    This is what I ended up with...

    DEFINE_MUTUALLY_EXCLUSIVE
    ([TP,9],[TP,10])

    DEFINE_START
    CREATE_BUFFER Projector,PBUFFER
    CLEAR_BUFFER PBUFFER

    DEFINE_EVENT
    DATA_EVENT [Projector]
    {
    STRING:
    {
    IF(LENGTH_STRING(PBUFFER))
    {
    SELECT
    {
    ACTIVE(FIND_STRING(PBUFFER,"$81,$01,'@',$01,$02,$E5",1)):
    {PROJ_Status=PROS_ON
    [TP,9] = (PROJ_Status=PROS_ON)}

    ACTIVE(FIND_STRING(PBUFFER,"$81,$01,'@',$01,$00,$E3",1)):
    {PROJ_Status=PROS_OFF
    [TP,10] = (PROJ_Status=PROS_OFF)}
    }}
    PBUFFER=""
    }
    }

    DEFINE_PROGRAM

    WAIT 300
    SEND_STRING Projector,"$00,$81,$00,$00,$00,$81" //Running Sense
  • a_riot42a_riot42 Posts: 1,624
    I use data.text all the time from serial/IP devices, and it hasn't failed me yet. I think its faster than create_buffer as well, and requires less code so use it as needed. The only caveat is that since its a small buffer, around 2000 bytes, for devices that have feedback with much longer strings, you may need to combine buffers to get the full response. I've noticed some odd things occurring with create_buffer in terms of timing so I've stayed away from it.
    Paul
  • I've definitely broken "create_buffer" with some things I've tried to do, and have learned the hard way to stay away from it. I always just manually add data.text to whatever buffer I've defined for a device:
    ...
    string: { 
         devicebuffer = "devicebuffer,data.text" 
    }
    
    ...then my buffer processing picks up whatever got put in the buffer and works with it.
  • ericmedleyericmedley Posts: 4,177
    ACTIVE(FIND_STRING(PBUFFER,"$81,$01,'@',$01,$02,$E5",1)):
    {PROJ_Status=PROS_ON
    [b][i][TP,9] = (PROJ_Status=PROS_ON)}[/i][/b]
    
    ACTIVE(FIND_STRING(PBUFFER,"$81,$01,'@',$01,$00,$E3",1)):
    {PROJ_Status=PROS_OFF
    [b][i]][TP,10] = (PROJ_Status=PROS_OFF)}[/i][/b]
    }}
    PBUFFER=""
    }
    }
    

    A side issue for you...

    the two feedback statements are a bit unnecessary. Since you've already done the string operatoion to determine the status of the projector and set the stat variable to "on" or "off" you don't need to redo the check in the statement where you check again and make the TP button go on or off. Just go ahead and turn the button on or off.
    ACTIVE(FIND_STRING(PBUFFER,"$81,$01,'@',$01,$02,$E5",1)):{
      PROJ_Status=PROS_ON
      [b][i]OFF[TP,10]
      ON[TP,9][/i][/b]
      }
    ACTIVE(FIND_STRING(PBUFFER,"$81,$01,'@',$01,$00,$E3",1)):
    {PROJ_Status=PROS_OFF
    [b][i]]ON[TP,10][/i][/b]
    [b][i]]OFF[TP,9][/i][/b]
    }}
    PBUFFER=""
    }
    }
    

    or you could do this as well.
    DATA_EVENT [Projector]
     {
     STRING:
     {
     IF(LENGTH_STRING(data.text))
     {
     SELECT
     {
     ACTIVE(FIND_STRING(data.text,"$81,$01,'@',$01,$02,$E 5",1)):{
        PROJ_Status=PROS_ON
        }
    
     ACTIVE(FIND_STRING(data.text,"$81,$01,'@',$01,$00,$E 3",1)):{
        PROJ_Status=PROS_OFF
     }
    }
     PBUFFER=""
        [TP,9] = (PROJ_Status)   
        [TP,10] = (!PROJ_Status)
     }
     }
    

    or even better you could put this into a function or call so you could also update the button feedback outside the data event of the projector as in the case of a TP coming online and needing current feedback.
    DEFINE_FUNCTINO fn_Update_TP_Proj_Power_Button_FB(){
        [TP,9] = (PROJ_Status)   
        [TP,10] = (!PROJ_Status)
      }
    
    ...
    DEFINE_EVENT
    ...
    // bla bla bla
     }
    }
     PBUFFER=""
      fn_Update_TP_Proj_Power_Button_FB() // update the feedback
     }
     }
    
    DATA_EVENT[TP]{
      online:{
        // when the TP comes online update teh feedback
        fn_Update_TP_Proj_Power_Button_FB()
      }
    }
    

    -or-
    -or-
    -or-
    there's a lot of layers to this onion. :)
  • DHawthorneDHawthorne Posts: 4,584
    a_riot42 wrote: »
    I use data.text all the time from serial/IP devices, and it hasn't failed me yet. I think its faster than create_buffer as well, and requires less code so use it as needed. The only caveat is that since its a small buffer, around 2000 bytes, for devices that have feedback with much longer strings, you may need to combine buffers to get the full response. I've noticed some odd things occurring with create_buffer in terms of timing so I've stayed away from it.
    Paul

    Perhaps you haven't seen the issue, but it exists. If your device sends back "Long string of text," you might get two events, one with "Long string," and the other "of text." I have not seen it happen with IP communications, but have seen it a lot with RS-232. It determines the "end" of data by looking for a pause in the flow ... I couldn't tell you how long a pause it looks for, but I can tell you that if your devices pauses or hiccups, you are going to get a broken response if you aren't buffering it somehow. Probably the more modern your equipment is, the less likely there will be an issue, but test it extensively if you want to be sure.
  • ericmedleyericmedley Posts: 4,177
    data.text has bitten me in the arse a few times with the scenario Dave describes - particularly web page returns. Web servers are notroiously weird when it comes to sending back data. Packets are broken up to 2K chunks and sent back at the pleasure of the web server's whims and the intervening switches et all.

    The end result is a pretty stuttery message. AMX just doesn't handle this very well. I find myself doing both what Paul does by appending incoming data.text event messages to the end of my buffer and waiting patiently for the darned thing to quick spewing (looking for a true end terminatior) or letting Create_Buffer do it for me.

    I've found that Create_Buffer seems to do a pretty okay job of this kind of thing. I'm not sure just why. But, I've seen cases whwere data.text gets a bit confussed and will drop chunks within the 2K data packages. Not always, nor even predictibly.

    Honestly, I usuallly try data.text first and bail in favor of Create_Buffer if I find it starting to misbehave.

    But, that's just me.
  • TUTechTUTech Posts: 70
    Thanks Eric,
    That answers my question about data.text. It would work unless I a really long response or got an error in the return.
    One HEX character ($FF) is 255 bytes. Does Data.text see it as 255 or two characters?

    That makes sense about the button feedback. It was more than necessary, but I was glad I had something that worked!! LOL. I used that method somewhere else in the code where I had 5 variables so that's why I came up with it.
    I wrote another block using ON[TP,9] OFF[TP,10] etc. I'll have to wait until the room is available to test it.
    I'm working on this room a block at a time.

    One more question.
    Shouldn't the request for status (Wait 300 Send_string "Running Sense") be in the same DATA_EVENT? I tried it, but it wouldn't compile. (I know I can also use FOR(Count=0;Count<300;Count++). Should it go in the same STRING event or under a COMMAND event?

    David
Sign In or Register to comment.