Home AMX User Forum NetLinx Studio

Help needed parsing strings from GE alarm panel

I am trying to communicate with a GE alarm panel, model NX8E, using their virtual keypad accessory, model NX 587. We are using an NI-4100.

All of my commands to the alarm panel are working correctly however I'm having trouble properly interpreting the strings returning from the device.

I began by connecting my laptop to the virtual keypad device and here is what it looks like in HyperTerminal:
DL1System Not Ready

DL2For help, press~

DL1Service Required

DL2Type *2 for help

DL1System Not Ready

DL2For help, press~

DL1Service Required

DL2Type *2 for help

LDS-r-p

LDF---b-

BZ0

PA1Rasceeps

PA2Rasceeps

This conforms with the instructions given for the virtual keypad. The trouble I'm having is the strings look like this to the NI-4100:
Line     96 (15:27:12):: String From [5001:7:1]-[$0ALR1$0D$0ADL1  System Ready  $0D$0ADL2Type code to arm$0D$0APA1Rasceeps$0D]
Line     97 (15:27:26):: String To [5001:7:1]-[1$0D]
Line     98 (15:27:29):: String To [5001:7:1]-[9$0D]
Line     99 (15:27:32):: String To [5001:7:1]-[8$0D]
Line    100 (15:27:34):: String To [5001:7:1]-[4$0D]
Line    101 (15:27:35):: String From [5001:7:1]-[$0ALA1$0D$0ALE1$0D$0ADL1  System Armed  $0D$0ADL2Zone(s) Bypassed$0D$0ABZ3$0D$0APA1RAs]
Line    102 (15:27:35):: String From [5001:7:1]-[ceEps$0D]
Line    103 (15:27:37):: String To [5001:7:1]-[4$0D]
Line    104 (15:27:37):: String From [5001:7:1]-[$0ALR0$0D$0APA1rAsceEps$0D]
Line    105 (15:27:42):: String From [5001:7:1]-[$0ALR1$0D$0APA1RAsceEps$0D]
Line    106 (15:27:52):: String To [5001:7:1]-[1$0D]
Line    107 (15:27:58):: String To [5001:7:1]-[9$0D]
Line    108 (15:28:02):: String To [5001:7:1]-[8$0D]
Line    109 (15:28:04):: String To [5001:7:1]-[4$0D]
Line    110 (15:28:05):: String From [5001:7:1]-[$0ALA0$0D$0ALR0$0D$0ALE0$0D$0ADL1System Not Ready$0D$0ADL2For help, press~$0D$0ABZ0$0D$0AP]
Line    111 (15:28:05):: String From [5001:7:1]-[A1rasceeps$0D]
Line    112 (15:28:05):: String To [5001:7:1]-[4$0D]
Line    113 (15:28:06):: String From [5001:7:1]-[$0ALB0$0D]

It seems like the NI-4100 isn't properly reacting to the Line Feed character. Since the incoming lines don't begin with the data I was expecting, I was having trouble figuring out how to parse these strings to get the information I need. Do I need to change something in my Netlinx code to fix this? If this is just the way it is, any suggestions on how to extract the useful info from the chaff?

Anyone have experience with this alarm configuration and have any helpful tips?

Shane

Comments

  • a_riot42a_riot42 Posts: 1,624
    sijandi wrote: »
    It seems like the NI-4100 isn't properly reacting to the Line Feed character.

    What reaction were you expecting to the line feed character? Notifications printed it, so its done its job. What you are likely seeing is that the device isn't speaking in complete sentences, so you see parts of or combined commands that you then have to combine and parse in your code. If you get a line feed that's the start of the command and the carriage return is the end. That should be pretty easy to parse, but you might have to concatenate the serial strings as they come in before parsing.
    Paul
  • AlekseyAleksey Posts: 22
    I think you just need to collect all incoming data to a buffer and parse it to strings:
    DATA_EVENT[NX587Port]
    {
        STRING:
        {
    	cBuffer="cBuffer,DATA.TEXT";
            cTmpString=REMOVE_STRING(cBuffer,"$0D",1);
    	WHILE(cTmpString!="")
    	{
                fnDoSomething(cTmpString);
                cTmpString=REMOVE_STRING(cBuffer,"$0D",1);
             }
          }
    }
    
  • sijandisijandi Posts: 8
    Paul,

    Every other device I'm familiar with gives me a fresh line in the notifications so that I can use Left_String and Mid_String keywords with predictability. The run on sentence that I am getting here is what has me boggled. I couldn't think of the correct syntax to break this data into the parts that I need.

    shane
  • viningvining Posts: 4,368
    I would imagine that the diagnostic print out is just printing out what is actually received in each data event that is triggered by the sending device without regard to $0a or $0d and that's really the way it should be. Your job is to create a buffer to store the incoming data, concantenate it as it comes in and then determine at what point you've receive a complete string worthy of parsing, removing only that parsible portion of the buffer until another complete parsible string is found in the buffer.

    Allot of devices send their data in fragmented chunks so you have to wait for a string to be complete before it is parsable or more easily parseble.
  • viningvining Posts: 4,368
    Aleksey wrote: »
    I think you just need to collect all incoming data to a buffer and parse it to strings:
    DATA_EVENT[NX587Port]
    {
        STRING:
        {
    	cBuffer="cBuffer,DATA.TEXT";
            cTmpString=REMOVE_STRING(cBuffer,"$0D",1);
    	WHILE(cTmpString!="")
    	{
                fnDoSomething(cTmpString);
                cTmpString=REMOVE_STRING(cBuffer,"$0D",1);
             }
          }
    }
    
    Not to pick on your code :) but this isn't a very good example since you will usually have left over data in your buffer and eventually your buffer will become full of data and then every time the data event triggers you'll be parsing old data. How old depends on the size of your buffer. If you look at line 101 of the OP's diagnostic print out there are at least 4 $0D's in that data event and your code will only ever retrieve the oldest (first) $0D in the buffer and everything else remains until the next data event fires and then you grab the next $0D and possibly even more data and $0D's are left in the buffer then were there before and it eventually fills.

    Using your example your would need to add an additional while loop:
    DATA_EVENT[NX587Port]
         
         {
         STRING:
    	  {
    	  cBuffer="cBuffer,DATA.TEXT";
    	  WHILE(find_string(cBuffer,"$0D",1))
    	       {
    	       cTmpString=REMOVE_STRING(cBuffer,"$0D",1);
    	       WHILE(cTmpString!="")
    		    {
    		    fnDoSomething(cTmpString);
    		    cTmpString=REMOVE_STRING(cBuffer,"$0D",1);
    		    }
    	       }
    	  }
         }
    
    For me I would probably loose the 2nd while loop and just do:
    DATA_EVENT[NX587Port]
         
         {
         STRING:
    	  {
    	  cBuffer="cBuffer,DATA.TEXT";
    	  WHILE(find_string(cBuffer,"$0D",1))
    	       {
    	       fnDoSomething(REMOVE_STRING(cBuffer,"$0D",1));
    	       }
    	  }
         }
    
    and put that while loop that was removed into fnDoSomething() since that's really where it belongs as part of that routine.
  • AlekseyAleksey Posts: 22
    vining wrote: »
    .... put that while loop that was removed into fnDoSomething() since that's really where it belongs as part of that routine.

    Actually, my example and your code are equal. You just took away variable cTmpString which doesn't really need here. And why do you need second loop ?
  • viningvining Posts: 4,368
    Aleksey wrote: »
    Actually, my example and your code are equal. You just took away variable cTmpString which doesn't really need here. And why do you need second loop ?

    They're not the same at all, close but not the same. Your method leaves parseable data in the buffer by only grabbing the 1st occurrance of $0D and then only deals with that while my method will grab and deal with every occurrence of $0D that may come in a single data event which is what happens in the OPs diagnostic print out. Read what I posted again and if you still don't get it I'll try to explain it better. Right now I'm not near my PC so it's hard to post examples.
Sign In or Register to comment.