September 7, 2008

Posting Windows Messages Accross Processes

public class WinMessagePoster
{
  [DllImport("user32")]
  public static extern bool PostMessage(IntPtr hwnd, int msg, 
          IntPtr wparam, IntPtr lparam);

  [DllImport("user32")]
  public static extern int RegisterWindowMessage(string message);

  // this class just wraps some Win32 stuffthat we're going to use
  public const int HWND_BROADCAST = 0xffff;

  public static readonly int WM_APP_MYMESSAGE = 
                                 RegisterWindowMessage("WM_APP_MYMESSAGE");

  public void PostWinMessageToAnotherApp()
  {
    Process[] processes = Process.GetProcessesByName("ApplicatioName");
    foreach (Process p in processes)
    {
      IntPtr pFoundWindow = p.MainWindowHandle;
      PostMessage(pFoundWindow, "WM_APP_MYMESSAGE", IntPtr.Zero, IntPtr.Zero);
    }
  }
}
In the application that receives the windows message
// In .exe Main Form
#region Detect Custom Windows Message

public static readonly int WM_APP_MYMESSAGE = 
  RegisterWindowMessage("WM_APP_MYMESSAGE");

[DllImport("user32")]
public static extern int RegisterWindowMessage(string message);

protected override void WndProc(ref Message m)
{
  if (m.Msg == WM_APP_MYMESSAGE)
  {
    DoSomething();
  }
  base.WndProc(ref m);
}

#endregion Detect Custom Windows Message

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: