Shop OBEX P1 Docs P2 Docs Learn Events
String parsing — Parallax Forums

String parsing

ThricThric Posts: 109
edited 2011-12-23 16:21 in Propeller 1
Hi,
I've been working on my project haphazardly for a while now and now that its winter break I can finally get a bit organized. I'm fixing up my new PCB this Friday and so while that is on hold I've been working on the software protocol with one of my older propeller boards. I just finished typing up a computer program that sends a string of characters much like NMEA in a GPS:

$WLO,3,1234,1234,1234,p

Sent through an XBEE the propeller confirms the sent data and then parses the data, supposedly creating a pointer to each of the value between the commas. I'm not exactly sure how the function copy_buffer ( buffer,args) actually works as I took that aspect from a GPS parsing program (see attachment). The program itself is suppose to return one of the values it receives, but currently its only transmitting 4696 instead of 1234. I know that it does actually collect the string I sent it as I can send all the characters from comm_buff back to a terminal screen and its the same.

How does the copy_buffer function work?
What is wrong with my implementation that is making it return the wrong values?

Thanks

This is the code that is running in my propeller
Con

 _clkmode = xtal1 + pll16x
 _xinfreq = 5_000_000
 led = 17

                                  
var
  byte comm_buff[100]
  long cptr
  long Rx
  long MMMb[100],MMMa[100]                                         
  long cog,ptr,arg,j
  long Null[1]
  byte GPRMCb[68],GPGGAb[80],PGRMZb[40],WLOb[100]   
  long GPRMCa[20],GPGGAa[20],PGRMZa[20],WLOa[20]   

    
Obj
 
  uart: "pcFullDuplexSerial4FC"'   
   
Pub Main |p,int


{*****Set up the communications*****}
  uart.init   
  uart.AddPort(2,2,3,-1,-1,0,0,9600)    'XBEE
  uart.start

  repeat until p=="$"
    p:=uart.rx(2)
  cptr:=0
  repeat until Rx== "p"        'continue to collect data until the end
    Rx:=uart.rx(2) 
    if Rx == ","
       comm_buff[cptr++] := 0    '  If "," replace the character with 0
    else
       comm_buff[cptr++] := Rx   '  else save the character
   
  if comm_buff[0] == "W"             
    if comm_buff[1] == "L"            
      if comm_buff[2] == "O"           
        uart.tx(2,"s")
        copy_buffer(@WLOb, @WLOa)
                     
         
  waitcnt(300_000_000+cnt)
  repeat
    uart.dec(2,valid)
      
    uart.newline(2)
    ld
    

  show


pub copy_buffer ( buffer,args)
         bytemove(buffer,@comm_buff,cptr) '  copy received data to buffer
         ptr := buffer
         arg := 0
         repeat j from 0 to 79           ' build array of pointers
          if byte[ptr] == 0               ' to each
             if byte[ptr+1] == 0           ' record
                long[args][arg] := Null     ' in 
             else                            ' the
                long[args][arg] := ptr+1      ' data buffer
             arg++
          ptr++
          
' now we just need to return the pointer to the desired record


pub valid
   return WLOa[1]
   
Pub show
  repeat
    dira[19]:=1
    outa[19]:=1
    waitcnt(10_000_000+cnt)
    !outa[19]  

pub ld
  dira[19]:=1
  outa[19]:=1
  waitcnt(100_000_000+cnt)
  !outa[19]  

Comments

  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-21 19:10
    Sometimes "borrowing" code leads to these kinds of problems. Perhaps it's best that you define your protocol and then write code around that. In the January issue of Nuts & Volts I describe a cheeky little object called "Human Friendly Control Protocol" that, like your strings, uses comma-delimited fields so that you can use a terminal to "talk" to the Propeller. If I knew what your protocol requirements are I could show you how to use the general-purpose objects I've written.
  • pedwardpedward Posts: 1,642
    edited 2011-12-21 19:38
    Well, your first problem is that the copy_buffer isn't parsing for commas, it's parsing for a NULL delimited list of parameters.

    To write the function more simply:
    
    pub copy_buffer ( buffer,args)
      bytemove(buffer,@comm_buff,cptr)   '  copy received data to buffer
      ptr := buffer
      arg := 0
      repeat cptr           ' Parse a string cptr bytes long
        if byte[ptr++] == ","               ' check buffer and post increment ptr
                    if ptr-1 > buffer             ' don't underrun the buffer
                      byte[ptr-1] := 0            ' null terminate string
          long[args][arg++] := ptr      ' record pointer to argument and post increment argument 
    
  • ThricThric Posts: 109
    edited 2011-12-21 20:07
    Well I'm not sure how to define my protocol but i'll give it a shot:

    Computer side:
    my computer sends a string that starts with a $ and then the name of the string, so: $WLO, $WLA, $DGS, so on and so forth for a few others
    At the end of each string is the letter p which is what tells the propeller that the string has come to an end.
    My computer constantly sends it until the propeller sends a character telling it that everything is received.

    Propeller side:
    The propeller constantly waits until it receives a $ sign.
    It then starts collecting the entire string until a p is received.
    After sending the confirmation character it needs to view the data that the string has so as an example:

    $WLO,3,1234,567,893,p

    I need to be able to isolate the 3, the 1234, the 567, and the 893 or more.

    Is this what you were looking for?
  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-22 07:31
    That makes sense. Does the 3 in this string:

    $WLO,3,1234,567,893,p

    ...indicate that there are three parameters? Any reason you chose to terminate with "p"? If you use CR then terminal entry is user-intuitive (assuming you want that, as I did in HFCP).
  • ThricThric Posts: 109
    edited 2011-12-22 07:57
    Yes the three indicates the number of parameters. I just choose "p" randomly :lol: and that can change.
  • ThricThric Posts: 109
    edited 2011-12-23 06:07
    @pedward- I tried your code fix but now all i'm receiving on my terminal screen is a 0.
  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-23 10:13
    As we (EFX-TEK) have three Propeller-based products with RS-485 built in coming out in 2012, I've been very interested in simple command string parsing (this lead me to create my HFCP object). I borrowed some elements from that to create the attached demo for you -- with a couple changes:

    The string header changed from "$" to ">" (this is constant in the program). Why? Well, in my strings library I have the ability to convert a string to a number, and if binary (%) or hex ($) is indicated, those values are properly parsed. If any of your commands have to do with setting/clearing bits, using binary is easier IMHO.

    The terminating character is CR to make entry from a terminal very intuitive. The program allows your known commands to have from 0 to 8 parameters -- again, the parameter count can be changed by a constant. The field separator is the comma, and that can be changed, too. One of the methods counts the number of separator characters in your string to know how many parameters you've passed. You can do anything you'd like with them, including using one of them to verify the others.

    The screen shot shows the program in action, accepting a decimal, binary, and hex value. Happy Holidays!
  • ThricThric Posts: 109
    edited 2011-12-23 10:26
    You my good sir, are a Miracle worker!
    Thank you!
    Happy holidays to you too!
  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-23 10:50
    You're welcome. I enjoy writing demos for others as it helps me improve my own skills and sometimes -- as happened today -- help me discover problems or make improvements to my code. While working on your demo I uncovered a very subtle bug in my strings library. That's fixed now.

    In case you're interested in my HFCP, which uses numeric commands (versus strings like your "WLO", etc.), I've just posted it in ObEx with a demo program.
    -- http://obex.parallax.com/objects/826/
  • ThricThric Posts: 109
    edited 2011-12-23 16:19
    Thanks Again, I was just able to get it running and it works fantastically! I'm just curious to know if decimal function is handled? Currently when I put in a decimal say: 3.142, it comes out with 3.
  • JonnyMacJonnyMac Posts: 9,198
    edited 2011-12-23 16:21
    It does not handle floating point values. To keep things easy you may want to use fixed point values and convert to floats in your program. In your case you would send "3142" and then divide the parsed value by 1000 (with the proper FP library support, of course).

    BTW... the numeric conversion code tolerates the underscore character, so the text in your string could be "3_142" -- I use the underscore in most of my listings to make large values easy to read; in this case it could represent a decimal point.
Sign In or Register to comment.