Shop OBEX P1 Docs P2 Docs Learn Events
strcomp with Local Variable — Parallax Forums

strcomp with Local Variable

ryfitzger227ryfitzger227 Posts: 99
edited 2013-09-04 17:41 in Propeller 1
I'm working on something that is running on another cog and using a local variable to compare two strings. I really have no clue what the rules are on this and I've searched the Propeller manual and can't find anything. Here's my code that I have so far.
PUB main

cognew(readSerial, @stack)

PUB readSerial | readBuffer

repeat

  readBuffer := string("0")
  
[COLOR=#ff0000]  repeat while strcomp(@readBuffer, string("0"))[/COLOR]

  dira[16] := 1
  outa[16] := 1


The red statement should continue repeating until the readBuffer variable is changed, but it doesn't ever change at this point. As soon as the program is started the Pin 16 LED lights up. What could I be doing wrong?

Comments

  • Dave HeinDave Hein Posts: 6,347
    edited 2013-09-01 14:14
    readBuffer contains the address of the string "0". @readBuffer is the address of the stack variable readBuffer. You should use strcomp(readBuffer, string("0")) instead of strcomp(@readBuffer, string("0")).
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-09-01 16:14
    I don't know if you were just using a single character to make your test code simple or if you really only need to compare a single character. If it's the latter then you can just compare the value of the character directly.
    singleCharacter := "0"
      repeat while singleCharacter == "0"
    
  • ryfitzger227ryfitzger227 Posts: 99
    edited 2013-09-01 18:17
    Dave,

    That fixed my problem. I don't know if you can help me with the next one or not.

    I've added code that is supposed to read the serial port and check to see if it equals something.. Here's my code I have now.
    PUB main
    
    cognew(readSerial, @stack)
    
    PUB readSerial | readBuffer
    
    
    repeat
    
    
      dira[16] := 1
      outa[16] := 1
    
    
      readBuffer := string("0")
      
      repeat while strcomp(readBuffer, string("0"))
        serial.RxStr(readBuffer)
    
    
      dira[17] := 1
      outa[17] := 1
    
    
    [COLOR=#ff0000]  if strcomp(readBuffer, string("ABC")) 'tell the computer to RESET me.[/COLOR]
         serial.str(string("RESET"))
         dira[18] := 1
         outa[18] := 1
    

    The red line should be where the problem is. I know for a fact the computer is sending the correct string and the repeat loop is stopping at the correct time (when the readBuffer variable changes - or the serial port contains a value). Why is the serial port sending RESET to the computer/Lighting LED 18.
  • msrobotsmsrobots Posts: 3,709
    edited 2013-09-01 18:54
    well strings in spin are just bytearrays.
    your readbuffer is one long - 4 bytes.

    not much but ok for "0" and ok for "ABC"

    but you need to provide the address of the readbuffer to RxStr
      readBuffer := "0" ' this puts the value "0" into readbuffers first byte out of four (all others are 0 thus terminating the string in the bytearray
      
      repeat while strcomp(@readBuffer, string("0")) ' compare string (bytearray) at address of readbuffer with string at address provided by string("0")
        serial.RxStr(@readBuffer) ' will read string into the first 4 bytes at address readbuffer, using a one long (4 byte) destination
    
      dira[17] := 1
      outa[17] := 1
    
    
    [COLOR=#ff0000]  if strcomp(@readBuffer, string("ABC")) 'tell the computer to RESET me.  - and now it will work[/COLOR]
    ...
    
    

    Enjoy!

    Mike
  • Dave HeinDave Hein Posts: 6,347
    edited 2013-09-01 18:58
    You are using readBuffer to hold the address of string("0"), which should be treated as a constant string. You then use readBuffer with RxStr to pass the address of a buffer to hold an input string. So readBuffer should point to a variable buffer in this case. You don't need to do a strcomp of readBuffer to string("0"), unless you want to skip any input strings that are just "0". So I would suggest that you do something like this.
    PUB readSerial | readBuffer, buffer[20]
      readBuffer := @buffer
      repeat
        dira[16] := 1
        outa[16] := 1
     
        serial.RxStr(readBuffer)
        dira[17] := 1
        outa[17] := 1
    
        if strcomp(readBuffer, string("ABC")) 'tell the computer to RESET me.
           serial.str(string("RESET"))
           dira[18] := 1
           outa[18] := 1
    
    You could just use @buffer instead of readBuffer. Also, you need to make sure that you stack is large enough to accommodate buffer[20], of you could define buffer in a DAT or VAR section. I used the size of 20 longs to allow for accepting a string of up to 80 characters. You could use a smaller buffer if you can ensure that the input string will always fit in the buffer.
  • UnsoundcodeUnsoundcode Posts: 1,532
    edited 2013-09-01 18:58
    Hi, the following link contains information regarding what you are looking for, in a different manner but just as good.

    http://forums.parallax.com/showthread.php/149956-Extended-Full-Duplex-Serial-RxStr-Question

    Jeff T.
  • ryfitzger227ryfitzger227 Posts: 99
    edited 2013-09-02 07:54
    I tried both Dave's and msrobot's code. Neither of them worked right. Let me explain a little more. As soon as you start the Propeller it waits for the computer to "read" it. The computer will send out a string of "ABC" to all available serial ports, and this propeller will send back its name. That's what the computer is looking for. Then the VB program can log the COM Port name and Device name in a database somewhere. Let's say that a user accidentally shuts down the program and they start it back up. The VB program will again send "ABC" to all available serial ports. The only problem is that the Propeller is no longer at the beginning of the code - it's doing something else. So to make sure everything runs smoothly, in this readSerial cog, when/if it receives that ABC string it instead of sending its name sends a string of "RESET" which the VB program recognizes and a Message Box displays saying to reset the board and then retry. It's kind of complicated, but it will grow as I get further into the project. What is so weird is that it works just fine at the beginning of the program, and it won't work in the readSerial Cog. Here's my full code.
    VAR
    
    LONG stack[50]
    LONG startc
    
    PUB main
    
    
      startc := string("0")
    
    
      serial.start(31,30,0,9600)
    
    
      repeat until strcomp(@startc, string("ABC"))
        serial.RxStr(@startc)
    
    
      serial.str(string("PB1")) 'PB1 is the name of this board
    
    
      serial.rxflush
      
      cognew(readSerial, @stack) 'the above code works just fine, it's when we get to this readSerial cog that nothing works.
    
    
    PUB readSerial | readBuffer
    
    
    repeat
    
    
      readBuffer := string("0")
    
    
      repeat while strcomp(readBuffer, string("0"))
        serial.RxStr(readBuffer)
    
    
      if strcomp(readBuffer, string("ABC")) 'tell the computer to RESET me.
         serial.str(string("RESET"))
    
    
    

    I still think it's in that if statement. Because when I had the LEDs lighting up along with everything, you could see when as soon as I hit the button that sent "ABC" on the computer, that LED lit up (indicating that the readBuffer no longer equaled 0.). The only problem was that it would never send "RESET" to the computer. This absolutely makes no sense to me. (By the way - I made a typo in my second post. It should be that it does NOT send the "RESET" string. - I forgot the word NOT if anyone didn't catch that).
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-09-02 11:48
    Are you dead set on using a local variable for the buffer? I know it can be done, but in general character strings are stored as byte arrays and I think most of us have experience with manipulating byte arrays rather than dealing with longs. I'm not sure if the way bytes are packed into a long (little endian) can interfere with strcomp or not (I doubt it).

    I just had another thought. Local variables are not initialized to zero. Try using readBuffer := 0 early in the method to make sure the long has a terminating zero for the string in stick in it. Though I'm betting the "string" statement puts one in for you.

    I think the RxStr method is expecting a buffer location. I think you want to use ".RxStr(@readBuffer)" if you want the incoming data stored in the long. Otherwise it will stor it where the "0" string was stored. You'll then be storing four bytes (including terminating zero) where previously two bytes had been stored. This may cause you trouble.

    I still think you'd be better off using some temporary global byte array to hold your strings. I think the way you're doing it now make it very easy to make an error in manipulating strings.

    Edit: IIRC, the rxStr method uses a terminating carriage return. That with a terminating zero will put you over the four bytes of a long.
    Edit again: It looks like rxStr overwrites the carriage return with a zero so nevermind about the above edit.
  • AribaAriba Posts: 2,690
    edited 2013-09-02 12:52
    Here is your code with a byte array for the string.
    The Extended FDS object receives max. 15 characters, but copies always 16 bytes to the string. So you need to define a bytearray with min. 16 bytes.
    startc := string("0") does not copy the string into startc. string("") builds the string in memory and returns a pointer to it. Because it makes no sense to have "0" in the string I just make the string empty with startc[0] := 0. The [0] is not really needed but makes it clear that the first character is set to zero, which marks the end of the string. So the string is empty.

    You can use the same string in the main routine and the readSerial cog, as long as you don't use it at the same time.
    VAR
      LONG stack[30]
      BYTE startc[16]     'define a string with max 15 chars
    
    PUB main
    
      startc[0] := 0
      serial.start(31,30,0,9600)
    
      repeat
        serial.RxStr(@startc)
      until strcomp(@startc, string("ABC"))
    
      serial.str(string("PB1")) 'PB1 is the name of this board
    
      serial.rxflush
      
      cognew(readSerial, @stack) 
    
    
    PUB readSerial | readBuffer
    
     repeat
       startc[0] := 0
    
       repeat
         serial.RxStr(@startc)
       until strcomp(@startc, string("ABC"))
       
       serial.str(string("RESET"))
    
    Andy
  • Duane DegnDuane Degn Posts: 10,588
    edited 2013-09-02 13:18
    Ariba wrote: »
    Here is your code with a byte array for the string.

    Andy, you broke the rules. Didn't you read the thread title?:smile:

    FWIW, I think Andy's way makes much more sense.

    It was unclear in the original code if the local variable was used to store the characters or if was to be used to store the location generated by the "string("0")" command. If the latter, then the "string("0")" wasn't reserving enough room for your three character input. If the former, then the code had other problems.
  • AribaAriba Posts: 2,690
    edited 2013-09-02 13:57
    Duane

    sometimes you have to break the rules to get ahead :smile:

    Andy
  • ryfitzger227ryfitzger227 Posts: 99
    edited 2013-09-04 17:41
    I got it working. Thanks guys.
Sign In or Register to comment.