Welcome

首页 / 软件开发 / .NET编程技术 / .NET Compact Framework下的GPS NMEA data数据分析(下)

.NET Compact Framework下的GPS NMEA data数据分析(下)2010-11-22 博客园 Jake.NET代码5

从ParseGPGSA看,这个比较特别,他把在使用的卫星信息分开 多条语句output。如下:

$GPGSV,3,1,12,03,43,246,46,06,57,263,52,09,10,090,00,14,2 9,357,41*71
$GPGSV,3,2,12,15,12,140,00,16,10,307,00,18,59,140,00,19,20,224,00*75 $GPGSV,3,3,12,21,48,089,00,22,69,265,36,24,09,076,00,34,00,000,00*76

字段1为一共分开多少条语句。字段2为当前语句的序号。字段3为 在使用的卫星的数量。后面字段分别表示三个不同卫星的信息,取其中一个卫星 来解释,字段4为卫星的ID,字段5为太空海拔,字段6为角度,字段7为信号强弱 。

对于厂商的私有NMEA data也是同样的方法进行分析,根据文档的描述 进行分析。下面为整个类的代码。

NmeaParser
public class NmeaParser
{
public struct Coordinate
{
public int Hours;
public int Minutes;
public double Seconds;
}

public enum FixStatus
{
NotSet,
Obtained, //A
Lost //V
}

public enum FixMode
{
Auto, //A
Manual
}

public enum FixMethod
{
NotSet,
Fix2D,
Fix3D
}

public enum DifferentialGpsType
{
NotSet,
SPS,
DSPS,
PPS,
RTK
}

public class GpsSatellite
{
public int PRC { get; set; }
public int Elevation { get; set; }
public int Azimuth { get; set; }
public int SNR { get; set; }
public bool InUsed { get; set; }
public bool InView { get; set; }
public bool NotTracking { get; set; }
}

private static readonly CultureInfo NmeaCultureInfo = new CultureInfo("en-US");
private static readonly decimal KMpHPerKnot = decimal.Parse("1.852", NmeaCultureInfo);

private Coordinate latitude;
private Coordinate longitude;
private decimal altitude = 0;

private DateTime utcDateTime;
private decimal velocity = 0;
private decimal azimuth = 0;

private FixStatus fixStatus;
private DifferentialGpsType differentialGpsType;
private FixMode fixMode;
private FixMethod fixMethod;

private int satellitesInView;
private int satellitesInUsed;
private readonly Dictionary<int, GpsSatellite> satellites;

private decimal horizontalDilutionOfPrecision = 50;
private decimal positionDilutionOfPrecision = 50;
private decimal verticalDilutionOfPrecision = 50;

public NmeaParser()
{
satellites = new Dictionary<int, GpsSatellite>();
}

public bool Parse(string sentence)
{
string rawData = sentence;
try
{
if (!IsValid(sentence))
{
return false;
}

sentence = sentence.Substring(1, sentence.IndexOf("*") - 1);
string[] Words = Getwords(sentence);
switch (Words[0])
{
case "GPRMC":
return ParseGPRMC (Words);
case "GPGGA":
return ParseGPGGA (Words);
case "GPGSA":
return ParseGPGSA (Words);
case "GPGSV":
return ParseGPGSV (Words);
default:
return false;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message + rawData);
return false;
}
}

private bool IsValid(string sentence)
{
// GPS data can"t be zero length
if (sentence.Length == 0)
{
return false;
}

// first character must be a $
if (sentence[0] != "$")
{
return false;
}

// GPS data can"t be longer than 82 character
if (sentence.Length > 82)
{
return false;
}

try
{
string checksum = sentence.Substring (sentence.IndexOf("*") + 1);
return Checksum(sentence, checksum);
}
catch (Exception e)
{
Console.WriteLine("Checksum failure. " + e.Message);
return false;
}
}

private bool Checksum (string sentence, string checksumStr)
{
int checksum = 0;
int length = sentence.IndexOf("*") - 1;
// go from first character upto last *
for (int i = 1; i <= length; ++i)
{
checksum = checksum ^ Convert.ToByte (sentence[i]);
}

return (checksum.ToString("X2") == checksumStr);
}

// Divides a sentence into individual Words
private static string[] Getwords(string sentence)
{
return sentence.Split(",");
}

private bool ParseGPRMC (string[] Words)
{
if (Words[1].Length > 0 & Words [9].Length > 0)
{
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;

// Extract milliseconds if it is available
if (Words[1].Length > 7)
{
UtcMilliseconds = Convert.ToInt32(Words[1].Substring(7));
}

int UtcDay = Convert.ToInt32(Words[9].Substring(0, 2));
int UtcMonth = Convert.ToInt32(Words [9].Substring(2, 2));
// available for this century
int UtcYear = Convert.ToInt32(Words [9].Substring(4, 2)) + 2000;

utcDateTime = new DateTime(UtcYear, UtcMonth, UtcDay, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds);
}

fixStatus = (Words[2][0] == "A") ? FixStatus.Obtained : FixStatus.Lost;

if (Words[3].Length > 0 & Words [4].Length == 1 & Words[5].Length > 0 & Words[6].Length == 1)
{
latitude.Hours = int.Parse(Words [3].Substring(0, 2));
latitude.Minutes = int.Parse(Words [3].Substring(2, 2));
latitude.Seconds = Math.Round (double.Parse(Words[3].Substring(5, 4)) * 6 / 1000.0, 3);
if ("S" == Words[4])
{
latitude.Hours = - latitude.Hours;
}

longitude.Hours = int.Parse(Words[5].Substring(0, 3));
longitude.Minutes = int.Parse(Words [5].Substring(3, 2));
longitude.Seconds = Math.Round (double.Parse(Words[5].Substring(6, 4)) * 6 / 1000.0, 3);
if ("W" == Words[6])
{
longitude.Hours = - longitude.Hours;
}
}

if (Words [8].Length > 0)
{
azimuth = decimal.Parse(Words[8], NmeaCultureInfo);
}

if (Words [7].Length > 0)
{
velocity = decimal.Parse(Words[7], NmeaCultureInfo) * KMpHPerKnot;
}
return true;
}

private bool ParseGPGGA (string[] Words)
{
if (Words[6].Length > 0)
{
switch (Convert.ToInt32(Words[6]))
{
case 0:
differentialGpsType = DifferentialGpsType.NotSet;
break;
case 1:
differentialGpsType = DifferentialGpsType.SPS;
break;
case 2:
differentialGpsType = DifferentialGpsType.DSPS;
break;
case 3:
differentialGpsType = DifferentialGpsType.PPS;
break;
case 4:
differentialGpsType = DifferentialGpsType.RTK;
break;
default:
differentialGpsType = DifferentialGpsType.NotSet;
break;
}
}

if (Words [7].Length > 0)
{
satellitesInUsed = Convert.ToInt32 (Words[7]);
}

if (Words [8].Length > 0)
{
horizontalDilutionOfPrecision = Convert.ToDecimal(Words[8]);
}

if (Words [9].Length > 0)
{
altitude = Convert.ToDecimal(Words [9]);
}
return true;
}

private bool ParseGPGSA (string[] Words)
{
if (Words[1].Length > 0)
{
fixMode = Words[1][0] == "A" ? FixMode.Auto : FixMode.Manual;
}

if (Words [2].Length > 0)
{
switch (Convert.ToInt32(Words[2]))
{
case 1:
fixMethod = FixMethod.NotSet;
break;
case 2:
fixMethod = FixMethod.Fix2D;
break;
case 3:
fixMethod = FixMethod.Fix3D;
break;
default:
fixMethod = FixMethod.NotSet;
break;
}
}

foreach (GpsSatellite s in satellites.Values)
{
s.InUsed = false;
}
satellitesInUsed = 0;
for (int i = 0; i < 12; ++i)
{
string id = Words[3 + i];
if (id.Length > 0)
{
int nId = Convert.ToInt32 (id);
if (!satellites.ContainsKey (nId))
{
satellites[nId] = new GpsSatellite();
satellites[nId].PRC = nId;
}
satellites[nId].InUsed = true;
++satellitesInUsed;
}
}

if (Words [15].Length > 0)
{
positionDilutionOfPrecision = Convert.ToDecimal(Words[15]);
}

if (Words [16].Length > 0)
{
horizontalDilutionOfPrecision = Convert.ToDecimal(Words[16]);
}

if (Words [17].Length > 0)
{
verticalDilutionOfPrecision = Convert.ToDecimal(Words[17]);
}
return true;
}

private bool ParseGPGSV (string[] Words)
{
int messageNumber = 0;

if (Words[2].Length > 0)
{
messageNumber = Convert.ToInt32(Words [2]);
}
if (Words[3].Length > 0)
{
satellitesInView = Convert.ToInt32 (Words[3]);
}

if (messageNumber == 0 || satellitesInView == 0)
{
return false;
}

for (int i = 1; i <= 4; ++i)
{
if ((Words.Length - 1) >= (i * 4 + 3))
{
int nId = 0;
if (Words[i * 4].Length > 0)
{
string id = Words[i * 4];
nId = Convert.ToInt32 (id);
if (! satellites.ContainsKey(nId))
{
satellites[nId] = new GpsSatellite();
satellites [nId].PRC = nId;
}
satellites[nId].InView = true;
}

if (Words[i * 4 + 1].Length > 0)
{
satellites [nId].Elevation = Convert.ToInt32(Words[i * 4 + 1]);
}

if (Words[i * 4 + 2].Length > 0)
{
satellites[nId].Azimuth = Convert.ToInt32(Words[i * 4 + 2]);
}

if (Words[i * 4 + 3].Length > 0)
{
satellites[nId].SNR = Convert.ToInt32(Words[i * 4 + 3]);
satellites [nId].NotTracking = false;
}
else
{
satellites [nId].NotTracking = true;
}
}
}
return true;
}
}