📄 gpsreader.cs
字号:
/// Wrapper method to simplify reading a GPS sentence from the COMM port
/// Method blocks until the COMM port driver receives a CR ('\n') or the COMM port is closed
/// Return value indicates if any data was read - A 'false' return value occurs in one of 3 scenarios
/// 1. COMM port was closed, which usually indicates that StopRead has been called
/// 2. An error has occurred on the COMM port
/// 3. The read has timed out - this should never happen because we don't read until
/// were notified by the COMM port driver that the carriage-return ('\n') has arrived
/// </summary>
/// <param name="hPort"></param>
/// <param name="numBytes"></param>
/// <param name="buffer"></param>
/// <param name="numBytesRead"></param>
/// <returns></returns>
private bool ReadPort_Message(int numBytes, out Byte[] buffer, out int numBytesRead)
{
numBytesRead = 0;
buffer = new Byte[numBytes];
uint eventMask = 0 ;
int readRetVal = 0 ;
bool retVal = false;
SetCommMask(_portHandle, EV_RXFLAG) ; // Indicate that we want to wait for the '\n'
WaitCommEvent(_portHandle, out eventMask, IntPtr.Zero) ;// Wait...
if ((eventMask & EV_RXFLAG) != 0) // If received '\n' - do the read
{ // only other reason we'd be here is if the port was closed
readRetVal = ReadFile(_portHandle, buffer, numBytes, ref numBytesRead, IntPtr.Zero) ;
retVal = readRetVal != 0 && numBytesRead > 0 ; // success only if non-zero return value and
} // at least one byte read
return retVal ;
}
/// <summary>
/// Perform a single character read
/// Internally manages timeouts & null characters
/// Only returns 0 when StopRead is called. Unline ReadPort_Message, it is reasonable to
/// expect that the ReadFile may occasionally timeout if there is a long delay between
/// GPS messages.
/// </summary>
/// <returns>the character read or 0 if _readData is set to false</returns>
private byte ReadPort_Character()
{
int numBytesRead = 0;
Byte[] buffer = new Byte[1];
int retVal = ReadFile(_portHandle, buffer, 1, ref numBytesRead, IntPtr.Zero) ;
while ( _readData && (ReadTimedOut(retVal, numBytesRead) || buffer[0] == 0) )
{
retVal = ReadFile(_portHandle, buffer, 1, ref numBytesRead, IntPtr.Zero) ;
}
return _readData ? buffer[0] : (byte)0 ;
}
/// <summary>
/// Checks to see if ReadFile returned due to a timeout
/// a ReadFile return value of non-zero (true) with number of bytes read of zero indicates timeout
/// This method is used only by ReadPortCharacter
/// </summary>
/// <param name="readRetVal"></param>
/// <param name="numBytesRead"></param>
/// <returns></returns>
private static bool ReadTimedOut(int readRetVal, int numBytesRead)
{
return readRetVal != 0 && numBytesRead == 0 ;
}
#endregion
#region DllImports for Win32 methods
/// <summary>
/// Win32 method used to determine the COMM port's current settings
/// </summary>
/// <param name="hCommDev"></param>
/// <param name="lpDCB"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
private static extern int GetCommState(uint hCommDev, DCB lpDCB) ;
/// <summary>
/// Win32 method used update the COMM portsettings
/// </summary>
/// <param name="hCommDev"></param>
/// <param name="lpDCB"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
private static extern int SetCommState(uint hCommDev, DCB lpDCB);
/// <summary>
/// Win32 method to read data from the COMM port
/// </summary>
/// <param name="hFile"></param>
/// <param name="Buffer"></param>
/// <param name="nNumberOfBytesToRead"></param>
/// <param name="lpNumberOfBytesRead"></param>
/// <param name="notUsedPassZero"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
static extern int ReadFile(uint hFile, Byte[] Buffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, IntPtr notUsedPassZero ) ;
/// <summary>
/// Win32 method to open the COMM port
/// </summary>
/// <param name="lpFileName"></param>
/// <param name="dwDesiredAccess"></param>
/// <param name="dwShareMode"></param>
/// <param name="lpSecurityAttributes"></param>
/// <param name="dwCreationDisposition"></param>
/// <param name="dwFlagsAndAttributes"></param>
/// <param name="notUsedPassZero"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
static extern uint CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, uint lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr notUsedPassZero) ;
/// <summary>
/// Win32 method to close the COMM port
/// </summary>
/// <param name="hObject"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
static extern int CloseHandle(uint hObject);
/// <summary>
/// Win32 method used to sets read timeouts
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpCommTimeouts"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
static extern int SetCommTimeouts(uint hFile, COMMTIMEOUTS lpCommTimeouts);
/// <summary>
/// Win32 method used to set COMM port event masks
/// In our code it is specifically used to identify that we want to be notified when
/// the '\n' character is received
/// </summary>
/// <param name="hFile"></param>
/// <param name="dwEvtMask"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
static extern int SetCommMask(uint hFile, uint dwEvtMask);
/// <summary>
/// Win32 method used to wait for COMM port events to signal
/// In our code it is used to wait for the arrival of the '\n' character
/// </summary>
/// <param name="hFile"></param>
/// <param name="lpEvtMask"></param>
/// <param name="notUsedPassZero"></param>
/// <returns></returns>
[DllImport("coredll.dll")]
static extern int WaitCommEvent(uint hFile, out uint lpEvtMask, IntPtr notUsedPassZero);
#endregion
}
/// <summary>
/// GPS Message Structure
/// Sent each time a GPS Message is received
/// </summary>
public class GPSEventArgs : EventArgs
{
// ** GPGGA Message Info **
// Raw Message
public readonly string MessageText ;
// Message Identifier (GPGGA, etc..)
public readonly string MessageType ;
// GMT Time
public readonly double Time ;
// Lat Stuff
public readonly double Lat ;
public readonly double LatOriginal ;
public readonly string LatDirection ;
// Lon Stuff
public readonly double Lon ;
public readonly double LonOriginal ;
public readonly string LonDirection ;
// Quality
public readonly int Quality ;
// Sat Count
public readonly int NumSats ;
// ** GPGSA Message Info **
public readonly int FixType ;
// ** GPRMC & GPVTG Message Info **
public readonly double Bearing ;
#region Sentence Parsing Methods
/// <summary>
/// Internal constructor which automatically parses the GPS sentence
/// and populates the appropriate fields
/// </summary>
/// <param name="messageText"></param>
internal GPSEventArgs(string messageText)
{
MessageText = messageText ;
// Parse Message
string[] tokens = MessageText.Split(new char[] { ',' });
if (tokens.Length > 0)
{
MessageType = tokens[0].Substring(1); // Strip leading $
if (MessageType == "GPGGA")
{
// Time
if (tokens[1].Length > 0)
Time = Convert.ToDouble(tokens[1]);
// Lat Stuff
if (tokens[2].Length > 0)
LatOriginal = Convert.ToDouble(tokens[2]);
LatDirection = tokens[3].ToUpper();
Lat = LonLatToDegrees(LatOriginal, LatDirection);
// Lon Stuff
if (tokens[4].Length > 0)
LonOriginal = Convert.ToDouble(tokens[4]);
LonDirection = tokens[5].ToUpper();
Lon = LonLatToDegrees(LonOriginal, LonDirection);
// Quality
if (tokens[6].Length > 0)
Quality = Convert.ToInt32(6);
// Sat Count
if (tokens[7].Length > 0)
NumSats = Convert.ToInt32(tokens[7]);
}
else if (MessageType == "GPGSA")
{
if (tokens[2].Length > 0)
FixType = Convert.ToInt32(tokens[2]);
}
else if (MessageType == "GPRMC")
{
if (tokens[8].Length > 0)
Bearing = Convert.ToDouble(tokens[8]);
}
else if (MessageType == "GPVTG")
{
if (tokens[1].Length > 0)
Bearing = Convert.ToDouble(tokens[1]);
}
}
}
/// <summary>
/// Converts Longitude and Latitude to Degrees
/// </summary>
/// <param name="original"></param>
/// <param name="direction"></param>
/// <returns></returns>
private double LonLatToDegrees(double original, string direction)
{
// y = m_dLatOrig / 100
// m_dLat = (((y - Int(y)) * 100) / 60) + Int(y)
double temp = original / 100 ;
int tempAsInt = (int) temp ;
double result = (((temp - tempAsInt) * 100) / 60) + tempAsInt ;
return direction == "S" || direction == "W" ? -result : result ;
}
#endregion
}
#region Port Configuration Enums - ParitySetting, StopBitsSetting and ReadMode
/// <summary>
/// Used to identify valid COMM port Parity Settings
/// </summary>
public enum ParitySetting
{
NoParity = 0,
OddParity = 1,
EvenParity = 2,
MarkParity = 3,
SpaceParity = 4
}
/// <summary>
/// Used to identify COMM port Stop Bit Settings
/// </summary>
public enum StopBitsSetting
{
OneStopBit = 0,
One5StopBits = 1,
TwoStopBits = 2
}
/// <summary>
/// Used to identify GPS driver read mode. Used for both to indicate to the GPSReader
/// the preferred read mode and also for the GPSReader to indicate what read mode it
/// is using.
/// In the implementation setting a PreferredReadMode of Auto amd Message are basically
/// equivalent because the GPSReader class will always verify that MessageMode is supported
/// before attempting to use it.
/// </summary>
public enum ReadMode
{
Undefined = 0, // Only used to indicate that the GPSReader has not yet determined which mode to use
Message, // Indicates to read entire messages from the driver, if supported
Character, // Indicates to build messages character-by-character
Auto // Indicates the GPSReader should choose the read mode based on driver ability
}
#endregion
#region GPSEventHandler decleration
/// <summary>
/// Delegate definition for the GPSMessage event
/// </summary>
public delegate void GPSEventHandler(object sender, GPSEventArgs arg) ;
#endregion
#region COMMTIMEOUTS definition
[StructLayout(LayoutKind.Sequential)]
internal class COMMTIMEOUTS
{
public uint ReadIntervalTimeout = 0 ;
public uint ReadTotalTimeoutMultiplier = 0 ;
public uint ReadTotalTimeoutConstant = 0 ;
public uint WriteTotalTimeoutMultiplier = 0 ;
public uint WriteTotalTimeoutConstant = 0 ;
}
#endregion
#region DCB definition
[StructLayout(LayoutKind.Sequential)]
internal class DCB
{
public DCB()
{
// Initialize the length of the structure.
this.DCBlength = (uint)Marshal.SizeOf(this);
}
public uint DCBlength = 0 ;
public uint BaudRate = 0 ;
public uint Control = 0 ;
public ushort wReserved = 0 ;
public ushort XonLim = 0 ;
public ushort XoffLim = 0 ;
public byte ByteSize = 0 ;
private byte _parity = 0 ;
private byte _stopBits = 0 ;
public sbyte XonChar = 0 ;
public sbyte XoffChar = 0 ;
public sbyte ErrorChar = 0 ;
public sbyte EofChar = 0 ;
public sbyte EvtChar = 0 ;
public ushort wReserved1 = 0 ;
public ParitySetting Parity
{
get {return (ParitySetting) _parity;}
set {_parity = (byte) value;}
}
public StopBitsSetting StopBits
{
get {return (StopBitsSetting) _stopBits;}
set {_stopBits = (byte) value;}
}
}
#endregion
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -