Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Program a Windows Mobile GPS Device using the Intermediate Driver

The intermediate driver enables multiple applications to use the GPS receiver hardware at the same time.


advertisement
A couple weeks back I was highly influenced by a small-map-based GPS (Global Positioning System) application, developed using C#, targeting windows mobile devices. Embedded GPS receivers are becoming a standard for mobile devices, and all recent Windows Mobile devices feature GPS receivers. Windows mobile users can also add third-party GPS receivers to their devices if needed.

These GPS receivers collect data from satellites, specifically latitude, longitude, altitude, speed, and direction data from four different satellites. Mobile GPS receivers refresh collected data every second and display your present location on the Microsoft MapPoint, a powerful data-mapping tool. Your location is calculated using a mathematical formula called three-dimensional trilateration, which uses the positions of the satellites and their distance from Earth.

[login]

GPS Intermediate Driver



Any GPS-customized application written by a mobile developer can directly interact with GPS receivers (the hardware) using the COM port, serial port, or Bluetooth. But for most GPS receivers, only one application can directly interact with it at a time if it is using the COM port, serial port, or Bluetooth.

This problem can be solved by using the GPS intermediate driver -- GPSID and corresponding GPSAPI layer -- which enables multiple applications to use the GPS receiver hardware at the same time. Another advantage developers get by using the intermediate driver is they don't need to parse the NMEA strings received from the GPS receiver. The intermediate layer itself contains APIs to purse NMEA strings in a readable format. Using this intermediate driver layer, developers can also write code that works with any GPS receiver. In this article I will show you how Windows Mobile developers can use the GPS intermediate driver layer to write GPS-based applications.

Develop GPS Apps Using Intermediate Driver Layer

The GPS intermediate driver layer is exposed through a library (a Windows dll file). You can access that library from C# managed code. With installation of Microsoft mobile DTK version 6.5, a sample GPS class library-type solution gets copied on your local machine (C:\Program Files\Windows Mobile 6.5.3 DTK\Samples\PocketPC\CS\GPS path). By referring this sample project dll to your source code, you can access the intermediate driver layer library and APIs to develop a customized GPS application for your Windows Mobile device.

This sample application contains the following classes.

GPS -- This class is used to manage GPS intermediate driver API's. Developer can create instance of this class to open, close, query the device state and to query the device position data from GPS receiver hardware. All These functionalities are achieved by importing gpsapi.dll and coredll.dll. Following are the list native intermediate driver function calls to achieve these functions.

[DllImport("gpsapi.dll")] static extern IntPtr GPSOpenDevice(IntPtr hNewLocationData, IntPtr hDeviceStateChange,
string szDeviceName, int dwFlags);        [DllImport("gpsapi.dll")]        static extern int  GPSCloseDevice(IntPtr hGPSDevice);        [DllImport("gpsapi.dll")]  static extern int  GPSGetPosition(IntPtr hGPSDevice, IntPtr pGPSPosition, int      dwMaximumAge, int dwFlags);        [DllImport("gpsapi.dll")]        static extern int  GPSGetDeviceState(IntPtr pGPSDevice);        #endregion        #region PInvokes to coredll.dll        [DllImport("coredll.dll")]        static extern IntPtr CreateEvent(IntPtr lpEventAttributes, int bManualReset, int        bInitialState, StringBuilder lpName);        [DllImport("coredll.dll")]        static extern int CloseHandle(IntPtr hObject);        const int waitFailed = -1;        [DllImport("coredll.dll")]        static extern int WaitForMultipleObjects(int nCount, IntPtr lpHandles, int fWaitAll,        int dwMilliseconds);        const int eventSet = 3;        [DllImport("coredll.dll")]        static extern int EventModify(IntPtr hHandle, int dwFunc);

GpsDeviceState -- To get the present GPS receiver device state, this class is used.

GpsPosition -- Class contains GPS position data received from the GPS receiver hardware. This class uses following GPS_VALID_ driver constrains.

internal static int GPS_VALID_UTC_TIME = 0x00000001;        internal static int GPS_VALID_LATITUDE = 0x00000002;        internal static int GPS_VALID_LONGITUDE = 0x00000004;        internal static int GPS_VALID_SPEED = 0x00000008;        internal static int GPS_VALID_HEADING = 0x00000010;        internal static int GPS_VALID_MAGNETIC_VARIATION = 0x00000020;        internal static int GPS_VALID_ALTITUDE_WRT_SEA_LEVEL = 0x00000040;        internal static int GPS_VALID_ALTITUDE_WRT_ELLIPSOID = 0x00000080;        internal static int GPS_VALID_POSITION_DILUTION_OF_PRECISION = 0x00000100;        internal static int GPS_VALID_HORIZONTAL_DILUTION_OF_PRECISION = 0x00000200;        internal static int GPS_VALID_VERTICAL_DILUTION_OF_PRECISION = 0x00000400;        internal static int GPS_VALID_SATELLITE_COUNT = 0x00000800;        internal static int GPS_VALID_SATELLITES_USED_PRNS = 0x00001000;        internal static int GPS_VALID_SATELLITES_IN_VIEW = 0x00002000;        internal static int GPS_VALID_SATELLITES_IN_VIEW_PRNS = 0x00004000;        internal static int GPS_VALID_SATELLITES_IN_VIEW_ELEVATION = 0x00008000;        internal static int GPS_VALID_SATELLITES_IN_VIEW_AZIMUTH = 0x00010000;        internal static int GPS_VALID_SATELLITES_IN_VIEW_SIGNAL_TO_NOISE_RATIO = 0x00020000;

Utils -- This class is referred for memory allocation and de allocation functionality using coredll.dll. Following are the native intermediate driver function calls for allocation and de allocation of memory.

public const int LMEM_ZEROINIT = 0x40; [System.Runtime.InteropServices.DllImport("coredll.dll", EntryPoint = "#33", SetLastError = true)]        public static extern IntPtr LocalAlloc(int flags, int byteCount); [System.Runtime.InteropServices.DllImport("coredll.dll", EntryPoint = "#36", SetLastError = true)]        public static extern IntPtr LocalFree(IntPtr hMem);

DeviceStateChangedEventArgs and LocationChangedEventArgs classes are used for device state change and location change events.

If you are using an external GPS receiver with Windows Mobile check the following MSDN article to configure your third party receiver http://msdn.microsoft.com/en-us/library/bb158600.aspx. Also you need to configure GPS intermediate driver before executing GPS application. Follow the steps mentioned in this MSDN article http://msdn.microsoft.com/en-us/library/bb202069(v=MSDN.10).aspx to configure your driver.

After all configuration settings I have created a device type project using visual studio 2008 and selected windows mobile SDK version 6.5 as execution framework. Also Added reference of Microsoft.WindowsMobile.Samples.Location.dll (GPS sample library provided by Microsoft) to my device project for using GPS intermediate driver layer. To retrieve GPS receiver location details I have created an instance of GPS class and opened the GPS receiver device by calling open method. To display GPS longitude, latitude and heading details I have created a GPS position object in gps_LocationChanged event and displayed in a label. Following code snipped explains in details.

using System; using System.Linq; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using Microsoft.WindowsMobile.Samples.Location; namespace GPSApplication    {        public partial class GPSData : Form        {        private Gps objgps;        public GPSData ( )            { objgps.DeviceStateChanged += new DeviceStateChangedEventHandler ( gps_DeviceStateChange ); objgps.LocationChanged += new LocationChangedEventHandler ( gps_LocationChanged );            InitializeComponent ( );            objgps = new Gps ( );            objgps.Open ( );            }        private void menuGPSExit_Click ( object sender, EventArgs e )            {            objgps.Close ( );            Close ( );            } private void gps_LocationChanged ( object sender, LocationChangedEventArgs args )                    {            GpsPosition position = objgps.GetPosition ( );            string Latitude = string.Empty;            string Longitude= string.Empty;            string Heading =string.Empty;            if ( position.LatitudeValid )                Latitude = position.Latitude.ToString ( );            if ( position.LongitudeValid )                Longitude = position.Longitude.ToString ( );            if ( position.HeadingValid )                Heading = position.Heading.ToString ( );            StringBuilder strdisplay = new StringBuilder ( );            strdisplay.AppendLine ( );            strdisplay.Append ( "GPS Latitude = " );            strdisplay.AppendLine ( Latitude );            strdisplay.Append ( "GPS Longitude = " );            strdisplay.AppendLine ( Longitude );            strdisplay.Append ( "GPS Heading = " );            strdisplay.AppendLine ( Heading );            lbldisplay.Text = sb.ToString ( );            }        }    }

Next to get device state I have added following code snipped in gps_DeviceStateChange event.

private void gps_DeviceStateChange ( object sender, DeviceStateChangedEventArgs args )              {               GpsDeviceState device = args.DeviceState;               StringBuilder strdisplay = new StringBuilder ( );   strdisplay.AppendLine ( );   strdisplay.Append ( "Device Name = " );   strdisplay.Append (device.FriendlyName.ToString ( ));   strdisplay.Append ( "Device State = " );   strdisplay.Append (device.DeviceState.ToString ( ));   strdisplay.Append ( "Service State = " );   strdisplay.Append (device.ServiceState.ToString ( ));               lbldevicedisplay.Text = sb.ToString ( );                                           }

When mobile user minimizes GPS application or another application supersedes GPS application on the screen then the GPS application goes to background. We can minimize the processing of GPS background application by unsubscribing gps_LocationChanged and gps_DeviceStateChange events. Application that executes in the background saves battery life. By adding following code snipped in the winform deactivate event I have restricted my application not to process GPS data when application is in background.

private void GPSData_Deactivate(object sender, EventArgs e)        {            if ( objgps.Opened )              {                    objgps.DeviceStateChanged -= gps_DeviceStateChange;                    objgps.LocationChanged -= gps_LocationChanged;              }        }        

I have again subscribed gps_LocationChanged and gps_DeviceStateChange in winform activate event so that GPS application can process GPS data when the application is activated again.

private void GPSData_Activated(object sender, EventArgs e)        {            if ( objgps.Opened )              {                    objgps.DeviceStateChanged += gps_DeviceStateChange;                    objgps.LocationChanged += gps_LocationChanged;              }        }

Conclusion

GPS intermediate drivers are backward compatible and the future of GPS mobile application development. While testing your GPS application in Windows Mobile, you need emulators to run an instance of FakeGPS. This tool simulates GPS receiver hardware and transfers position data using a text file.


   
Tapas Pal is a Microsoft Platform technical professional with Tata Consultancy Services, India. He has with seven years of experience, holds Microsoft certifications in .NET 1.1 and .NET 2.0.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap