Re: GPS Library - Listed Here

Tech Tip: Click here to run a free scan for Windows Errors and optimize PC performance

From: Compulim (noone)
Date: 10/07/04


Date: Wed, 6 Oct 2004 18:26:49 -0700

GPS may returns multiple sentence regarding the current physical location
(e.g. GPGLL, GPRMC, GPGGA).

For compatibility reason, I think you should process all of these sentences
and store the state locally in the object. And everytime you receive a
sentence, you should overwrite the state and check if any modifications
occurred. If yes, then fire a location changed event.

Compulim @ kasuei

"Richard Jones" <richard@binaryrefinery.com> wrote in message
news:5880cf71.0410061220.2acc6a7f@posting.google.com...
> Hi I've been developing a generic GPS library that will shortly be in
> the code drop of OpenNetCF under the namespace OpenNETCF.IO.Serial.GPS
>
> To get the ball rolling. Listed below is the namespace. Would
> really appreciate some upfront feedback from the group as to stability
> of serial port communication (i.e correct com threasholds etc), how I
> implement the threading etc.
>
> So here goes....
>
> using System;
> using OpenNETCF.IO.Serial;
> using System.Text;
> using System.Collections;
> using System.Threading;
> using System.IO;
>
>
> namespace OpenNETCF.IO.Serial.GPS
> {
>
> /// <summary>
> /// Produced Under the Terms Of The OpennetCF License
> ///
> /// By Richard Jones - Richard@BinaryRefinery.com
> ///
> /// </summary>
> public class Misc // utility functions
> {
> public static decimal KnotsToMph(decimal Knots)
> {
> return Knots * 1.151m;
> }
>
> //TODO grabbed conversion from MSDN editor
> //not sure what the actual unit for altitude is
> public static decimal AltToFeet(decimal Alt)
> {
> return (Alt / 39.36m) * 12;
> }
>
> /// <summary>
> /// convert decimal degrees to sexagesimal format
> /// </summary>
> /// <param name="thedata"></param>
> /// <returns></returns>
> ///
> public static string DecimalToSexagesimal(decimal inputdata)
> {
>
> // orignal input = the data 4533.3512
>
> string strdata=Math.Abs(inputdata).ToString("00000.0000");
>
> // degrees is 45
> string degrees=strdata.Substring(0,3);
>
>
> string minutes = strdata.Substring(3,2);
> // minutes is 33
>
> decimal decseconds = Convert.ToDecimal(strdata.Substring(5));
> // decseconds = .3512
>
> decseconds = Math.Round(decseconds*60,2);
>
> // seconds = 21.07
>
> return degrees+"°"+minutes+"'"+decseconds.ToString("00.00")+"\"";
>
>
> }
>
>
> }
> public enum CardinalDirection
> {
> North = 0,
> East = 1,
> South = 2,
> West = 4,
> NorthWest = 5,
> NorthEast = 6,
> SouthWest = 7,
> SouthEast = 8,
> Stationary = 9
> }
>
> public enum States
> {
> Opening,
> Running,
> Stopping,
> Stopped
> }
>
> public enum StatusType
> {
> NotSet,
> OK, //A
> Warning //V
>
> }
>
> public class GpsGPRMCEventArgs:EventArgs
> {
> #region private members
> StatusType blfixextablished=StatusType.Warning;
>
> decimal latitude=0;
> string latitude_sexagesimal="";
> CardinalDirection latitude_direction=CardinalDirection.North;
>
> decimal longitude=0;
> string longitude_sexagesimal="";
> CardinalDirection longitude_direction=CardinalDirection.West;
>
> decimal speedknots=0;
> decimal track=0;
> #endregion
> #region properties
> public string Latitude_Sexagesimal
> {
> get
> {
> return latitude_sexagesimal;
> }
> }
>
> public string Longitude_Sexagesimal
> {
> get
> {
> return longitude_sexagesimal;
> }
>
> }
>
> public string DirectionLongitude
> {
> get
> {
> return longitude_direction.ToString();
> }
> }
>
> public string DirectionLatitude
> {
> get
> {
> return latitude_direction.ToString();
> }
> }
>
> public decimal Latitude
> {
> get
> {
> return latitude;
> }
>
> }
>
> public decimal Longitude
> {
> get
> {
> return longitude;
> }
>
> }
>
> public decimal SpeedKnots
> {
> get
> {
> return speedknots;
> }
>
> }
>
> public decimal SpeedMPH
> {
> get
> {
> return Math.Round(Misc.KnotsToMph(speedknots),1);
> }
>
> }
>
> public decimal Track
> {
> get
> {
> return Math.Round(track,1);
> }
> }
> #endregion
>
> public GpsGPRMCEventArgs(string[] strdata, ref StatusType gpsstatus)
> {
>
> //if (strdata.Length!=12) return;
>
> // 0 180432 UTC of position fix in hhmmss format (18 hours, 4
> minutes and 32 seconds)
>
> // 1 A Status (A - data is valid, V - warning)
> blfixextablished=(strdata[1]=="A")?StatusType.OK:StatusType.Warning;
>
> if (gpsstatus!=blfixextablished)
> {
> // status has changed so fire our event;
> gpsstatus=blfixextablished;
> }
>
>
> //2 4027.027912 Geographic latitude in ddmm.mmmmmm format (40
> degrees and 27.027912 minutes)
> if (strdata[2].Length>0)
> {
> latitude=(decimal) Convert.ToDecimal(strdata[2]);
> latitude_sexagesimal=Misc.DecimalToSexagesimal(latitude);
> }
>
> // 3 N Direction of latitude (N - North, S - South)
> if (strdata[3].Length>0)
> if (strdata[3][0]=='N')
> latitude_direction=CardinalDirection.North;
> else
> latitude_direction=CardinalDirection.South;
>
> // 4 08704.857070 Geographic longitude in dddmm.mmmmmm format (87
> degrees and 4.85707 minutes)
> if (strdata[4].Length>0)
> {
> longitude=(decimal) Convert.ToDecimal(strdata[4]);
> longitude_sexagesimal=Misc.DecimalToSexagesimal(longitude);
>
> }
>
> // 5 W Direction of longitude (E - East, W - West)
>
> if (strdata[5].Length>0)
> if (strdata[5][0]=='W')
> longitude_direction=CardinalDirection.West;
> else
> longitude_direction=CardinalDirection.East;
>
>
>
> //6 000.04 Speed over ground (0.04 knots)
> if (strdata[6].Length>0)
> speedknots=(decimal) Convert.ToDouble(strdata[6]);
>
>
> // 7 181.9 Track made good (heading) (181.9º)
> if (strdata[7].Length>0)
> track=(decimal) Convert.ToDecimal(strdata[7]);
>
> //8 131000 Date in ddmmyy format (October 13, 2000)
>
> // 9 1.8 Magnetic variation (1.8º)
>
> //10 W Direction of magnetic variation (E - East, W - West)
>
> // 11 D Mode indication (A - autonomous, D - differential, N - data
> not valid)
> }
> }
>
> public class GpsSentenceEventArgs:EventArgs
> {
> private string sentence="";
> private int counter=0;
>
> public string Sentence
> {
> get
> {
> return sentence;
> }
> }
>
> public int Counter
> {
> get
> {
> return counter;
> }
> }
> public GpsSentenceEventArgs(string sentence,int counter)
> {
> this.counter=counter;
> this.sentence=sentence;
> }
> }
>
> public class GpsCommStateEventArgs:EventArgs
> {
>
> private States state;
>
>
> public States State
> {
> get
> {
> return state;
> }
>
> }
> public GpsCommStateEventArgs(States state)
> {
> this.state=state;
> }
> }
> public class GpsStatusEventArgs
> {
>
> private StatusType gpsstatus;
>
> public StatusType GpsStatus
> {
> get
> {
> return gpsstatus;
> }
> }
> public GpsStatusEventArgs(StatusType gpsstatus)
> {
>
> this.gpsstatus=gpsstatus;
> }
> }
> public class GPS
> {
> #region private members
> Port cp;
> OpenNETCF.IO.Serial.BaudRates
> baudrate=OpenNETCF.IO.Serial.BaudRates.CBR_4800;
> string comport="COM1:";
>
> string strreceived="";
> int sentencecount=0;
> string storedgprmc="";
>
> private States state=States.Stopped;
> private Thread thrd;
>
> private StatusType gpsstatus=StatusType.Warning;
>
> private bool traceon=false;
> private string tracefile=@"\gpslog.txt";
> #endregion
>
> #region public members
> public void Start()
> {
> if (state!=States.Stopped) return;
>
> ThreadStart runner = new ThreadStart(run);
> thrd = new Thread(runner);
> thrd.Priority=ThreadPriority.BelowNormal;
> thrd.Start();
> }
>
> public void Stop()
> {
> if (state!=States.Running) return;
> setstate=States.Stopping;
> }
>
> #endregion
>
> #region protected methods
> protected virtual void OnGpsGPRMC(GpsGPRMCEventArgs e)
> {
>
> if (GpsGPRMC != null) GpsGPRMC(this, e);
>
> }
>
> protected virtual void OnGpsSentence(GpsSentenceEventArgs e)
> {
>
> if (GpsSentence != null) GpsSentence(this, e);
>
> }
>
> protected virtual void OnGpsCommState(GpsCommStateEventArgs e)
> {
> if (GpsCommState!=null) GpsCommState(this, e);
> }
>
> protected virtual void OnGpsStatus(GpsStatusEventArgs e)
> {
> if (GpsStatus!=null) GpsStatus(this, e);
> }
> #endregion
>
> #region events
> public event GpsGPRMCEventHandler GpsGPRMC;
> public event GpsSentenceEventHandler GpsSentence;
> public event GpsCommStateEventHandler GpsCommState;
> public event GpsStatusEventHandler GpsStatus;
> #endregion
>
> #region delegates
> public delegate void GpsGPRMCEventHandler(object sender,
> GpsGPRMCEventArgs e);
> public delegate void GpsSentenceEventHandler(object sender,
> GpsSentenceEventArgs e);
> public delegate void GpsCommStateEventHandler(object sender,
> GpsCommStateEventArgs e);
> public delegate void GpsStatusEventHandler(object sender,
> GpsStatusEventArgs e);
> #endregion
>
> #region properties
>
> public bool TraceOn
> {
> set
> {
> traceon=value;
> }
> get
> {
> return traceon;
> }
> }
>
> public string TraceFile
> {
> set
> {
> tracefile=value;
> }
> get
> {
> return tracefile;
> }
>
> }
>
> public States State
> {
> get
> {
> return state;
> }
> }
>
> public StatusType GpsState
> {
> get
> {
> return gpsstatus;
> }
> }
>
> private States setstate
> {
> set
> {
> state=value;
> this.OnGpsCommState(new GpsCommStateEventArgs(value));
> }
> }
>
> public string ComPort
> {
> set
> {
> comport=value;
> }
> }
>
> public OpenNETCF.IO.Serial.BaudRates BaudRate
> {
> set
> {
> baudrate=value;
> }
> }
>
>
> #endregion
>
> #region private members
>
> private void run()
> {
> setstate=States.Opening;
> // reset all private members
> strreceived="";
> sentencecount=0;
> storedgprmc="";
> gpsstatus=StatusType.NotSet;
>
> DetailedPortSettings portSettings = new HandshakeNone();
>
> cp = new Port(comport,portSettings);
> cp.RThreshold = 8;
> cp.InputLen = 8;
> cp.Settings.BaudRate=this.baudrate;
> cp.RThreshold=16;
> cp.InputLen=64;
>
> try
> {
> cp.Open();
> }
> catch
> {
> cp.Dispose();
> setstate=States.Stopped;
> return;
> }
>
> if (cp.IsOpen)
> {
> // just trash anything in the input buffer
>
> if (cp.InBufferCount>0)
> {
> byte[] inputData = new byte[cp.InBufferCount];
> inputData = cp.Input;
> }
>
> }
>
> cp.OnError+=new OpenNETCF.IO.Serial.Port.CommErrorEvent(cp_OnError);
> cp.DataReceived+=new
> OpenNETCF.IO.Serial.Port.CommEvent(cp_DataReceived);
> cp.PowerEvent+=new
> OpenNETCF.IO.Serial.Port.CommEvent(cp_PowerEvent);
>
> setstate=States.Running;
> while (state==States.Running)
> {
> Thread.Sleep(10);
> }
>
> if (cp.IsOpen) cp.Close();
> cp.Dispose();
> setstate=States.Stopped;
> }
>
> /// <summary>
> /// this is fired when the comport receives data
> /// </summary>
> private void cp_DataReceived()
> {
> if (state!=States.Running) return;
>
> if (cp.InBufferCount==0) return;
>
> byte[] inputData = new byte[cp.InBufferCount];
>
> inputData = cp.Input;
>
> string strret = Encoding.ASCII.GetString(inputData,
> 0,inputData.Length);
>
> // belt and braces - double check if our received data is over 200
> chars. trash the first part
> if (strreceived.Length>200)
> {
> strreceived=strreceived.Substring(200);
> }
>
> this.strreceived+=strret;
>
> int intcrl=strreceived.IndexOf("\r\n");
> if (intcrl==-1) return;
>
>
> string strdata=strreceived.Substring(0,intcrl);
> // is this the last 2 chars ?
> if (intcrl+2==strreceived.Length)
> strreceived="";
> else
> strreceived=strreceived.Substring(intcrl+2);
>
> nmea(strdata);
> }
>
>
>
>
> /// <summary>
> /// processes our string of Nema data
> /// </summary>
> /// <param name="gps_data">string of input data</param>
> /// <returns>Boolean to indicate if we were able to process string
> of data ok</returns>
> private bool nmea(string gps_data)
> {
>
> if (state!=States.Running) return false;
> // GPS data can't be zero length
> if (gps_data.Length==0) return false;
>
>
> // GPS data can't be longer than 82 character
> if (gps_data.Length>82) return false;
>
> // first character must be a $
> if (gps_data[0]!='$') return false;
>
> // remove our leading character
> string strdata=gps_data.Substring(1);
>
> // see if the last block contains a * used to see if we have a
> checksum
> int intstarpos=strdata.IndexOf('*');
> if (intstarpos>=0)
> {
> // we have a checksum so check it...
> string strchecksum=strdata.Substring(intstarpos+1);
>
> // remove checksum from end of string
> strdata=strdata.Substring(0,strdata.Length-strchecksum.Length-1);
>
> if (!checksum(strdata,strchecksum))
> return false;
> }
>
> String[] strrecarray = strdata.Split(',');
>
>
> // get the first block which is the sentance id
> string strsentance=strrecarray[0];
>
> ArrayList sbdata = new ArrayList();
>
> // get the data block minus the first block
> for (int i=1;i<strrecarray.Length;i++)
> sbdata.Add(strrecarray[i]);
>
>
> // if all is well raise our main GPS event
> string[] arrydata = (string[]) sbdata.ToArray(typeof(string));
>
> // incremenet our counter
> if (sentencecount==int.MaxValue) sentencecount=0;
>
> sentencecount++;
> OnGpsSentence(new GpsSentenceEventArgs(gps_data,sentencecount));
>
> if (traceon)
> {
> StreamWriter sw = File.AppendText(tracefile);
> sw.WriteLine(gps_data);
> sw.Close();
>
> }
> switch (strsentance)
> {
> case "GPRMC": // Recommended minimum specific GPS/Transit data
>
> // only fire our event if something has changed.
> if (storedgprmc!=gps_data)
> {
> storedgprmc=gps_data;
> StatusType oldstatus=this.gpsstatus;
> OnGpsGPRMC(new GpsGPRMCEventArgs(arrydata,ref gpsstatus));
>
> // see if our status has changed
> if (oldstatus!=gpsstatus)
> {
> OnGpsStatus(new GpsStatusEventArgs(gpsstatus));
> }
> }
> break;
>
>
> // TODO The following cases are still to complete
> case "GPGSA": // GPS DOP and active satellites
> break;
> case "GPGSV": // sats in view
> //process_sat(arrydata);
> break;
>
> case "GPGGA": // GPS DOP and active satellites
> break;
> case "GPGLL": //Geographic position, Latitude and Longitude
> break;
> }
>
> return true;
>
> }
>
> // TODO - Complete this method
> private void process_sat(string[] arrydata)
> {
> if (arrydata.Length!=7) return;
>
> /*
> 1 = Total number of messages of this type in this cycle
> 2 = Message number
> 3 = Total number of SVs in view
> 4 = SV PRN number
> 5 = Elevation in degrees, 90 maximum
> 6 = Azimuth, degrees from true north, 000 to 359
> 7 = SNR, 00-99 dB (null when not tracking)
> */
>
> int satsinview=Convert.ToInt32(arrydata[0]);
> int intmessage=Convert.ToInt32(arrydata[1]);
>
> if (intmessage==1)
> {
>
> }
> if (arrydata[0]==arrydata[2])
> {
> // fire the sat event
> }
>
> }
>
>
> /// <summary>
> /// this checksums all nema sequences
> /// </summary>
> /// <param name="strtocheck">string to check</param>
> /// <param name="strchecksum">checksum</param>
> /// <returns>true if checksum computes</returns>
> private bool checksum(string strtocheck,string strchecksum)
> {
> int intor=0;
> // go from first character upto last *
> for(int i=0;(i<strtocheck.Length);i++)
> intor=intor^ (int) (strtocheck[i]);
>
>
> int y = 0;
>
> try
> {
> y = Convert.ToInt32(strchecksum,16);
> }
> catch
> {
> return false;
> }
> return (intor == y);
> }
>
> private void cp_OnError(string Description)
> {
> if (state!=States.Running) return;
> this.setstate=States.Stopping;
> }
>
> private void cp_PowerEvent()
> {
> if (state!=States.Running) return;
> this.setstate=States.Stopping;
> }
> #endregion
>
> }
> }



Relevant Pages

  • Re: Data Object Collection Inheritance
    ... > private System.Windows.Forms.ListBox listBox1;> private System.Windows.Forms.Button cmdID;> private System.Windows.Forms.Button cmdText; ... > private void InitializeComponent() ... > // TODO: Add BaseDataCollection.IsReadOnly getter implementation> return false; ... > public sealed class SubClassCollection: ...
    (microsoft.public.dotnet.languages.csharp)
  • RE: Problem in converting to C#
    ... public delegate void delegate1 ... private void InitializeComponent() ... private void Button1_Click(object sender, System.EventArgs e) ... Private Sub Form1_Load(ByVal sender As System.Object, ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Redraw problem - please help
    ... >> public int CurrentX; ... >> public void Create ... >> private System.ComponentModel.IContainer components; ...
    (microsoft.public.dotnet.framework.drawing)
  • Re: Law of Demeter can be supported without eliminating object coupling
    ... void C::M ... // do something to change solution state ... or there is a disconnect here as well. ...
    (comp.object)