📄 nmeaparser.cs
字号:
using System;
using System.Globalization;
namespace GPSPet
{
public class NmeaParser
{
public static CultureInfo NmeaCultureInfo = new CultureInfo("en-US");
//用来进行速度转换 1海里=1.150779英里 1英里=1.609344公里 1海里=1.852公里
public static double KPHPerKnot = double.Parse("1.8520", NmeaCultureInfo);
#region Delegates
//位置
public delegate void PositionReceivedEventHandler(string latitude, string longitude);
//时间
public delegate void DateTimeChangedEventHandler(System.DateTime dateTime);
//航向
public delegate void BearingReceivedEventHandler(double bearing);
//速度
public delegate void SpeedReceivedEventHandler(double speed);
//限制速度,不大于55
public delegate void SpeedLimitReachedEventHandler();
//定位
public delegate void FixObtainedEventHandler();
//导航
public delegate void FixLostEventHandler();
//接受卫星信息(PRV号星号,仰角,方位,信噪比)
public delegate void SatelliteReceivedEventHandler(int pseudoRandomCode, int azimuth, int elevation,int signalToNoiseRatio);
//水平精度
public delegate void HDOPReceivedEventHandler(double value);
//垂直精度
public delegate void VDOPReceivedEventHandler(double value);
//位置精度
public delegate void PDOPReceivedEventHandler(double value);
//可见卫星总数目
public delegate void SatellitesInViewReceivedEventHandler(int value);
//使用卫星号
public delegate void SatellitesUsedReceivedEventHandler(int value);
//海平面高度
public delegate void EllipsoidHeightReceivedEventHandler(double value);
//定位模式,M-手动,A-自动
public delegate void ModeEventHandler(string value);
//定位状态,1-无定位,2-2D,3-3D
public delegate void CurrentStateEventHandler(string value);
#endregion
#region Events
public event PositionReceivedEventHandler PositionReceived; //位置
public event DateTimeChangedEventHandler DateTimeChanged; //时间
public event BearingReceivedEventHandler BearingReceived; //航向
public event SpeedReceivedEventHandler SpeedReceived; //速度
public event SpeedLimitReachedEventHandler SpeedLimitReached;//限制速度
public event FixObtainedEventHandler FixObtained; //定位
public event FixLostEventHandler FixLost; //导航
public event SatelliteReceivedEventHandler SatelliteReceived;//接受卫星信息(PRV号星号,仰角,方位,信噪比)
public event HDOPReceivedEventHandler HDOPReceived; //水平精度
public event VDOPReceivedEventHandler VDOPReceived; //垂直精度
public event PDOPReceivedEventHandler PDOPReceived; //位置精度
public event SatellitesInViewReceivedEventHandler SatellitesInViewReceived; //显示卫星总数目
public event SatellitesUsedReceivedEventHandler SatellitesUsed; //使用卫星号
public event EllipsoidHeightReceivedEventHandler EllipsoidHeightReceived; //海平面高度
public event ModeEventHandler Mode; //定位模式
public event CurrentStateEventHandler CurrentState; //当前状态
#endregion
/// <summary>
/// 处理从接收器接受来的信息
/// </summary>
/// <param name="sentence"></param>
/// <returns></returns>
public bool Parse(string sentence)
{
// 丢弃不符合序列的句子
if (!IsValid(sentence)) return false;
//检查句子的第一个词确定从哪种格式开始解析
switch (GetWords(sentence)[0])
{
case "$GPRMC":
return ParseGPRMC(sentence);
case "$GPGSV":
return ParseGPGSV(sentence);
case "$GPGSA":
return ParseGPGSA(sentence);
case "$GPGGA":
return ParseGPGGA(sentence);
default:
return false; // 预示句子没通过检查
}
}
/// <summary>
/// 将句子切隔成词串
/// </summary>
/// <param name="sentence"></param>
/// <returns></returns>
public string[] GetWords(string sentence)
{
//去掉最后的 *
sentence = sentence.Substring(0, sentence.IndexOf("*"));
//按逗号进行分隔
return sentence.Split(',');
}
/// <summary>
/// 解析 $GPRMC 格式的信息
/// </summary>
/// <param name="sentence"></param>
/// <returns></returns>
public bool ParseGPRMC(string sentence)
{
string[] Words = GetWords(sentence);//将句子拆分成词
if (Words[3] != "" & Words[4] != "" & Words[5] != "" & Words[6] != "") //提取经度,纬度
{
//// Append hours
//string Latitude = Words[3].Substring(0, 2) + "\"";
//// Append minutes
//Latitude = Latitude + Words[3].Substring(2) + "\"";
//// Append the hemisphere
//Latitude = Latitude + Words[4];
//// Append hours
//string Longitude = Words[5].Substring(0, 3) + "\"";
//// Append minutes
//Longitude = Longitude + Words[5].Substring(3) + "\"";
//// Append the hemisphere
//Longitude = Longitude + Words[6];
// Append hours
string Latitude = Words[3];//纬度
string Longitude = Words[5];//经度
// 将变化通知回调应用程序
if (PositionReceived != null)
PositionReceived(Latitude, Longitude);
}
if (Words[1] != "") //提取时,分,秒,毫秒
{
int UtcHours = Convert.ToInt32(Words[1].Substring(0, 2));
int UtcMinutes = Convert.ToInt32(Words[1].Substring(2, 2));
int UtcSeconds = Convert.ToInt32(Words[1].Substring(4, 2));
int UtcMilliseconds = 0;
if (Words[1].Length > 7) //提取毫秒
{
UtcMilliseconds = Convert.ToInt32(Words[1].Substring(7));
}
// 用所有的值建立时间对象
//用对象today将当前时间转换为通用时间
System.DateTime Today = System.DateTime.Now.ToUniversalTime();
System.DateTime SatelliteTime = new System.DateTime(Today.Year,
Today.Month, Today.Day, UtcHours, UtcMinutes, UtcSeconds,
UtcMilliseconds);
// 通知新时间,并调整成本地时间
if (DateTimeChanged != null)
DateTimeChanged(SatelliteTime.ToLocalTime()); //将当前对象satelliteTime的值转化为本地时间
}
if (Words[7] != "") //地面速度
{
//将速度解析并表达成 公里/小时
double Speed = double.Parse(Words[7], NmeaCultureInfo) * KPHPerKnot;
// 通知新速度
if (SpeedReceived != null)
SpeedReceived(Speed);
// 是否超出限定速度
if (Speed > 55)
if (SpeedLimitReached != null)
SpeedLimitReached();
}
if (Words[8] != "") //航向
{
double Bearing = double.Parse(Words[8], NmeaCultureInfo);
if (BearingReceived != null)
BearingReceived(Bearing);
}
//当前设备是否有satellite fix?
if (Words[2] != "")
{
switch (Words[2])
{
case "A": //状态A=定位
if (FixObtained != null)
FixObtained();
break;
case "V": //状态V=导航
if (FixLost != null)
FixLost();
break;
}
}
return true; //表示句子被检验完毕
}
/// <summary>
/// 解析 $GPGSV 格式的信息
/// </summary>
/// <param name="sentence"></param>
/// <returns></returns>
public bool ParseGPGSV(string sentence)
{
int PseudoRandomCode = 0; //卫星的PRV号星号
int Azimuth = 0; //方位
int Elevation = 0; //仰角
int SignalToNoiseRatio = 0;//信噪比
// 将句子分隔成词串
string[] Words = GetWords(sentence);
// 每句话包含四块卫星信息
// 读每一块并报告每一块的卫星信息
int Count = 0;
for (Count = 1; Count <= 4; Count++)
{
if (Words[3] != "") //可见卫星数目
{
if (SatellitesInViewReceived != null)
SatellitesInViewReceived(int.Parse(Words[3]));
}
if ((Words.Length - 1) >= (Count * 4 + 3))
{
if (Words[Count * 4] != "" & Words[Count * 4 + 1] != ""
& Words[Count * 4 + 2] != "" & Words[Count * 4 + 3] != "")
{
PseudoRandomCode = System.Convert.ToInt32(Words[Count * 4]); //卫星的PRV号星号
Elevation = Convert.ToInt32(Words[Count * 4 + 1]); //仰角
Azimuth = Convert.ToInt32(Words[Count * 4 + 2]); //方位
SignalToNoiseRatio = Convert.ToInt32(Words[Count * 4 + 3]); //信噪比
// 报告卫星信息
if (SatelliteReceived != null)
SatelliteReceived(PseudoRandomCode, Azimuth,
Elevation, SignalToNoiseRatio);
}
}
}
return true; //表示句子被检验完毕
}
/// <summary>
/// 解析 $GPGSA 格式的信息
/// </summary>
/// <param name="sentence"></param>
/// <returns></returns>
public bool ParseGPGSA(string sentence)
{
string[] Words = GetWords(sentence);
if (Words[1] != "") //定位模式
{
if (Mode != null)
Mode(Words[1]);
}
if (Words[2] != "") //定位状态
{
if (CurrentState != null)
CurrentState(Words[2]);
}
if (Words[15] != "") //位置精度
{
if (PDOPReceived != null)
PDOPReceived(double.Parse(Words[15], NmeaCultureInfo));
}
if (Words[16] != "") //水平精度
{
if (HDOPReceived != null)
HDOPReceived(double.Parse(Words[16], NmeaCultureInfo));
}
if (Words[17] != "") //垂直精度
{
if (VDOPReceived != null)
VDOPReceived(double.Parse(Words[17], NmeaCultureInfo));
}
return true;
}
/// <summary>
/// 解析$GPGGA格式信息
/// </summary>
/// <param name="sentence"></param>
/// <returns></returns>
public bool ParseGPGGA(string sentence)
{
string[] Words = GetWords(sentence);
if (Words[7] != "") //使用卫星号
{
if (SatellitesUsed != null)
SatellitesUsed(int.Parse(Words[7]));
}
if (Words[8] != "")
{
if (HDOPReceived != null) //精度百分比
HDOPReceived(double.Parse(Words[8], NmeaCultureInfo));
}
if (Words[9] != "") //海平面高度
{
if (EllipsoidHeightReceived != null)
EllipsoidHeightReceived(double.Parse(Words[9]));
}
return true;
}
public bool IsValid(string sentence)
{
// Compare the characters after the asterisk to the calculation
return sentence.Substring(sentence.IndexOf("*") + 1) ==
GetChecksum(sentence);
}
// Calculates the checksum for a sentence
public string GetChecksum(string sentence)
{
// Loop through all chars to get a checksum
int Checksum = 0;
foreach (char Character in sentence)
{
if (Character == '$')
{
// Ignore the dollar sign
}
else if (Character == '*')
{
// Stop processing before the asterisk
break;
}
else
{
// Is this the first value for the checksum?
if (Checksum == 0)
{
// Yes. Set the checksum to the value
Checksum = Convert.ToByte(Character);
}
else
{
// No. XOR the checksum with this character's value
Checksum = Checksum ^ Convert.ToByte(Character);
}
}
}
// Return the checksum formatted as a two-character hexadecimal
return Checksum.ToString("X2");
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -