⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gpsreader.cs

📁 功能:基于windows mobile 的地图查看器。使用vs2005开发
💻 CS
📖 第 1 页 / 共 3 页
字号:
// GPSReader.cs
//
// Copyright (C) 2003 JW Hedgehog, Inc.  All rights reserved
//
// JW Hedgehog, Inc
// http://www.jwhh.com
// 
// Direct questions to mailto:jimw@jwhh.com
// 
// This code, comments and information are provided "AS IS" with
// no warrenty of any kind, either expressed or implied, including
// but not limited to the implied warranties of merchentability and/or
// fitness for a particular purpose
// ---------------------------------------------------------------------

using System;
using System.Data;
using System.Windows.Forms ;
using System.Runtime.InteropServices ;
using System.Text ;
using System.Collections ;
using System.Threading ;
using System.IO ;

namespace GPSExample.Util
{

	/// <summary>
	/// Class that manages the GPS reading process.
	/// 
	/// To get started using the class do the following
	/// 1) Construct GPSReader passing the port name and baud rate of the GPS device
	///		C#: GPSReader gps = new GPSReader("COM4:", 4800) ;
	///		VB: Dim WithEvents gps As New GPSReader("COM4:", 4800)
	///	2) Handle the OnGPSMessage event
	///		This event will fire each time the GPS sends an update
	///	3) Call gps.StartRead()
	///		Launches the GPS reading process on a background thread
	///		
	/// Use the StartRead and StopRead methods to control the GPS reading process.  Before calling 
	/// StartRead you must provide at least the port name in the form "COMx" (x is the port number) and
	/// the baud rate.  You can do this using either a constructor or the PortName and BaudRate properties.
	/// Each time a GPS message is received, the OnGPSMessage event will fire passing an instance of the 
	/// GPSEventArgs class containing the raw GPS sentence along with some of the values already parsed into
	/// read-only fields.
	/// 
	/// This class does the actual GPS reading work on a background thread.  The individual OnGPSMessage events
	/// are raised in a UI thread safe manner so no special handling is required.  Because it is considered unsafe
	/// to interact with UI elements (TextBox, ListBox, etc.) from a thread other then the thread on which they were
	/// created, the GPS reader thread raises the OnGPSMessage event on the UI thread.  These is acheived by deriving 
	/// the GPSReader class from Control and then using the inherited Invoke method.  Calling this.Invoke causes the 
	/// event to be raised on the same thread on which the GPSReader was created.  Since the GPSReader is usually 
	/// created as a member of either a Form or a method on a Form, it is safe to assume that the GPSReader was
	/// created on the same thread as the Form and the Form's associated UI elements.
	/// 
	/// Because there can sometimes be a short delay between when StartRead/StopRead are called and when the 
	/// action actually occurs on the background thread, OnGPSStartRead and OnGPSStopRead events are provided.  
	/// Each fires when the background thread actually performs the action.  Like the OnGPSMessage event, 
	/// these are raised in a UI thread safe manner.
	/// 
	/// To support the broadest number of GPS devices, the class actually supports two different read modes.
	/// The preferred read mode is "MesssageMode".  In MessageMode, we let the COMM port driver monitor the 
	/// GPS stream watching for the arrival of the carriage-return (\n).  Our code blocks until the COMM port
	/// driver notifies us of the carriage-return, at which time we then go read the entire GPS sentence from 
	/// the COMM port driver.
	/// The alternative read mode is "CharacterMode".  In CharacterMode we read the data character-by-character
	/// from the COMM port driver manually building the GPS sentence and watching for the carriage-return.  This
	/// mode was added because experimentation showed that some GPS devices that simulate COMM ports(i.e. the GPS
	/// might be an expansion pack of compact flash card but appears as a COMM port to the device) do not 
	/// support letting the COMM port driver monitor for the carriage-return.
	/// Using the PreferredReadMode property, you can set which mode the GPSReader uses  If you choose MessageMode
	/// or Auto (the default) The GPSReader class tests to see if the driver supports MessageMode and if so use it.
	/// Otherwise it will downgrade to CharacterMode.  The ActiveReadMode property indicates which read mode is 
	/// actually being used.
	/// The code that tests for MessageMode support is in the "DriverSupportsMessageMode method.  Because its not 
	/// possible to test every GPS in existence there is no way to be 100% sure that this test will always work but 
	/// on the devices tested it has been reliable. 
	/// ***************************************************************************************************************
	///        Note                                         ***********************************************************
	/// If you try reading from a device and the GPSReader never returns any data, the cause may be that MessageMode
	/// support has been falsly indicated as supported.  Setting the GPSReader PreferredReadMode to ReadMode.Character 
	/// should over come the problem.  The need to do this has never been observered but since its not possible to test
	/// every GPS device the possibility always exists.
	/// ***************************************************************************************************************
	/// </summary>
	public class GPSReader : Control
	{
		// *************************************************************
		//   Constructors
		// *************************************************************

		/// <summary>
		/// Default constructor
		/// At a minimum, will need to set the PortName and BaudRate properties before calling StartRead 
		/// </summary>
		public GPSReader()
		{
		}

		/// <summary>
		/// Constructor - Accepts COMM port name (COMx:)
		///  Will need to set the BaudRate properties before calling StartRead
		/// </summary>
		/// <param name="portName"></param>
		public GPSReader(string portName)
			: this()
		{
			_portName = portName ;
		}

		/// <summary>
		/// Constructor - Accepts COMM port name (COMx:) and BaudRate
		///  If default COMM port settings (NoParity, 8 bits/byte and OneStopBit) are acceptable,
		///  can call StartRead without setting any of the configuration properties
		/// </summary>
		/// <param name="portName"></param>
		/// <param name="baudRate"></param>
		public GPSReader(string portName, int baudRate)
			: this(portName)
		{
			_baudRate = baudRate ;
		}

		/// <summary>
		/// Constructor - verbose
		/// Provides full control over all COMM port settings
		/// </summary>
		/// <param name="portName"></param>
		/// <param name="baudRate"></param>
		/// <param name="parity"></param>
		/// <param name="byteSize"></param>
		/// <param name="stopBits"></param>
		public GPSReader(string portName, int baudRate, ParitySetting parity, byte byteSize, StopBitsSetting stopBits)
			: this(portName, baudRate)
		{
			_parity = parity ;
			_byteSize = byteSize ;
			_stopBits = stopBits ;
		}

		// *************************************************************
		//   Events
		// *************************************************************

		/// <summary>
		/// Fires each time a GPS message is received
		/// </summary>
		public event GPSEventHandler OnGPSMessage ;

		/// <summary>
		/// Fires when the background thread begins the read process
		/// </summary>
		public event EventHandler OnGPSReadStart ;

		/// <summary>
		/// Fires when the background thread exits the read process
		/// </summary>
		public event EventHandler OnGPSReadStop ;

		// *************************************************************
		//   Start/Stop Reading
		// *************************************************************

		/// <summary>
		/// Initiate GPS Reading 
		///  Actual reading done on a background thread - this method returns immediatly
		///
		/// Throws an error if either PortName or BaudRate not set
		/// </summary>
		public void StartRead()
		{
			if (_readData == true)
				return;

			// Verify that we know the port name and baud rate
			if (_baudRate == baudRateNotSet || _portName == portNameNotSet)
				throw new ApplicationException("<GPSReader> Must set Baud Rate & Port Name before opening the port") ;

			Cursor.Current = Cursors.WaitCursor ;
			_readData = true ;

			_gpsReadThread = new Thread(new ThreadStart(this.GPSReadLoop)) ;
			_gpsReadThread.Start() ;
			Cursor.Current = Cursors.Default ;
		}

		/// <summary>
		/// Terminate GPS Reading
		/// Sets _readData to false which exits the underlying read loop
		///  Also closes the COMM port which aborts any pending COMM port operations
		/// </summary>
		public void StopRead()
		{
			//if (_readData == false)
			//	return;

			Cursor.Current = Cursors.WaitCursor ;
			_readData = false ;
			Thread.Sleep(500) ;		// Give thread time to finish any pending work

			ClosePort() ;
			Cursor.Current = Cursors.Default ;
		}

		// *************************************************************
		//   Port Setup and configuration
		// *************************************************************

		/// <summary>
		/// Set Port Name (COMx:)
		/// </summary>
		public string PortName
		{
			get { return _portName ;}
			set {_portName = value ;}
		}

		/// <summary>
		/// Set Baud Rate - No Default 
		/// </summary>
		public int BaudRate
		{
			get { return _baudRate ;}
			set {_baudRate = value ;}
		}

		/// <summary>
		/// Set Port Parity - defaults to NoParity
		/// </summary>
		public ParitySetting Parity
		{
			get { return _parity ;}
			set {_parity = value ;}
		}

		/// <summary>
		/// Set Port StopBits - defaults to OneStopBit 
		/// </summary>
		public StopBitsSetting StopBits
		{
			get { return _stopBits ;}
			set {_stopBits = value ;}
		}

		/// <summary>
		/// Set Port Byte Size (in bits) - defaults to 8
		/// </summary>
		public byte ByteSize
		{
			get { return _byteSize ;}
			set {_byteSize = value ;}
		}

		// *************************************************************
		//   Port Reading
		// *************************************************************

		/// <summary>
		/// Main Read Loop
		/// After openning the COMM Port, repeatedly retrieves a GPS sentence.
		///  If the sentence appears correct (starts with $GP) the GPSMessage event is fired
		/// If an exception should occur, the COMM Port is closed and the exception is propagated
		/// </summary>
		private void GPSReadLoop()
		{
			EventHandler GPSMessageHandler = new EventHandler(this.DispatchGPSMessage);
			EventHandler GPSReadStartHandler = new EventHandler(this.DispatchGPSReadStart);
			EventHandler GPSReadStopHandler = new EventHandler(this.DispatchGPSReadStop);

			try //MOD
			{
			OpenPort() ;

			// Signal beginning of read process - event fired on UI thread
			this.Invoke(GPSReadStartHandler) ;

			//try //MOD
			//{
				gpsSentence = ReadSentence() ;
				while (gpsSentence != null)	// will only be null if StopRead() is called
				{
					// If appears to be valid message, Signal GPS Message received - event fired on UI thread
					// Invoke blocks this thread until the method wrapped by the GPSMessageHandler returns.
					//  If this code is ever changed to an asynchronous method of execution then the gpsSentence
					//  variable will have to be protected against simultaneous access.
					if (gpsSentence.StartsWith("$GP"))
						this.Invoke(GPSMessageHandler) ; 

					gpsSentence = ReadSentence() ;
				}
			}
			catch (Exception e)
			{   // If any exception is thrown, close the COMM port and propagate the exception
				ClosePort() ;
				//throw e ; //MOD
			}
			// Signal end of read process - event fired on UI thread
			this.Invoke(GPSReadStopHandler) ;

		}

		/// <summary>
		/// Handoff to the appopriate ReadSentence based on active ReadMode
		/// </summary>
		/// <returns>GPS Sentence</returns>
		private string ReadSentence()
		{
			string returnVal = string.Empty ;
			if (_activeReadMode == ReadMode.Message)
				returnVal = ReadSentence_Message() ;
			else
				returnVal = ReadSentence_Character() ;
			return returnVal ;
		}

		/// <summary>
		/// Retrieves the sentence and translates from ASCII to Unicode
		/// </summary>
		/// <returns>GPS Sentence</returns>
		private string ReadSentence_Message()
		{
			Byte[] buffer;
			Byte[] temp = new Byte[1] ;
			int numBytesRead = 0 ;
			Encoding asciiConverter = Encoding.ASCII ;

			// keep reading until we are told to stop or we get something 
			//  looped read should only occur if read errors are encountered
			bool portReturnedData = ReadPort_Message(MAX_MESSAGE, out buffer, out numBytesRead) ;
			while (_readData && ! portReturnedData)
				portReturnedData = ReadPort_Message(MAX_MESSAGE, out buffer, out numBytesRead) ;

			// if still reading, Translate from ASCII to Unicode
			return _readData ? asciiConverter.GetString(buffer, 0, numBytesRead) : null ;
		}

		/// <summary>
		/// Builds the sentence by doing single character reads then translates from ASCII to Unicode
		/// Additional code is used to adjust whether translation starts at the beginning of the string
		/// or skips the first character.  This had to be added because one of the GPS simulators we were
		/// using would send an extra character after the carriage-return (\n).
		/// </summary>
		/// <returns>GPS Sentence</returns>
		public string ReadSentence_Character()
		{
			Byte[] data = new Byte[MAX_MESSAGE] ;
			Byte temp = 0 ;
			int pos = 0 ;
			Encoding asciiConverter = Encoding.ASCII ;

			// Build the sentence until carriage-return encountered
			while(_readData && temp != endOfGPSSentenceMarker) 
			{
				temp = ReadPort_Character() ;
				data[pos++] = temp ;
			} 
			
			// Translation adjustment to handle extra character sent by some simulation programs
			int translateStartPos = 0 ;
			int translateCount = pos ;
			if (data[0] != (Byte) '$')
			{
				translateStartPos++ ;
				translateCount-- ;
			}

			// Perform translation

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -