Parsing serial data in SPIN; converting ASCII hex to a decimal number
K6MLE
Posts: 106
Is there a library program for either of these tasks? The serial data will be coming in as ASCII hex and once a particular field is grabbed, I need to convert the values to decimal. Any help will be greatly appreciated, as I'm currently trying to learn SPIN and put it to immediate use.
Comments
Handle A-F separately.
For each subsequent digit received, multiply the accumulator with 16 before adding that digit.
Done.
By ASCII hex I assume you mean you are receiving the ascii digits zero to nine and letters A to F (or a to f). Pretty simple to convert that to a 32 bit binary number and then use the serial object functions to display them as decimal numbers. Just do the following:
1. Set the number variable to zero.
2. Make sure the characters are valid (0-9, A-F, a-f)
3. Add 9 to the character if it is not numeric
4. Mask off the 4 lsb's
5. Add the 4 lsb's to the number variable
6. Shift the number variable left 4 bits
7. Repeat 2 to 6 for a maximum of 8 hex digits
You may want to look at Numbers by Jeff Martin and Simple Numbers by Chip Gracey in the OBEX. IIRC JonnyMac also had some number conversion routines in his Nuts & Volts articles.
The firmware for the Eddie robot parses incoming hex data. The latest version of the Eddie firmware (which will also work with Arlo hardware) can be found on my GitHub.
https://github.com/ddegn/EddieFirmware
This code should be enough of an example to get me heading in the proper direction!
Thanks for the help!
As a matter of interest I am testing out a VGA text object in Tachyon and it could just as well be a TV object too. There is of course a lot of number and string handling built into Tachyon, I wouldn't think it would hardly be any bother at all. What does the string look like and what to you need to do with it?
The only pst call you really need is "pst.HexIn". The other pst calls display text to the terminal. This text should also be displayed on the TV.
The method "HexIn" requires a carriage return to enter the data. Any characters which aren't part of a hexadecimal number are ignored. The leading "$" can be included or not. It won't change the value of the number.
The longest hex value one can hold in a long variable is 8 digits long. If your 24 characters hold values of multiple numbers, you'll need to use a carriage return to separate the values to different variables.
The project at hand is to take the serial data coming from my weather station ( Peet Bros. Ultimeter 100) and display some of the data on a wall-mounted display, so it's viewable from across the room. The data string looks like this:
$ULTW002C00DD03060505,CR,LF
I will want to watch for the "$" character and then ignore the "ULTW" portion. Following that, the data breaks down as follows:
002C = Wind speed in MPH.
00DD = Wind direction in degrees
0306 = Last detected outdoor temperature in degrees F.
0505 = Long term rain total, in inches.
In testing the serial receive portion of the code, I wanted to be able to read the string and display the elements using the TV-text object. Once this works, the data will be fed into a case statement for direction and light an appropriate LED on a compass rose I already have waiting. The wind speed will be next and is to be displayed on a 3-digit multiplexed 7-segment display. My thought were to use the Propeller for this and just have the LED routine and 3-digit routine grab their data from a set of global variables and assign each of the routines to their own cog. My old way of doing this was to use a PIC microcontroller and have the multiplexed display get interrupted by the serial port, so the data could be updated. New data comes in every 5 minutes.
Clearly, my experience with PicBasicPro isn't helping me at all with SPIN! While I'd like to learn SPIN, I wouldn't be adverse to trying this in a FORTH environment (my favorite language, actually!!).
Thank you for your input!!
Being REAL new to SPIN, I only minimally understand the code you posted. My hope is to use a low-order I/O pin (7 in this case) for serial data reception. What keeps getting me stumped is the syntax of SPIN related to the handling of string data. It appears the data needs to be read into an array type of variable. It's unclear to me if this can be done all at once, or if it needs to be done byte-by-byte.
Once the data is stored in an array, it appears relatively easy (I think!) to parse the array and load up appropriate variables to be able to display the data.
My reply to Peter gives an illustration of the serial data format.
Thanks for your input!!
There are of course multiple ways to approach this. In the code below I read the full packet at once and then parse out the four digit hex values.
If "StrToBase" were made public from within the object "Parallax Serial Terminal" then the calls of "StrToBase(@smallBuffer, 16)" could be changed to "pst.StrToBase(@smallBuffer, 16)" and the method "StrToBase" could be deleted from the top object.
Again I didn't test this code with a TV attached. You might need to add some formatting commands to get the data displayed as you'd like it on the TV.
This is what it looks like in the serial terminal:
I manually entered "$ULTW002C00DD03060505,CR" into the terminal twice. A line feed character wasn't sent with my test but I'm pretty sure this won't make a difference since the code watches for the "$" character to indicate the start of the message.
Because the W character comes right before the data and never else, you can just wait for this character and then read the 4 hex values.
Here is a simple Spin code (untested):
Andy
To parse the string in Forth I would cheat and preprocess by just inserting spaces in the correct places then pass this to Forth as ULTW 002C 00DD 0306 0505 with ULTW being the deferred (execute at end of line) function to read in those four hex numbers, easy peasy.
Now here's another take on a remote display as I have done this in some projects. I use a dedicated Prop mounted on a VGA monitor that is running 512x384 bitmapped graphics including scalable font routines and interface to this over serial, RS485 in fact. The reason for the dedicated Prop is that it uses up pretty much all it's memory running graphics. So the main Prop does what it does and communicates with the VGA Prop (which btw also supports a keypad) and this monitor can be hundreds of metres away too, or you can have more than one. How does that sound?
I took a look at Tachyon, but I'm unsure how to load it, along with EXTEND, and then have much room left for development. Would I want to add some external memory somehow?
Here is a link to Kye's String Handling Object
http://obex.parallax.com/object/579
Changing the mode from zero to one when you start FullDuplexSerial will invert the data. Duane's code in post 11 should then do what you need although it looks like you need to add some decimal points. Implementing Ariba's suggestion in post 12 is also a good idea.
There is plenty of room left over as Tachyon code is very compact and after EXTEND I typically load hardware headers, SDCARD, EASYFILE, WIZNET drivers, EASYNET, and then my "development" files
However I think I've made the whole thing pretty easy to get working with as besides the intro document which will also run you through the steps of loading EXTEND which is really only pasting into a serial terminal with line delays, there is also the easy way of just loading the binary Explorer image which is just the kernel + EXTEND plus some little extras. As I mentioned earlier I am testing some VGA/TV code in the current kernel which I probably will finalize in the next day of two when I get around to it. So with this kernel you can do your large text display with Tachyon in the one chip.
EDIT: To answer your first question about more detail on a remote VGA Prop solution I refer to an old post.
It can be easily modified to get its input from some other place (like a keyboard or serial input) and some other error handling technique could be used. There's no overflow checking, but this could be easily added.
If one searches the forum for "DecPoint" they should find a method to display scaled integers with a decimal point added in the appropriate location.
There's a link to Rich's forum search page at the top of post #1 of my index (see my signature for link).
Since you're new to Spin it may not be obvious that I'm using the local long tbuf as a 4-byte work buffer (locals are always declared as longs, but can have their constituent parts manipulated). As with Duane's excellent example, this returns everything in whole numbers, though I suspect some fields should be displayed in tenths.
Since your hex2dec method doesn't require a terminating zero in the string you don't even need to move the characters to a temporary buffer.
Doesn't this do the same thing? (No need to answer.)
I doubt this version is easier to understand for someone new to Spin. It think there are probably more ways to parse this data with Spin than there are people who program in Spin.
Eliminating the need for a terminating zero gives "hex2dec" a big advantage over "StrToBase" in many applications.
I do tend to write verbose code, optimizing very late in the process.
If you are still interested I have the 32x15 VGA object integrated into Tachyon but it also draws big characters on the screen as well using big dot symbols in a 5x7 matrix. There are also box and turtle drawing commands and it's all so easy to use. I'm glad I finally got around to doing this as I do have quite a few applications and the big digit mode means I don't have to resort to 512x384 bitmap graphics.
Even with the bloated Explorer image there is still 3.6k code/name space available (that's a lot of Tachyon code!) as well as the 2K BUFFER normally used by the SD card FAT32 system. You can also load EXTEND without all the bloat plus if you have a 64kB EEPROM you can even free up about 8 or 10k of hub memory by compacting the dictionary into the top 64k of the EEPROM.
Check out the latest in the Tachyon thread for more info, there's a link to the latest VGA Explorer image.