preload
Aug 31

In my pet project Run Smart With Me I decided to use GPS.NET 3.0 to handle the GPS functionality. GPS.NET is an open source project and can be found on CodePlex. My pet project will use the built in GPS device on mobile devices to track speed and distance when working out (running, cycling, skating).

In this post I will explain how I used the GPS.NET in my project.

I copied the following introduction to GPS.NET from CodePlex:

GPS.NET is a formerly commercial .NET component maintained by GeoFrameworks, LLC from 2004 to 2009. In 2009, Jon Person decided to release the full source code of GPS.NET to the public domain for the benefit of the open source development community. This version (3.0) is the latest release which had a short lifespan before being released here on CodePlex. The purpose of this framework is to deliver intuitive real-time GPS functionality with maximum laziness efficiency for all possible computers, mobile devices and NMEA-compliant GPS devices.

First of all you need to download the C# source code of GPS.NET (I downloaded the 3.0.1 version). Extract the downloaded .zip file and you will find the Compact Framework 3.5 Visual Studio Solution file.

GPS.NET depends on another open source project called GeoFramework 2.0 which can also be found on CodePlex. I copied the following introduction to GeoFramework from CodePlex.

This project was formerly a commercial library maintained by the company “GeoFrameworks” for two components it sold (GPS.NET and GIS.NET) from 2004 to 2009. In 2009, Jon Person decided to release the source code for this library in order to assist the open source community. This project contains classes designed to simplify the task of writing Location-Based Services as well as mapping applications. The most frequently used classes in this project are Angle, Latitude, Longitude, and Position. These classes represent coordinates on Earth’s surface and provide functions for calculating distance and bearing to other points on Earth. Other classes such as Speed and Distance encapsulate measurements as well as conversions to other unit types.

Then you need to download the C# source code for GeoFramework (I downloaded the 2.0.1 version). Extract the downloaded .zip file and you will find the Compact Framework 3.5 Visual Studio Solution file that you can use to open the project in Visual Studio. Building this project will give you the GeoFramework.PocketPC.dll that you need to add as a referenced assembly in the GPS.NET project. You will now be able to successfully build your GPS.NET project.

The GeoFramework.Gps.PocketPC.dll you get when building the GPS.NET project and the GeoFramework.PocketPC.dll  you get when building the GeoFramework project needs to be added as a referenced assembly in the project where you are using the functionality from GPS.NET. When this is done you are able to use the wide range of functionality available in the GPS.NET project.

I have created a simple GPS status screen just to show you how to get started using the GPS.NET 3.0 framework. I used this to get to know GPS.NET and I am also using it as an GPS diagnostics tool when developing my pet project. With the Visual Studio designer I created a very simple screen that this example is using.

The following code examples are using the Model View Presenter (MVP) pattern. I will not explain the pattern in this post, but if you want to know more about the MVP pattern you can have a look at a previous post I have written: Using Model-View-Presenter (MVP) pattern in Compact Framework.

I have an interface called IGpsView that will be implemented by the GpsScreen class (view implementation). The IGpsView is a contract with methods that GpsScreen must implement and will be used by the GpsPresenter to pass data on to the view.

IGpsView.cs

using System;

namespace RunSmartWithMe.View
{
    public interface IGpsView
    {
        void InitializeView();
        void DeviceDetected();
        void PositionChanged(TimeSpan updated, string latitude, string longitude);
        void FixQualityChanged(string quality);
        void SatellitesChanged(string satellites);
        void ExceptionOccured(string exceptionMessage);
        void FixAcquired();
        void ConnectionLost();
        void DistanceChanged(double distance);
    }
}

The interface IGpsPresenter will be implemented by the GpsPresenter class. The IGpsPresenter is a contract with methods that GpsPresenter must implement and will be used by the GpsScreen to request data. In this simple example it will only be used to initialize the view.

IGpsPresenter.cs

namespace RunSmartWithMe.Presenter
{
    public interface IGpsPresenter
    {
        void InitializeView();
    }
}

The GpsPresenter is the class where I have placed all the GPS logic and this is were I am actually using the GPS.NET 3.0 framework. Some might say that I should move this logic out of the Presenter, but this is just a simple example so I have kept it all there to make it easier to follow.

In the InitializeGps() the GPS is initialized by creating a NMEA interpreter and hooking event handlers up to the interpreter. GPS.NET 3.0 provides a lot of event handlers but I have only selected a handful for this example. Notice that the Device.BeginDetection() is commented out and that the last two lines in the method is starting a NMEA emulator. This is to be able to emulate a GPS unit on your emulator. FakeGPS does not work for GPS.NET 3.0. If you want to use the built in GPS unit on your device uncomment Device.BeginDetection() and comment out the last two code lines in this method.

The rest of this class is simply methods triggered by the event handlers and most of them are only reading data from the NMEA interpreter and passing this data on to the view to be displayed. The only method I have added a little logic in is the PositionChanged(object sender, PositionEventArgs e) were I am also calculating the distance between the previous position and the new position and sum this up to get the total covered distance.

GpsPresenter.cs

using System;
using GeoFramework;
using GeoFramework.Gps;
using GeoFramework.Gps.Emulators;
using GeoFramework.Gps.IO;
using GeoFramework.Gps.Nmea;
using RunSmartWithMe.View;

namespace RunSmartWithMe.Presenter
{
    public class GpsPresenter : IGpsPresenter
    {
        private readonly IGpsView _currentView;
        private NmeaInterpreter _nmeaInterpreter;
        private Position _position;
        private double _totalDistanceCovered;

        public GpsPresenter(IGpsView view)
        {
            _currentView = view;
            _position = new Position();
            InitializeGps();
        }

        public void InitializeView()
        {
            _currentView.InitializeView();
        }

        private void InitializeGps()
        {
            _nmeaInterpreter = new NmeaInterpreter {AllowAutomaticReconnection = true, IsFixRequired = false};
            _nmeaInterpreter.PositionChanged += PositionChanged;
            _nmeaInterpreter.FixAcquired += FixAcquired;
            _nmeaInterpreter.ConnectionLost += ConnectionLost;
            _nmeaInterpreter.SatellitesChanged += SatellitesChanged;
            _nmeaInterpreter.ExceptionOccurred += ExceptionOccurred;
            _nmeaInterpreter.FixQualityChanged += FixQualityChanged;

            Devices.DeviceDetected += DeviceDetected;

            // Detect GPS device
            //Devices.BeginDetection();

            // Use an emulated GPS device
            var emulatedDevice = new VirtualDevice(new NmeaEmulator());
            _nmeaInterpreter.Start(emulatedDevice);
        }

        private void DeviceDetected(object sender, DeviceEventArgs e)
        {
            if (e.Device.Name.StartsWith("GPS Intermediate Driver"))
            {
                _nmeaInterpreter.Start(e.Device);
                _currentView.DeviceDetected();
            }
        }

        private void PositionChanged(object sender, PositionEventArgs e)
        {
            _totalDistanceCovered += _position.DistanceTo(e.Position).ToMeters().Value;
            _currentView.PositionChanged(DateTime.Now.TimeOfDay, LatitudeAsString(e.Position.Latitude), LongitudeAsString(e.Position.Longitude));
            _position = e.Position;
            _currentView.DistanceChanged(_totalDistanceCovered);
        }

        private static string LatitudeAsString(Latitude latitude)
        {
            return String.Format("Latitude:  {0}°{1}' {2}", latitude.Hours, latitude.DecimalMinutes, latitude.Hemisphere.ToString().Substring(0, 1));
        }

        private static string LongitudeAsString(Longitude longitude)
        {
            return String.Format("Longitude: {0}°{1}' {2}", longitude.Hours, longitude.DecimalMinutes, longitude.Hemisphere.ToString().Substring(0, 1));
        }

        private void FixAcquired(object sender, EventArgs e)
        {
            _currentView.FixAcquired();
        }

        private void ConnectionLost(object sender, ExceptionEventArgs e)
        {
            _currentView.ConnectionLost();
        }

        private void SatellitesChanged(object sender, SatelliteListEventArgs e)
        {
            _currentView.SatellitesChanged(String.Format("Satellites: {0}\n", _nmeaInterpreter.FixedSatelliteCount));
        }

        private void ExceptionOccurred(object sender, ExceptionEventArgs e)
        {
            _currentView.ExceptionOccured(e.Exception.Message);
        }


        private void FixQualityChanged(object sender, FixQualityEventArgs e)
        {
            _currentView.FixQualityChanged(String.Format("Accurate to {0} {1}",
 _nmeaInterpreter.FixPrecisionEstimate.Value.ToString("#.#"), _nmeaInterpreter.FixPrecisionEstimate.Units));
        }
    }
}

The GpsScreen is where the view is implemented and the GpsPresenter is passing data on to this class. For this example the class is very simple and mainly just display the data received from the GpsPresenter in labels.

GpsScreen.cs

using System;
using System.Windows.Forms;
using RunSmartWithMe.Presenter;
using RunSmartWithMe.View;

namespace RunSmartWithMe.Screens
{
    public partial class GpsScreen : Form, IGpsView
    {
        public delegate void MethodInvoker();

        private GpsPresenter _gpsPresenter;

        public GpsScreen()
        {
            InitializeComponent();
        }

        private void GpsScreenLoaded(object sender, EventArgs e)
        {
            if (_gpsPresenter == null)
            {
                _gpsPresenter = new GpsPresenter(this);
                _gpsPresenter.InitializeView();
            }
        }

        public void InitializeView()
        {
        }

        public void DeviceDetected()
        {
            BeginInvoke(
                new MethodInvoker(() => _lblStatus.Text = "Acquiring fix..."));
        }

        public void PositionChanged(TimeSpan updated, string latitude, string longitude)
        {
            BeginInvoke(new MethodInvoker(delegate()
                {
                       _lblPositionUpdated.Text = "Position Updated: " + updated;
                       _lblLatitude.Text = latitude;
                       _lblLongitude.Text = longitude;
                }))
                ;
        }


        public void FixQualityChanged(string quality)
        {
            BeginInvoke(
                new MethodInvoker(() => _lblAccuracy.Text = quality));
        }

        public void SatellitesChanged(string satellites)
        {
            BeginInvoke(
                new MethodInvoker(() => _lblSatellites.Text = satellites));
        }


        public void ExceptionOccured(string exceptionMessage)
        {
            BeginInvoke(
                new MethodInvoker(() => MessageBox.Show(exceptionMessage, "NMEA Error")));
        }

        public void FixAcquired()
        {
            BeginInvoke(
                new MethodInvoker(() => _lblStatus.Text = "Fix acquired"));
        }

        public void ConnectionLost()
        {
            BeginInvoke(
                new MethodInvoker(() => _lblStatus.Text = "Connection lost"));
        }

        public void DistanceChanged(double distance)
        {
            BeginInvoke(
                new MethodInvoker(() => _lblDistanceCovered.Text = String.Format("{0:0.## meters}", distance)));
        }
    }
}

If you just need simple GPS functionality you can consider using the GPS Intermediate Driver from managed code. You can read in a previous post of mine how to do that: The easiest way to develop and debug Windows Mobile GPS application. I recommend using GPS.NET 3.0 if you are planning a more advanced GPS application. With this framework you have a lot of functionality available (also graphics) and algorithms for calculations are more sophisticated.

Follow me on twitter @PerOla

Share & enjoy
You can subscribe to my comments feed to keep track of new comments.

15 Comments to “Using open source project GPS.NET 3.0”

  1. Marcelo says:

    Where this class Position at line 15 in GpsPresenter class?
    thanks!

  2. Hi Marcelo.
    The Position class is a part of the GeoFramework and is a struct found in GeoFramework.Position

    You need the GeoFramework.PocketPC.dll to use the GeoFramework.Position. In the start of this post I explain how to download the GeoFramework and how to compile it in order to get the GeoFramework.PocketPC.dll

  3. Sachin says:

    hi sur,
    Actually i am an final year B.E student and planned to build GPS base project but i am not able to get how to take maps in .net will you please help me out and also i want make Advt through GPS any idea or information abt source code plz give me..
    Plz Reply me…

  4. Hi Sachin,
    I’m afraid that I can’t help you. I have never used maps in .net cf applications. Good luck with your project and studies.

  5. Matthew says:

    Hi,
    How can I stop positioning?
    I use _nmeaInterpreter.Dispose(); in private void FixAcquired
    however when I start positioning again, it’s not possible, showed NMEA Error.

    Please help :)
    Thanks for lot

  6. Hi Matthew,
    To stop positioning I am using the following method:
    public void StopGps()
    {
    _nmeaInterpreter.Stop();
    _gpsDevice.Reset();
    }

    _gpsDevice is an emulated GPS device created in my InitializeGPS method:
    _gpsDevice = new VirtualDevice(new NmeaEmulator());

    To start positioning again I have the following method:
    public void StartGps()
    {
    if (_gpsDevice != null)
    {
    _nmeaInterpreter.Start(_gpsDevice);
    }
    }

    I hope this will help you.

  7. Matthew says:

    Per Ola Sather thanks for help :)

    However I don’t know how use this method.
    Ok, I write this method in GpsPresenter.cs.
    How use this in .cs my Form ? (Form1.cs)

    I try:
    private void GpsScreenLoaded(object sender, EventArgs e)
    {
    if (Form1.Dane.gps == true)
    {
    _gpsPresenter = new GpsPresenter(this);
    _gpsPresenter.StartGps();
    }
    else
    {
    Form1.Dane.gps = true;
    if (_gpsPresenter == null)
    {
    _gpsPresenter = new GpsPresenter(this);
    _gpsPresenter.InitializeView();

    }
    }

    }

  8. I don’t know if I understand your question Matthew, but I’ll try to answer it anyway.

    If you are using the four classes shown in this post the GpsScreen class is your Form.

    The GpsScreenLoaded is trigged by an EventHandler, add the following code line in GpsScreen.Designer.cs to have the GpsScreenLoaded method called when your screen is loaded:
    this.Load += new System.EventHandler(this.GpsScreenLoaded);

    In the GpsScreen I have added a Start/Stop button and a method for toggle between starting and stopping the GPS positioning:

    private void BtnToggleSessionClicked(object sender, EventArgs e)
    {
    if (_isGpsStarted)
    {
    _gpsPresenter.StopGps();
    _btnToggleSession.Text = “Start GPS”;
    }
    else
    {
    _gpsPresenter.StartGps();
    _btnToggleSession.Text = “Stop GPS”;
    }
    _isGpsStarted = !_isGpsStarted;

    }

    That is the way I am using the StartGps() and StopGps() located in the GpsPresenter. If you are using this architecture you must add these methods in the IGpsPresenter:
    void StartGps();
    void StopGps();

    Good luck with your GPS app

  9. Matthew says:

    I don’t understand this method.
    What’s: _gpsDevice = new VirtualDevice(new NmeaEmulator()); ?
    I use hardware GPS, no virtual.
    When i press Stop GPS: “Nmea don’t stop”

    I have no more ideas :(

    Once again:
    I have form with button “Start GPS”
    When i press it: run GpsScreenLoaded
    When position is fixed: run is StopGPS
    When i press it again: run is StartGPS
    When position is fixed: run is StopGPS

    Sory for my English :)

  10. The virtual device is just what I use when testing the application from emulator.
    When you run on a device with GPS HW remove the new VirtualDevice line and add this instead:
    Devices.DeviceDetected += DeviceDetected;
    // Detect GPS device
    Devices.BeginDetection();
    You also need the DeviceDetected method:
    private void DeviceDetected(object sender, DeviceEventArgs e)
    {
    if (e.Device.Name.StartsWith(“GPS Intermediate Driver”))
    {
    _gpsDevice = e.Device;
    _currentView.GpsStatusChanged(GpsStatus.Detected);
    }
    }

    You should not run GpsScreenLoaded when you press Start GPS, this method should only be run once when the screen is done loading.

  11. Matthew says:

    This is it!!!
    There was a lack of lines:
    _gpsDevice = e.Device;
    in the method:
    private void DeviceDetected

    Very very thanks Per Ola Sether :)

  12. No problem Matthew, I’m just glad that I could help you :)

  13. Brajesh Kumar Singh says:

    When I run this code on Trimble Juno SA Windows 6.1 device. Which has GPS enabled.
    It doesn’t work not even detected the device.
    With emulator and FAKE GPS its working fine.
    I have also uncommented the below code, anythis else I have to do

    // Detect GPS device
    Devices.BeginDetection();
    // Use an emulated GPS device
    //var emulatedDevice = new VirtualDevice(new NmeaEmulator());

    047

    _nmeaInterpreter.Start(emulatedDevice);

  14. Hi Brajesh,

    I wish I could help you but this post was written more than two years ago and I don’t have this project available any more. I would guess that the device you are using have some kind of special handling regarding GPS.

    Good luck!

  15. riyas says:

    so useful…
    thank u so much…

No Pingbacks to “Using open source project GPS.NET 3.0”

Leave a Reply

Subscribe to my comments feed

Subscribe to my feeds Follow me on Twitter
DZone MVB