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

📄 gpsreader.cs

📁 功能:基于windows mobile 的地图查看器。使用vs2005开发
💻 CS
📖 第 1 页 / 共 3 页
字号:
			return _readData ? asciiConverter.GetString(data, translateStartPos, translateCount) : null;
		}

		// *************************************************************
		//   Read mode related methods and properties
		// *************************************************************

		/// <summary>
		/// Indicates whether the COMM Port driver supports reading entire GPS messages at once
		/// The preferred way to read data is to let the driver signal when a carriage-return (\n)
		/// is received and then we read the whole message at once.  Experimentation has shown that 
		/// some of the GPS devices that simulate a serial port do not support this mode.  In that 
		/// case, we need to read the port data character-by-character.
		/// On the GPS devices tested, support for character notification can be verified by attempting
		/// to set the EvtChar (event character) member of the DCB structure using SetCommState and then
		/// reading the DCB back with GetCommState.  If character notification is supported the returned
		/// DCB will contain the EvtChar that was set with SetCommState.  If it is not supported, EvtChar
		/// will contain 0.  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.
		/// </summary>
		/// <returns></returns>
		public bool DriverSupportsMessageMode()
		{
			// Verify that we know the port name
			if (_portName == portNameNotSet)
				throw new ApplicationException("<DriverSupportsMessageMode> Must set Port Name before calling this method") ;

			uint localPortHandle = INVALID_FILE_HANDLE ;
			DCB dcb = new DCB() ;

			// Check to see if port is currently open
			bool openPortLocally = _portHandle == INVALID_FILE_HANDLE ;
			// If port not open then open it, otherwise use current handle
			localPortHandle = openPortLocally ? OpenPort_Raw(_portName) : _portHandle ;
			if (localPortHandle == INVALID_FILE_HANDLE)
				throw new ApplicationException("<DriverSupportsMessageMode> Invalid port: " + _portName) ;

			// Get current port settings
			GetCommState(localPortHandle, dcb) ;
			// Attempt to set event character
			dcb.EvtChar = endOfGPSSentenceMarker ;
			SetCommState(localPortHandle, dcb) ;
			// Read port settings back
			GetCommState(localPortHandle, dcb) ;

			// if port opened locally - close it
			if (openPortLocally)
				CloseHandle(localPortHandle) ;

			// Check to see if driver accepted event character
            return dcb.EvtChar == endOfGPSSentenceMarker ;
		}

		/// <summary>
		/// Preferred Read Mode to use - Defaults to Auto
		/// In Auto, reader will attempt message mode if driver supports it, otherwise uses character-by-character mode
		/// Undefined doesn't make sense in this usage, so if someone tries to set the value to Undefined, make it Auto
		/// </summary>
		public ReadMode PreferredReadMode
		{
			get {return _preferredReadMode;}
			set {_preferredReadMode = (value == ReadMode.Undefined) ? ReadMode.Auto : value ;	}
		}

		/// <summary>
		/// Read Mode that the GPSReader is actually using
		/// Set to Undefined until reading is started
		/// </summary>
		public ReadMode ActiveReadMode
		{
			get {return _activeReadMode;}
		}

		// *************************************************************
		//   Other COMM port related methods
		// *************************************************************

		/// <summary>
		/// This method doesn't actually have anything to do with GPS reading but is helpful for determining
		/// which ports are available on the device
		/// The code simply attempts to open (and immediatly close) all COMM ports between COM1: and COM9:, if it opens
		/// successfully, then it is added to the port list
		/// </summary>
		/// <returns>string array of available ports</returns>
		public static string[] GetPortList()
		{
			ArrayList portList = new ArrayList() ;
			uint hPort = INVALID_FILE_HANDLE ;

			// Walk list of possible ports
			for (int i = 1; i < 10; i++)
			{
				string port = "COM" + i.ToString() + ":" ;
				hPort = OpenPort_Raw(port) ;
				if (hPort != INVALID_FILE_HANDLE)
				{
					portList.Add(port) ;
					CloseHandle(hPort) ;
				}
			}

			// Convert to regular string array
			return (string []) portList.ToArray(typeof(string)) ;
		}

		#region Constants
		private const uint            GENERIC_READ				= 0x80000000;
		private const uint            OPEN_EXISTING				= 3;
		private const uint            INVALID_FILE_HANDLE		= 0xFFFFFFFF ;
		private const uint            EV_RXFLAG					= 0x0002 ;

		private const int             baudRateNotSet			= 0 ;
		private const string          portNameNotSet			= "PortNotSet" ;
		private const ParitySetting   defaultParity				= ParitySetting.NoParity;
		private const StopBitsSetting defaultStopBits			= StopBitsSetting.OneStopBit ;
		private const byte            defaultByteSize			= 8 ;

		private const sbyte			  endOfGPSSentenceMarker	= (sbyte)'\n' ;
		private const int             MAX_MESSAGE				= 256 ;
		#endregion

		#region Private fields

		private string _portName = portNameNotSet ;				// COMM Port Name - must end with ":"
		private int _baudRate = baudRateNotSet ;				// COMM Port Baud Rate
		private ParitySetting _parity = defaultParity ;			// COMM Port Parity - Defaults to NoParity
		private StopBitsSetting _stopBits = defaultStopBits ;	// COMM Port Stop Bits - Defaults to OneStopBit
		private byte _byteSize = defaultByteSize ;				// COM Port Byte Size - Defaults to 8 bits/byte

		private uint _portHandle = INVALID_FILE_HANDLE ;		// COMM Port File Handle
		private Thread _gpsReadThread ;							// Reader Thread
		private bool _readData = false ;						// Indicates whether read loop should continue

		public bool ReadData
		{
			get
			{
				return _readData;
			}
		}

		// Read mode indicates how messages should be read.  The most efficient is to read whole messages
		//  from the COMM port but not all GPS drivers support this mode.  The alternative is to manually
		//  build the messages by reading a character at a time from the driver.
		private ReadMode _preferredReadMode = ReadMode.Auto ;	// COMM Port Preferred Read Mode - Auto lets the reader decide
		private ReadMode _activeReadMode = ReadMode.Undefined ; // COMM Port Read Mode being used - Undefined until reading starts

		// gpsSentence is populated by the GPS read thread and consumed by the UI Thread.  No lock
		//  is currently required because the GPS read thread uses Control.Invoke, which is synchronous, to signal the UI thread.
		// If the code is ever changed to use an asynchronous notification then gpsSentence will need to be protected from simulaneous
		//  access.  
		private string gpsSentence ;							// Represents the current GPS Sentence
		
		#endregion

		#region Cleanup
		/// <summary>
		/// Terminates GPS reading as part of dispose process
		/// </summary>
		/// <param name="disposing"></param>
		protected override void Dispose(bool disposing)
		{
			if (disposing)
				ClosePort() ;
			GC.SuppressFinalize(this) ;
		}

		/// <summary>
		/// Catch all cleanup - if StopRead was never called and Dispose wasn't called then
		/// force shutdown as part of Garbage Collection - hopefully this method is never used
		/// </summary>
		~GPSReader()
		{
			ClosePort() ;
		}
		#endregion

		#region Event Dispatch Helper Methods
		/// <summary>
		/// Raise Events back to listeners
		/// These are helper methods to raise events to the UI layer.  Because updating UI elements from
		///  background threads is considered unsafe, these methods are initiated from the background reader
		///  thread using this.Invoke which causes these methods to run on the same thread that the GPSReader
		///  class was originally created on (usually the same thread as the application UI).  These methods
		///  now do a regular event fire to notify the UI of the actual event.
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void DispatchGPSMessage(object sender, EventArgs e)
		{
			try
			{
				//this has exceptioned before, on GPSEventArgs constructor
				GPSEventArgs arg = new GPSEventArgs(this.gpsSentence);

				if (arg.Lat != lastLat && arg.Lon != lastLon)
				{
					lastLat = arg.Lat;
					lastLon = arg.Lon;

					if (OnGPSMessage != null)
						OnGPSMessage(this, arg);
				}
				//else dont send
			}
			catch (Exception ex)
			{
				System.Diagnostics.Debug.WriteLine(ex.ToString());
			}
		}

		private double lastLat = Double.MinValue;
		private double lastLon = Double.MinValue;

		private void DispatchGPSReadStart(object sender, EventArgs e)
		{
			if (OnGPSReadStart != null)
				OnGPSReadStart(this, EventArgs.Empty) ;
		}

		private void DispatchGPSReadStop(object sender, EventArgs e)
		{
			if (OnGPSReadStop != null)
				OnGPSReadStop(this, EventArgs.Empty) ;
		}
		#endregion

		#region COMM Port Housekeeping Methods

		/// <summary>
		/// Open COMM Port
		/// Configures the Port communication values and timeouts
		/// </summary>
		private void OpenPort()
		{
			if (_portHandle == INVALID_FILE_HANDLE)  // Only open if not yet opened
			{
				_portHandle = OpenPort_Raw(_portName) ;		
				if (_portHandle == INVALID_FILE_HANDLE)
					throw new ApplicationException("<OpenPort> Unable to Open Port: " + _portName) ;

				System.Threading.Thread.Sleep(100) ;	// Some experiments showed problems when the state
														//  was set without a short pause after Open

				_activeReadMode = DetermineActiveReadMode() ;  // Determine Read Mode to use

				ConfigurePort(_baudRate, _parity, _byteSize, _stopBits) ;
				SetReadTimeOuts() ;
			}
		}

		/// <summary>
		/// Determine the active read mode to use based on the preferred read mode and driver capability
		/// Defaults to character mode because works with all drivers
		/// Will attempt message mode if Message or Auto preferred - will downgrade to Character if not supported
		/// </summary>
		/// <returns>ReadMode to use</returns>
		private ReadMode DetermineActiveReadMode()
		{
			ReadMode returnVal = ReadMode.Character ;	// Default to character - everyone supports it

			// If Message mode or Auto preferred - Set active to Message Mode if the driver supports it
			if (_preferredReadMode == ReadMode.Message || _preferredReadMode == ReadMode.Auto)
			{
				if (DriverSupportsMessageMode())
					returnVal = ReadMode.Message ;
			}

			return returnVal ;
		}

		/// <summary>
		/// Close COMM port
		/// </summary>
		private void ClosePort()
		{
			if (_portHandle != INVALID_FILE_HANDLE)
			{
				CloseHandle(_portHandle) ;
				_portHandle = INVALID_FILE_HANDLE ;
			}
		}

		/// <summary>
		/// Set COMM port configuration values
		///  Baud Rate, Parity (default: NoParity), Bits per Byte (default: 8) and Stop Bits (default: OneStopBit)
		///  If using MessageMode, the event character is set to carriage-return (\n) 
		/// </summary>
		/// <param name="baudRate"></param>
		/// <param name="parity"></param>
		/// <param name="byteSize"></param>
		/// <param name="stopBits"></param>
		private void ConfigurePort(int baudRate, ParitySetting parity, byte byteSize, StopBitsSetting stopBits)
		{
			DCB dcb = new DCB() ;
	
			dcb.BaudRate = (uint) baudRate ;
			dcb.Parity = parity ;
			dcb.ByteSize = byteSize;
			dcb.StopBits = stopBits;
			dcb.EvtChar = _activeReadMode == ReadMode.Message ? (sbyte)'\n' : (sbyte)0 ;

			SetCommState (_portHandle, dcb); 
		}

		/// <summary>
		/// Sets COMM Port read timeout values
		/// Hands off to the proper SetReadTimeOuts method based on the active read mode
		/// </summary>
		private void SetReadTimeOuts()
		{
			if (_activeReadMode == ReadMode.Message)
				SetReadTimeOuts_MessageMode() ;
			else
				SetReadTimeOuts_CharacterMode() ;
		}

		/// <summary>
		/// Sets COMM Port read timeout values
		/// Using minimal timeout values because we don't try to read from the COMM port
		///  until we are signaled that a carriage-return ('\n') has been recevied.  As a
		///  result we already know that we have all of the data so no need to wait to see what
		///  comes.
		/// </summary>
		private void SetReadTimeOuts_MessageMode()
		{
			COMMTIMEOUTS timeOuts = new COMMTIMEOUTS();

			timeOuts.ReadIntervalTimeout = 10 ; 
			timeOuts.ReadTotalTimeoutMultiplier = 0 ; 
			timeOuts.ReadTotalTimeoutConstant = 0 ; 
			timeOuts.WriteTotalTimeoutMultiplier = 0 ;
			timeOuts.WriteTotalTimeoutConstant = 0 ;
			SetCommTimeouts(_portHandle, timeOuts) ;
		}

		/// <summary>
		/// Use long timeout multiplier so that we wait efficiently between GPS messages.  The
		/// interval timeout doesn't matter for us because we read the data one character at a
		/// time in character mode.
		/// </summary>
		private void SetReadTimeOuts_CharacterMode()
		{
			COMMTIMEOUTS timeOuts = new COMMTIMEOUTS();

			timeOuts.ReadIntervalTimeout = 0 ; 
			timeOuts.ReadTotalTimeoutMultiplier = 2000 ; 
			timeOuts.ReadTotalTimeoutConstant = 0 ; 
			timeOuts.WriteTotalTimeoutMultiplier = 0 ;
			timeOuts.WriteTotalTimeoutConstant = 0 ;
			SetCommTimeouts(_portHandle, timeOuts) ;
		}
		#endregion

		#region Wrappers over Win32 Methods
		/// <summary>
		/// Wrapper method to simplify the opening of the COMM port
		///  Port name must be of the form COMx: - the colon is required
		/// </summary>
		/// <param name="portName"></param>
		/// <returns></returns>
		private static uint OpenPort_Raw(string portName)
		{
			return CreateFile(portName, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, IntPtr.Zero);
		}

		/// <summary>

⌨️ 快捷键说明

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