PDA

View Full Version : For those of you that use or have used other microchips ...



turbosupra
09-01-2011, 07:38 PM
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) .

Chris Savage
09-01-2011, 07:50 PM
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 (http://www.parallaxsemiconductor.com/an018) has been provided by Parallax discussing Propeller to PC communication with code examples for Propeller and PC (http://www.parallaxsemiconductor.com/an018). However if your message is to find another product the message is not suitable in the Propeller forum.

Leon
09-01-2011, 07:55 PM
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.
09-01-2011, 08:00 PM
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.

Duane Degn
09-01-2011, 08:04 PM
Have you seen these threads?

http://forums.parallax.com/showthread.php?126486-What-could-we-stuff-into-a-100kB-quot-Prop-Welcome-Mat-quot-drive-image&p=1032241#post1032241

http://forums.parallax.com/showthread.php?133979-Project-In-Progress-New-Serial-Terminal-Taking-Suggestions

Duane

Heater.
09-01-2011, 08:11 PM
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.

turbosupra
09-02-2011, 12:34 PM
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



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.





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_braino
09-02-2011, 01:24 PM
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 G
09-02-2011, 01:50 PM
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 Digital
09-02-2011, 01:59 PM
A simple LPC1342 (http://luisdigital.com/tienda/product.php?id_product=8&id_lang=1) can do USB-Serial.

Heater.
09-02-2011, 02:50 PM
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.

turbosupra
09-05-2011, 06:04 PM
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 Green
09-05-2011, 06:18 PM
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.

JeremyJ
09-09-2011, 05:44 AM
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 Green
09-09-2011, 02:22 PM
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 ]

JeremyJ
09-09-2011, 04:00 PM
Thanks Mike - that's exactly what I was wondering...how you interface between assembly (tabular info) and spin to get the value.

Jeremy

turbosupra
09-22-2011, 05:28 PM
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)
01110110011101100111010001101100010100100111000001 10110101010110011000010110110001110101011001010101 01010111000001100100011000010111010001100101

(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?

01110110011101100111010001101100010100100111000001 10110101010110011000010110110001110101011001010101 01010111000001100100011000010111010001100101001011 1100110110001100000011000000110000

Mike Green
09-22-2011, 06:00 PM
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 (http://obex.parallax.com/objects/31/)" 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).

turbosupra
09-22-2011, 07:47 PM
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) "

01110110011101100111010001101100010100100111000001 10110101010110011000010110110001110101011001010101 01010111000001100100011000010111010001100101001111 01001101100011000000110000001100000010100000110001 0011001100101001


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)

01110110011101100111010001101100010100100111000001 10110101010110011000010110110001110101011001010101 01010111000001100100011000010111010001100101

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.






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 (http://obex.parallax.com/objects/31/)" 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 G
09-23-2011, 02:27 AM
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 Green
09-23-2011, 02:42 AM
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.

turbosupra
09-23-2011, 03:07 PM
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.



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.

turbosupra
09-27-2011, 08:43 PM
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))




8542685427

Mike G
09-27-2011, 10:03 PM
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))

turbosupra
09-28-2011, 01:35 PM
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?



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))

turbosupra
09-28-2011, 03:02 PM
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

turbosupra
09-28-2011, 04:01 PM
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 Green
09-28-2011, 04:10 PM
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.

turbosupra
09-28-2011, 05:33 PM
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!



85478 85479 85480






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 Green
09-28-2011, 05:53 PM
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}

turbosupra
09-28-2011, 07:59 PM
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!

Mike Green
09-28-2011, 09:55 PM
I think the problem you're running into is that the Strings object uses an internal buffer to hold the results of the last operation. It's the address of this buffer that's returned from a lot of the method calls. If you call one of the Strings methods, the buffer's contents will likely be modified. If you want to save the contents of the last Strings operation, you have to copy the string. It's not enough to save the buffer address.

Typically you'd do something like:

variableName := strings.StrRev(@rxVariableNameTemp)
bytemove(@otherStringTemp,variableName,strsize( variableName )+1)
delimiterPositionForName := strings.StrPos(@otherStringTemp, delimiter, 0)
variableName := strings.StrParse(@otherStringTemp, delimiterPositionForName + 1, byteLimit)
bytemove(@yetAnotherTemp,variableName,strsize( variableName )+1)
variableName := strings.StrRev(@yetAnotherTemp)

turbosupra
09-29-2011, 01:02 AM
Mike, thank you ... that was the answer. I can now enter in one variable=value at a time (in between prop power cycles), but when I enter a second/different variable=value after the code loops, everything bombs out. I'm guessing this is related to the previous issue of buffers. I tried using a bytefill at the beginning of the loop, but that is not fixing it. I'd like to clear each variable array after a final value is returned, for the next time it is used.

I guess I've been a little spoiled with .net and the garbage collector ... is there a place I can read more about this, so that whatever is happening I can have a better understanding of?

Thanks again.




I think the problem you're running into is that the Strings object uses an internal buffer to hold the results of the last operation. It's the address of this buffer that's returned from a lot of the method calls. If you call one of the Strings methods, the buffer's contents will likely be modified. If you want to save the contents of the last Strings operation, you have to copy the string. It's not enough to save the buffer address.

Typically you'd do something like:

variableName := strings.StrRev(@rxVariableNameTemp)
bytemove(@otherStringTemp,variableName,strsize( variableName )+1)
delimiterPositionForName := strings.StrPos(@otherStringTemp, delimiter, 0)
variableName := strings.StrParse(@otherStringTemp, delimiterPositionForName + 1, byteLimit)
bytemove(@yetAnotherTemp,variableName,strsize( variableName )+1)
variableName := strings.StrRev(@yetAnotherTemp)

Mike Green
09-29-2011, 02:20 AM
There's not really a place where this is written down other than in the comments of objects like strings. The problem is that we're not talking about a language feature. We're talking about adding features through the use of what are essentially library routines. Those can be written all kinds of ways with all sorts of assumptions. In any event, Spin, like C, doesn't really have any kind of built-in strings. Strings are simply byte arrays. There are no string values. What passes for a string value is just the starting address of a byte array containing the string. The fact that there's a built-in STRING function that allocates storage for a string constant and provides the address of the first byte of the constant just confuses people used to languages with built-in strings. To some extent the same thing is true for floating point. The Spin compiler supports floating point constants and constant expressions, but there's no such thing as a floating point variable and, although you can write floating point constant expressions, you can't do the same thing with a variable in the expression.

I suspect you've still got a few places where you're still referencing the built-in result buffer in the strings object. Also make sure that all your strings (byte arrays) are long enough to hold whatever you're putting in them and make sure that all string values end with a zero byte. The strings object is supposed to take care of the zero byte, but I haven't looked through your code in detail to make sure it respects that.