Shop OBEX P1 Docs P2 Docs Learn Events
How to keep pst.StrIn from stopping a loop? — Parallax Forums

How to keep pst.StrIn from stopping a loop?

turbosupraturbosupra Posts: 1,088
edited 2012-03-12 04:55 in Propeller 1
I feel like I'm over complicating this and I can't figure out a good way to do this, I do not want to give it its own cog, how can this be done?

Right now I have pst.StrIn inside of my main loop and I won't be sending too much data to it, but I'd like to do so without using a dedicated cog for this. I'm also using the main loop to transmit data to the PST and to my GUI as well.

Thanks.
«1

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-10 12:24
    You can't really do this with PST's "StrIn" method. It stops the loop. What you need to do is change "rxcheck" to a public method and build the string with bytes are they are recieved. "rxcheck" returns a "-1" when there isn't a new character.

    I have a modified version of Tim Moore's four port serial object that alerts you when a new string has arrived by incrementing a counter. I just check the counter against its previously know value to see when a new string has arrived. With a 512 rx byte buffer, I don't worry about the buffer filling up.
  • Cluso99Cluso99 Posts: 18,069
    edited 2012-03-10 12:44
    You should post your code (zipped by proptool) so we can check.

    I presume you are using the Serial Terminal object. It requires, as does FullDuplexSerial, its own cog to run the pasm section. This is because it is bit-banging the serial and needs to do so with precise timing. The spin code will run in your main cog.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-10 14:45
    Can I do what you describe while using the parallax serial terminal and typing by hand?

    I was reading about your pcFullDuplexSerial4FC in a forum search and when I read that you thought it was becoming quite complicated, I knew it wasn't something I would be able to understand.



    Duane Degn wrote: »
    You can't really do this with PST's "StrIn" method. It stops the loop. What you need to do is change "rxcheck" to a public method and build the string with bytes as they are recieved. "rxcheck" returns a "-1" when there isn't a new character.

    I have a modified version of Tim Moore's four port serial object that alerts you when a new string has arrived by incrementing a counter. I just check the counter against its previously know value to see when a new string has arrived. With a 512 rx byte buffer, I don't worry about the buffer filling up.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-10 14:50
    Hello Clusco,

    I will clean up my code and archive/attach it as you've asked. I am using the Parallax serial terminal object and I'm using it to send values already. To me it seems a waste to have it use a separate cog to receive values also, especially when it will be sending values 99% of the time and receiving them only 1% of the time.

    What I was hoping to be able to do is have it loop through sending and receiving, and when there was a byte to receive, it would add it to a byte array and continue on through the loop until the next byte is received, and continue to do that until it received a carriage return indicating the string was complete.



    Cluso99 wrote: »
    You should post your code (zipped by proptool) so we can check.

    I presume you are using the Serial Terminal object. It requires, as does FullDuplexSerial, its own cog to run the pasm section. This is because it is bit-banging the serial and needs to do so with precise timing. The spin code will run in your main cog.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2012-03-10 16:27
    Here is an example. Like Duane said, it is necessary to change the PST RxCheck method from PRI to PUB. I can't imagine why they made it PRI, because it is a workhorse routine in any serial port access.

    A demo is attached, but the main method is one that you install in your own program, not in pst necessarily. You also need a global byte array of a certain maximum length to receive your string and a global variable to index it. There are many ways to go about this. The following starts with the index at zero, and adds characters to the array each time your program calls it, until a CR is found or until the buffer hits the maximum length. At that point it sets the index to -1, which signals to your program that a complete record is now available. Then your program does something with it and sets the index back to zero so that it can capture a next record.
    [SIZE=1][FONT=courier new]PUB updateMyBuffer |  myChar
      repeat while (myChar := pst.RxCheck) > -1  ' available chars from pst.
        if myBufIdx>-1
           myBuf[myBufIdx++] := myChar      ' add to buffer
           myBuf[myBufIdx]~                 ' always a null termination
          if myChar==13 or myBufIdx == MYBUF_LAST_IDX
             myBufIdx~~                     ' complete record flag
      return myBufIdx[/FONT][/SIZE]
    
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-10 18:04
    Tracy, thank you!

    I will get out my demoboard and try this tomorrow and report back with success or any questions :)
  • StefanL38StefanL38 Posts: 2,292
    edited 2012-03-11 01:49
    Hi Brad,

    I want to add some information about how the serial connection works:

    the object "parallax serial terminal.spin" starts a PASM-cog that does all the bitbanging details about receiving and sending the serial data.
    You could say the serial "driver". This PASM-driver has a send and receive-buffer of 64bytes.
    This means you can send up to 64 bytes from a PC to the propeller-chip running "parallax serial terminal.spin" and this driver will keep
    this received bytes in RAM for hours and days as long as you don't stop the serial driver or reset switch off power.

    If you would send a 65'th byte, the oldest byte would get overwritten by the newest byte. (That's how a FIFO-buffer works First In First Out

    If you call one of the methods like "Rx" or
    PUB CharIn : bytechr
    PUB StrIn(stringptr)
    PUB StrInMax(stringptr, maxcount)
    PUB DecIn : value
    PUB BinIn : value
    PUB HexIn : value = any of the receiving methods

    All these receiving methods take bytes out the receive-buffer of the driver.

    This means if you can make sure that you really don't send more than 64 bytes before you call any of the receive-methods
    all bytes will be there. Just the time when these bytes are transferred from the driver-buffer to your variables is later.

    If you can't make sure this - you have to transfer the received bytes before the buffer is filled completely.
    Here comes in the suggestion of the others. RxCheck checks if there are any bytes in the receivebuffer
    if YES RxCheck takes this single byte out of the receivebuffer and hands it over to you
    example

    MyReceivedByte := RxCheck

    Now it is up to you to do the further processing of this byte. (as it belongs to a string = bytesequence with a defined termination-byte))

    If you are sending always a string
    RxCheck contains the first byte of this string and if you do a StrIn then the bytearray contains all the bytes of this string except the first one.

    example-pseudo code
    MyReceivedByte := RxCheck
    
      if MyReceivedByte <> -1 
        StrIn (@RestOfMyString)
    
        MyCompleteString   must be "put together" out of MyReceivedByte and RestOfMyString 
    

    Please describe the most complicated case that could occur in this project.

    minimum time between sending two strings to the prop
    maximum length of the strings you are sending

    maximum time between two runs through your main-loop

    global purpose of all these string receiving

    If we have this information a suitable solution can be found

    best regards

    Stefan
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 05:08
    Hi Stefan,

    Thanks for the reply and FIFO buffer explanation. Can I change the byte array size in the code below (from the PST) and increase its array count to a larger value?

    To answer your questions:
    minimum time between sending two strings to the prop
    I would be sending multiple variable updates via a loop, all at once from a PC serially, such as value1=2[carraigereturn]value2=3[carriagereturn]value3=4[carraigereturn] etc etc

    maximum length of the strings you are sending
    I do not have all of this code completely written yet, but I think I can say with certainty that each individual string value would not be longer than 32 bytes including the terminating 0. I could be sending up to 500 longs/updates (estimated maximum) at a time if I were to estimate (right now it is a much smaller number) to update approximately up to 500 variables that the propeller would be using.
    maximum time between two runs through your main-loop
    The main loop is also transmitting serial data to the GUI on the PC, if I were to estimate the maximum amount of time, I would put that at clkfreq/20? I would think it would be much much faster, but I'm not sure how much the serial data transmission is going to hurt my speed.
    global purpose of all these string receiving
    The purpose of receiving these strings is so that I can parse through them and update variables that are already in my code through a GUI and without resending the entire code to the uC, to update value1, value2, value3 etc etc.


    VAR
    
      long  cog                     'cog flag/id
    
      long  rx_head                 '9 contiguous longs
      long  rx_tail
      long  tx_head
      long  tx_tail
      long  rx_pin
      long  tx_pin
      long  rxtx_mode
      long  bit_ticks
      long  buffer_ptr
                         
      byte  rx_buffer[16]           'transmit and receive buffers
      byte  tx_buffer[16]  
    
    
    
  • StefanL38StefanL38 Posts: 2,292
    edited 2012-03-11 06:28
    OK so a single string would be 32bytes long which fits into the 64 byte buffer.
    As long as the buffer is in cog-ram I guess the size is limited to 256 / 2 = 128 bytes. half and half for send and receive.

    There is a derivate of the Serialobject that uses hub-ram for the buffer. This offers buffersizes of as many kBytes to fill up the complete 32kB of HUB-RAM.
    Which method is used depends on how often do you send strings from the PC in comparison to how fast you process them in the propeller-code.

    simple example your buffer is 10 bytes long
    every minute 2 bytes are sended from PC to prop. This means a buffer of ten bytes is filled after 5 minutes.
    if you process ALL the received strings surely every 4 minutes the concept of just process the bytes when the loop has time for it will work.
    If you process the strinsg only every 6 minutes some bytes would get get lost as after 5 minutes the oldest two bytes get overwritten by the newest two bytes.

    In this case it will be better to have a method that is checking the receive-buffer very often and when a byte is received transfering the byte to a variable as soon as it is received.
    This will keep space free in the buffer for further bytes.

    So it depends on how often do you send bytes and how often do you process them.

    What you have described so far isn't the REAL global purpose. What does the propeller do in the end?
    Lighten up a chrismas-tree with light-patterns? Making an mechanical easter-rabbit stepping in the floor dropping eggs? :-) :-)

    I don't know. If you are willing to share the real global purpose of the whole project please describe it.
    As soon as this information is here I'm sure that new solutions to the problem can be found.

    Example to what I mean:

    imagine a small tube. Diameter one inch 6 feet long sticking solid in a cement-ground. Something small dropped into this tube.
    Diamater 1 inch is way too small to put your hand into it. 6 feet is way too long to grab it with your fingers.

    Now you are asking for a mechanical three-finger-telescope-arm with a glasfiber-optic to get light into the lower end of this tube and then trying to grab the object with these mechanical three fingers.
    Or even worse you try to build this three-finger-grabber DIY and you are asking on a even more detailed level what's the G-Code for milling oval wholes into aluminium?

    If you provide the information its a small part out of wood and the tube is vertical - an altenative solution could be simply fill water into this tube until the object swims up!

    Now you might answer no this will not work it's out of steel. OK why didn't you say that earlier? We just glue a magnet at one end of a rod of wood 8 feet long
    and voila! there it is.

    Ah no its stainless steel that's not magnetic and the tube is horizontal . OK so let's take something adhesive on the end of the rod of wood.

    Got the principle of what I'm trying to say? So again if you don't mind to share the whole project and the role the strings are playing in it please describe it.

    best regards
    Stefan
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-11 07:38
    StefanL38 wrote: »
    As long as the buffer is in cog-ram I guess the size is limited to 256 / 2 = 128 bytes. half and half for send and receive.
    <snip>
    There is a derivate of the Serialobject that uses hub-ram for the buffer. This offers buffersizes of as many kBytes to fill up the complete 32kB of HUB-RAM.

    None of the usual serial objects use cog RAM for a buffer. They all use hub RAM (PST, FDX, Tim's 4 port).

    I suppose it's possible to use cog RAM as a buffer but I'd think it would be very awkward for other cogs to access the buffer.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-11 07:52
    BTW, It's easy to change the buffer size in PST. The size just needs to be a power of two.

    This were you'd change it.
    CON
       BUFFER_LENGTH = [COLOR=#ff0000]64[/COLOR]             'Recommended as 64 or higher, but can be 2, 4, 8, 16, 32, 64, 128 or 256.
    
    

    As long as you have room left in hub RAM you could even make the buffer larger. 512 or 1024.

    If you don't remove characters from the rx buffer in PST or FDX in time and the buffer head catches up with the buffer tail, you'll lose all the data in the buffer (the methods will think the buffer is empty instead of full).
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 08:44
    That makes sense, and at least I can do that as a possible catch all, thanks Duane!

    Duane Degn wrote: »
    BTW, It's easy to change the buffer size in PST. The size just needs to be a power of two.

    This were you'd change it.
    CON
       BUFFER_LENGTH = [COLOR=#ff0000]64[/COLOR]             'Recommended as 64 or higher, but can be 2, 4, 8, 16, 32, 64, 128 or 256.
    
    

    As long as you have room left in hub RAM you could even make the buffer larger. 512 or 1024.

    If you don't remove characters from the rx buffer in PST or FDX in time and the buffer head catches up with the buffer tail, you'll lose all the data in the buffer (the methods will think the buffer is empty instead of full).
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 08:54
    Hi Stefan,

    I should have been more detailed and would have, had I known it would help. Excellent analogy though :)

    This project (as most of my other projects) is automotive related. I had the prop controlling some solenoids on my car based on some analog inputs such as pressure sensors, a few digital inputs such as the crank trigger wheel and some variables whose value I want to be able to change through a GUI I wrote, instead of re-flashing the prop. So if I felt a value should say be 5000rpm instead of 4000rpm, I would type "5000" into a listbox, and then press a button which would send the data to the propeller serially. Behind the scenes, my GUI would send "[specific variable name here]=5000" and now the propeller would process the serial data, update the variables value and react to data concerning that variable name, based on the value of 5000 instead of 4000. Does that make sense? I wouldn't be sending data to the propeller that often, only when I am "tuning" things.

    On the transmission of data from the prop, this would be happening quite regularly. Any time my laptop is connected, I will be sending data from the prop to the GUI on screen and displaying it. It will also tell my GUI when it has enabled out disabled outputs and the readings it has calculated from analog sensors.

    Is that detailed enough? If not, I can show you the GUI via Skype if you'd like.




    StefanL38 wrote: »
    OK so a single string would be 32bytes long which fits into the 64 byte buffer.
    As long as the buffer is in cog-ram I guess the size is limited to 256 / 2 = 128 bytes. half and half for send and receive.

    There is a derivate of the Serialobject that uses hub-ram for the buffer. This offers buffersizes of as many kBytes to fill up the complete 32kB of HUB-RAM.
    Which method is used depends on how often do you send strings from the PC in comparison to how fast you process them in the propeller-code.

    simple example your buffer is 10 bytes long
    every minute 2 bytes are sended from PC to prop. This means a buffer of ten bytes is filled after 5 minutes.
    if you process ALL the received strings surely every 4 minutes the concept of just process the bytes when the loop has time for it will work.
    If you process the strinsg only every 6 minutes some bytes would get get lost as after 5 minutes the oldest two bytes get overwritten by the newest two bytes.

    In this case it will be better to have a method that is checking the receive-buffer very often and when a byte is received transfering the byte to a variable as soon as it is received.
    This will keep space free in the buffer for further bytes.

    So it depends on how often do you send bytes and how often do you process them.

    What you have described so far isn't the REAL global purpose. What does the propeller do in the end?
    Lighten up a chrismas-tree with light-patterns? Making an mechanical easter-rabbit stepping in the floor dropping eggs? :-) :-)

    I don't know. If you are willing to share the real global purpose of the whole project please describe it.
    As soon as this information is here I'm sure that new solutions to the problem can be found.

    Example to what I mean:

    imagine a small tube. Diameter one inch 6 feet long sticking solid in a cement-ground. Something small dropped into this tube.
    Diamater 1 inch is way too small to put your hand into it. 6 feet is way too long to grab it with your fingers.

    Now you are asking for a mechanical three-finger-telescope-arm with a glasfiber-optic to get light into the lower end of this tube and then trying to grab the object with these mechanical three fingers.
    Or even worse you try to build this three-finger-grabber DIY and you are asking on a even more detailed level what's the G-Code for milling oval wholes into aluminium?

    If you provide the information its a small part out of wood and the tube is vertical - an altenative solution could be simply fill water into this tube until the object swims up!

    Now you might answer no this will not work it's out of steel. OK why didn't you say that earlier? We just glue a magnet at one end of a rod of wood 8 feet long
    and voila! there it is.

    Ah no its stainless steel that's not magnetic and the tube is horizontal . OK so let's take something adhesive on the end of the rod of wood.

    Got the principle of what I'm trying to say? So again if you don't mind to share the whole project and the role the strings are playing in it please describe it.

    best regards
    Stefan
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 11:30
    While trying to start off with something, I have this code in the main loop and I'm seeing the latter in the pst window when I haven't sent a single character? Any idea as to why?

    (b_MyReceivedByte is a 100 container byte array)


    b_MyReceivedByte := pst.RxCheck
        
        if b_MyReceivedByte <> -1
          pst.str(string("Received is "))
          pst.hex(@b_MyReceivedByte, 1)
          pst.str(string(pst#NL))
    
    Received is 9
    Received is 9
    Received is 9
    Received is 9
    Received is 9
    Received is 9
    Received is 9
    Received is 9
    Received is 9
    Received is 9
    Received is 9
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-11 12:38
    Give this a try:
    PUB Test
      result := 0
      repeat while result < 100
        b_MyReceivedByte[result] := pst.RxCheck
         
        if b_MyReceivedByte[result] <> -1 and b_MyReceivedByte[result] <> 0
          pst.str(string("Received is $"))
          pst.hex(b_MyReceivedByte[result], [COLOR=#ff0000]2[/COLOR])
          pst.str(string(", string so far = "))
          pst.str(@b_MyReceivedByte)
          pst.char(pst#NL)
          pst.str(string("b_MyReceivedByte array starts at memory location $"))
          pst.hex(@b_MyReceivedByte[result], 4) ' memory locations are usually word sized
          pst.char(pst#NL)
          result++
    


    We're just using "result" as an index variable. Sometimes the receive line will pickup no activity as all zeros if there isn't a pull-up resistor on the line so I excluded zeros as well as negative ones.

    If you want to see the value of a byte with the "hex" method you want to use two digits. Your original code displayed the last digit of the memory location used by the first element of your array.

    The "str" method needs the address symbol "@" since it needs to know the first location of the characters (bytes) to be displayed. It will display (or try to display, some byte values aren't valid display characters) the bytes starting at location "@b_MyReceivedByte" and continue displaying characters until it finds a zero.

    The "hex" method works a lot like the "dec" method. You just pass it the variable you want displayed and how many digits of the variable. As I mentioned a byte needs two digits to display a word four digits and a long eight digits. I included a couple of lines to display the location in hub RAM your "b_MyReceivedByte" array starts.

    Edit: The above code uses a byte variable when a long is needed. See kuroneko's posts below.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 12:47
    Hi Duane,

    I used hex just because it says in the method it returns a hexadecimal value, not for any other reason. I see the sentence is still there, but I thought I'd post what I'm seeing.

    The output from this kind of looked like the output mine was giving when I had it set to pst.str
    b_MyReceivedByte array starts at memory location $1D6B
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D6C
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D6D
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D6E
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D6F
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D70
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D71
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D72
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D73
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D74
    Received is $FF, string so far = ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
    b_MyReceivedByte array starts at memory location $1D75
    Received is $FF, string so far = ÿÿ
  • StefanL38StefanL38 Posts: 2,292
    edited 2012-03-11 12:58
    Edit: at 9 pm MET: oops some other postinsg arrived before I sended mine.

    Brad please post your complete code as a zip-archive created by the propeller-tool.
    The value of variable b_MyReceivedByte increments with each loop. I guess this is not how it should work
    Or Duane you have to explain a bit more what you are trying to do with this code.



    first of all thank you Duane for correcting me about cog-RAM. Yes of course it must be HUB-RAM. Cog-RAM is cog-exclusive.
    Other cogs can't access it.

    @Brad, Yes this is mostly detailed enough. So the prop is only receiving data for tuning values from time to time.
    If you do this while your car is at home in your garage even waiting for receiving a string seems no problem.
    Somehow it seems to be a problem. Can you describe why it is a problem?

    best regards
    Stefan
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 13:01
    The code still is seeing phantom values such as is displayed above? Maybe I need to initialize b_MyReceivedByte[0] somehow?

    Duane Degn wrote: »
    Give this a try:
    PUB Test
      result := 0
      repeat while result < 100
        b_MyReceivedByte[result] := pst.RxCheck
         
        if b_MyReceivedByte[result] <> -1 and b_MyReceivedByte[result] <> 0
          pst.str(string("Received is $"))
          pst.hex(b_MyReceivedByte[result], [COLOR=#ff0000]2[/COLOR])
          pst.str(string(", string so far = "))
          pst.str(@b_MyReceivedByte)
          pst.char(pst#NL)
          pst.str(string("b_MyReceivedByte array starts at memory location $"))
          pst.hex(@b_MyReceivedByte[result], 4) ' memory locations are usually word sized
          pst.char(pst#NL)
          result++
    


    We're just using "result" as an index variable. Sometimes the receive line will pickup no activity as all zeros if there isn't a pull-resistor on the line so I excluded zeros as well as negative ones.

    If you want to see the value of a byte with the "hex" method you want to use two digits. Your original code displayed the last digit of the memory location used by the first element of your array.

    The "str" method needs the address symbol "@" since it needs to know the first location of the characters (bytes) to be displayed. It will display (or try to display, some byte values aren't valid display characters) the bytes starting at location "@b_MyReceivedByte" and continue displaying characters until it finds a zero.

    The "hex" method works a lot like the "dec" method. You just pass it the variable you want displayed and how many digits of the variable. As I mentioned a byte needs two digits to display a word four digits and a long eight digits. I included a couple of lines to display the location in hub RAM your "b_MyReceivedByte" array starts.
  • kwinnkwinn Posts: 8,697
    edited 2012-03-11 13:03
    turbosupra wrote: »
    Can I do what you describe while using the parallax serial terminal and typing by hand?

    I was reading about your pcFullDuplexSerial4FC in a forum search and when I read that you thought it was becoming quite complicated, I knew it wasn't something I would be able to understand.

    It's not that complicated to use. I use it as my standard serial object. If you are interested I can post a very simple demo program with added comments
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 13:10
    Hi Stefan,

    The problem is that when I have the code using the pst.StrIn method, it will not allow the code to continue to loop but instead hangs the code and waits for input values, similar to what a waitpeq would do if you never received that state at all, the cog would be paused and not do anything. This is what is happening, my code will run through each line until it gets to the pst.StrIn line and then will sit there until it receives a string.

    I want it to cycle through performing the normal prop to pc transmission, and when it receives a pc to prop transmission, to queue each byte of the updated command until it receives a carriage return and at that point, pass the byte array to another method that parses the update command and then updates the actual variable with the value, for example rpm=5000. I want pst.StrIn to queue the r, p, m, =, 5, 0, 0, 0 and the carriage return terminating 0 for a total of 9 bytes. Then realizing there was a terminating 0, to pass the byte array to a parse method which then passes the variable name and variable value to an update method.

    I don't want to use an entire cog just to have it monitor the pc to prop transmission and so I'm trying to figure out a way to use pst.StrIn in a way that it does not pause the entire cog that I am using to send data from the prop to the pc, and prevent it from looping through the code.



    StefanL38 wrote: »
    @Brad, Yes this is mostly detailed enough. So the prop is only receiving data for tuning values from time to time.
    If you do this while your car is at home in your garage even waiting for receiving a string seems no problem.
    Somehow it seems to be a problem. Can you describe why it is a problem?

    best regards
    Stefan
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-11 13:12
    Add one more and to exclude $FF values that your line is picking up when there isn't any activity. This isn't a great solution. I think your line needs some sort of pull-up or pull-down resistor (I don't know which, I always use pull-up resistors).
    if b_MyReceivedByte[result] <> -1 and b_MyReceivedByte[result] <> 0 and b_MyReceivedByte[result] <> $FF
    

    Edit: The above code uses a byte variable when a long is needed. See kuroneko's posts below.
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-11 13:18
    StefanL38 wrote: »
    The value of variable b_MyReceivedByte increments with each loop. I guess this is not how it should work
    Or Duane you have to explain a bit more what you are trying to do with this code.
    I think the code fills the 100 element array "b_MyReceivedByte" with characters as they are entered from the terminal window.

    b_MyReceivedByte isn't incremented, the index to the array is incremented.

    The code (untested) should display the hex value of the last character entered followed by all the characters in the array so far. It also displays the starting memory location of the array.

    Edit: The code by itself isn't very useful as is. It's meant to be an example and I just wanted to modify Brads code without making too many changes(I don't think I keep this last goal).
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 13:23
    I'm using the demoboard, so I can't just pop a pull up/down resistor in there :( . When I checked the hex/dec value before for the "ÿ", it was a tab character? I won't be sending that, so I think it would be safe to exclude, what do you think?

    By the way, nicely done, thank you!
    Beginning
    yReceived is $79, string so far = y
    b_MyReceivedByte array starts at memory location $1D45
    aReceived is $61, string so far = ya
    b_MyReceivedByte array starts at memory location $1D46
    yReceived is $79, string so far = yay
    b_MyReceivedByte array starts at memory location $1D47
    Received is $20, string so far = yay
    b_MyReceivedByte array starts at memory location $1D48
    iReceived is $69, string so far = yay i
    b_MyReceivedByte array starts at memory location $1D49
    tReceived is $74, string so far = yay it
    b_MyReceivedByte array starts at memory location $1D4A
    'Received is $27, string so far = yay it'
    b_MyReceivedByte array starts at memory location $1D4B
    sReceived is $73, string so far = yay it's
    b_MyReceivedByte array starts at memory location $1D4C
    Received is $20, string so far = yay it's
    b_MyReceivedByte array starts at memory location $1D4D
    wReceived is $77, string so far = yay it's w
    b_MyReceivedByte array starts at memory location $1D4E
    oReceived is $6F, string so far = yay it's wo
    b_MyReceivedByte array starts at memory location $1D4F
    rReceived is $72, string so far = yay it's wor
    b_MyReceivedByte array starts at memory location $1D50
    kReceived is $6B, string so far = yay it's work
    b_MyReceivedByte array starts at memory location $1D51
    iReceived is $69, string so far = yay it's worki
    b_MyReceivedByte array starts at memory location $1D52
    nReceived is $6E, string so far = yay it's workin
    b_MyReceivedByte array starts at memory location $1D53
    gReceived is $67, string so far = yay it's working
    b_MyReceivedByte array starts at memory location $1D54
    Received is $20, string so far = yay it's working
    b_MyReceivedByte array starts at memory location $1D55
    :Received is $3A, string so far = yay it's working :
    b_MyReceivedByte array starts at memory location $1D56
    )Received is $29, string so far = yay it's working :)
    b_MyReceivedByte array starts at memory location $1D57
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-03-11 13:33
    turbosupra wrote: »
    When I checked the hex/dec value before for the "ÿ", it was a tab character?

    I'm pretty sure it's not the tab character (IIRC it's 9). The Prop was picking up all ones. A byte of all ones is "$FF" When you send "$FF" to the terminal you get "ÿ". If you use a VGA or TV terminal object you'd see infinity signs instead since the Prop's $FF character is the infinity sign.


    I noticed I left the index in the command to print the address of the array to the screen. So the address of the last character added to the display is shown, not the address of the beginning of the array as I had previously stated.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 13:34
    I also have to keep "result" out of the loop and can therefore only initialize it when the code is first loaded, otherwise the code will still hang and wait for characters to be sent, just like pst.StrIn would. So I've made it "repeat while result < 100 and result <> 0" which I'll have to tweak to get working.
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 16:14
    What do you all think of this? It actually works pretty good in my limited testing, but with my limited experience I am concerned about things I am not foreseeing. I couldn't get anything else to work, that did not interfere with the speed of the loop.

    b_MyReceivedByte := pst.RxCheck
    
        if b_MyReceivedByte <> $FF and b_MyReceivedByte <> -1
          bytemove(@b_waitingToBeParsed[byteMoveIndex], @b_MyReceivedByte, strsize(@b_MyReceivedByte))
          byteMoveIndex += 1
          pst.str(@b_waitingToBeParsed)
          pst.str(string(pst#NL))
          if b_MyReceivedByte == 13
            DelimiterFinder(@b_waitingToBeParsed)
            ByteFill(@b_waitingToBeParsed, 0, strsize(@b_waitingToBeParsed))
            byteMoveIndex := 0
    
    
  • kuronekokuroneko Posts: 3,623
    edited 2012-03-11 17:45
    b_MyReceivedByte := pst.RxCheck
    
        if b_MyReceivedByte <> $FF and b_MyReceivedByte <> -1
          bytemove(@b_waitingToBeParsed[byteMoveIndex], @b_MyReceivedByte, strsize(@b_MyReceivedByte))
          byteMoveIndex += 1
          pst.str(@b_waitingToBeParsed)
          pst.str(string(pst#NL))
          if b_MyReceivedByte == 13
            DelimiterFinder(@b_waitingToBeParsed)
            ByteFill(@b_waitingToBeParsed, 0, strsize(@b_waitingToBeParsed))
            byteMoveIndex := 0
    
    
    Judging by the b_ prefix, b_MyReceivedByte is a byte variable (is that still true). If so forget it, RxCheck returns results outside byte range, i.e. b_MyReceivedByte <> -1 is always true. Also, what you get back is not a string, it's a single character (no bytemove, no strsize). Try this:
    VAR
      [COLOR="orange"]long[/COLOR]  b_MyReceivedByte
    
      ...
    
        b_MyReceivedByte := pst.RxCheck
    
        if b_MyReceivedByte <> -1
          b_waitingToBeParsed[byteMoveIndex++] := b_MyReceivedByte
    
          pst.str(@b_waitingToBeParsed)
          pst.str(string(pst#NL))
    
          if b_MyReceivedByte == 13
            DelimiterFinder(@b_waitingToBeParsed)
            ByteFill(@b_waitingToBeParsed, 0, strsize(@b_waitingToBeParsed))
            byteMoveIndex := 0
    
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 18:35
    Hi Kuroneko,

    Thank you for the code. For my own learning experience, can you tell me why byte b_MyReceivedByte[_byteLimit] works under the limited testing I did but will not work well in the long run? It is a byte array, does that make a difference? I chose a byte array because it allows me to have a string with approximately 100 bytes in it. This is also why I chose the bytemove. I'm sorry I didn't include that in the original code, I thought that was included.

    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      _clkHz = 80_000_000
      _byteLimit = 100
    
    VAR
    
      byte b_delimiter
      byte b_MyReceivedByte[_byteLimit]
      byte b_RxString[_byteLimit]
    
    
    
    b_MyReceivedByte := pst.RxCheck
    
        if b_MyReceivedByte <> $FF and b_MyReceivedByte <> -1
          bytemove(@b_waitingToBeParsed[byteMoveIndex], @b_MyReceivedByte, strsize(@b_MyReceivedByte))
          byteMoveIndex += 1
          pst.str(@b_waitingToBeParsed)
          pst.str(string(pst#NL))
          if b_MyReceivedByte == 13
            DelimiterFinder(@b_waitingToBeParsed)
            ByteFill(@b_waitingToBeParsed, 0, strsize(@b_waitingToBeParsed))
            byteMoveIndex := 0
    
    
    kuroneko wrote: »
    Judging by the b_ prefix, b_MyReceivedByte is a byte variable (is that still true). If so forget it, RxCheck returns results outside byte range, i.e. b_MyReceivedByte <> -1 is always true. Also, what you get back is not a string, it's a single character (no bytemove, no strsize). Try this:
    VAR
      [COLOR="orange"]long[/COLOR]  b_MyReceivedByte
    
      ...
    
        b_MyReceivedByte := pst.RxCheck
    
        if b_MyReceivedByte <> -1
          b_waitingToBeParsed[byteMoveIndex++] := b_MyReceivedByte
    
          pst.str(@b_waitingToBeParsed)
          pst.str(string(pst#NL))
    
          if b_MyReceivedByte == 13
            DelimiterFinder(@b_waitingToBeParsed)
            ByteFill(@b_waitingToBeParsed, 0, strsize(@b_waitingToBeParsed))
            byteMoveIndex := 0
    
  • kuronekokuroneko Posts: 3,623
    edited 2012-03-11 19:34
    turbosupra wrote: »
    For my own learning experience, can you tell me why byte b_MyReceivedByte[_byteLimit] works under the limited testing I did but will not work well in the long run? It is a byte array, does that make a difference? I chose a byte array because it allows me to have a string with approximately 100 bytes in it. This is also why I chose the bytemove. I'm sorry I didn't include that in the original code, I thought that was included.
    RxCheck will return a byte (or -1). So this is a single value. There is no requirement for an array because the string gets assembled in a different array (b_waitingToBeParsed[]). Also, because you made it an array the string handling works (b_MyReceivedByte[0] is the received character, b_MyReceivedByte[1] is null). I didn't specifically say that it doesn't work but then I didn't know how b_MyReceivedByte was defined. Imagine it being followed by a byte that isn't null, then your string handling fails, e.g.
    VAR
      byte  b_MyReceivedByte
      byte  guard_after
    
      ...
    
      guard_after := $FF
      ...
    
    In this case, after you received the byte in b_MyReceivedByte the strsize(@b_MyReceivedByte) will include said byte (unless already null) the guard_after and anything after that until it reaches a null byte again. HTH
  • turbosupraturbosupra Posts: 1,088
    edited 2012-03-11 20:46
    Thank you Kuroneko, that does make sense, I thought I had written something clever for once, but I humbly accept the constructive criticism and corrected code. :)


    With the following code:

    b_waitingToBeParsed[byteMoveIndex++] := b_MyReceivedByte

    It appears that only the first byte of the long b_MyReceivedByte is copied to that particular byte array container (b_waitingToBeParsed[byteMoveIndex]), have I understood that correctly? The remaining 3 bytes are discarded whether they hold non zero data, a null value or terminating zeros? And then that single byte is added to the incrementing byte array?


    kuroneko wrote: »
    RxCheck will return a byte (or -1). So this is a single value. There is no requirement for an array because the string gets assembled in a different array (b_waitingToBeParsed[]). Also, because you made it an array the string handling works (b_MyReceivedByte[0] is the received character, b_MyReceivedByte[1] is null). I didn't specifically say that it doesn't work but then I didn't know how b_MyReceivedByte was defined. Imagine it being followed by a byte that isn't null, then your string handling fails, e.g.
    VAR
      byte  b_MyReceivedByte
      byte  guard_after
    
      ...
    
      guard_after := $FF
      ...
    
    In this case, after you received the byte in b_MyReceivedByte the strsize(@b_MyReceivedByte) will include said byte (unless already null) the guard_after and anything after that until it reaches a null byte again. HTH
Sign In or Register to comment.