SPLat Logo

ComRx_StrFind c [D>=27]

NOTICE: SPLat Controls has moved. We are now at 1/85 Brunel Rd, Seaford, 3198. map

ComRx_StrFind c [D>=27]

Match a received string to a table in NVEM. This is subtly different to ComRx_StrFind2, which uses a different table format.

This instruction seeks to match the data at the head of the default serial Rx buffer with one or more "canned" strings stored in NVEM. Its primary use is for detecting received commands and machine generated ASCII messages. For example, we initially created it to assist in interacting with a cellular modem, for sending and receiving SMS messages.

If argument c is zero, the instruction treats upper and lower case letters as equivalent. If c is non-zero, the case of the received string must match exactly the string stored in NVEM.

The data in NVEM must be stored in a very specific "NULL terminated" format. This is best illustrated by an example. Lets say we want to detect which fruit has been requested, typed in on a terminal emulator and ending in a carriage return ('0D or 13)

1. NVEM: Message list

First you construct a list of all possible receive strings in NVEM. Each string must be terminated with a 0 byte. The 0 is not part of the string, it merely signals the end of the string (C-style NULL terminated strings).

strOrange:      NV0Byte   "Orange",13,0
strApple:       NV0Byte   "Apple",13,0
strBanana:      NV0Byte   "Banana",13,0
strLemon:       NV0Byte   "Lemon",13,0
strPear:        NV0Byte   "Pear",13,0
strGrape:       NV0Byte   "Grape",13,0
;        Terminator _________________^

2. NVEM: Pointer table

Next you construct a table, in NVEM, of pointers to the individual strings. This must be terminated in two 255 bytes. The 255s tell ComRx_StrFind that it has come to the end of the table.

FruitNames:     NV0Ptr    strOrange	;Entry #1
                NV0Ptr    strLemon 	;Entry #2
                NV0Ptr    strApple 	;Entry #3
                NV0Ptr    strPear  	;Entry #4
                NV0Ptr    strBanana	;Entry #5
                NV0Ptr    strGrape 	;Entry #6
                NV0Byte   255        ;<<<<< Essential!!!

You will notice that the order of entries is different to the order of the strings themselves. They can be in any order you like, and you can have several such tables, with different ordering, even different sets of strings.

3. Code: Wait for a message string

Now to your actual code (the above is tables, not executable code). The first thing your code needs to do is wait until it knows there's a string the the Rx buffer, ready to be interpreted. In this case we know that a carriage return signals the end of an incoming string in the Rx buffer. Hence, we might wait until there is a carriage return present. Let's say this is a MultiTrack task, so we simply write a loop that waits for the carriage return, thus:

CRWait:         YieldTask
                LoadX      13         ;Carriage return 
                ComRx_FindXInBuf      ;Is there a CR in the Rx buffer?
                GoIfXEQ    255,CRWait ;loop back if not

This code snippet will sit and loop until a CR appears. Then it will "fall through". Once it falls through we now for sure that there is a message waiting for us (barring something going wrong!).

4. Code: Find a string match.

This is where we use the actual ComRx_StrFind instruction. First we have to make sure the NVEM access is correctly set up.

                NVSetPtr   FruitNames
                NVSetPage  0           ;0 is the default, so playing very safe!
                ComRx_StrFind          ;Seek a match between Rx buffer and the tabulated strings

5. Code: Evaluate the result.

The ComRx_StrFind returns its result in X, as follows:

If a match is found, the matching string is removed from the Rx buffer. If no match is found the Rx buffer is not changed.

                Branch
                Target     NoMatch
                Target     RxOrange
                Target     RxLemon
                Target     RxApple
                Target     RxPear
                Target     RxBanana
                Target     RxGrape

RxOrange:   ;Do the orange thing ....
RxLemon:    ;Do the lemon thing ....
RxApple:    ;Do the apple thing ....
RxPear:     ;Do the pear thing ....
RxBanana:   ;Do the banana thing ....
RxGrape:    ;Do the grape thing ....

You would place your own code to respond to each of the strings at RxOrange, RxLemon, etc. Quite likely you would then go back to CRWait and wait for the next incoming message.

6. Flush any garbage.

This step is what may make the difference between something that works perfectly in the lab but falters in the field. It handles the case of a message being received garbled. Serial communications is not a perfect medium ... things can and do go wrong over any communications medium. Even if you believe you have a perfect transmission channel, something as simple as a cable being plugged halfway through a message will corrupt it. An electrical noise spike can corrupt a character. If your program can get hung up because it can't detect a partial message, it will have to be restarted.

The strategy to overcome this risk is that whenever there should be a valid message in the Rx buffer (in our case when there's a carriage return character), but ComRx_StrFind is unable to decide what it is, we discard one single character from the head of the buffer. Remember, ComRx_StrFind will only detect a message that starts at the head of the buffer. One single stray character at the very start will "blind" it. So we "shave" character off the head until we either expose a valid message or we have emptied the buffer. This strategy will ensure that any corrupted messages get discarded. Other strategies are possible, depending on what is known about a given application.

In the above code the Branch target for no message is NoMatch. So ....

NoMatch:        ComRx_ReadOne		;Shave one character off the head
                GoTo       CRWait      ;Go back and try again 

Putting it all together

To make it easier to understand, the description above started with the NVEM tables and ended with the executable code. In a real program all NVEM data must come last, and be preceded by a NVEM0 directive. If this is all new to you, please see NVEM Documentation. Here it all is, in the correct order (this is still just a skeleton, as you must make sure it gets invoked in the manner best suited to your program, and you must of course add the actions required for each detected type of fruit):

;Wait for a carriage return character to appear in the Rx buffer
CRWait:         YieldTask
                LoadX      13         ;Carriage Return 
                ComRx_FindXInBuf      ;Is there a CR in the Rx buffer?
                GoIfXEQ    255,CRWait ;loop back if not

;There's a CR in the buffer, hence a full message. Find a string match.
                NVSetPtr   FruitNames
                NVSetPage  0           ;0 is the default, so playing very safe!
                ComRx_StrFind  0       ;Seek a case insensitive match between Rx buffer and the tabulated strings
;Evaluate the result.
                Branch
                Target     NoMatch
                Target     RxOrange
                Target     RxLemon
                Target     RxApple
                Target     RxPear
                Target     RxBanana
                Target     RxGrape
;Actions
RxOrange:   ;Do the orange thing ....
RxLemon:    ;Do the lemon thing ....
RxApple:    ;Do the apple thing ....
RxPear:     ;Do the pear thing ....
RxBanana:   ;Do the banana thing ....
RxGrape:    ;Do the grape thing ....

;Flush any garbage.
NoMatch:        ComRx_ReadOne		;Shave one character off the head
                GoTo       CRWait      ;Go back and try again 
;===================================================================
                NVEM0        ;Start of NonVolatile MEMory region 0
;Messages/strings
strOrange:      NV0Byte   "Orange",13,0
strApple:       NV0Byte   "Apple",13,0
strBanana:      NV0Byte   "Banana",13,0
strLemon:       NV0Byte   "Lemon",13,0
strPear:        NV0Byte   "Pear",13,0
strGrape:       NV0Byte   "Grape",13,0

;Table of pointers
FruitNames:     NV0Ptr    strOrange	;Entry #1
                NV0Ptr    strLemon 	;Entry #2
                NV0Ptr    strApple 	;Entry #3
                NV0Ptr    strPear  	;Entry #4
                NV0Ptr    strBanana	;Entry #5
                NV0Ptr    strGrape 	;Entry #6
                NV0Byte   255,255      ;<<<<< Essential!!!

Notes/reminders:

  1. The instruction only removes from the buffer the characters of any string it matches.
  2. The string must be at the very head of the buffer.
  3. The instruction argument controls case sensitivity
  4. Each string in NVEM must end in a 0 (NULL) byte.
  5. The table of pointers must end in two 255 bytes.
  6. The record length and record number pointers are not involved in this instruction. Only the page and pointer matter.