After numerous mishaps with my lappy and Outlook in the last two days, I am finally ready to pass you the code for the LocateMe Client… ?
I have decided to use the Smartphone as the choice of client today, but the Pocket PC will be able to do the same using the same code.
Part of this application runs using an Assembly that was written by Jim Wilson. His name will ring a few bells in the Windows Mobile arena as he is a member of the OpenNetCF team and has been an MVP for Windows Mobile dev since it started… (i.e. He’s a bit good)
He has given us the opportunity to use this assembly and the source code for it. So visit to his blog and say thanks
LocateMe for Smartphone (Source)
OK to start with you need to add a reference to the GPSReader assembly and the Web Service that you built the other day…
Once that is in place, we can add them into the code…
using GPSExample.Util;
using OpenNETCF.Win32;
As you can see I have also used the OpenNETCF.Win32 assembly too. This is to get the user name from the device, but this will become clearer later.
private GPSReader _gpsReader = new GPSReader();
private Timer _timer = new Timer();
private string _deviceID = null;
Declare a new GPSReader a Timer for timing uploads and a string to hold the device id, but I guess you gathered that already :)
In the designer I racked up a few labels… I have added the following;
- lblLon;
- lblLonDirection;
- lblLatDirection;
- lblLat;
- lblTime;
- lblNumSats;
- lblQuality;
- lblFixType;
- lblBearing;
- lblStatus;
I also added these as static labels.
- Quality;
- GPSSats;
- Fixtype;
- Bearing;
But it’s up to you what if any labels you can put on there… I have just because I can stare at Lat/Lon’s coming down form the GPS unit all day (GEEK – Ed)
I’ve also added some menu items.
- miUpload;
- miGPS;
- miExit;
- miSeperator;
- miStart;
- miStop;
But again, ‘tis upta you…
// Create the Tick event.
_timer.Tick += new EventHandler(_timer_Tick);
// Set the interval to 60000 (1 Minute)
_timer.Interval = 60000;
// Open a registry key to retrieve the Name from the Owner Information using the OpenNETCF.
RegistryKey registryKey = OpenNETCF.Win32.Registry.CurrentUser.CreateSubKey("ControlPanel\\Owner");
// Set it to the _deviceID, but you can read right!
_deviceID = (string)registryKey.GetValue("Name");
// With the instance of the GPSReader set "new" it and set it to read from COM7 port
// with a baud rate of 38400. Now these are set for the C500 Smartphone, you may need
// change them to your phone's configuration.
_gpsReader = new GPSReader("COM7:", 38400) ;
// Attach to GPSReader Events
_gpsReader.OnGPSMessage += new GPSEventHandler(_gpsReader_OnGPSMessage);
_gpsReader.OnGPSReadStart += new EventHandler(_gpsReader_OnGPSReadStart);
_gpsReader.OnGPSReadStop +=new EventHandler(_gpsReader_OnGPSReadStop);
/// <summary>
/// This event is called everytime a GPS sentence is received by the GPSReader.
/// </summary>
/// <param name="sender"></param>
/// <param name="arg"></param>
private void _gpsReader_OnGPSMessage(object sender, GPSEventArgs arg)
{
// Update the appropriate screen labels based on the message type.
switch(arg.MessageType)
{
case "GPGGA":
lblTime.Text = ((int)arg.Time).ToString("D6");
// Show only whole time value
lblLat.Text = arg.Lat.ToString("F6");
// Show exactly 6 decimal places
lblLatDirection.Text = arg.LatDirection;
lblLon.Text = arg.Lon.ToString("F6") ;
// Show exactly 6 decimal places
lblLonDirection.Text = arg.LonDirection ;
lblNumSats.Text = arg.NumSats.ToString() ;
lblQuality.Text = arg.Quality.ToString() ;
break;
case "GPGSA":
lblFixType.Text = arg.FixType.ToString() ;
break;
case "GPRMC":
lblBearing.Text = arg.Bearing.ToString() ;
break;
case "GPVTG":
lblBearing.Text = arg.Bearing.ToString() ;
break;
}
}
Fairly straight forward that one, but if you want to know more about what the different GPS message types are look here.
/// <summary>
/// This is not required that your code handle this event. It simply provides a confirmation
/// that the reading process has actually begun
/// </summary>
/// <param name="sender"></param>
/// <param name="arg"></param>
private void _gpsReader_OnGPSReadStart(object sender, EventArgs arg)
{
lblStatus.Text = "Read Started - Mode: " + _gpsReader.ActiveReadMode.ToString() ;
}
/// <summary>
/// Also is not required that your code handle this event. It simply provides a notification
/// that the read loop is shutting down. The event fires whether the thread terminated because
/// of a call to StopRead or if an error occured.
/// </summary>
/// <param name="sender"></param>
/// <param name="arg"></param>
private void _gpsReader_OnGPSReadStop(object sender, EventArgs arg)
{
lblStatus.Text = "Read Stopped" ;
}
That’s the GPSReader dealt with… Hard wasn’t it :p
Now the usual stop/start click events…
lblStatus.Text = "Read Starting..." ;
_gpsReader.StartRead();
and
lblStatus.Text = "Read Stopped." ;
_gpsReader.StopRead();
The exit event should have a call to stop the GPS read or it’ll hang…
miStop_Click(sender, e);
Application.Exit();
Now on its own you should be able to run that code and see the GPS messages coming down your and being shown on your phone, which in my book is cool on its own. But we want to send those parsed sentences to the web service.
So let’s wire in the Upload Click event;
private void miUpload_Click(object sender, System.EventArgs e)
{
// If we are uploading already stop it.
if(_timer.Enabled)
{
miUpload.Text="Upload";
_timer.Enabled = false;
}
// Set the uploading running.
else
{
lblStatus.Text="Uploading";
miUpload.Text="Stop";
_timer.Enabled = true;
uploadLocation();
}
}
private void _timer_Tick(object Sender, EventArgs e)
{
// every 60000 ticks (1 min)
uploadLocation();
}
// Now I’m breaking rules here BIG BAD rules of not doing things
// like threading and best practices with the UI, but hey I
// don’t want you to be scared I want you to go out there and
// use this.
private void uploadLocation()
{
string lat = lblLat.Text;
string latDirection = lblLatDirection.Text;
string lon = lblLon.Text;
string lonDirection = lblLonDirection.Text;
// Call the Upload location Web Service
LocateMeWS.LocateMe lm = new LocateMeWS.LocateMe();
if(lm.StoreLocation(_deviceID,lat,latDirection,lon,lonDirection))
{
lblStatus.Text="Location Uploaded";
}
else
{
lblStatus.Text="Not Uploaded";
}
}
Yep, as simple as that!
Enjoy.