2 questions regaurding string sizes - evolving to formatting variables
Joms
Posts: 279
I have a string that consists of the following...
(space)(space)(space)21900(space)(space)(space)(space)00
I am trying to remove the data after the 21900.· That brings up two additional questions...
1) When I use the TV_Text object to display this string is displays just like I typed above, however when I debug it using FDS Object it will debug as a weird 4 digit number.
2) I am also trying to use this string to compare to another decimal number.· example, if the number is over 5000, activate an output.· But it appears that the number is stored as a string and not a decimal.· Am I correct on this?
I know I do not have a complete understanding of variables on the prop.· I have the Prop Manual next to me and from my reading I tried changing the size of the variable, but that did not fix the problem.· (When I say size I mean the 8 number...·· VariableName[noparse][[/noparse]8])
Post Edited (Joms) : 7/21/2009 11:03:03 PM GMT
(space)(space)(space)21900(space)(space)(space)(space)00
I am trying to remove the data after the 21900.· That brings up two additional questions...
1) When I use the TV_Text object to display this string is displays just like I typed above, however when I debug it using FDS Object it will debug as a weird 4 digit number.
2) I am also trying to use this string to compare to another decimal number.· example, if the number is over 5000, activate an output.· But it appears that the number is stored as a string and not a decimal.· Am I correct on this?
I know I do not have a complete understanding of variables on the prop.· I have the Prop Manual next to me and from my reading I tried changing the size of the variable, but that did not fix the problem.· (When I say size I mean the 8 number...·· VariableName[noparse][[/noparse]8])
Post Edited (Joms) : 7/21/2009 11:03:03 PM GMT
Comments
2) Yes. The number is stored as a string
What you show in your message is a 14 byte string that occupies 15 bytes (including the zero byte at the end). You will need at least 15 bytes to store it. If you don't have that much, the string will spill over the next variable(s) in memory.
Keep in mind that Spin really doesn't have string variables. It has string constants that are represented by their starting address, but no built-in string types. There are two built-in functions, STRSIZE and STRCOMP that can deal with strings to find their length and compare two of them for equality, but that's it. Everything else that deals with strings is constructed out of other stuff.
The spaces actually are a hex 20 which is a space. How could I write a line that would delete the last 6 bytes? Or do I just have to over-write them with something else?
When I debug that number I would expect to get 21900 but I get 4928 as a decimal or 1340 as a hex... I assume that would be because I have not removed the extra 6 bytes?
EDIT -
Also, what does the @ due when I use it in front of the string?· When I look in the manual (on page 278) it says that it is the 'Symbol Address Operator'.· Does this mean I can type BYTE[noparse][[/noparse]@StringName]· := $0, where BYTE is the number of the position the byte is in, and zero would be what I want to set the byte to?· Would be setting it to zero the same as deleting it?
Sorry for all the questions, just trying to actually learn these strings as I have never really understood them completely, but really would like to as it would help fix a lot of problems I think...
Post Edited (Joms) : 7/21/2009 4:04:02 AM GMT
Remember that a string is represented by the address of the first byte. Perhaps $1340 is the address of your string.
The question is not how to delete the last 6 bytes, but how to delete extra stuff that may be there if the number isn't 21900. Also, where do the spaces come from? How do you get the string in the first place?
Most string manipulation in Spin is done one byte at a time. For example, I'd write a routine that would start at the first byte of the string and increment the address of the first byte until that byte was non-blank. I'd save that address for later, then increment the address until the first non-digit was found and replace the non-digit character with a zero byte to mark the end of the string. I'd use the saved address as the actual address of the string since it points to what part I want.
stringname[noparse][[/noparse]8] := 0
The string is actually input from a scale I am reading data from.· I will attach the code and maybe that will help with the explanation.·· And I think you are right about the $1340 being the first byte of the string.· What I am trying to do is get the actual data off the string.
Basically I can make it display properly on the monitor (TV_Text) but I would like to compare it, for example, if it is over say 5000, activate a light or something.· So I have been just trying to debug as a test before I try to program the compair line.
One important comment ... You're calling Main recursively for some reason. That will eventually cause the program to run out of stack memory and die. Maybe you should use a REPEAT statement instead.
Do you actually know what data you're supposed to receive? Do you know why you're getting the spaces? That's the first thing you should investigate.
As for the data...· The data with the spaces is the way the scale outputs the data.· I actually just like the string time out each time because I really can't use a delimiter like a carriage return.· The data keeps repeating over and over...· Attached is a sheet that shows exactly how it is sent out of the scale...
I just typed this up and it is probably a lot easier to understand...
1. The string is consistant in length every time
2. The part in Yellow is the weight that I am trying to capture and work with
3. The part in blue just changes if there is a negative number.
4. What is happening in my current programming is I am waiting for the (13,2,49) combination at which time I start inputing the data. The leading (20,20,20,30,30) is actually showing up at the end of my string because it is coming back around until it gets to the 13 again. Because there is really no delimiter in this system I am trying to only input a string of a certain length, say 8 bytes in this case.
My advice for parsing it, which has worked for me in everything from VB to Stamp BASIC, is:
1. Input characters until you see the STX (2)
2. Input the next character. If it's also STX input another character, because the checksum is enabled and it can sometimes assume the value 2 itself.
3. Input and discard the next three characters after the STX. (You might want the second one since it contains the motion, minus sign, and error bits.)
4. Input the next six characters into your string; that's the displayed weight.
5. If you want to be picky, input and discard six more characters (the tare weight which you probably aren't using)
6. Make sure the next character is CR (13). If it isn't something is wrong, if it is you're golden.
Be aware that those three spaces will NOT always be spaces; the middle one in particular will change when the scale is in motion, under zero, etc.
Of course this might be some other format in which case you can ignore me
VariableName[noparse][[/noparse]6]
Would the 6 be the 6th byte in this variable or would it make the string 6 bytes long?
I am still trying to figure out how to treat the string as one variable number.
I think now understand what each of the bytes does in the string. I am not using the tare weight, just plain old weight of the truck.
If you look at my program I attached above can you see any errors on how I am inputing the string? The whole project basically has two goals, 1) display the weight using TV_Text, 2) compair the weight and if it is over a certian value, say 5000, activate a relay.
I have the video part working by still trying to compair the data and activate an output. The problem is that I am displaying the whole string yet, even the bytes after the weight, however to get around that I am printing the 'LBS' label over the top to cover it up...
Thanks for all your help so far everyone....This is a big learning step for me...
Char/function:
1: STX (ASCII 2)
2: Status Word A generally $20 plus some bits indicating scale capacity
3: Status word B important! $20 +
$01 = scale is in net mode
$02 = weight under zero
$04 = over capacity
$08 = scale in motion
$10 = KG mode
4: Status word C varies a bit, bit $08 generally indicates PRINT button is pushed
5-10 = displayed weight
11-16 = tare weight
17 = CR
18 = optional checksum; many modern scales don't output this, but beware it can be $02
Hope this is useful...
Joms, I would use character I/O for this. I don't have time to test this because I need to leave in a few minutes, but off the top of my head I'd advise trying something like this:
This will fairly reliably give you the last valid weight reading as the return value for readwt, and collect the 6 fixed width digits of the weight string into wtbuf.
You can add timeout/error checks, etc. One nice thing about continuous output is that you don't have to worry about blocking calls like rx; as long as the scale is connected you will get another character very shortly.
Post Edited (localroger) : 7/21/2009 2:06:59 PM GMT
2) Yes, a typo
3) I can't tell what you're trying to do since you didn't include GUI. loadout should be a long variable and "loadout := readScale" reads a value and assigns the weight value to loadout. It also has a side effect of setting statusA, statusB, and statusC.
4) If you want, you could add a test for a negative value for loadout which would indicate a timeout or missing final carriage return character.
I have actually tried a few different things and this is where I am at at the moment...
I removed all of the comments that Roger put in and commented out only the lines I added. I did not save it this was but did this only for this post.
Do you see why this timeout command wouldn't work?
EDIT - I think I figured it out...· I have to use the rxtime instead of rx in addition to the code above...
Post Edited (Joms) : 7/21/2009 10:24:02 PM GMT
You can use rxtime for all your .rx calls but you should check for -1 and bail if it happens.· I don't know what you're using your relay output for but it's kind of embarrassing when the fill valve stays open because the scale died and your weight output froze...· If you use rxtime you don't need to use timeout code yourself; just give it the appropriate number of milliseconds and look for the -1 return value.
·
It's also really a good practice to grab SWB and check the error and under-zero bits too for the same reason.· You can do that by saving it in the repeat while n < 3 loop, right before the else put elseif n == 2 / swb := c, then you can check swb & various maps to make sure everything is OK.
You might also want to look at the source for the rxtime function, it' s a bit cryptic but it's the better way to handle timeouts on the prop; you grab the system cnt variable, and keep subtracting that start value from the progressively later new current cnt.· When the difference is greater than your timeout in clocks, you handle the timeout.· This has the advantage of working properly at any clock rate if you use clkfreq to set the difference, and due to the magic of modulo 2 integer math it even works when the counts roll over.· On an 80 MHz prop this is good to about 50 seconds.
I've used -1 for the bad return code everywhere but since some of these indicate a scale that is working but in error, you might want to follow Mike's example and use different codes so you can tell the operator that the scale is in the wrong mode instead of no data, etc.· But remember that negative return values are valid, just not integer values that aren't multiples of 20.
Post Edited (localroger) : 7/21/2009 11:02:45 PM GMT
Does anyone see anything quick that looks like I have the format wrong, or storing a variable wrong?
I can post the full code as an attachement if it will help, but thought it would be easier to take a quick look just pasting it as code...
Thanks for all your help everyone on this project.... I could never have done it alone... We are almost there...
Post Edited (localroger) : 7/21/2009 11:07:28 PM GMT
I tried different combinations, making the loadoutwt a long, and it would either cause the debug or the TV_Text to quit working... But it is going now, so that part is good, I am just going to play around a little more with the combinations to try and learn why it is that way.
EDIT -
Also, I can not get the math part to work either way. I tried the loadout, loadoutwt, and @loadoutwt. I do know my hardware is working because I changed the pin on my heartbeat from 8 (LED) to 9 (relay), and the relay cycles...
Does the number have to be in hex or something other then a decimal? I was using a decimal because that is how I am debugging it.
EDIT 2 -
Something simple here is wrong that I don't understand. I even moved my 'outa[noparse][[/noparse]9] := 1' to just under the debug statement which should activate the relay, but it does not. I am declaring them outputs earlier in the program... 'dira[noparse][[/noparse]9..10] := 1'
Post Edited (Joms) : 7/21/2009 11:29:38 PM GMT
elseif loadinwt == -1
'pretend the next line is indented
outa[noparse][[/noparse]10] := (cnt & $4000) == 0
What this will do is blink your output if the weight is an error condition; it masks the ever changing cnt against a bit which should be changing every second or so at 80 MHz.
I don't know what your display object is but that usage doesn't look right. As I've written it you can use any of the usual debug, vga, tv drivers to output the fixed width weights like this:
object.str(@loadin)
object.out(13) 'carriage return
Also, sorry for the lack of comments, I am just putting those back and and adding extra ones...
Edit -
Yes, it is a make-shift presence detector.· I need the data to display the entire time on the monitor, but if the scale goes over say 4000 (just something random that is less then a truck but more then a person or lawn-mower), it will activate the relay.· There is a seperate relay for each scale.· Is there a better way to do that then?
Post Edited (Joms) : 7/21/2009 11:45:35 PM GMT
readloadin / readloadout = the read functions, they return -1 for error or a weight as result and incidentally set the fixed-length string outputs.
loadin / loadout = the string outputs, these are byte arrays of dimension 7 for 6 digits + null terminator.
loadinwt / loadoutwt = the numeric weight values, these are longs and you use them to do math.
Also, I was re-reading through the posts and like your idea of using multiple cogs.· Actually what I was playing with earlier is making a sperate spin file for the Jag Extream controller...· Bascially any time that I need to input the weight of a jag scale I could just use the jagextream.spin file.· In my main program I would just have to declare the RX pin and like the file return the weight.
Is this worth the programming?· Would it actually save time and coding or take more?· What do you think of the idea?· I could see using this in the future again...
It will debug a '-1' and will not display anything on the screen....
I would like to thank everyone for your help!
Mike and Roger, I couldn't have done it without you. Thank you so much for not only helping me with the code but taking the time to explain it so I could learn more about the prop and how to program it. I have learned a lot from this project. I can not say enough about how great it was to have you help on this project and other projects on the forums. THANKS!