Shop OBEX P1 Docs P2 Docs Learn Events
Need to get a string back — Parallax Forums

Need to get a string back

T ChapT Chap Posts: 4,223
edited 2006-08-14 04:46 in Propeller 1
I have put together various code from some demos trying to learn a few basics. I can Tx a byte on pin 2 and Rx on Pin 0 and pass the byte back for display no problem, thanks to Mikes advice on an earlier post. I cannot solve for a string however. I enclosed the code if someone could take a quick glance and point me in the right direction.

I have sent a string term.str(string("led")) and want to get it back for display on the tv.

Thanks

A definition of "string" would help also, as well as a definition of "terminating the string with $0D" I did attempt to add the character $0D to the end of "LED" using the chart under help, but it would not add it. Therefore I don't know how to terminate "LED".

Note: This code will send the string, but it will not pass it back as I was trying to do.

Post Edited (originator99) : 8/13/2006 5:18:02 AM GMT

Comments

  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2006-08-13 05:27
    originator99,

    I don't see term.str(string("led")) in your program. I do however see ser.str(string("led")).

    I added term.str(string("led")) right underneath ser.str(string("led")) and was able to see
    led just fine on my TV monitor.

    When you use the string modifier,....

    term.[b]str[/b]([b]string[/b]("led"))
    
    



    ...it is equivalent to using the DAT descriptor and putting the information there. See below...

    [b]PUB[/b]
    term.[b]str[/b](@TextData)
    
    
    [b]DAT[/b]
    TextData   [b]byte[/b]    "led",0
    
    



    ...In the case of using the string descriptor, the "termination character" of $00 is automatically added.
    $0D is not the termination character, but instead the "return key" character.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 8/13/2006 5:31:52 AM GMT
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 05:35
    Sorry for the ambiguity Beau. I was in fact trying to send the string serially from a Tx pin 2 to the Rx pin 0, then pass the received string back to my program for display. I am using term.str for debug only. I am looking for the way to pass either the entire string that was received, or a charachter at a time as shown using the attempted array[noparse][[/noparse]0] etc.

    Thanks for the additional info.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-13 05:43
    You'll need to write your own routine to receive the characters of a string into a byte array which you can then display.
    You have to decide what passes for a terminator (usually a return). Something like this might work:
    PRI receiveStr(address,count) | c
      repeat count
        c := ser.rx
        if c == $0D
          byte[noparse][[/noparse]address] := 0
          return
        byte[noparse][[/noparse]address++] := c
    
    


    You call this with "receiveStr(@array,20)" assuming array is a 20 byte area. If no more than count-1 characters are used in the array, the string is zero terminated when a return is received. The return is discarded.
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2006-08-13 06:01
    Another illustration on how you can affect data...


    [b]PUB[/b]
    
    [b]TextData[noparse][[/noparse]2] := $44[/b]
    
    term.[b]str[/b](@TextData)
    
    
    [b]DAT[/b]
    TextData   [b]byte[/b]    "led",0
    
    




    ...Notice the added line TextData[noparse][[/noparse]2] := $44. Adding this will replace the lower case d
    with an uppercase D in the displayed TV output of leD.

    In a similar situations...

    l would correspond to TextData[noparse][[/noparse]0]
    e would correspond to TextData[noparse][[/noparse]1]
    d would correspond to TextData[noparse][[/noparse]2]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.

    Post Edited (Beau Schwabe (Parallax)) : 8/13/2006 6:04:40 AM GMT
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 06:42
    Ok that is a big help. The idea here is to pass the string through a medium at various speeds, receive it at the Rx, then look at it and compare it to see if it went through ok. In otherwords, a transmission test.

    Here is the revised code with what I think Mike is suggesting, although I am unclear as to if he really meant to use the literal code: PRI receiveStr(address,count)

    These lines seem to be causing a hickup as the program never gets past this when I call it. I am getting the concept a little clearer.

    Notes are in the new file.
  • Beau SchwabeBeau Schwabe Posts: 6,559
    edited 2006-08-13 07:32
    originator99,

    I believe this section of code is working properly.... When I add the line c := %11001001
    effectively bypassing whatever ser.rx is doing, Array0 to Array3 all show the bit pattern.

    I do not see a hiccup or program halt on this end do to this section of code.



    [b]PRI[/b] receiveStr(address,count) | c     '***address is a real ram address?**** [color=#990000]<-- This is correct[/color]
      [b]repeat[/b] count
        c := ser.rx
        c := %11001001
        [b]if[/b] c == $0D
          [b]byte[/b][noparse][[/noparse]address&#093; := 0
          [b]return[/b]
        [b]byte[/b][noparse][[/noparse]address++&#093; := c
    
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Beau Schwabe

    IC Layout Engineer
    Parallax, Inc.
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 08:24
    Very strange, I can sub that new line and get the same result in all 4 array slots, but using the c := ser.rx line I get an all white screen, no text.

    Maybe I am making this more complicated that need be anyway. The goal is this::

    1. Send a string containing the propellers unique address(ip address possibly w max address capacity = 1000) to another propeller acting as an intermediary, which will in turn gathers from its group info and relays the info as required to a third location(master), logging and responding with a PC application.
    2. Send a follow-up string with several data bits to indicate some sensors states.

    For example:

    %00000000 string contains the following info possibilities:

    databit 0 = sensor 1 state 1 or 0
    databit 2 = sensor 2 state 1 or 0
    databit 3 = sensor 3 state 1 or 0
    databit 4 = some info state 1 or 0
    databit 5 = some info state 1 or 0
    databit 6 = unused
    databit 7 = unused
    databit 8 = alarm

    so that %00000001 means sensor 1 is high and requires attention or logging from the master controller,

    So that is what I am looking to accomplish withthe FullDuplexSerial object.... Send strings at a timed interval to show ACTIVE(avoid polling), plus show any sensors high as needed to call attention. My thoughts were to start out simple like what I posted with the serialtest code, then incorporate the sub level receivers, then move on the master. I see it as using 1 propeller sub level hub that talks to maybe 12 to 24 other propellers, then it serially talks to the Master to give a run down of the 12 - 24 that it is monitoring, for example,

    sub level prop to master>
    some string that says
    address1 just had this sensor high
    address2 just had this state high
    address3 just had this state high

    The master in turn sends a string back to the appropiate prop needing attenion and that prop acts accordingly. The Rx string may include a new passcode to be used by a cardkey attached to the prop. This cardkey serial number can be changed on a some basis by the master, magnetically entered onto the card, and the prop checks for the serial number as the card is entered. The master can revoke access by sending the prop a null serial number for the reader. Hotel door concept.

    All that ramble aside, is the path I am on with the early stages of code the way to go about this? My thoughts are, the prop 1 of 1000 receives a string into a buffer, I then need to get that info into a tangible and usable form, and act on it.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-13 14:24
    Looking at your serialtest2.spin, you've asked the receiveStr routine to receive 4 characters, but you've only supplied 3 characters. It's sitting there waiting for the 4th. The routine will stop early if it sees a $0D, so you could change the ser.str(string("led")) to ser.str(string("led",$0D)) and that will satisfy it. So would ser.str(string("ok",$0D)).

    From your description of what you want to do, it sounds like you want to encode some bit information into the bytes of serial data. That's a nice way to pack information to minimize how much is transmitted and to simplify unpacking on the receive side. If you ever need to use more than one byte of information, you may need to uniquely identify the first byte (in case there's an error and the master and slave processors have to re-synchronize). Alternatively, you could limit the number of bits of information to 6 and add 64 to every value to make your data into printable characters. Then you can use the control characters like return and the punctuation characters as delimiters.

    Sometimes, fixed length sequences are used (2 bytes, 3 bytes, etc.) with the first byte being a zero value or all one bits, then the remaining bytes follow (with none of them being all zero or all ones). Look at some of the Stamp AppMods or the IRBuddy for examples of serial devices that allow arbitrary binary values in their control sequences.

    Post Edited (Mike Green) : 8/13/2006 2:29:48 PM GMT
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 15:15
    Mike, that solved it! I think I understood from an earlier post that there is a fixed string length of 20 characters per string, myabe I misunderstood but a simple test will show. I just used term.dec to decode the result and this code works really exactly like I wanted. I am surpirsed I haven't seen this as a demo somewhere. I thought extracting recevied data and putting it to use would be very popular info.

    Thanks a whole lot fellas, I am off to figure how to make a byte from several bits. Maybe something like addition will work.

    FinalByte := Sensor1+Sensor2+Sensor3

    00000000 + 00000100 + 00100000 = 00100100

    ser.tx(FinalByte)
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-13 15:21
    Addition works. So does bit-wise or (|).
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 15:36
    Yes I just checked it, worked great adding the 23 sensors and transmitting and receiving using getrx (ser.rx) but hangs up when trying to recieveStr method. Maybe it is looking for a string that doesn't exist or the termination chararcter. I thought that it would receive whatever was in the array as a string, even if from array and up was all 0's.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-13 15:42
    Here are some routines I've used before for scanning commands from the vga screen buffer. I've modified them to get their input from the serial routines (and I haven't tested the modifications yet). One just skips blanks, the second copies a sequence of non-blank characters into a holding area (and optionally converts lower case to upper case). The third converts a signed decimal, hexadecimal, or binary number (with "$" or "%" as leading delimiters) into a long word. The comments should be pretty clear.
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 16:23
    I will check that out Mike.

    This works in reverse to extract your original sensor info back into bits:

    first add your individual bytes before Tx:

    sensor1 := 00000001
    sensor2 := 00000100
    sensor3 := 10000000

    finalbyte = sensor1 + sensor2 + sensor3
    ser.tx(finalbyte)
    ser.rx to get the byte back in
    display received byte term.bin(finalybyte,8) = 10000101

    then to extract individual bits back out:

    sensor1 = (finalbyte - sensor2) - sensor3 = 00000001

    Pretty simple.

    It seems if you send a byte only, you have to ser.rx for a byte only, you can't do receiveStr and expect to get the byte you sent, it give a solid white screen. But if you send a byte and then a string, you can do both.

    How cool is this TV object? Especially since my only LCD died. Replacement here on Monday. It works in its demo mode, but thats it.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-13 16:42
    You want to use bit-wise and (&) to extract the values from 'finalByte' because you don't know what the sensor values are (try it with subtraction).
    You need a set of bit masks like:
    CON
    Sensor1 = %00000001
    Sensor2 = %00000010
    Sensor3 = %00000100
    
    


    Then to extract the values and test for them:
    if (finalValue & Sensor1) == Sensor1
      ' Sensor 1 was true
    if (finalValue & Sensor2) == Sensor2
      ' Sensor 2 was true
    if (finalValue & Sensor3) == Sensor3
      ' Sensor 3 was true
    
    
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 20:03
    Yes I realized that after I said it! Thanks for the answer, I was already looking for a method but had no luck.
  • T ChapT Chap Posts: 4,223
    edited 2006-08-13 21:27
    Mike I added the routine and it works under certain conditions.

    When variables Sensor1 := %00000001 and Sensor2 := %00000010 and Sensor3 := %00000100, I get a return value and can display it on the screen. BUT, If I change various simulated sensor states, the return may happen or not, if it does return, all the values are shown correctly, but some cases nothing returns and there is a blank screen.

    For example,

    Sensor1 := %00000000
    Sensor2 := %00000000
    Sensor3 := %00000000


    Will return a blank screen

    Sensor1 := %00000001
    Sensor2 := %00000000
    Sensor3 := %00000000

    but this always works.

    Sensor1 := %00000001
    Sensor2 := %00000010
    Sensor3 := %00000100
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-13 23:51
    Why are you doing "if (recbyte & Sensor1) == Sensor1Con", "sensor1 := %00000001"? What I wrote was equivalent to "if (recbyte & Sensor1Con) == Sensor1Con". The "recbyte & Sensor1Con" masks off the bit used to indicate whether sensor1 is present. The "== Sensor1Con" tests to see if that bit is present (or is zero). If you use "sensor1" for the mask, it only works when "Sensor1 := %00000001" which is what you are seeing.

    I don't know if you've given up on the receiveStr routine or just figured out that you don't need it. Remember, it's written to accept the specified number of characters and only stops early if one of the input characters is $0D which it stores as a zero byte (to get a zero-terminated string).

    Post Edited (Mike Green) : 8/13/2006 11:55:29 PM GMT
  • T ChapT Chap Posts: 4,223
    edited 2006-08-14 00:52
    Yes you are right, that was an oversight. I could not have VAR sensor1 and CON sensor1 in the same program as it gave an error, so I create the sensor1con to avoid the problem, and forgot to apply it back to the mask equation.

    When I set all sensor variables to %00000000, and receive back the finalbyte and compare it using:

    if (recbyte & Sensor1Con) == Sensor1Con

    Then of course recbyte & Sensor1Con are NOT equal, sense I sent sensor1 out as %00000000, therefore the IF statement does nothing in effect without a further implied THEN to follow? Which is why I was putting the implied THEN statement "sensor1 := %00000001" after the IF, to make the variable become %00000001 if the recbyte & sensor1con resulted in %00000001. If the result was not equal, the sensor1 should automatically remain at 0 be default.

    That being said, with the correction, there is still a solid screen when all values are sent out as 0. When I bring a debug line down to see how far it is getting, it actually gets to the IF statements, but the subsequent lines to display the sensor values are ignored for some reason. My guess is that either the ser.rx is seeing all 0's, and doesnt bother, or the IF statements are tripping me up since they don't have anywhere to go IF false.

    I didn't really give up on receiveStr, as I was focussing on learning how to create a single compacted byte and extract it on Rx. Since I wasn't dealing with a string in this case, I didn't think I needed it.

    I am much closer now to the understanding. Whats nice is, this lesson applies to many other uses in the future.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-08-14 03:06
    How about using an if/else statement and displaying one character at a particular place on the display if ... well here:
      if (recbyte & Sensor1Con) == Sensor1Con
        term.out("+")
      else
        term.out("-")
      if (recbyte & Sensor2Con) == Sensor2Con
        term.out("+")
      else
        term.out("-")
      if (recbyte & Sensor3Con) == Sensor3Con
        term.out("+")
      else
        term.out("-")
    
    


    This will display 3 characters with a "+" if the sensor is true and a "-" if it is false. For test purposes, you can make a series of test values that you send out the serial port and listen for the echo like:
      repeat x from 0 to 5
        ser.tx(testSamples[noparse][[/noparse]x])
        ...
        recbyte := ser.rx
        ...
    
    DAT
      testSamples  byte  %00000101,%00000110,.....
    
    
  • T ChapT Chap Posts: 4,223
    edited 2006-08-14 04:46
    Ok it is solved, there's nothing like spending hours trying to solve something and the indention is the culprit. Below the If statements, there were the term debug code that were failing to work, hence the white screen of death, the term lines were shifted over to the right by one space, causing the IF's to return back to the top I suppose.

    This works as desired to set the sensor back to its original state.

    Thanks Mike!

    if (recbyte & Sensor1con) == Sensor1Con
    sensor1 := %00000001
    else
    sensor1 := %00000000
    if (recbyte & Sensor2con) == Sensor2Con
    sensor2 := %00000010
    else
    sensor2 := %00000000
    if (recbyte & Sensor3con) == Sensor3Con
    sensor3 := %00000100
    else
    sensor3 := %00000000
Sign In or Register to comment.