Previous Topic

Next Topic

Book Contents

Book Index

User programmable protocol: Receiving messages

To be able to effectively program a SPLat to receive messages via a user programmable protocol, you first need to be very accurately informed about what the external device sends out. You should not only study the documentation on the device, but preferably also connect it to a terminal emulator and actually see the messages displayed on your screen. The terminal function built into SPLat/PC is useful for doing this. It can display received data in ASCII and hex, and allows you to easily generate outgoing messages with a mixture of printable and non-printing characters. It also allows multiple outgoing messages to be stored and sent with a button click. There are also a number of terminal emulators available online, such as RealTerm. Ideally you should try and fully interact with the device manually, and understand exactly what's happening, before trying to code the interaction into SPLat.

The relevant instructions are those that start with COMRx_ under communications instructions. These allow you to look out for specific "signal" character, trim out filler characters (like space), and extract decimal or hexadecimal numbers from the receive buffer.

SPLat/PC includes a serial communications simulation window, which is very useful when you are at the stage of single-stepping your program in the SPLat/PC simulator. You can also use the terminal function in SPLat/PC to interact with a program running in the SPLat controller.

Example 1.

This example presumes an external instrument that transmits periodic readings in ASCII. The reading format is simple a number followed by carriage return. A typical message would look like this:

123.45<CR>

when <CR> represents the carriage return character, or '0D. At this point I advise you to go to the SPLat/PC terminal. In the Module window click SIO, in the window that appears select the Terminal tab. This gives you the terminal emulator. The bottom half is dedicated to sending stuff to a connected SPLat controller (or anything else you care to connect serially!). Type in what I typed in the image below, and take special not of the blue help text and what appears in the very bottom section. Play around until you are comfortable with composing messages with printing and non-printing characters. (a letter A is printing, as is a space, while a carriage return is not)

The nice thing about this terminal function is that you can type in a message once and click its Send button many times.

Once you are comfortable with how to send a message to the SPLat, you can proceed with the program below. Translate and send the program to your board, and run it, make sure the Terminal setting are as shown in the lower lefthand corner of the screen shot above. Now try sending numbers terminated in <CR>. (Click here for some tips for working around problems with copy and paste out of Internet Explorer and HTML-help (.chm) files)

;Example of receiving ASCII numbers into the serial port. Designed for MS120, easily adapted to MMi202.
;There is one MultiTrack task per function.     

        OBLCD_Dim       1,8,2                   ;Set up LCD backlight for dimming
#       Open_Serial     User(38400, 8, N)       ;Start up the serial port in "user" protocol. This will delay 10 seconds
        LaunchTask      ReceiveNumbers
        LaunchTask      HeartBeat       ;Run indicator
        LaunchTask      CrashMe         ;Suicide task
        RunTasksForever
        
fRxNumb  defFLOAT                        ;The received

ReceiveNumbers:
;Wait until there is a CR in the receive buffer
        YieldTask
        LoadX           '0D             ;CR
        COMRx_FindXInBuf                ;X become 255 if NOT found
        IncX
        GoIfZ           ReceiveNumbers
;Now I have a CR, I know there has to be a number   
        COMRx_fGetNum   255             ;Fetch the number 
        COMRx_ReadOne                   ;Gobble the CR
        OBLCD_SetCur    0,0
        OBLCD_fDispW    9,3             ;Display the number
        fStore          fRxNumb         ;Save it
        GoTo            ReceiveNumbers
        
CrashMe: ;Suicide
        WaitOnK         16
Die     GoSub           Die     ;Program wil restart at once, but with 10S delay before user comms starts up.

HeartBeat:                     
        On              8       ;The LED under the kill button
        Pause           2
        Off             8
        Pause           20
        GoTo            HeartBeat

Example 2.

This example is more elaborate. A hypothetical device, connected to the SPLat, can send 4 different messages: These are:

ON<CR>

OFF<CR>

W=123.45<CR>

H=78.9<CR>

The first two should result in an output (front panel LED) turning on or off. The last two start with W= or H= and include a variable numeric value, which is to be displayed. The program uses the COMRx_StrFind instruction to identify received text strings via a table of expected strings. COMRx_StrFind is a very powerful instruction, and you should spend a few minutes reading up on it.

;Example of receiving ASCII commands into the serial port. Designed for MS120, easily adapted to MMi202.
        OBLCD_Dim       1,8,2                   ;Set up LCD backlight for dimming
#       Open_Serial     User(38400, 8, N)       ;Start up the serial port in "user" protocol. This will delay 10 seoonds
        LaunchTask      ReceiveStuff
        LaunchTask      HeartBeat       ;Run indicator
        LaunchTask      CrashMe         ;Suicide task
        RunTasksForever

ReceiveStuff:
;Wait until there is a CR in the receive buffer, signalling a complete command.
        YieldTask
        LoadX           '0D             ;CR
        COMRx_FindXInBuf                ;X = 255 if NOT found
        GoIfXEQ         255,ReceiveStuff 
;Now I have a CR, I know there has to be something else. 
        NVSetPtr        Pointers        ;Point to table of string pointers
        COMRx_StrFind   0               ;Look for a match with the strings stored in NVVEM 
        Push
        iiPrintText     251,"Got one "  ;Diagnostic
        iiHexPrintX     251             ;Diagnostic
        iiPrintText     251,'0D,'0A     ;Diagnostic
        Branch                          ;Test X and branch accordingly
        Target          Nothing
        Target          doON
        Target          doOFF
        Target          doW
        Target          doH
        
DoON:   On              11               ;Tuirn on a LED
        GoTo            ReceiveStuff
        
DoOFF:  OFF             11               ;Tuirn off a LED
        GoTo            ReceiveStuff             

DoW:            
        COMRx_fGetNum   255             ;Get the number
        OBLCD_SetCur    0,0
        OBLCD_Text      "W="
        OBLCD_fDispW    9,3 
        COMRx_ReadOne                   ;Flush the terminating CR
        GoTo            ReceiveStuff

DoH:            
        COMRx_fGetNum   255             ;Get the number
        OBLCD_SetCur    1,0
        OBLCD_Text      "H=" 
        OBLCD_fDispW    9,3
        COMRx_ReadOne                   ;Flush the terminating CR
        GoTo            ReceiveStuff
                           
Nothing:   ;If no match, flush one character to (hopefully!) expose something we can recognise
        COMRx_ReadOne           ;Waste one character out of RX buffer  
        GoTo            ReceiveStuff
              
CrashMe: ;Suicide
        WaitOnK         16
Die     GoSub           Die     ;Program will restart at once, but with 10S delay before user comms starts up.

HeartBeat:                     
        On              8       ;The LED under the kill button
        Pause           2
        Off             8
        Pause           20
        GoTo            HeartBeat
**********************************************************************
       NVEM0
;NVEM tables      
;List of expected "commands". Note they must all terminate in 0
strON:  NV0Byte         "ON",'0D,0
strOFF: NV0Byte         "OFF",'0D,0
strW:   NV0Byte         "W=",0
strH:   NV0Byte         "H=",0

;Pointers into the list of commands
Pointers:
        NV0Ptr          strON
        NV0Ptr          strOFF
        NV0Ptr          strW
        NV0Ptr          strH
        NV0Byte         255     **** Essential terminator ****        

Experiment with this program, and getting it receiving and acting on inputs from the Terminal window.

I have left in a bit of diagnostic code, which prints out the index number of the string found in the table. Its output appears on the Terminal screen.

Note the code at the program line Nothing: If a received string is not recognised, we throw away one receive character from the head of the buffer. This ensures that, should anything go wrong, the program will eventually recover so long as it is receiving <CR> characters.

Exercises.

  1. Remove the COMRx_ReadOne at Nothing:, then try sending a bad message like OX instead of ON. What happens? Restore the COMRx_ReadOne and try again.
  2. Why have I got <CR> (or '0D) terminators on the first two strings in the NVEM table, but not for the second 2? Hint: Why do I have COMRx_ReadOne instructions in the segments doW; and doH:?
  3. Experiment with the COMRx_StrFind argument.
  4. Merge this example with the one under "User programmable protocol: Sending out messages" to make a program that both receives and decodes stuff and sends stuff out. Get creative, so what is sent out is in response to something received.

Previous Topic

Next Topic