This week, I'm leading the Mobility Metro this week in Cincinnati. During one of the labs, I had the opportunity to start looking at querying the GPS on my BlackJack II. And then this evening, I had time to dig in more. This is very cool stuff. Here's what I've done so far.
Connect my BlackJack II device to Visual Studio 2008
There's probably some cool way to do this, but to unlock my device enough for VS to connect, there are a couple of not well documented steps. Note, this is specific to Windows Standard (i.e. Smartphone). These devices usually come with a more locked down setup.
- Connect the device via ActiveSync or Windows Mobile Device Center (Vista). Sorry for the obvious.
- Copy the Certs.CAB file into the Temp folder on the device. On the device, click on the file to launch install. Reboot the device. This file is located in C:\Program Files (x86)\Windows Mobile 6 SDK\Tools\Security\SDK Development Certificates. (Omit the x86 path if you're not running 64 bit.)
- Copy the SecurityOff.CPF into the Temp folder on the device. Launch on the device. Reboot. This file is located in C:\Program Files (x86)\Windows Mobile 6 SDK\Tools\Smartphone\SecurityConfiguration.
- Now you can connect in Visual Studio. (Make sure to choose "device", not one of the emulator options.
- Test this to make sure.
Now, we need a way to talk to the GPS.
Querying the GPS
So, (the official way that Microsoft employees start informative statements), I need a GPS API that I can access from the .NET Compact Framework. How do I get there? If you looked at .NET Compact Framework 2.0 or 3.5, you would be disappointed. One of the features touted in WM5 launch days was the new GPS Intermediate Driver. This driver has several special capabilities, including allowing multiple applications to talk to GPS simultaneously (or, I should really say listen simultaneously). The problem with this GPS setup is that there is no managed GPS classes. That's a problem, because there's a lot happening in this GPS API in Windows Mobile.
So, refer to the Day 2 module in the Mobility Metro lab, and what does it say: "MANAGED GPS". That's right. Where is this Managed GPS stuff at?
The WM6 SDK has a managed code sample, in the C:\Program Files (x86)\Windows Mobile 6 SDK\Samples\Smartphone\CS, called GPS. Originally, this showed up in the WM5 SDK. Anyway, this is a C# solution, named GPS, and comes with two projects, 1) GPS, a .NET CF application project, and 2) a child project that is the managed wrapper of the GPS Intermediate Driver interface. So, kudo's who designed the solution this way so that someone can easily re-use in other applications. The library is namespace'd as Microsoft.WindowsMobile,Samples.Location (note the namespace on the slide, which might make you believe this is in the .NET Compact Framework).
So, I open up the project, compile, deploy, and debug. Interesting stuff. I've got .NET code receiving GPS events on a device. Cooooool!!!!!
Now, there are a couple of issues to deal with. First, I get a random error out of a function - which happens to be without a Try/Catch block, so I'll have to look into that. It's sporadic so that even makes it more fun.
Second, you will need to utilize some patience waiting for the GPS chipset to find a set of satellites to start listening to. Once you get connected, you're fine as long as some app is talking to the satellites.
Third, there's a lot going on in the API. Fortunately, this sample does a good jump of showing a fairly rich implementation of working with the GPS driver. It's not for the faint of heart since there are plenty of marshaling attributes, P/Invokes to Win32 land like WaitForObject, calls to LocalAlloc and LocalFree (man, I love managed code), and working with Windows handles; however, they hide that pretty well from the UI code. It is interesting what the application does. In the wrapper, they create a background thread that receives the GPS events, basically reacting to position change events and satellite state change events. They nicely call Control.Invoke in order to do the UI updates on the main thread. Good stuff, mostly.
After looking at this application, I'm ready to start understanding what I can do with what is exposed to me in the managed wrapper. The display is a text windows showing a concatenated string of properties from a GPS_POSITION (native structure is converted to a .NET class), and only a few interesting properties are shown like Latitude and Longitude. But what are these other properties?
When I start looking at the GPS_POSITION properties exposed by the GPS Intermediate Driver (note in the slide above), I can see that I need some more understanding of GPS workings. One good source that is a sorta short read is the Wikipedia page for GPS. They have a little history, some inner-workings, some definitions that will fill in a few blanks in the GPS_POSITION structures, and resource links to bunches more. I had no idea that there were so many GPS satellites in the sky (30+, although you only need 3-4 for decent accuracy).
You can see some information about Assisted GPS (A-GPS), which is the ability to triangulate location based on cell towers, part of the E911 initiatives from the U.S. government. This capability is used in several mapping applications, like our Live Search for Mobile, which uses this to find the appropriate satellites faster.
Another interesting but useless fact: "Following the shooting down of Korean Air Lines Flight 007 in 1983, President Ronald Reagan issued a directive making the system available for free for civilian use as a common good..." I'm not a history buff, but sometimes I find some things that just grab my attention.
For me, the main thing in this reading was to get a little background understanding of the properties in the GPS structures. Example, what is a PRN, why does a satellite return "satellite time", etc.
My Additions to the GPS project
- I removed some properties that were redundantly displayed. I don't need to see Latitude/Longitude display several ways.
- Took out formatting, specifically too many line feeds. On the BlackJack, some of the sample data was displayed off the screen below.
- Added Altitude. Also note that you should check the AltitudeValid property before displaying this information.
- Also did similar additions with Heading (as well as ValidHeading check), and Speed (and ValidSpeed). Note that if you're not moving in the beginning of listening to the GPS reciever events, you will not get this information - as in the picture below. On the flip side, after moving for a while and then stopping, I continued to get these properties sent for a time. I know my wife will like to have this data when she is doing her speed walking.
- Here's a work-around for the sporadic error that I'm getting from the managed wrapper code. In the client application, the main function that is called when different GPS events fire is the UpdateData method in Form1. I added a Try/Catch block to trap the error, display it in the textbox, and keep on moving. The error only happens once in a while.
- I found that one of the culprit exceptions is in the GpsPosition::GetSatellitesInSolution method. Early in that method, an array (inViewSatelites) is returned from a called function (GetSatellitesInView), and the code expects it to always come back with data (and blows up when a NULL object is returned). Easy to fix, but not sure of the underlying issue.
- I ended up with a display like this, that's good enough for today's learning.
Hope this helps you get started with adding location data to your applications. I'll have more posts on my potential usage of this in the future.
I'm certainly am glad to have a open platform that allows me to easily code a mobile application, easily deploy to a device, and enjoy it today.