Shop OBEX P1 Docs P2 Docs Learn Events
StrComp question — Parallax Forums

StrComp question

Mikael SMikael S Posts: 60
edited 2012-01-20 03:18 in Propeller 1
Hello!

I try to compare a string recieved from my gsm modem with a given DAT byte, but without luck. I think the problem is that the recieved string does not contain a terminating zero.
Can someone please give me a example how i can add that zero to my recieved string, or what can it be??

Thanks!

/Micke
«1

Comments

  • JonnyMacJonnyMac Posts: 9,198
    edited 2012-01-11 14:47
    It's a pretty simple matter of replacing the terminator from your original string with a zero, then doing the comparison. If you provide a code snippet of what you're doing that doesn't work, it will be easier to show you a specific solution.
  • Mikael SMikael S Posts: 60
    edited 2012-01-11 15:03
    Thanks for your fast answer!
    Here comes the code:
    var
    
     byte message[15], phonenumber[16], mess1[16], mess2[16], mess3[16], mess5[16], mess6[16], mess7[16]
    
    dat
    
       on byte "on", 0
       off byte "off", 0
    
    pub main
       
    debug.start (115200)
    gsm.start (26, 27, 0, 9600)
    waitcnt (clkfreq * 2 + cnt)
    
    dira[2] :=1
    
    readmessage
    
    pub readmessage 
    
    
    repeat  
    
      waitcnt (clkfreq * 5 + cnt)
      gsm.rxflush
      gsm.str (string("AT+CMGR=1")) 'Read sms in first memory
      gsm.tx(13)                    'CT
      
      debug.str (string("Get message in memory1..."))
    
      debug.newline
      gsm.RxStrTime(300,@mess1)
      gsm.RxStrTime(300,@mess2)
      gsm.RxStrTime(300,@mess3)
      gsm.RxStrTime(300,@phonenumber) 
      gsm.RxStrTime(300,@mess5)
      gsm.RxStrTime(300,@mess6)
      gsm.RxStrTime(300,@mess7)
      gsm.RxStrTime(200,@message)
      waitcnt (clkfreq * 1 + cnt)
      gsm.str(string("AT+CMGD=1"))      'Delete message in first memory
      gsm.tx(13)
      waitcnt (clkfreq * 1 + cnt)
    
    
         if strcomp (@on, @message)
            on2 
         elseif strcomp (@off, @message)
            off2
    
      debug.str(string("no message, repeat"))      
    
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-11 15:15
    Something I've found useful is to do a bytefill prior to gathering data.
    bytefill(@message, 0, 127)
    

    I think I added up 127 bytes in your buffers.
  • JonnyMacJonnyMac Posts: 9,198
    edited 2012-01-11 15:57
    I've used Duane's trick, too. What you do is have a buffer that is at least one byte longer than any string you expect to receive. You use bytefill to fill that array with zeros and then receive your new string into it. So long as your string is in fact shorter than the buffer used, you will now have a zero terminator. This is probably the best route as you're using a canned routine and don't want to change it.
  • T ChapT Chap Posts: 4,223
    edited 2012-01-11 17:42
    If you have to receive the data each time before the compare, another option is to use rxtime, and specify a time that will allow the receive code block to time out after the last byte. After the timeout, the return value is -1, so you can create a test in the read loop that says that if it gets a -1 from a time out, the current and position is set to 0. Once a -1 is received. quit the loop.

    Example using a 4port serial object:
    PUB ReadData   | ii, val    'copy content of incoming message to an array
         ii := 1
         response := ser.rxtime(2, 1000)  serial port 2, waits here for first byte response for 1 second
         If response > -1   ' if something was received, get the rest of the data now
          Repeat 511                    'look for more, else return
            Val :=  ser.rxtime(2, 2)   'read more, wait only 2 ms if no byte found
            If val == -1                     'if the wait timed out with no data
              response[ii] := 0      'set this array position to a 0
              quit             'quit, return, or abort...  no more reading 
            response[ii] := Val   ' write to the array if data was received
            ii++
    
  • Mikael SMikael S Posts: 60
    edited 2012-01-12 10:31
    Thanks everyone for your answers!

    It doesent work for me...
    I have increased the "var byte message" to 127, and i have put the "bytefill(@message, 0, 127" just before the gsm.RxStr.
    What is it im doing wrong, can someone please help me?!

    /Micke
  • T ChapT Chap Posts: 4,223
    edited 2012-01-12 10:51
    Do you already know how many bytes are in the message reply? Is it possible it is more than 127?
  • Mikael SMikael S Posts: 60
    edited 2012-01-12 11:01
    no, the reply is just two characters.
  • T ChapT Chap Posts: 4,223
    edited 2012-01-12 11:05
    Have you tried to print to screen the content of message to be sure that you do have the correct characters in the string before doing the compare?
  • Mikael SMikael S Posts: 60
    edited 2012-01-12 11:13
    yes, i have. I deleted that part, just to shorten my post.
  • T ChapT Chap Posts: 4,223
    edited 2012-01-12 11:17
    Try getting rid of the elseif, just use another if
  • Mikael SMikael S Posts: 60
    edited 2012-01-12 11:30
    I really appreciate your help!

    Now i have tried that, same result...

    Here is my latest code, the message consists just of the two letters "on".

    [code]
    obj

    gsm: "Extended_FDSerial"
    debug: "Parallax Serial Terminal"
    var

    byte message[127], phonenumber[16], mess1[16], mess2[16], mess3[16], mess5[16], mess6[16], mess7[16]

    dat

    on byte "on", 0
    off byte "off", 0

    pub main

    debug.start (115200)
    gsm.start (26, 27, 0, 9600)
    waitcnt (clkfreq * 2 + cnt)

    dira[2] :=1

    readmessage

    pub readmessage


    repeat

    waitcnt (clkfreq * 5 + cnt)
    gsm.rxflush
    gsm.str (string("AT+CMGR=1")) 'Read sms in first memory
    gsm.tx(13) 'CT

    debug.str (string("Get message in memory1..."))
    bytefill(@message, 0, 127)
    debug.newline
    gsm.RxStrTime(300,@mess1)
    gsm.RxStrTime(300,@mess2)
    gsm.RxStrTime(300,@mess3)
    gsm.RxStrTime(300,@phonenumber)
    gsm.RxStrTime(300,@mess5)
    gsm.RxStrTime(300,@mess6)
    gsm.RxStrTime(300,@mess7)
    gsm.RxStrTime(200,@message)
    waitcnt (clkfreq * 1 + cnt)
    gsm.str(string("AT+CMGD=2")) 'Delete message in first memory
    gsm.tx(13)
    waitcnt (clkfreq * 1 + cnt)
    debug.newline
    debug.str(@mess1)
    debug.newline
    debug.str(@mess2)
    debug.newline
    debug.str(@mess3)
    debug.newline
    debug.str(@phonenumber)
    debug.newline
    debug.str(@mess5)
    debug.newline
    debug.str(@mess6)
    debug.newline
    debug.str(@mess7)
    debug.newline
    debug.str(string("H
  • T ChapT Chap Posts: 4,223
    edited 2012-01-12 11:48
    Try this code instead:

       if message[0] == "o"
          if message[1] == "n"
               outa[2] :=  1     'assumed to be an LED???
       if message[0] == "o"
          if message[1] == "f"
            if message[2] == "f"
               outa[2] := 0
    
  • Mikael SMikael S Posts: 60
    edited 2012-01-12 12:13
    No luck with this either....
  • T ChapT Chap Posts: 4,223
    edited 2012-01-12 12:19
    Ok since I am on a wild goose chase, please try this and post the result:

    debug.str(string("H
  • Mikael SMikael S Posts: 60
    edited 2012-01-12 12:57
    Here comes the result...
    (I cant copy and paste from Serial Terminal, i hope this will do)
  • T ChapT Chap Posts: 4,223
    edited 2012-01-12 13:50
    I have tested this and it works, not sure why your code is not working.
    var 
       byte test1[3]
    
    pub 
       test1[0]  := "o"
       test1[1]  := "n"
       test1[2]  := 0
       if strcomp(@test1, @test2)
         dosomething
    dat
        test2 byte "on", 0
    

    The only last thing I might try for some understanding is to look at each element in the var:
    debug.str(@message[0])
    debug.newline
    debug.str(@message[1])
    debug.newline
    debug.str(@message[2])
    debug.newline

    Hopefully someone will enlighten us both.
  • John AbshierJohn Abshier Posts: 1,116
    edited 2012-01-12 14:20
    This works for me.
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
    VAR
      byte Str2[30]
       
    OBJ
      SIO      : "FullDuplexSerialPlus"
      
    Pub Main
      waitcnt(clkfreq * 4 + cnt)
      SIO.StartPST(115200)
      repeat
        SIO.GetStr(@Str2)
        SIO.Str(string("Str2 is: "))
        SIO.Str(@Str2)
        SIO.tx(13)
        if strcomp(@Str1, @Str2)
          SIO.Str(string("Str1 and Str2 are equal",13,13))
        else
          SIO.Str(string("Str1 and Str2 are different",13,13))
              
    DAT
    Str1 byte "Hello World", 0
    

    Results from Parallax Serial Terminal
    Str2 is: Fred
    Str1 and Str2 are different
    
    Str2 is: Hello World
    Str1 and Str2 are equal
    

    John Abshier
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-12 18:11
    The output from post #17 looks odd (date/time for example, why is it split when double quotes are used?). The default delimiter used with RxStrTime is a comma. So assuming date and time are delimited by a comma (not unreasonable) then they will be returned over two separate calls to RxStrTime. To check this theory please add the following call somewhere after gsm.start in your main method:
    gsm.SetDelimiter(13)   ' do not use comma, CR is hardwired into RxStrTime so no harm re-using it
    
    Also, you should increase the 15 character limit for RxStrTime in the Extended_FDSerial object. Not doing so will split longer messages after 15 characters which may upset your (hard-wired) receive sequence (e.g. date and time won't fit into a 15 character buffer assuming they come as one line).
  • Mikael SMikael S Posts: 60
    edited 2012-01-12 22:22
    The output is ok in my eyes. Im just need to recieve three different messages, on, off, and status. So the buffersize is ok. Im only intressted in the message and the phonenumber for the reply message.
    My problem is why i cant parse the incomming message with the actual three given words.
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-12 22:40
    OK, what does the uninterpreted message look like? After
    debug.str (string("Get message in memory1..."))
      bytefill(@message, 0, 127)
      debug.newline
    
    add the following loop
    repeat
        if (c := gsm.rx) < 32
          debug.char("<")
          debug.hex(c, 2)
          debug.char(">")
        else
          debug.char(c)
    
    This is simply to verify whether the command actually arrives.
  • Mikael SMikael S Posts: 60
    edited 2012-01-13 00:58
    Now i have tried that, i get a strange result!
    But in my code i have the debug.str(@message) and that give me the right result from the string (on).

    Another question, is there any way to copy the result from the Serial Terminal, without using the print screen?
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-13 01:10
    Mikael S wrote: »
    Now i have tried that, i get a strange result! Another question, is there any way to copy the result from the Serial Terminal, without using the print screen?
    What's your _clkmode setup like? If you don't have any please add some (115k2 is not reliable at RCFAST). If you don't have a crystal try a lower baudrate.
    CON
      _clkmode = XTAL1|PLL16X
      _xinfreq = 5_000_000
    
    As for the rest, it looks like you get CRLF line endings from the gsm device (<0D><0A>). Unfortunately the string reader only uses CR as a delimiter. Which means your command will be preceded by the remaining LF. This needs filtering out otherwise strcomp will never match.

    copy/paste is possible. Just select the area with the mouse then press ctrl+C. Once you have your clock setup sorted can you generate another data dump?

    Apologies for using the wrong method names. PST uses char instead of tx (I modified the code fragment posted earlier).
  • Mikael SMikael S Posts: 60
    edited 2012-01-13 08:49
    I have that clockmode that you refer to.
  • Mikael SMikael S Posts: 60
    edited 2012-01-13 13:42
    OK, i think i have a <LF> in the begining of my string, how can i get rid of that?
    Or is there any other solution to read a "part" of a string without knowing the start bit??
  • Mike GMike G Posts: 2,702
    edited 2012-01-13 13:58
    Let's see if this example helps
    CON
       _clkmode = xtal1 + pll16x
       _xinfreq = 5_000_000
    
    DAT
      message     byte  " Some stuff", $0A, "My received string", $00
      compareTo   byte  "My received string", $00 
      
    VAR
      Byte buffer[3]
    
    
    OBJ
      pst : "Parallax Serial Terminal"
     
    
    PUB Main | i, isMatch
      pst.start(115200)
      Pause(500)
    
      i := 0
      isMatch := false
    
      ' Find the string that starts after an <lf>
      'Then compare the string to "compareTo" 
      repeat strsize(@message)
        if(message[i++] == $0A)
          isMatch := strcomp(@message[i], @compareTo)
    
      'Print the results
      pst.str(string("Have a match: "))
      if(isMatch)
        pst.str(string("True", $0D))
      else
        pst.str(string("False", $0D))
             
    
    PRI Pause(Duration)  
      waitcnt(((clkfreq / 1_000 * Duration - 3932) #> 381) + cnt)
      return
    
  • T ChapT Chap Posts: 4,223
    edited 2012-01-13 14:55
    Would searching within the string (instring) find the "on" if there is a LF at the front? I can't test it right now. I included Jon's string methods.
    pub instr(str1, str2) | len1, len2, pos, idx
    
    '' Returns position of str2 in str1
    '' -- if str2 not in str1 returns -1
    
      len1 := strsize(str1)
      len2 := strsize(str2)
      pos  := -1                                           
      idx  := 0
    
      if (len1 => len2)                                    
        repeat (len1 - len2 + 1)                           
          if (byte[str1] == 0)                             
            quit
          else
            if (strncmp(str1++, str2, len2) == 0)          
              pos := idx                                   
              quit                                         
            else
              ++idx
    
      return pos
    

    Or, try this test:
    PUB parsemessage  |  i
     i := 0
     repeat 4   '10 should handle 'on',  or repeat strsize(message) for crude method of repeats
       if message[i] == "o"
          if message[i+1] == "n"
               outa[2] :=  1     'assumed to be an LED???
       if message[i] == "o"
          if message[i+1] == "f"
            if message[i+2] == "f"
               outa[2] := 0
       i++
    

    This would normally search within the string and find on or off, not sure how it reacts with LF as part of the string.
  • Mikael SMikael S Posts: 60
    edited 2012-01-14 01:43
    Thanks!
    How can i add the <LF> in my DAT byte?
    I have a "on byte "on", 0" in my DAT section, is there any way to add the <LF> command before the "on" ?
    Just to test my theory...
  • kuronekokuroneko Posts: 3,623
    edited 2012-01-14 01:48
    Mikael S wrote: »
    How can i add the <LF> in my DAT byte?
    label   byte    10, "on", 0
    
    That said, this feels wrong. But maybe that's just me :)
  • Mikael SMikael S Posts: 60
    edited 2012-01-17 11:35
    When i add the <LF> in my compare string everything works, thanks everyone!

    Now to the next issue....
    I use the code below to read the message from my modem, and it seems to work fine, for a while...
    It seems like the prop hangs if the modem recieves a message exactly at the same time this code is executed.
    If there is no message to read, i just use the time-out part in the RxStrTime, and its then this seems to happen.

    [code]
    gsm.rxflush
    gsm.str (string("AT+CMGR=1")) 'Read sms in first memory
    gsm.tx(13) 'CT

    debug.str (string("Get message in memory 1..."))
    bytefill(@message, 0, 127)
    gsm.RxStrTime(300,@mess1) '
Sign In or Register to comment.