Need a bit more help on Strings2
bdickens
Posts: 110
I'm still not getting what I need and I've tried a whole bunch of combinations. Mike Green got me part of the way, but I'm still stuck and after a few hours of frustration, I'm reaching out. It's almost the same problem as last time.
I have a string that is coming in from outside the routine. InDataRec.
That string contains a comma delimited set of values. I need to break it up into the individual values. So INdataRec contains the string
"WD01,1,40385,5,360,90,27,0,0,10" and needs to be parsed so that
Var1 = "WD01"
Var2 = "1"
Var3 = "40385"
Var4 = "5"
etc
I'm using the STRINGS2 and NUMBERS library in addition to PST. For this example, I just "print" the value (fromAddr). My issue is that it seems to be modifying the variables in odd ways.
I'm struggling with when to use the address (@) vs the variable name and I am pretty sure thats the issue, but I have tried many combinations and some were worse than this. So I am pretty sure it's in there
code is attached.
I have a string that is coming in from outside the routine. InDataRec.
That string contains a comma delimited set of values. I need to break it up into the individual values. So INdataRec contains the string
"WD01,1,40385,5,360,90,27,0,0,10" and needs to be parsed so that
Var1 = "WD01"
Var2 = "1"
Var3 = "40385"
Var4 = "5"
etc
I'm using the STRINGS2 and NUMBERS library in addition to PST. For this example, I just "print" the value (fromAddr). My issue is that it seems to be modifying the variables in odd ways.
I'm struggling with when to use the address (@) vs the variable name and I am pretty sure thats the issue, but I have tried many combinations and some were worse than this. So I am pretty sure it's in there
code is attached.
Comments
Byte containing 8 bit
word containing 16 bit
long containing 32 bit
strings are stored in arrays of BYTES
each character is represented by an 8bit value
so something like
byte MyChar
MyChar := "A"
makes sense
but something like MyChar := "ABC" makes no sense at all
because the string "ABC" needs 3x8=24 bits
which can't be stored in a byte
For strings longer than one byte you use arrays of byte
methods that work with strings need the RAM-adress where the bytearray begins
This means if you want to use method str of FullDuplexSerial
you would code
then method str sends byte for byte until it encounters value zero
(which terminates the string)
so for your string it would look similar like this
assigning the substrings
For parsing a string you would use a loop that increments the byteindex
until INdataRec[index] == ","
if you need a higher speed for assigning the characters of the string
you can use the command bytemove
best regards
Stefan
So presuming I define
VAR
byte InDataRec(70), tDataRec(70)
byte PrseChar
Pub TestTRans | jindx, idx, tlen, tval
pst.start(115_200)
InDataRec := String("WD01,1,40385,5,360,90,27,0,0,10")
Now I'm presuming that this will produce an array that has 31 elements, in the form
InDataRec(0) will be W
InDataRec(1) will be D
InDataRec(2) will be 0
...
InDataRec(30) will be 0
inDataRec(31) will be the terminator.
But I am not wholly sure that's true. The string is delivered to me as a parameter. In any event, I can loop through the array.
prseChar := ","
jindx := 0
Repeat idx from 0 to strsize(InDataRec)
->pst.Char(InDataRec(idx)) ' This should show the characters. But even in HEX it's not
->if InDataRec(idx) <> prseChar
--->TdataRec(jindx):= InDataRec(idx)
--->jindx++
->else
--->TDataRec(Jindx)~
--->pst.str(tDataRec)
--->jindx := 0
I get garbage from the other pst.str(tDatarec)
This code is loaded in the String Parse Problem BigLoop v1.spin attached.
Thanks.
Parameters and Local Variables
Parameters and local variables are all longs (four bytes). In fact, parameters are really just variables that are initialized to the corresponding values specified by the caller of the method. Local variables, however, are not initialized; they contain random data whenever the method is called.
Passing a value by reference with the Symbol Address operator is commonly used when
providing a string variable to a method. Since string variables are really just byte arrays, there is no way to pass them to a method by value; doing so would result in the method receiving only the first character. Even if a method does not need to modify a string, or other logical array, the array in question still needs to be passed by reference because there are multiple elements to be accessed.
Also see page 438 under PUB:
• LocalVar is a name for a local variable (optional). LocalVar must be globally unique,
but other methods may also use the same symbol name. All local variables are of
size long (four bytes) and are left uninitialized upon each call to the method.
Methods can contain zero or more comma-delimited local variables.
CON
_CLKMODE=XTAL1+ PLL2X 'The system clock spec
_XINFREQ = 5_000_000
Try this instead:
CON
_clkmode = xtal1 + pll16x ' use crystal x 16
_xinfreq = 5_000_000
I also appreciated the parameters pointer. I had read that as well. But in my code example I eliminated any of the complexity on that. It doesn't seem to explain why the code I posted isn't working. I don't have a choice on the string coming in. But I am getting all of the parameters passed.
So can someone please look at either sets of code and help me ? I don't need a whole lot of explanation but getting either sets of code to work once will do the job. I've gotten almost the entire rest of the code to work, just this one block is defeating me.
Thanks
The only reason I mentioned the speed is in case at your baud 115,000 whether the communication can be achieved at that rate, maybe it can but that seems like a fast baud for a slow clock speed. The PST demos all use x16 so that's why I was curious.
But my frustration on this string issue is reaching really annoying. Hoping someone can aim me at the right direction.
Thanks
John Abshier
startlen is length of string in byte. longmove moves that many longs. Also since they are used as strings I sould make tDataRec and IndataRec byte arrays instead of long arrays.
John Abshier
variable := string("somestring")
What I experienced is that I could not parse the string that was created this way. When I create a string it is always by some method like (oversimplified):
variable[idx] := tempvar
This way you populate the array one byte at a time. Then, you can use PST to display the values pst.dec(variable[idx]) and see all the values correctly. John has given you one method to populate the array.
You access each byte in the string as shown above.
If the methods are all in the same cog, you can do this:
If the caller is in one cog and the parse method is in another, then you send a pointer to the byte with a parameter using @
But the second code sample doesn't need it. BIGLOOP.
And I tried the BYTEMOVE a while ago. Won't seem to work either.
T Chap - That is exactly what I tried to do in the BIGLOOP code, and I couldn't do it either. Something about the way the string is stored is not blatantly obvious. I've fixed some minor anoyances in BIGLoop but uncovered a disaster a bit later.
Thanks
BTW you don't use @ as you are doing if it is all in the same cog.
Try this:
Can't thank you enough. That was a big help.
the variable InDataRec does NOT contain the string itself
The variable InDataRec contains the RAM-Adress of the first byte
where the string is stored as a bytesequence.
best regards
Stefan
That's what it tested out as, so that in other words the VAR declaration could have been
InDataRec and it works out identical to if it were InDataRec[20], and trying to affect the memory following InDataRec on the next variable declaration did not seem to affect the string content of InDataRec.
VAR Byte InDataRec, otherbyte[20]
InDataRec := string("asdfasdfasdf")
otherbyte := 10
The string content of InDataRec is still in tact somehow, so the byte memory doesn't seem to be in consecutive order as they normally would have been use a normal means of assigning values to the array. I assume at compile the string gets written to DAT by default.
the idea is that you input data as a byte within a loop. when you hit the comma, you
break the loop and do something with what you have received.
the only variable needed is for the ascii character coming in. sort of like processing a list.
you know the number of items in the list, each item separated by a comma. length of the item or data type does not matter since all you are taking in is ascii.
outer loop - number of commas that make up a line of input [items in the list]
inner loop - keep inputting bytes until you hit a comma
process the item within the loop - like print a; or b=b+a
close inner loop
process item - feed into a variable, print it, build a string, use in function, etc.
fetch the next line of data until there ain't no mo. close loop. use data.
But of course it has to work.... I still don't understand why the STRING2 object did not do what I expected.
So the current generation of code does what you describe, but still does not work the way I'm expecting. But I'm getting closer.
Thanks
EVERY method of the strings2-object works with pointers.
This means you have to define byte-arrays where the characters of the strings are stored and you have to define variables that are LONGs !!
longs = 32 bit NOT bytes = 8bit which are used as pointers that contain the
RAM-adresses of the byte-arrays.
Whenever you code something like
string("abc")
somewhere in the RAM four bytes are reserved ("ABC+zero)
and coding
debug.str(string("abc")) is translated from the compiler to
debug.str(RAM-adress where characters "ABC" are stored)
do you get the principle by this desrciption?
best regards
Stefan
VAR
byte InDataRec[MaxRec], tDataRec[MAXREC]
byte PrseChar, inChar
I could be wrong, but it looks like InDataRec and TDataRec both share the same "string" space. So a value put into InDataRec in byte 2 shows up in TdataRec as byte 1. So it looks like the compiler assigns one address to InDataRec and the next contiguous address to tDataRec. Then when I try to access them, I end up with colliding strings. All this is making it difficult to do what seems to be a simple job.
So I'm up for some additional help.
My original issue is that the system on the other end of this application sends a comma delimited stream of characters through an XBee, with no more than 10 variables but no less than 3. All are separated by commas. Other than the first 4 bytes, which are standard, the rest are variable length, all less than 60 bytes total. The XBee puts them in a string. All in a separate COG (eventually).
The sending system is running behind, I'm running ahead. So my intent was to simulate the stream coming in. I defined a variable, loaded a comma delimited string into it and the fun started.
This is the routine that took the string, and copied it into what will be a global variable. That variable is accessible by multiple cogs. This code seems simple enough but displays some interesting behaviour. T Chap cracked the "cast" statement so at least I see whats happening.
My intent, was to define 10 variables. Loop through the string and everywhere i find a comma, go ahead and close the variable. Save the result and move on.
I've attached 3 pieces of code.
Solution 5 - The basic code for a string copy (thats not working). This was my attempt to simulate what I'm going to get from the XBEE
Solution 4 - this is the same code with the Parallax serial terminal code for debugging
Solution 2 - This is the first cut at the parse routine. If I get copy to work, then Parse should be a snap. But I included it for reference.
I'll take all the help I can get. I'm amazed at how much I got done, but how one itty bitty issue has stumped me.
Thanks
Here is a changed version of version 5
John Abshier
Thanks
Why pst.str(@InDataRec) after copystring and not just pst.str(InDataRec) ?
Tstring is defined as Long, inChar and InDataRec as byte. The statement : inChar := (byte[istring][idx]) casts the long to the byte variable. If I wanted to create long variables (WS1, WS2, etc) , could I have eliminated the cast ? and just done WS1[JDX] := istring[Idx] ? (this assumes that JDX is on a different loop, reset by the comma)
Appreciate the help. I'm getting there. Slowly, but getting there
John Abshier
Did I read the manual ? yes,
Do I get it all. Nope. This is my first large program past the labs and judging from the number of "string" related questions on the forum. I'd have to say it's not wholly clear. But I think that why I am asking questions.
Appreciate the help.
Wow, just like bdickens I am working with a sensor (except mine is a blackfin camera that does image processing) that I WANT to use the prop to send / receive commands and process the information. I have spent the past few weeks going through my prop books, the pekit, and LOTS of forum searches. Just before I called it quits and fell off my chair I found this thread..
I have no problems using the prop to send commands to my sensor, (115200 baud) the problems come into play when I want to debug the result to pst and also use the data. Lets say for example I send a command and the prop receive's the data in the format:
##vmean 111 222 333
12345678912345678912
result[20]
and I need to take each group of 3 numbers(no higher than 255) and assign a value to each one, so there are 3 values
value1[0] = result[9]
value1[1] = result[10]
value1[2] = result[11]
value1[3] = 0 4th byte of each value being 0(terminator)
etc,etc,etc
a note on the sensor I use, most responces are returned then followed by using cr then lf.
Looking at the code examples myself I am trying to understand this better myself. I attached the objects I am using.
I didn't see anything I could use from the object exchange, and there aren't really any useful examples other than this thread.
One thing that I am hoping to do is write an object for the Blackfin Camera and post it in the obex for others to make use of.
I don't use PST, but assume that you are sure that it requires the byte[y_mean][x] to access your local variable and not @y_mean. In all your earlier calls to print from PST, you use @ plus yo9ur local variable, but then for the number you are getting wrong, you are not using @ and are using byte.
Thank you for getting back to me..
I think you are talking about this part of my code?
Y_Mean[0] := BFinMean[8]
Y_Mean[1] := BFinMean[9]
Y_Mean[2] := BFinMean[10]
Y_Mean[3] := 0
I made changes so now it looks like:
Y_Mean[0] := @BFinMean[8]
Y_Mean[1] := @BFinMean[9]
Y_Mean[2] := @BFinMean[10]
Y_Mean[3] := 0
If this is correct, I just want to be able to output via pst the value of Y_Mean which 'should' match the first 3 numbers, just trying to get that part of it right but I am still missing something here...
Do this and post the result:
PST.dec (Y_Mean[0])
PST.dec (Y_Mean[1])
PST.dec (Y_Mean[2])
PST.Str (String(13))
You should see:
111
Also if that works, then try this and post the result:
Create a new Long called MeanResult[3]
MeanResult[0] := Y_Mean[0] * 100
MeanResult[1] := Y_Mean[1] * 10
MeanResult[2] := MeanResult[0] + MeanResult[1] + Y_Mean[0]
PST.dec (MeanResult[2])
PST.Str (String(13))
EDIT: this did not account for a byte possibly exceeding a byte maximum 255. See corrected code above.