Showing posts with label GPS. Show all posts
Showing posts with label GPS. Show all posts

September 7, 2008

GPS Serial Port Provider

For the actual serial port provider we have a base class. This takes care of all the serial port side of things
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;

namespace GpsTest
{
  public abstract class SerialPortGpsProviderBase : IGpsDataProvider
  {
    /// <summary>
    /// Fire this event when A GPS line of data has been received
    /// </summary>
    public event GpsDataReceivedEventHandler GpsDataReceived;

    #region Attributes

    protected SerialPort comPort = new SerialPort();

    #endregion

    public SerialPortGpsProviderBase()
    {
    }

    ~SerialPortGpsProviderBase()
    {
      Dispose(false);
    }

    #region IDisposable Members

    private bool m_disposed = false;

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (!m_disposed)
      {
        if (disposing)
        {
          // Dispose managed resources
        }

        // Dispose unmanaged resources
        comPort.Dispose();
      }
      m_disposed = true;
    }

    #endregion

    public bool IsOpen()
    {
      return comPort.IsOpen;
    }

    public void Open()
    {
      //set up the delegate used to read data in.......
      comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);

      try
      {
        //finally open the port....
        comPort.Open();
        Trace.WriteLine("Com port " + comPort.ToString() + " Open=" + comPort.IsOpen.ToString());
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now.ToString() + 
           ": Failed to open COM port with exception: " + ex.Message);
      }
    }

    protected abstract void comPort_DataReceived(object sender, 
            SerialDataReceivedEventArgs e);

    protected void FireGpsDataReceived(string data)
    {
      try
      {
        if ((data.Length > 0) &&
            (GpsDataReceived != null))
        {
          GpsDataReceived(this, new GpsDataLineEventArgs(data));
        }
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now + 
            ": Failed to extract GPS data in comPort_DataReceived: " +
             ex.Message);
      }
    }


    public void Close()
    {
      try
      {
        //check we have a valid COM port to close...
        if (comPort.IsOpen)
        {
          comPort.Close();
          Debug.WriteLine("Com port " + comPort.ToString() + " CLOSED");
        }
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now.ToString() + 
                ": Failed to close COM port with exception: " +
                ex.Message);
      }
    }
  }

}

The actual provider just implements the code to read the data and parse it
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;

namespace GpsTest
{

  // First simple provider 
  public class GpsSerialPortDataProvider : SerialPortGpsProviderBase
  {
    #region Attributes

    private const string comPortName = "COM14"; 
    private const int baudRate = 4800;

    #endregion

    public GpsSerialPortDataProvider()
    {
      //set up the com port settings.....
      comPort.PortName = comPortName;
      comPort.BaudRate = baudRate;
      comPort.Parity = Parity.None;
      comPort.StopBits = StopBits.One;
      comPort.DataBits = 8;
      comPort.Handshake = Handshake.None;
      comPort.ReadTimeout = 1000;
      comPort.NewLine = "\r\n";
    }

    ~GpsSerialPortDataProvider()
    {
      Dispose(false);
    }

    protected override void comPort_DataReceived(
      object sender, 
      SerialDataReceivedEventArgs e)
    {
      //Read a line of GPS data (each is sent with a \r\n at the end)
      try
      {
        string data = comPort.ReadLine();
        FireGpsDataReceived(data);
      }
      catch (System.Exception ex)
      {
        Trace.WriteLine(DateTime.Now + 
          ": Failed to extract GPS data in comPort_DataReceived: "
          + ex.Message);
      }
    }

  }

}
Due to a driver fault on the device we were using we could not read the data a line at a time. We had to clear the buffer out every time we read it, so here is the alternative provider
using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Diagnostics;

namespace GpsTest
{

public class GpsSerialPortDataProvider3 : SerialPortGpsProviderBase
{

  #region Attributes

  private const string comPortName = "COM14";
  private const int baudRate = 4800;

  #endregion

  public GpsSerialPortDataProvider3()
  {
    //Setup the COM port
    comPort.PortName = comPortName;
    comPort.BaudRate = baudRate;

    //set up the other settings.....
    comPort.Parity = Parity.None;
    comPort.StopBits = StopBits.One;
    comPort.DataBits = 8;
    comPort.Handshake = Handshake.None;
    comPort.ReadTimeout = 1000;
    comPort.ReceivedBytesThreshold = 256;
  }

  ~GpsSerialPortDataProvider3()
  {
    Dispose(false);
  }

  private string buffer = "";
  private object bufferLock = new object();

  protected override void comPort_DataReceived(object sender, 
           SerialDataReceivedEventArgs e)
  {
    //Read a line of GPS data (each is sent with a \r\n at the end)
    try
    {
      // Read out everything in the buffer
      string data = comPort.ReadExisting();
      if (data.Length > 0)
      {
        string ready = string.Empty;
        lock (bufferLock)
        {
          buffer += data;
          // Do we have any complete lines in the buffer
          int ix = buffer.LastIndexOf("\r\n");
          if (ix >= 0)
          {
            // Remove all the complete lines
            ready = buffer.Remove(ix);
            // Truncate the buffer any incomplete data at the end
            buffer = buffer.Remove(0, ix + 2);
          }
        }
        if (ready.Length > 0) // found some complete lines
        {
          // Extract them
          string[] lines = ready.Split(new string[] { "\r\n" },
               StringSplitOptions.RemoveEmptyEntries);
          foreach (string line in lines)
          {
            // Invoke the GpsDataReceived event with the complete line
            FireGpsDataReceived(line);
          }
        }

      }
    }
    catch (System.Exception ex)
    {
      Trace.WriteLine(DateTime.Now.ToString() + 
           ": Failed to extract GPS data in comPort_DataReceived: " +
            ex.Message);
    }
  }

}

}

GPS Monitoring Test Provider

Here is a test provider
using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;
using System.Diagnostics;
using System.IO;

namespace GpsTest
{
  class GpsTestProvider : IGpsDataProvider, IDisposable
  {
    Timer timer = new Timer();
    int index = 0;
    string[] sampleData = new string[]
      {
          "$GPRMC,135150.000,A,5106.7058,N,00123.8886,W,4.07,192.74,250808,,,A*74",
          "$GPRMC,135151.000,A,5106.7044,N,00123.8903,W,4.75,210.87,250808,,,A*74",
          "$GPRMC,135152.000,A,5106.7037,N,00123.8916,W,3.52,212.41,250808,,,A*7D",
          "$GPRMC,135153.000,A,5106.7033,N,00123.8927,W,2.88,208.03,250808,,,A*71",
          "$GPRMC,135154.000,A,5106.7030,N,00123.8928,W,2.72,205.69,250808,,,A*7E",
          "$GPRMC,135155.000,A,5106.7024,N,00123.8942,W,2.70,211.83,250808,,,A*75",
          "$GPRMC,135156.000,A,5106.7021,N,00123.8945,W,1.60,188.74,250808,,,A*7D",
          "$GPRMC,135157.000,A,5106.7017,N,00123.8945,W,1.21,168.54,250808,,,A*70",
      };


    public GpsTestProvider()
    {
      const string sampleDataFile = "GPSTestData.txt";
      if (File.Exists(sampleDataFile))
      {
        sampleData = File.ReadAllLines(sampleDataFile);
      }
    }

    #region Dispose Implementation

    // Use C# destructor syntax for finalization code.
    ~GpsTestProvider()
    {
      Debug.Assert(false, "This object was not disposed of");
      Dispose(false);
    }

    private bool m_Disposed = false;

    //Implement IDisposable.
    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (m_Disposed)
        return;

      if (disposing)
      {
        // TODO: cleanup managed resources in GpsTestProvider
      }
      Close();
      timer.Dispose();

      m_Disposed = true;
    }

    #endregion Dispose Implementation


    #region IGpsDataProvider Members

    public void Close()
    {
      timer.Stop();
      timer.Enabled = false;
    }

    public event GpsDataReceivedEventHandler GpsDataReceived;

    public void Open()
    {
      timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
      timer.Interval = 100;
      timer.Start();
      timer.Enabled = true;
    }

    public bool IsOpen()
    {
      return timer.Enabled;
    }
    #endregion

    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
      if (GpsDataReceived != null)
      {
        GpsDataReceived(this, new GpsDataLineEventArgs(sampleData[index]));
        index = (index + 1) % sampleData.Length;
      }
    }

  }
}

September 2, 2008

GPS Monitoring

Here is the structure view of the Gps Design: Define the provider interface
  public interface IGpsDataProvider
  {
    void Close();
    event GpsDataReceivedEventHandler GpsDataReceived;
    void Open();
    bool IsOpen();
  }
Later we can derive a test provider Here are the event helpers

    public delegate void GPSDataEventHandler(object sender, GPSDataEventArgs e);

    public class GPSDataEventArgs : EventArgs
    {
        #region Members
        private GPSFix m_FixState = GPSFix.NoFix;
        private double m_Longitude = 0;
        private double m_Latitude = 0;
        private double m_SpeedMetresPerSec = 0;
        private double m_BearingDegrees = 0;
        #endregion

        #region Properties
        public GPSFix FixState { get { return m_FixState; } }
        public double Longitude { get { return m_Longitude; } }
        public double Latitude { get { return m_Latitude; } }
        public string CoordinateSystem { get { return GpsListener.coordindateSystem; } }
        public double SpeedMetresPerSec { get { return m_SpeedMetresPerSec; } }
        public double BearingDegrees { get { return m_BearingDegrees; } }
        #endregion

        #region Constructor
        public GPSDataEventArgs(GPSFix a_FixState, double a_Longitude, 
                  double a_Latitude, double a_SpeedMetresPerSec, 
                  double a_BearingDegrees)
        {
            m_FixState = a_FixState;
            m_Longitude = a_Longitude;
            m_Latitude = a_Latitude;
            m_SpeedMetresPerSec = a_SpeedMetresPerSec;
            m_BearingDegrees = a_BearingDegrees;
        }
        #endregion

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder(128);
            sb.Append(" FixState=" + m_FixState.ToString());
            sb.Append(" Long=" + m_Longitude.ToString());
            sb.Append(" Long=" + m_Longitude.ToString());
            sb.Append(" Lat=" + m_Latitude.ToString());
            sb.Append(" Speed=" + m_SpeedMetresPerSec.ToString());
            sb.Append(" Bearing=" + m_BearingDegrees.ToString());
            return sb.ToString();
        }
    }

    public delegate void GpsDataReceivedEventHandler(object sender,
              GpsDataLineEventArgs e);

    public class GpsDataLineEventArgs : EventArgs
    {
        #region Members
        private string m_Data = string.Empty;
        #endregion

        #region Properties

        public string Data
        {
            get { return m_Data; }
            set { m_Data = value; }
        }

        #endregion

        #region Constructor
        public GpsDataLineEventArgs(string data)
        {
            m_Data = data;
        }
        #endregion
    }
Here is the Listener: