Shop OBEX P1 Docs P2 Docs Learn Events
Serial TX/RX Communication Question — Parallax Forums

Serial TX/RX Communication Question

WookieWookie Posts: 27
edited 2007-12-03 23:18 in Propeller 1
I am attempting to parse and then display (via a serial LCD) serial transmitted data from a 3rd party device. Nothing fancy on the settings:

baud rate: 9600 bits per second
parity: none
No. of data bits: 8
No. of stop bits: 1
Flow control: Xon/Xoff (Software controlled handshaking)

I am using an Sipex RS233 to shift the signal levels over to pins P6 & P7. Output to my LCD is same serial criteria as listed above, but is done on P0. Display is currently working properly, so no issues here.

I have successfully interfaced with other serial devices sending data (mostly GPS units in NEMA format), but all of these continuously transmitted data and I had existing code to work with. The device I am attempting to link to requires me to send a command (in this case "OUTPUT<cr>"). The unit will respond with a data stream "output 75.2 64.5 25.1 50. 0.435", where each of the variables may be from 1 to 8 digits in length (i.e., 75.2 could grow to be 2000.255). I need to take each of the five variables (separated by the spaces) and break them out independently.

The question is this, do I need to use the full extended serial code to perform the parsing, and if so, does the data stream exceed the 15 character length maximum or is this maximum for each of the parsed variables? If not, what would be the easiest way to attack this problem?

Any example code would be greatly appreciated.

Thanks in advance!

Joe

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2007-11-27 00:13
    The main problem you may have is the 16 byte buffer in FullDuplexSerial. It's easy to increase the size of the buffer to 32 or 64 characters (any power of two). Download DongleBasic from the Object Exchange and look at the version of FullDuplexSerial used in that. It allows you to compile your program with any power of two for a buffer size. There was another version of FullDuplexSerial posted in the last few weeks that did the same thing (increase the buffer size).

    Once the buffer is larger than the longest expected response string, it won't matter much how you do the parsing since the response will just sit in the buffer until you use it.
    ·
  • Nick MuellerNick Mueller Posts: 815
    edited 2007-11-27 00:20
    > The question is this, do I need to use the full extended serial code to perform the parsing, and if so, does the data stream
    > exceed the 15 character length maximum or is this maximum for each of the parsed variables? If not, what would be the
    > easiest way to attack this problem?

    Parsing is preferably done with a finite state machine.
    WHAT!?

    You need to read char by char and react upon *events*. One of the events is the "." or the blank or a number and the final event is the <CR>.
    Reading the numbers is just another FSM. A perfect number-parsing FSM can read numbers like ".3", "123.4" "1234", "-123" "-123E-6".

    An FSM is a (big) case statement with events. Every event changes the FSM's state to a new state. States are normally enums.


    Nick

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Never use force, just go for a bigger hammer!

    The DIY Digital-Readout for mills, lathes etc.:
    YADRO
  • WookieWookie Posts: 27
    edited 2007-11-27 00:41
    Nick, I can see how reading char by char could be programmed with a big case statement provided you cover all the possible scenarios, but I was hoping that there was a way to identify the incoming data by looking for the <spaces> between the values. The bruit force method is way more complex than I was hoping for.

    Mike, I looked at that code you hinted at, but being relatively new to the Propeller, I am not sure how easily it would be to modify it for my task. Any further thoughts or direction would be greatly appreciated.

    Thanks
  • Mike GreenMike Green Posts: 23,101
    edited 2007-11-27 00:55
    Wookie,
    The DongleBasic version of FullDuplexSerial is usable by itself. I think there's only a couple of constant definitions in the BB_definitions.spin file that you could just copy to BB_FullDuplexSerial.spin, then rename the file to FullDuplexSerial.spin. It should be a drop-in replacement with just some extra functionality.
  • Mike GreenMike Green Posts: 23,101
    edited 2007-11-27 01:01
    You could use the Extended FullDuplexSerial routines to break the data into pieces of strings. For example, you could get the integer part of a floating point number (up to the decimal point), then the fractional part (up to a space or return), compute the number of fractional places and convert both pieces to floating point. There's already a float to string routine for going the other way.

    If you don't need the actual numeric value, you could just use the Extended FullDuplexSerial routines to pick out the pieces between the spaces (or space and return) and make them available as zero terminated strings for display or other output.
    ·
  • WookieWookie Posts: 27
    edited 2007-11-27 01:07
    "You could use the Extended FullDuplexSerial routines to break the data into pieces of strings. For example, you could get the integer part of a floating point number (up to the decimal point), then the fractional part (up to a space or return), compute the number of fractional places and convert both pieces to floating point. There's already a float to string routine for going the other way."

    Mike,

    Thanks for the help. The only major question if I were to go that route, would be how to do this multiple times for a single data string. If I understand correctly, I could break the first reading up to the decimal, then from the decimal to the space, but how do I go on to the next variable in the string and do the same thing (x3) until the end, giving each separate variable a unique name?
  • Mike GreenMike Green Posts: 23,101
    edited 2007-11-27 01:19
    If you are going to convert the values to floating point, you'd do this in one subroutine and simply return the 32 bit floating point value as the result which can be stored, each in its own long variable. You'd call this routine for each value to be read from the input. You could even use an array of longs and store each value in its own array element.

    If you are going to keep these fields as strings, just define several byte arrays, each long enough to hold one field. Write your routine so that one of the parameters is the address of the byte array to store the value in (like @x). I think the Extended FullDuplexSerial routines return the address of their own work area and you can just copy it to the byte array you want (like: bytemove(@x,resultString,strsize(resultString)) where resultString contains the address of the Extended FullDuplexSerial result field).

    Have a look at the Extended FullDuplexSerial package including the demo program you'll probably find in it. The actual documentation and examples are always much better than my trying to explain it without a copy in front of me.
  • WookieWookie Posts: 27
    edited 2007-11-28 20:59
    Thanks to everyone that has responded to my initial questions on this. After some time, I think I have most of the details worked out with one exception. THe device I am attempting to talk to requires Xon/Xoff software controlled handshaking. I cannot tell from looking at the code if the new FullDuplex Serial programs support this functionality. If so, how are they implemented? If not, any ideas where I should go from here? I have searched out this topic on the forum, but have seen no concrete solutions yet.

    Thanks in advance!

    Joe
  • Mike GreenMike Green Posts: 23,101
    edited 2007-11-28 22:14
    None of the FullDuplexSerial versions implement Xon/Xoff. You can do it yourself in your calling code by trying to read from the receive end (using rxcheck) whenever you want to transmit something and, if an Xoff is received, you wait for an Xon to be received before transmitting any more. You can reduce the size of the transmit buffer if you want (to reduce the number of characters sent before you respond to the Xoff).

    If you want, you could use the tx routine in FullDuplexSerial as a model and implement Xon/Xoff in that as described above. You can then substitute this for the existing tx routine. The other transmit routines that do editing (like str / dec / hex) all use tx, so this addition would be transparent.
  • WookieWookie Posts: 27
    edited 2007-11-30 19:15
    Mike or others...

    I have yet another serial question. I have managed to solve the Software Xon/Xoff flow control issue by building in a small delay into the TX routine. Normally, I would imagine this would be less than desired, but the serial command I am sending is only several bytes and is repeated once a second anyway. So far, I have seen no complaints from the receiving device.

    Anyway, now that I can talk to the device, I have another question. Originally, I thought I would have a variable width reply as discussed in my first post. I have now learned that the reply is fixed width (i.e., OUTPUT______1.9______1.9__74.2__34___0.296#13 , where "_" = number of blank spaces between fields).

    My trouble seems to be in reading the reply. I have modified the serial.rx code to increase the buffer size to 64, but am still not getting the entire string (let alone the parsed pieces) to display on my LCD, which I know is working fine. Anyone see any reasons why my code isnt working?

    Here is the serial.rx code that has been modified:

    PUB RxStr (stringptr) : Value | ptr
    {{
      Accepts a string of characters - up to 15 - to be passed by reference
      String acceptance terminates with a carriage return or the defined delimiter character.
      Will accept up to 15 characters before passing back.
      Serial.Rxstr(@MyStr)        ' accept
      serial.str(@MyStr)          ' transmit
     }} 
        ptr:=0
        bytefill(@dataIn,0,64)                               
       dataIn[noparse][[/noparse]ptr] :=  Rx        
       ptr++                                                  
       repeat while ((DataIn[noparse][[/noparse]ptr-1] <> 13) and (DataIn[noparse][[/noparse]ptr-1] <> Delimiter)) and (ptr < 64)       
           dataIn[noparse][[/noparse]ptr] :=  RX    
           ptr++
       dataIn[noparse][[/noparse]ptr-1]:=0                                         
       byteMove(stringptr,@datain,64)
    



    Followed by the LCD display code:
    repeat
      delay.pause1s(1)
      'dataram.str(@str1)
      
      dataRAM.RxStr(@myStr)
      delay.pause1s(10)
      lcd.str(@mystr)
    



    Thanks,
  • Paul BakerPaul Baker Posts: 6,351
    edited 2007-12-03 23:18
    Hi Wookie, I understand that you are on a time limit, so I will do my best to help you. Since your datastrings are a fixed size, have you determined the size of each packet? How far from 64 are you?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Paul Baker
    Propeller Applications Engineer

    Parallax, Inc.
Sign In or Register to comment.