Shop OBEX P1 Docs P2 Docs Learn Events
For those of you that use or have used other microchips ... — Parallax Forums

For those of you that use or have used other microchips ...

turbosupraturbosupra Posts: 1,088
edited 2011-09-28 19:20 in General Discussion
What chip has good/existing support for Windows applications and duplex usb (serial) communication through a Windows application.

To be a bit more specific, I have been tinkering in my free time with trying to read from and write to the propeller from a GUI that I'll write in c sharp. I recently had a hard drive physical failure on the machine that had all of my spin code and it may be more advantageous to just start new with a chip that has more readily available classes for data communication via a Windows GUI and serial/usb.

I don't want to, nor do I have time to reinvent the wheel, so if I can, I would like to use what is already out there if possible. I've made a few posts about this before and this does not seem to be something anyone else (aside from Hanno) is doing. Even the parallax engineer that returned my support request, did not have a very clear solution as to how to do this. The closer in general design to the prop, the better (via voltage values, number of pins, etc) .
«1

Comments

  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-09-01 12:50
    Your post is off topic in the Propeller forums and is being moved to the appropriate forum. In the future please be sure to post in the appropriate forum for the content of your message.

    By the way an AppNote has been provided by Parallax discussing Propeller to PC communication with code examples for Propeller and PC. However if your message is to find another product the message is not suitable in the Propeller forum.
  • LeonLeon Posts: 7,620
    edited 2011-09-01 12:55
    The chip doesn't need to have anything to do with the Windows application, if all it does is transmit and receive RS-232 data. They typically don't have any built-in support for high-level protocols.
  • Heater.Heater. Posts: 21,230
    edited 2011-09-01 13:00
    From c# your GUI can talk to any serial device via a USB serial driver and a USB serial adapter cable. So on your MCU end you only need a UART. Pretty much any MCU can do that including the Prop with a simple thing like the FullDuplexSerial object. No special support for Windows is required at the MCU end. Indeed I would suggest that the MCU should not need to be aware of what OS is on the other end of the link at all.
    So the question is, what is it that you actually want to acheive with the MCU? Can the Prop do it? If not why not and what other device can?
    As you have not given any clue about the nature of your project it's impossible to advise so please do elaborate.
  • Heater.Heater. Posts: 21,230
    edited 2011-09-01 13:11
    Somewhere here there is a recent thread discussing the use of C# and the Prop to which I posted the beginnings of a serial port connection in C#. Try a search for uterm.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-02 05:34
    Thank you for the replies.

    My project controls functions in an automotive application. I want to be able to receive data, display it in real time and log it ... then write data, update values in real time and then start the process again of looking at the real time data that is received.

    I know the prop can do it, because Hanno has written code to do this, but I am not anywhere near the programmer that Hanno is. I've used his logger and it is great, but if this project comes to fruition I will need to write my own code to receive data, as well as have a way to update spin code variables on the propeller itself. I will look for your thread, if I can get a baseline to where I can read and write to the prop with a working example, I can build from there ... I am not at the point where I could write the code from scratch and have it work.

    @Chris - if a prop solution is readily available, I would choose that over starting from scratch and if it is not I wanted some opinions on what others with more experience than I had on my situation

    @Duane - I will check those out, thank you

    Heater. wrote: »
    From c# your GUI can talk to any serial device via a USB serial driver and a USB serial adapter cable. So on your MCU end you only need a UART. Pretty much any MCU can do that including the Prop with a simple thing like the FullDuplexSerial object. No special support for Windows is required at the MCU end. Indeed I would suggest that the MCU should not need to be aware of what OS is on the other end of the link at all.
    So the question is, what is it that you actually want to acheive with the MCU? Can the Prop do it? If not why not and what other device can?
    As you have not given any clue about the nature of your project it's impossible to advise so please do elaborate.



    Heater. wrote: »
    From c# your GUI can talk to any serial device via a USB serial driver and a USB serial adapter cable. So on your MCU end you only need a UART. Pretty much any MCU can do that including the Prop with a simple thing like the FullDuplexSerial object. No special support for Windows is required at the MCU end. Indeed I would suggest that the MCU should not need to be aware of what OS is on the other end of the link at all.
    So the question is, what is it that you actually want to acheive with the MCU? Can the Prop do it? If not why not and what other device can?
    As you have not given any clue about the nature of your project it's impossible to advise so please do elaborate.
  • prof_brainoprof_braino Posts: 4,313
    edited 2011-09-02 06:24
    Are you asking for specific chips to consider as candidates?

    I have an AVR chip, and there are bazzillions of libraries and examples for these parts. Each part has a different collection of physical peripherals, etc. so each part has its own set of baggage that must be handled.

    In my case the part ATmega103 was discontinued, and the weird hardware uart changed on the replacement ATmega128, and the software no longer worked. Getting the new part to work would be a matter of figuring out the assembler code for the interrupts, and straightening out the libraries. This should be no problem for someone who knows or wants to learn and become and expert on AVR assembler, but I do not; I want to concentrate on the application. It was much easier to switch to the prop and remove the entire class of variables related to the micro controller family. For what its worth, its much easier for me to experiment on a "larger" prop and leave converting to a "smaller" more specific part (for production) to somebody else. But, I tend to do things the easy way, being a bit lazy.
  • Mike GMike G Posts: 2,702
    edited 2011-09-02 06:50
    turbosupra wrote:
    I know the prop can do it, because Hanno has written code to do this, but I am not anywhere near the programmer that Hanno is. I've used his logger and it is great, but if this project comes to fruition I will need to write my own code to receive data, as well as have a way to update spin code variables on the propeller itself. I will look for your thread, if I can get a baseline to where I can read and write to the prop with a working example, I can build from there ... I am not at the point where I could write the code from scratch and have it work.
    Most micros support serial communication through a UART and UARTs work at the byte level; read bytes - write bytes. It does not matter what micro you select, you still have to deal with bytes in and bytes out.

    It sounds like you are asking for a high level protocol binding between a Prop and PC. As far as I know a standard does not exist because most programmers will complain that the binding is to restrictive. Therefore, we (programmers) establish a custom protocol or language that both the Prop and PC are programmed to understand.

    A protocol might look like the following. Read Pin 1...
    !RDP 1 <CR>
    

    Simple C# open source serial port listener.
    http://www.agaverobotics.com/SerialPortDemo.zip
  • Luis DigitalLuis Digital Posts: 371
    edited 2011-09-02 06:59
    A simple LPC1342 can do USB-Serial.
  • Heater.Heater. Posts: 21,230
    edited 2011-09-02 07:50
    A chip like the LPC will do the USB/serial for you which saves needing a USB serial adapter cable. That may be important if you are producing large numbers of whatever it is.
    However it does not help with the problem of how the data traveling over the link is generated and interpretted. The "protocol" that is. As far as the application code at the mcu and PC ends is concerned it still just a serial link shifting bytes up and down.
    In addition with a single core chip like that you are in the world of interrupts in order get what you want done. Rather than the elegant simplicity the Props multicore architecture offers.
    So, for production runs of cheap gadgets go with something like a LPC. For one offs go the easy way with the Prop, a serial USB adapter and something like FullDuplexSerial.
    But then, even with the Prop you can ditch the adapter and do USB directly using mparks usb object.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-05 11:04
    Does anyone have an psuedo code (to give me a general idea) as to how to use the FullDuplexSerial to receive data if my program were to send it over serial?
  • Mike GreenMike Green Posts: 23,101
    edited 2011-09-05 11:18
    1) You initialize the serial object by calling its start method and providing the I/O pin numbers you want to use, the Baud you want, and some mode bits in an integer value. See the source code comments for details.

    2) You call either the rxcheck method, retime method, or the rx method depending on what features you want. rx always waits for a character. rxcheck always returns a value, either the received character or a -1 indicating that the input buffer was empty. rxtime is like rxcheck, but it uses a (supplied) timeout and waits up to that time for a character to be received, then returns either a -1 or the value of the character.

    For more complex data (other than a single character at a time), you'd used an object like FullDuplexSerialPlus which adds some routines to handle formatted data like decimal values.
  • JeremyJJeremyJ Posts: 30
    edited 2011-09-08 22:44
    I was just reading through this post and wanted to check my understand of the Simple_Serial object.

    If I want to read a uni-directional input from an anemometer, to use an example, I would call the "rx" method in my main method to receive and write my 8 bits of data into the (returned) variable rxByte. Right?

    I imagine that I now have a table of 8-bit values that correspond to different wind velocities (again using the anemometer example). What's the best way to compare the rxByte array and find the corresponding windspeed? Do you just run your rxByte through a loop where it is compared against each value in the wind velocities array? Is this the best way to get/store/output your final value (again, in this case it would be the actual windspeed that corresponds to the byte of data received from the anemometer.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-09-09 07:22
    To use your example ... You have sensor that continuously transmits 8-bit serial data with each byte containing a value corresponding to the raw sensor output. You want to receive this data and look up the 8-bit values in a table to produce some final result that will be displayed.

    Note: All methods in spin have a return value which is value of the call to the method. That makes all method calls function calls. When you're just using the method as a subroutine, the return value is ignored. By default, the return value is zero, so this all works out. For convenience and clarity, you can rename the return value from "result" to anything you want like "rxByte". Renaming it doesn't change it's behavior.

    The easiest way to do the kind of conversion you want is to make a lookup table. In your case, all possible values of the 8-bit byte have wind velocity values, so you want a 256 entry table of wind velocities. Each time you get an 8-bit anemometer value, you use that as an index into the table to get your wind velocity. For small tables, you can also use the LOOKUP or LOOKUPZ statements which do the same kind of thing. They just embed the table in the statement itself.

    Preinitialized tables are done in an odd way in Spin ... actually in the Propeller's assembly language like this:
    OBJ ser : "Simple_Serial"
    
    ' You'd need some additional code to initialize the Simple_Serial object and to call getTheValue and display the result on some display.
    
            DAT
    table  long   3, 5, 7, 11, 14, 17, 21, 26
            long   30, 36, 43, 51, 62, 74, 86, 98
            ... There would be 6 more lines of 8 values each
            ...  to make up a total of 256 table entries
    
    PUB getTheValue
    ' This is a function that waits for the Simple_Serial function "rx"
    ' to receive a byte, then this returns the equivalent value from the
    ' lookup table.
       return table[ serial.rx ]
    
  • JeremyJJeremyJ Posts: 30
    edited 2011-09-09 09:00
    Thanks Mike - that's exactly what I was wondering...how you interface between assembly (tabular info) and spin to get the value.

    Jeremy
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-22 10:28
    Looking at this, I am still confused about a few things, so I apologize if this is elementary.

    If I were to use the FullDuplexSerial object and let's assume that the transmission of the data from the computer to the propeller is done correctly, how will the spin code delineate a variable name and variable value from the binary it is being sent. I believe the prop uses 8N1, so it will send 8 bits and a stop bit. Can someone briefly map this out for me please.

    Lets say the data I want to send is:

    (variable)
    011101100111011001110100011011000101001001110000011011010101011001100001011011000111010101100101010101010111000001100100011000010111010001100101

    (value)
    00110110001100000011000000110000

    Do I need something that sends serially a variable name, then a delimiter and then a value? So variable/value? And then a routine that does (sort of) a string split or string contains when it is able to recognize the variable portion, so spin can then extract the value portion?
    PUB receiveData
    
    
      repeat
      
        Debug.Rx(newData)
        
        case Value Updates
    
          vvtlRpmValueUpdate
            vvtlRpmValue := newData
    
    
          trunkOpenValueUpdate
            trunkOpenValue := newData
    


    If I'm completely off, and I want to send the following which is variable/value, with the "/" being the delimiter , how would I program spin code to receive this data to update an existing variable?

    0111011001110110011101000110110001010010011100000110110101010110011000010110110001110101011001010101010101110000011001000110000101110100011001010010111100110110001100000011000000110000
  • Mike GreenMike Green Posts: 23,101
    edited 2011-09-22 11:00
    FullDuplexSerial just deals with individual characters when receiving. It detects the start bit, assembles the 8 bits of data, and otherwise ignores the stop bit. Any further structure that you want has to be supplied by you. To make that easier, there's an object in the OBEX called "Extended Full Duplex Serial" that calls FullDuplexSerial to get characters and allows you to handle strings and numbers that are delimited by a carriage return (13) character. There are other character manipulation routines in the OBEX.

    You will have to program all the bits and pieces to figure out what variable to set and to do the actual work. If I were doing this, I would probably pick two different delimiters, maybe "=" and carriage return. Everything up to the "=" would be the value label and everything from the "=" to the return would be the value. I would use the Extended Full Duplex Serial object, modify it to use a delimiter character supplied by me when I call the routines and call the string input routine to get the value label text, then call the number input routine to get the corresponding value, look up the string in a table of such names, and update the variable value corresponding to the name, probably using some kind of CASE statement.

    You might look at the source code for FemtoBasic (in the OBEX). There's a nice routine near the end of FemtoBasic.spin called getAnyNumber that takes the characters from a byte array and returns the value of the number found there and stops with the pointer to the characters (tp) pointing to the first "illegal" character in the value. It allows for decimal, hexadecimal, and binary values as well as single quoted characters (as a numeric value).
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-22 12:47
    Mike, this is spectacular! I actually somewhat understand :D . Thank you very very much!

    If have a few more questions (I'm trying to think this through and ask intelligent questions). Do have to provide EFDS.RxStr a byte array? Will FullDuplexSerial detect all of the binary values and assemble a byte array after compiling each set of 8 bits into a byte?


    So I could write something close to the following?

    Computer sends (the first bold is the "=" sign and the second bold is the "(13)") ASCII is " vvtlRpmValueUpdate=6000(13) "

    011101100111011001110100011011000101001001110000011011010101011001100001011011000111010101100101010101010111000001100100011000010111010001100101001111010011011000110000001100000011000000101000001100010011001100101001


    Prop receives and runs through

    It will terminate the byte addition in the RxStr function after the final character in this string (and set the preceding last byte to 0)

    011101100111011001110100011011000101001001110000011011010101011001100001011011000111010101100101010101010111000001100100011000010111010001100101

    because following that is 00111101 representing the "=" sign. Then it copies the string to stringptr, which the prop reads as it is a predefined variable somewhere else in the program (this parts is a little confusing)? Then after that I run the rxDec routine?

    CON
    
      _CLKMODE = XTAL1 + PLL16X
      _XINFREQ = 5_000_000
    
     
    OBJ
      Debug : "FullDuplexSerial"
      EFDS : "Extended_FDSerial"
                                                         
    VAR
      long valueUpdate
      long byteArray[20]
         
    
    
    PUB receiveData
    
      EFDS.SetDelimiter("=") 
      EFDS.Start(31, 30, 0, 112000)
      
      repeat
        
        variable := EFDS.RxStr(byteArray)
    
        value := EFDS.RxDec   
        
        if variable == variable1
          variable1 := value
    
        if variable == variable2
            variable2 := value
            
        if variable == variable3
            variable3 := value
    
    
    


    Is this a start in the right direction? (I don't have access to a prop to test right now) I'm close to feeling like I have a a grasp on the whole picture and I see how the routines assemble byte arrays, but I'm still not clear on how I'm to delineate between the variable and the value.




    Mike Green wrote: »
    FullDuplexSerial just deals with individual characters when receiving. It detects the start bit, assembles the 8 bits of data, and otherwise ignores the stop bit. Any further structure that you want has to be supplied by you. To make that easier, there's an object in the OBEX called "Extended Full Duplex Serial" that calls FullDuplexSerial to get characters and allows you to handle strings and numbers that are delimited by a carriage return (13) character. There are other character manipulation routines in the OBEX.

    You will have to program all the bits and pieces to figure out what variable to set and to do the actual work. If I were doing this, I would probably pick two different delimiters, maybe "=" and carriage return. Everything up to the "=" would be the value label and everything from the "=" to the return would be the value. I would use the Extended Full Duplex Serial object, modify it to use a delimiter character supplied by me when I call the routines and call the string input routine to get the value label text, then call the number input routine to get the corresponding value, look up the string in a table of such names, and update the variable value corresponding to the name, probably using some kind of CASE statement.

    You might look at the source code for FemtoBasic (in the OBEX). There's a nice routine near the end of FemtoBasic.spin called getAnyNumber that takes the characters from a byte array and returns the value of the number found there and stops with the pointer to the characters (tp) pointing to the first "illegal" character in the value. It allows for decimal, hexadecimal, and binary values as well as single quoted characters (as a numeric value).
  • Mike GMike G Posts: 2,702
    edited 2011-09-22 19:27
    turbosupra, In response to your PM...

    The comments for Rxstr state
    {{
      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
     }} 
    

    vvtlRpmValueUpdate is 18 characters so the initial read would contain vvtlRpmValueUpd.


    This line of code...
    variable := EFDS.RxStr(byteArray)
    

    Variable contains a pointer to the string. That is, the value of "variable" is the starting memory address of a string. Therefore, the conditional statement below will (most likely) never be true.
    if variable == variable1
    

    Use the strcomp() method to check if two strings are equal, page 203 in the Propeller manual. Also take a look at the BYTE data type on page 51. This section explains how a string is an array of bytes with excellent examples.

    My suggestion is to put Extended_FDSerial on the self for a bit. Load the Parallax Serial Terminal Demo that comes with the Spin Tool. You can find it by selecting "Propeller Library - Demos" from the recent files drop down list in the left pane. The Parallax Serial Terminal Demo takes input from the Parallax Serial Terminal, manipulates the input, and displayed the results. The demo will provide a good basis for understanding serial data.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-09-22 19:42
    turbosupra,
    In the code you've posted, you're confusing strings and the address of strings. Spin doesn't really have strings although you can write string constants. What gets passed around is the address of the first byte of a sequence of bytes terminated by a byte containing zero. This is the same convention that's used in C and some other languages. .RxStr returns such an address.

    Mike G has a good point. You should first spend some time with some of the demo programs that deal with serial I/O. Forget about all the 0 and 1 bits and focus on the bytes that are transferred back and forth. The whole purpose of FullDuplexSerial and its cousins is to hide the details of how the bytes are transferred so you don't have to worry about that. Do look at Extended_FDSerial and experiment with it. Either add some debugging statements to show what's happening inside the Extended_FDSerial routines or invest in a debugging tool like ViewPort and use that to watch what's going on until you understand it.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-23 08:07
    Hi Mike,

    I will work with the demos so that I can see cause and effect. I own a viewport license, although my laptop had a head failure on the hard drive, so I will have to reinstall it and try and use it more effectively based on the explanations you and Mike G have given me. Thank you.

    Mike Green wrote: »
    turbosupra,
    In the code you've posted, you're confusing strings and the address of strings. Spin doesn't really have strings although you can write string constants. What gets passed around is the address of the first byte of a sequence of bytes terminated by a byte containing zero. This is the same convention that's used in C and some other languages. .RxStr returns such an address.

    Mike G has a good point. You should first spend some time with some of the demo programs that deal with serial I/O. Forget about all the 0 and 1 bits and focus on the bytes that are transferred back and forth. The whole purpose of FullDuplexSerial and its cousins is to hide the details of how the bytes are transferred so you don't have to worry about that. Do look at Extended_FDSerial and experiment with it. Either add some debugging statements to show what's happening inside the Extended_FDSerial routines or invest in a debugging tool like ViewPort and use that to watch what's going on until you understand it.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-27 13:43
    I've been using the PST demo and reading about bytes as everyone suggested. As well as reading different forum posts for hours.

    I'm not sure why the below code is not working. It appears I'm going to have to become familiar with string manipulation in spin. Maybe someone can tell me what I'm overlooking here? Thanks for reading!

    
    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    
    VAR
    byte  rxString[100]  'Holds incoming serial bytes
    byte  rxString2[100]  'Holds incoming serial bytes
    
    
    
    OBJ
    pst : "Parallax Serial Terminal"
    strings : "Strings"
    
    PUB TwoWayCom | value, stringValue, charValue, variableName[100], variableValue, delimiterPosition              ' defines local variable "value"
    
    ''Test Parallax Serial Terminal number entry and display.
      pst.Start(115_200)                                    ' starts with passed on variable of the baud rate                        
      pst.Clear                                             ' clears the PST screen
      
      repeat
        pst.Str(String(pst#NL, "Enter a name, then an equals sign and then their age: "))
        pst.StrIn(@rxString)
        pst.Str(String(pst#NL, "You said "))
        pst.Str(@rxString)
        pst.Str(String(pst#NL, "Equals sign is at position "))
        delimiterPosition := strings.StrPos(@rxString, "=", 0)    
        pst.Str(delimiterPosition) 
        
        pst.Str(String(pst#NL, " was ", pst#NL))
        pst.StrInSegmented(@rxString2, -1) 
        pst.Str(@rxString2)
        pst.Str(String(pst#NL, " years old.", pst#NL))
    
    


    Parallax Serial Terminal.spinStrings.spin
  • Mike GMike G Posts: 2,702
    edited 2011-09-27 15:03
    turbosupra wrote:
    I'm not sure why the below code is not working. It appears I'm going to have to become familiar with string manipulation in spin. Maybe someone can tell me what I'm overlooking here? Thanks for reading!

    It's helpful if you tell us what you expect to happen and what actually happens. Anyway, I fixed the first part of your code. Inline strings need to be inside of the string() method. Use the DEC method of PST to display an integer.

    I can't make heads or tails of the second part.
    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    
    VAR
    byte  rxString[100]  'Holds incoming serial bytes
    byte  rxString2[100]  'Holds incoming serial bytes
    
    
    
    OBJ
    pst : "Parallax Serial Terminal"
    strings : "Strings"
    
    PUB TwoWayCom | value, stringValue, charValue, variableName[100], variableValue, delimiterPosition              ' defines local variable "value"
    
    ''Test Parallax Serial Terminal number entry and display.
      pst.Start(115_200)                                    ' starts with passed on variable of the baud rate                        
      pst.Clear                                             ' clears the PST screen
      
      repeat
        pst.Str(String(pst#NL, "Enter a name, then an equals sign and then their age: "))
        pst.StrIn(@rxString)
        pst.Str(String(pst#NL, "You said "))
        pst.Str(@rxString)
        pst.Str(String(pst#NL, "Equals sign is at position "))
        delimiterPosition := strings.StrPos(@rxString, string("="), 0)    
        pst.dec(delimiterPosition) 
        
        ''NO Idea what is expected here
        pst.Str(String(pst#NL, " was ", pst#NL))
        pst.StrInSegmented(@rxString2, -1) 
        pst.Str(@rxString2)
        pst.Str(String(pst#NL, " years old.", pst#NL))
    
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-28 06:35
    Hi Mike,

    Thank you for the help, sorry I forgot the explanation. What I'm trying to do is to have the prop parse 1 string into 2 strings. So let's say the string was Mike=29. I'd want it to identify the delimiter (equals sign) and then I can hopefully use the StrParse method or something like it to split the string into a variable name ("Mike") and a variable value ("29") and then copy them to permanent memory addresses and clear the temporary cache of rxString (and possibly rxString2 if I need to use it)

    The part underneath was me trying to tweak a function to string split, the code is inside of the strings.spin attachment from the previous post and it probably won't be necessary once I understand how to use this code.

    It looks like some of the string functions I use in c#, but I'm not able to make the methods work?

    Mike G wrote: »
    It's helpful if you tell us what you expect to happen and what actually happens. Anyway, I fixed the first part of your code. Inline strings need to be inside of the string() method. Use the DEC method of PST to display an integer.

    I can't make heads or tails of the second part.
    CON
    _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    
    
    VAR
    byte  rxString[100]  'Holds incoming serial bytes
    byte  rxString2[100]  'Holds incoming serial bytes
    
    
    
    OBJ
    pst : "Parallax Serial Terminal"
    strings : "Strings"
    
    PUB TwoWayCom | value, stringValue, charValue, variableName[100], variableValue, delimiterPosition              ' defines local variable "value"
    
    ''Test Parallax Serial Terminal number entry and display.
      pst.Start(115_200)                                    ' starts with passed on variable of the baud rate                        
      pst.Clear                                             ' clears the PST screen
      
      repeat
        pst.Str(String(pst#NL, "Enter a name, then an equals sign and then their age: "))
        pst.StrIn(@rxString)
        pst.Str(String(pst#NL, "You said "))
        pst.Str(@rxString)
        pst.Str(String(pst#NL, "Equals sign is at position "))
        delimiterPosition := strings.StrPos(@rxString, string("="), 0)    
        pst.dec(delimiterPosition) 
        
        ''NO Idea what is expected here
        pst.Str(String(pst#NL, " was ", pst#NL))
        pst.StrInSegmented(@rxString2, -1) 
        pst.Str(@rxString2)
        pst.Str(String(pst#NL, " years old.", pst#NL))
    
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-28 08:02
    Ugh, I changed it to pst.Dec and it displays the number. I thought it would display it as a string value, and I just saw your "Use the DEC method" ... thank you for that.

    Let me see if I can make some progress now
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-28 09:01
    Ok, I've almost got it, but it appears that when I set a variable to a string manipulated version @rxString, it is not copying the manipulated version into a new memory address, only continuing to point to the memory address of @rxString.

    How can I copy my string manipulations to a new location in memory?
  • Mike GreenMike Green Posts: 23,101
    edited 2011-09-28 09:10
    Use BYTEMOVE. Your variable has to be a byte array of a size sufficient to hold the resulting string. For example, say that rxString is 16 bytes long and you want to copy it to tempString (also 16 bytes long). You could write

    BYTEMOVE(@tempString,@rxString,16)

    Remember that the amount to be copied has to include the zero byte that marks the end of the string.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-28 10:33
    Thanks Mike,

    I am so close now, but there is something I missing which is why I'm getting the output results below, care to straighten me out on this?

    I've attached my code and the dependent objects in this post, what I expect is to separate the incoming serial string into 2 independent values, which are printed as 2 separate variables in the last terminal output which is " 10.) " . It should have read as " The individual Tom is 100 years old. "





    Enter a name, then an equals sign and then their age: Tom=100

    You said Tom=100

    1.)
    The string character position 3 is the delimiterPositionForValue of rxString (0 based
    starting position)

    2.)
    Tom=100 is the rxVariableNameTemp value

    3.)
    Tom=100 is the rxVariableValueTemp value

    4.)
    100 is the (StrParse) variable value portion of the string

    5.)
    Tom=100 is the rxString value (mid process check)

    6.)
    001=moT is the entire string reversed

    7.)
    The string character position 3 is the delimiterPositionForName of reversed rxVariabl
    eNameTemp (0 based starting position)

    8.)
    = is the variable value

    9.)
    moT is the variable name truncated (still reversed)

    10.)
    The individual ToT is ToT years old.


    Done!

    Parallax Serial Terminal.spin Strings.spin testcode2.spin




    Mike Green wrote: »
    Use BYTEMOVE. Your variable has to be a byte array of a size sufficient to hold the resulting string. For example, say that rxString is 16 bytes long and you want to copy it to tempString (also 16 bytes long). You could write

    BYTEMOVE(@tempString,@rxString,16)

    Remember that the amount to be copied has to include the zero byte that marks the end of the string.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-09-28 10:53
    The following takes in the address of a string (like @rxString). At that address should be a string like "Tom=100" consisting of characters followed by an equal sign, then a number. The string ends as usual with a zero byte. This routine returns the value of the number after the equal sign. The equal sign is replaced by a zero byte so the string now consists of just the name portion. You can use STRCOMP to compare this with other names. If there's an error, this routine returns a negative number whose absolute value is the address of the character causing the error.
    PUB scanRxString( strPtr )
       repeat
          if byte[strPtr] == "="
             byte[strPtr++]~   ' Mark end of name field and bump pointer
             repeat
                if byte[strPtr] == 0
                   return
                if byte[strPtr] => "0" and byte[strPtr] =< "9"
                   result := result * 10 + byte[strPtr++] = "0"
                   next
                return -strPtr   ' error return
          if byte[strPtr] == 0   ' no equal sign
             return -strPtr
          strPtr++
    

    You could call this like so
    value := scanRxString(@rxString)
    if value < 0
       {do something when the string is invalid}
    if strcomp(@rxString,string("Tom"))
       Tom := value
    elseif strcomp(@rxString,string("Dick"))
       Dick := value
    else
       {do something if name isn't recognized}
    
  • turbosupraturbosupra Posts: 1,088
    edited 2011-09-28 12:59
    Thanks Mike.

    I know beggars can't be choosers, but do you have any idea why my function was returning incorrect data? I can't think of a reason why if I call a string display once and then a second time a few lines of code later, without altering it, that it would display something completely different then the first time. Even if my function cannot be used, I'd like to know for future spin coding why that is happening?

    To me it looks as if the bytemove is not creating an independent variable for some reason?

    I was originally rechecking the value of step 4, in step 8. I took step 8 and I tested it after step 5 and step 6 (no need to run after step 4 or 7) and somehow at step 6, one variables actions are still manipulating the other variables actions and it changes. Do you know why this is happening?



    Enter a name, then an equals sign and then their age: Tom=100

    You said Tom=100

    1.)
    The string character position 5 is the delimiterPositionForValue of rxString (0 based
    starting position)

    2.)
    Tom=100 is the rxVariableNameTemp value

    3.)
    Tom=100 is the rxVariableValueTemp value

    4.)
    100 is the (StrParse) variableValue portion of the string


    5.)
    Tom=100 is the rxString value (mid process check)

    8.)
    100 is the (StrParse) variableValue portion of the string


    6.)
    001nmoT is the entire string reversed

    8.)
    001nmoT is the (StrParse) variableValue portion of the string


    7.)
    The string character position 3 is the delimiterPositionForName of reversed rxVariabl
    eNameTemp (0 based starting position)

    8.)
    = is the (StrParse) variableValue portion of the string


    9.) n
    moT is the variableName truncated (still reversed)

    10.)
    The individual TomoT is TomoT years old.


    Done!
Sign In or Register to comment.