Sunday, February 20, 2005 10:58 PM
edjez
Hook up to your GPS with .NET
Looking for the killer CAB demo...
This week we spent a considerable amount of time working on the CAB - Composite UI Application Block ..aka Smart Client Portal. Part of the value it provides is simplifying how visual components (SmartParts - think WebParts for windows) find, share data with, and control each other.
One of the good things about this composable apprach is that it lets different teams with different expertise independently build and deploy SmartParts and support services that the end user will see in his UI . So I was thinking of a killer demo of how value can be added for incrementally to apps, that highlighted the smart client benefits. I thought of some options - such as displaying a clock (big deal..), a regional weather report (better, but dèja vu thanks to Thunderbird..), and wasn't convinced of the options I was coming up with.
Enter the nifty GPS gizmo...
So it happened that I was at the Microsoft Employee store and found a good deal for the Microsoft Streets & Trips 2005 with GPS Locator. At $60 with discounts, I could get a reasonable GPS, even with WAAS compatibility (WAAS is a GPS feature that gives extra horizontal and vertical precision, increasingly used by airplane pilots. Without going too much into it, augmented GPS could eventually phase out other precision approach techniques for landing airplanes such as ILS, and it caught my eye a 5cm x 5cm x 1.5 cm GPS receiver had it). I connected it to my computer and after installing the USB Serial Port driver I had my Streets and Trips displaying my location with a car icon on a map:
Note that my house was moving slowly (1 mph) at the time of the screenshot. I blame it on GPS inaccuracy and not giving it enough time to average out my position, but then again, the terrain is quite slanted and I could be drifitng, study laptop and all, into the lake as I write this....
Doh! Cool demo idea: Physical Location & GPS display
OK, not everyone has a GPS and not every conference room has good GPS reception but what the heck - I decided to code a little LocationService and associated SmartParts to display stuff. If the Streets & Trips team did it, so can I..Well after a little rumagging I figured out my computer was seeing my GPS (connected via a USB cable) as a serial port. If I could hook into the communication stream, I would be able to process the data and have my service tell any smart client app built with the CAB the position, speed and other GPS trivia.
Hooking into the GPS stream:
First step was to figure out what type of communication went on between the GPS and the computer. Knowing it was a COM port, I opened HyperTerminal and hooked up to the COM port as in the old dial-up days. Not knowing the nature of the protocol and with a slight reminiscence of my telco days, hooked up and started seeing what I could do. Surprisingly (whew!) the protocol was just an incoming stream with nicely-formatted data and sentence delimiters.
This is what it looks like. Note that with very little squinting patterns and obvious data points start appearing:
The documentation with Streets & Trips about the physical GPS was very little (granted, I'm not the typical audience, but..) and had to look around before finding that the protocol was part of a standard called NMEA (duhh..it was printed on the box). A couple of google searches afterwards, I was in posession of a good document with the full protocol state machine and enough parsing info to get me started. The GPS supports NMEA 2.0 but apparently it hasn't changed much in the basics.
The Visual GPS guys did a great job of explaining the protocol - Thanks Monte Variakojis for the NMEA Parser Design paper & the permission to blink. I'll let you know when I post the code & good luck with your IXMLDOMDocument issues.
Reading COM ports from .NET
The next step was hooking into the COM port stream using .NET. I knew COM ports are treated by Windows as file handles, so it was a matter of writing up some tests for initialize, read and close functions and doing a simple helper to fullfill them (no, there won't be a SerialPortAccess App Block). Here www.pinvoke.net was of invaluable help. I love Wikis, and hopefully my edits left it a little bit more complete than I found it, especially the DCB structure.
Once I had my serial helper up and running, I hooked it up to a simple window and tada! I had my GPS data streaming in and dumping to a textbox. Notice the occasional screwed up sentences. Fortunately the protocol is very robust - i.e. I can ignore bad sentences and move on to the next one.
Parsing the NMEA protocol
The NMEA protocol is quite simple - essentially the data streaming in is in a series of sentences clearly delimited by $GPxxx and \r\n. It has a couple of checksum characters at the end, and all the data in between is comma-delimited in the 1252 code page. My NMEA protocol parser just walks the bytes checking for full sentences and verifying the checksum - once a full sentence is found and verified it is a matter of passing the string over to a specific function that knows how to parse the sentence type. Different sentences have different information - e.g GPGGA has stuff about your location, GPGSV has information about the GPS satellites, and so on.
After passing basic unit tests, and trying out example sentences, the code was ready to parse real data.
Here is my example window with a simple disply of the GPGGA sentences, with my latitude, longitude, altitude and zulu time:
<Digression topic="Model-Driven-testing">
Protocol parsers are a great place to use Model-Driven-Testing, but I lacked the tools or the intent to try it out with this excercise. Model-driven-testing is an approach where you use a model (e.g. a state machine representation) as a verfication tool. You could then write tests against the model, or the model itself can then be used to generate tests. I think there may be promise in the future in this type of tools - you keep the inductive, TDD approach to development, but you use advanced tools to create better tests with better coverage of common and edge conditions.
</Digression>
Displaying Satellite Locations
I set my end-goal to be able to show which GPS satellites are hovering on my head and where - fortunately this is part of the information provided by the device. With elevation (degrees from the horizon) and azimuth (bearing degrees from true north) info I could build this nifty display of the information:
The dots represent satellites - the closer they are to the center, the closer they are to being "right on top" of the receiver. In the picture, the satellite on the top of the outer circle was then very close to the horizon, looking northward from my study.
Integrating it into CAB
Next steps will be integrating this with my own CAB SmartPart as a utility SmartPart. I imagined I could have a SmartPart based on the Streets & Trips control that displays a location provided by a CAB event, and directions from the current latitude and longitude, courtesy of my PhysicalLocation service. But Doh! I left my VPC with my Whidbey + CAB stuff on the external disk @ the office. I guess I'll post the code to GotDotNet or something once I've cleaned it up.
I wouldn't use this code as part of an airplane autopilot :) but if you are interested in this or the CAB just post here. Enjoy!
Links & Resources
MS GPS & Streets+Trips product with the GPS Locator: http://www.microsoft.com/streets/ProductDetails.aspx?pid=001
The not-so-helpful KB article on accessing COM ports: http://support.microsoft.com/default.aspx?scid=kb;en-us;823179&Product=vb6
Essential interop resource - http://www.pinvoke.net/
The best NMEA 0813 description I could find: http://www.visualgps.net/papers/nmeaparser/NMEA%20Parser%20Design.htm