Click here to Skip to main content
15,896,111 members
Articles / Mobile Apps / Windows Mobile

Speaking Garmin

Rate me:
Please Sign up or sign in to vote.
4.76/5 (24 votes)
14 Dec 2005CPOL11 min read 135K   1.4K   79  
Covers the basics needed to get a Pocket PC and a Garmin GPS talk in their own language and to graphically display the calculated data.
using System;
using System.Windows.Forms;
using System.IO;

namespace Speaking_Garmin
{
	/// <summary>
	/// Class that implements the Garmin Protocol.
	/// </summary>
	public class Garmin
	{
		#region Variables
		Serial.Port serialPort;
		private bool received=false;
		private bool logging=false;
		private bool done=false;

		private int q=0;
		private int bytesEstimated;

		private System.Collections.ArrayList bytesReceived=new System.Collections.ArrayList(100);
		#endregion


		#region Properties
		/// <summary>
		/// Estimate percentage already transfered
		/// </summary>
		public double Progress
		{
			get
			{
				return Math.Min((double)(bytesReceived.Count*100)/(double)bytesEstimated,100.0);
			}
		}
		/// <summary>
		/// Get bytes received from GPS to save them or whatever
		/// </summary>
		public System.Collections.ArrayList Bytes
		{
			get{return bytesReceived;}
		}
		#endregion


		#region Constructors
		public Garmin()
		{
		}
		#endregion


		#region Public Functions
		public System.Collections.ArrayList GetTracks()
		{
			bytesReceived.Clear();
			bytesEstimated=-1;
			logging=false;

			byte[] sendTracks = {0x10,0x0A,0x02,0x06,0x00,0xEE,0x10,0x03}; /* Ask for tracks */

			Serial.BasicPortSettings a=new Serial.BasicPortSettings();
			a.BaudRate = Serial.BaudRates.CBR_9600;
			serialPort=new Serial.Port("COM1:",a);

			serialPort.DataReceived += new Serial.Port.CommEvent(serialPort_DataReceived);
			serialPort.OnError += new Serial.Port.CommErrorEvent(OnError);

			if(!serialPort.IsOpen)
                serialPort.Open();

			logging=true;
			SendData(sendTracks); /* Ask for tracks */
			Application.DoEvents();
			System.Threading.Thread.Sleep(200); /* Wait for response */
			if(received)
				received=false;
			else
			{
				serialPort.Close();
				serialPort.Dispose();serialPort=null;
				return null;
			}
			q=Environment.TickCount; /* Keep track of elapsed time */
			while(!done)
			{
				if(Environment.TickCount-q>2000) /* Timeout */
				{
					serialPort.Close();
					serialPort.Dispose();serialPort=null;
					return null;
				}
				Application.DoEvents();
				System.Threading.Thread.Sleep(1000);
			}
			serialPort.Close();
			serialPort.Dispose();serialPort=null;

			System.Collections.ArrayList retval=new System.Collections.ArrayList(2);
			Track tempTrack=null;

			System.Collections.ArrayList al=SplitBytes(bytesReceived);
			
			System.Collections.ArrayList command;

			int nWaited=-1;
			int nReceived=0;
			for(int i=0;i<al.Count;i++)
			{
				command=(System.Collections.ArrayList)al[i];
                
				if(command.Count>=7 && (byte)command[0]==0x10)
				{
					if((byte)command[1]==0x1B)
					{ /* Number of commands to be sent */
						nWaited=0;
						for(int j=2+(byte)command[2];j>=3;j--)
						{
							nWaited <<= 8;
							nWaited+=(byte)command[j];
						}
					}
					else if((byte)command[1]==0x06)
					{ /* OK - Do nothing */
					}
					else if((byte)command[1]==0x22)
					{ /* New point */
						++nReceived;;
						if(tempTrack!=null)
						{
							/* Create new point based on received info. */
							tempTrack.AddPoint(command);
						}
					}
					else if((byte)command[1]==0x63)
					{ /* New track */
						++nReceived;

						/* Last received track is now done. Add it to the values to be returned */
						if(tempTrack!=null)
							retval.Add(tempTrack);
						/* Create new point based on received info. */
						tempTrack=new Track(command);
					}
					else if((byte)command[0]==0x10 &&
						(byte)command[1]==0x0C &&
						(byte)command[2]==0x02 &&
						(byte)command[3]==0x06 &&
						(byte)command[4]==0x00 &&
						(byte)command[5]==0xEC &&
						(byte)command[6]==0x10 &&
						(byte)command[7]==0x03)
					{ /* EOF */
						/* Last received track is now done. Add it to the values to be returned */
						if(tempTrack!=null)
							retval.Add(tempTrack);
						/* Check if the information received matches what was expected*/
						if(nReceived!=nWaited)
							MessageBox.Show("Transfer error...\nNumber of commands expected: " + nWaited.ToString() + "\nNumber of commands received: " + nReceived.ToString(),"Error",MessageBoxButtons.OK,MessageBoxIcon.Hand,MessageBoxDefaultButton.Button1);
					}
				}
				else /* command[0] != 0x10 */
				{
					/* Invalid! */
					retval=null;
				}
			}

			return retval;
		}

		public System.Collections.ArrayList GetTracksFromFile(string filename)
		{
			bytesReceived.Clear();

			FileInfo fi=new FileInfo(filename);       
			FileStream fs=fi.OpenRead();
			byte[] ByteArray=new byte[600000];
			int nBytesRead=fs.Read(ByteArray, 0, 600000);
			fs.Close();

			for(int i=0;i<nBytesRead;i++)
			{
				bytesReceived.Add(ByteArray[i]); /* Pretend we received data from a GPS device */
			}

			System.Collections.ArrayList retval=new System.Collections.ArrayList(2);
			Track tempTrack=null;

			System.Collections.ArrayList al=SplitBytes(bytesReceived);
			
			System.Collections.ArrayList command;

			int nWaited=-1;
			int nReceived=0;
			for(int i=0;i<al.Count;i++)
			{
				command=(System.Collections.ArrayList)al[i];
				if(command.Count>=7 && (byte)command[0]==0x10)
				{
					if((byte)command[1]==0x1B)
					{ /* Number of commands to be sent */
						nWaited=0;
						for(int j=2+(byte)command[2];j>=3;j--)
						{
							nWaited <<= 8;
							nWaited+=(byte)command[j];
						}
					}
					else if((byte)command[1]==0x06)
					{ /* OK - Do nothing */
					}
					else if((byte)command[1]==0x22)
					{ /* New point */
						++nReceived;;
						if(tempTrack!=null)
						{
							tempTrack.AddPoint(command);
						}
					}
					else if((byte)command[1]==0x63)
					{ /* New track */
						++nReceived;
						if(tempTrack!=null)
							retval.Add(tempTrack);
						tempTrack=new Track(command);
					}
					else if((byte)command[0]==0x10 &&
						(byte)command[1]==0x0C &&
						(byte)command[2]==0x02 &&
						(byte)command[3]==0x06 &&
						(byte)command[4]==0x00 &&
						(byte)command[5]==0xEC &&
						(byte)command[6]==0x10 &&
						(byte)command[7]==0x03)
					{ /* EOF */
						if(tempTrack!=null)
							retval.Add(tempTrack);
						if(nReceived!=nWaited)
							MessageBox.Show("File corrupt...\nNumber of commands expected: " + nWaited.ToString() + "\nNumber of commands received: " + nReceived.ToString(),"Error",MessageBoxButtons.OK,MessageBoxIcon.Hand,MessageBoxDefaultButton.Button1);
					}
				}
				else /* command[0] != 0x10 */
				{
					retval=null;
				}
			}

			return retval;
		}

		public void Exit()
		{
			if(serialPort!=null)
                serialPort.Close();
		}
		#endregion


		#region Private Functions
		/// <summary>
		/// Function called each time data comes in which stores the received bytes
		/// </summary>
		/// <param name="bytes">byte[] array whose bytes are to be added to the ArrayList receivedBytes</param>
		/// <returns></returns>
		private bool Append(byte[] bytes)
		{
			for(int i=0;i<bytes.Length;i++)
			{
				bytesReceived.Add(bytes[i]);
			}

			if(bytesEstimated==-1) /* Not initialized yet */
			{
				if(bytesReceived.Count>=16)
				{
					System.Collections.ArrayList Data=SplitBytes(bytesReceived);
					if( (byte)((System.Collections.ArrayList)Data[1])[0]==0x10 &&
						(byte)((System.Collections.ArrayList)Data[1])[1]==0x1B)
					{ /* Received number of commands to be sent */
						bytesEstimated=0;
						for(int j=2+(byte)((System.Collections.ArrayList)Data[1])[2];j>=3;j--)
						{
							bytesEstimated <<= 8;
							bytesEstimated+=(byte)((System.Collections.ArrayList)Data[1])[j];
						}
						bytesEstimated*=30; /*Estimate each message has 30 bytes average */
					}
				}
			}

			return true;
		}


		/// <summary>
		/// Main function in parsing the received bytes, it splits the received bytes into messages
		/// </summary>
		/// <param name="arrayListBytes">ArrayList filled with elements of type byte which are to be split</param>
		/// <returns></returns>
		private static System.Collections.ArrayList SplitBytes(System.Collections.ArrayList arrayListBytes)
		{
			System.Collections.ArrayList retval=new System.Collections.ArrayList(10);
			System.Collections.ArrayList tempBytes;
			int count=0;

			for(int i=0;i<arrayListBytes.Count;i++)
			{
				if((byte)arrayListBytes[i]==0x10)
				{ /* First byte in a message */
					tempBytes=new System.Collections.ArrayList(8);
					tempBytes.Add(arrayListBytes[i]);
					for(int x=i+1;;x++)
					{
						i=x;
						tempBytes.Add(arrayListBytes[x]);
						if((byte)arrayListBytes[x]==0x10)
							++count;
						else if((byte)arrayListBytes[x]==0x03)
						{
							if(count%2==1) /* If found an even number of 0x10 followed by 0x03 we have to split the message here */
								break;
						}
						else
							count=0;
					}
					retval.Add(tempBytes);
				}
			}

			return retval;
		}


		/// <summary>
		/// Function used to send data through the serial port
		/// </summary>
		/// <param name="buffer"></param>
		/// <returns></returns>
		private bool SendData(byte[] buffer)
		{
			if(serialPort.IsOpen)
                serialPort.Output=buffer;
			else
				return false;

			return true;
		}

		#endregion


		#region Events Actions
		/// <summary>
		/// Response to error event raised by the serial port
		/// </summary>
		/// <param name="Description">String that contains error specifics</param>
		private void OnError(string Description)
		{
			MessageBox.Show("An error occured during the transfer:\n" + Description,"Error",MessageBoxButtons.OK,MessageBoxIcon.Hand,MessageBoxDefaultButton.Button1);
		}

		/// <summary>
		/// Response to DataReceived event raised by serialPort called each time new data is received
		/// </summary>
		private void serialPort_DataReceived()
		{
			q=Environment.TickCount; /* Keep track of the time in order to check for timeouts */
			received=true; /* Received data */
			if(logging) /* Keep track of data received */
			{
				byte[] a=serialPort.Input; /* Get what was received */
				Append(a); /* Store received bytes */
				if(bytesReceived.Count>=8)
					if(
						(byte)bytesReceived[bytesReceived.Count-8]==0x10 &&
						(byte)bytesReceived[bytesReceived.Count-7]==0x0C &&
						(byte)bytesReceived[bytesReceived.Count-6]==0x02 &&
						(byte)bytesReceived[bytesReceived.Count-5]==0x06 &&
						(byte)bytesReceived[bytesReceived.Count-4]==0x00 &&
						(byte)bytesReceived[bytesReceived.Count-3]==0xEC &&
						(byte)bytesReceived[bytesReceived.Count-2]==0x10 &&
						(byte)bytesReceived[bytesReceived.Count-1]==0x03)
					{ /* EOF */
                        done=true; /* Transfer is complete */
						logging=false; /* Stop logging */
						return;
					}
				/* Ask for next record as soon as data is received */
				SendData(new byte[] {0x10,0x06,0x02,0x22,0x00,0xD6,0x10,0x03});
			}
		}
		#endregion
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Brazil Brazil
I am currently 18 years old and since I was very little I've been into computer-programming. Back then I used to play with a Basic compiler and now I am using the most powerful development environments out there for creating games and windows applications in general.

Comments and Discussions