C++实现GNSS/GPS的NMEA数据格式解析类示例
nmea数据具体各字段的含义请参考标准定义,这里给出一个C++实现的例子,环境是Android,本文只解析了几个常用的字段;
本示例的关键方法有split、startswith方法和stringToNumber模版函数
bool GnssNmeaParser::startsWith(const std::string &src, const std::string &str)
{
int srcpos = 0;
int srclen = src.length();
int sublen = str.length();
if (srclen < sublen) {
return false;
}
return (0 == src.compare(srcpos, sublen, str));
}
bool GnssNmeaParser::endsWith(const std::string &src, const std::string &str)
{
int srcpos = 0;
int srclen = src.length();
int sublen = str.length();
if (srclen < sublen) {
return false;
}
srcpos = srclen - sublen;
return (0 == src.compare(srcpos, sublen, str));
}
template <class T>
T stringToNumber(const std::string &sstr)
{
T number {};
std::istringstream iss {};
iss.str(sstr);
iss >> number; /* can auto remove leading 0 */
return number;
}
size_t GnssNmeaParser::split(const std::string &line, const std::string &delim, std::vector<std::string> &vstr)
{
size_t pstart = 0;
size_t phit = 0;
std::string sstr;
size_t length = line.length();
vstr.clear();
for (;pstart <= length;)
{
phit = line.find(delim, pstart);
if (std::string::npos != phit)
{
/* find delim, get substr */
sstr = line.substr(pstart, phit-pstart);
vstr.push_back(sstr);
pstart = phit + delim.size();
} else {
/* not find delim, append remaining str and break */
vstr.push_back(line.substr(pstart));
break;
}
}
return vstr.size();
}
for Android Gnss V1.0
解析.h头文件
#ifndef HAL_GNSS_V1_0_GNSSNMEAPARSER_H
#define HAL_GNSS_V1_0_GNSSNMEAPARSER_H
#include <cstdio>
#include <iostream>
#include <sstream>
#include <bitset>
#include <vector>
#include <map>
#include <queue>
#include <hardware/gps.h>
#define GNSS_NMEA_LINE_SEP "\n"
#define GNSS_NMEA_ELEMENT_SEP ","
#define GNSS_NMEA_PARSER_VERSION "v1.0-20.0716"
#if __GNSS_HAL_DEBUG_ON__
/* Flags that indicate information about the satellite */
typedef uint8_t LocGnssSvFlags;
#define GNSS_SV_FLAGS_NONE 0
#define GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA (1)
#define GNSS_SV_FLAGS_HAS_ALMANAC_DATA (2)
#define GNSS_SV_FLAGS_USED_IN_FIX (4)
//hardware/libhardware/include/hardware/gps.h
typedef int64_t GpsUtcTime;
/**
* Flags that indicate information about the satellite
*/
typedef uint8_t GnssSvFlags;
/**
* Constellation type of GnssSvInfo
*/
typedef uint8_t GnssConstellationType;
/** Represents a location. */
typedef struct {
/** set to sizeof(GpsLocation) */
size_t size;
/** Contains GpsLocationFlags bits. */
uint16_t flags;
/** Represents latitude in degrees. */
double latitude;
/** Represents longitude in degrees. */
double longitude;
/**
* Represents altitude in meters above the WGS 84 reference ellipsoid.
*/
double altitude;
/** Represents speed in meters per second. */
float speed;
/** Represents heading in degrees. */
float bearing;
/** Represents expected accuracy in meters. */
float accuracy;
/** Timestamp for the location fix. */
GpsUtcTime timestamp;
} GpsLocation;
typedef struct {
/** set to sizeof(GnssSvInfo) */
size_t size;
/**
* Pseudo-random number for the SV, or FCN/OSN number for Glonass. The
* distinction is made by looking at constellation field. Values should be
* in the range of:
*
* - GPS: 1-32
* - SBAS: 120-151, 183-192
* - GLONASS: 1-24, the orbital slot number (OSN), if known. Or, if not:
* 93-106, the frequency channel number (FCN) (-7 to +6) offset by + 100
* i.e. report an FCN of -7 as 93, FCN of 0 as 100, and FCN of +6 as 106.
* - QZSS: 193-200
* - Galileo: 1-36
* - Beidou: 1-37
*/
int16_t svid;
/**
* Defines the constellation of the given SV. Value should be one of those
* GNSS_CONSTELLATION_* constants
*/
GnssConstellationType constellation;
/**
* Carrier-to-noise density in dB-Hz, typically in the range [0, 63].
* It contains the measured C/N0 value for the signal at the antenna port.
*
* This is a mandatory value.
*/
float c_n0_dbhz;
/** Elevation of SV in degrees. */
float elevation;
/** Azimuth of SV in degrees. */
float azimuth;
/**
* Contains additional data about the given SV. Value should be one of those
* GNSS_SV_FLAGS_* constants
*/
GnssSvFlags flags;
} GnssSvInfo;
/**
* Legacy struct to represents SV information.
* Deprecated, to be removed in the next Android release.
* Use GnssSvInfo instead.
*/
typedef struct {
/** set to sizeof(GpsSvInfo) */
size_t size;
/** Pseudo-random number for the SV. */
int prn;
/** Signal to noise ratio. */
float snr;
/** Elevation of SV in degrees. */
float elevation;
/** Azimuth of SV in degrees. */
float azimuth;
} GpsSvInfo;
/**
* Legacy struct to represents SV status.
* Deprecated, to be removed in the next Android release.
* Use GnssSvStatus instead.
*/
typedef struct {
/** set to sizeof(GpsSvStatus) */
size_t size;
int num_svs;
GpsSvInfo sv_list[GPS_MAX_SVS];
uint32_t ephemeris_mask;
uint32_t almanac_mask;
uint32_t used_in_fix_mask;
} GpsSvStatus;
typedef struct {
/** set to sizeof(GnssSvStatus) */
size_t size;
/** Number of GPS SVs currently visible, refers to the SVs stored in sv_list */
int num_svs;
/**
* Pointer to an array of SVs information for all GNSS constellations,
* except GPS, which is reported using sv_list
*/
GnssSvInfo gnss_sv_list[GNSS_MAX_SVS];
} GnssSvStatus;
#endif
//GGA 定位信息
enum eGNSS_GGA_ITEM_T {
eGGA_Header = 0,
eGGA_UTCTime = 1,
eGGA_Latitude = 2,
eGGA_LatitudeHemi = 3,
eGGA_Longitude = 4,
eGGA_LongitudeHemi = 5,
eGGA_StatusIndicator = 6,
eGGA_SatellitesCount = 7,
eGGA_HDOP = 8,
eGGA_Altitude = 9,
eGGA_AltitudeUnit = 10,
eGGA_GeoidHeight = 11,
eGGA_GeoidHeightUnit = 12,
eGGA_DiffTemporal = 13,
eGGA_DiffStationId = 14,
eGGA_CheckSum = 15,
};
//GLL 定位地理信息
enum eGNSS_GLL_ITEM_T {
eGLL_Header = 0,
eGLL_Latitude = 1,
eGLL_LatitudeHemi = 2,
eGLL_Longitude = 3,
eGLL_LongitudeHemi = 4,
eGLL_UTCTime = 5,
eGLL_FixStatus = 6,
eGLL_PositioningMode = 7, //optional
eGLL_CheckSum = 8,
};
//GSA 当前卫星信息
enum eGNSS_GSA_ITEM_T {
eGSA_Header = 0,
eGSA_Mode = 1,
eGSA_Type = 2,
eGSA_PRN1 = 3,
eGSA_PRN2 = 4,
eGSA_PRN3 = 5,
eGSA_PRN4 = 6,
eGSA_PRN5 = 7,
eGSA_PRN6 = 8,
eGSA_PRN7 = 9,
eGSA_PRN8 = 10,
eGSA_PRN9 = 11,
eGSA_PRN10 = 12,
eGSA_PRN11 = 13,
eGSA_PRN12 = 14,
eGSA_PDOP = 15,
eGSA_HDOP = 16,
eGSA_VDOP = 17,
eGSA_CheckSum = 18,
};
//GSV 可见卫星信息
enum eGNSS_GSV_ITEM_T {
eGSV_Header = 0,
eGSV_ItemCount = 1,
eGSV_ItemSequence = 2,
eGSV_SatellitesCount = 3,
eGSV_PRNCode = 4,
eGSV_SatelliteElevation = 5,
eGSV_SatelliteAzimuth = 6,
eGSV_SignalNoiseRatio = 7,
eGSV_PRNCode2 = 8,
eGSV_SatelliteElevation2 = 9,
eGSV_SatelliteAzimuth2 = 10,
eGSV_SignalNoiseRatio2 = 11,
eGSV_PRNCode3 = 12,
eGSV_SatelliteElevation3 = 13,
eGSV_SatelliteAzimuth3 = 14,
eGSV_SignalNoiseRatio3 = 15,
eGSV_PRNCode4 = 16,
eGSV_SatelliteElevation4 = 17,
eGSV_SatelliteAzimuth4 = 18,
eGSV_SignalNoiseRatio4 = 19,
eGSV_CheckSum = 20,
};
// RMC
enum eGNSS_RMC_ITEM_T {
eRMC_Header = 0,
eRMC_UTCTime = 1,
eRMC_FixStatus = 2,
eRMC_Latitude = 3,
eRMC_LatitudeHemi = 4,
eRMC_Longitude = 5,
eRMC_LongitudeHemi = 6,
eRMC_SpeedKnots = 7,
eRMC_Azimuth = 8,
eRMC_UTCDate = 9,
eRMC_MagneticDeclination = 10,
eRMC_MagneticDeclinationDirection = 11,
eRMC_PositioningMode = 12, //optional
eRMC_CheckSum = 13,
};
//VTG 地面速度信息
enum eGNSS_VTG_ITEM_T {
eVTG_Header = 0,
eVTG_MovementAngle = 1,
eVTG_TrueNorthRef = 2,
eVTG_MovementAngle2 = 3,
eVTG_MagneticNorthRef = 4,
eVTG_HorizontalMoveSpeed = 5,
eVTG_SpeedKnots = 6,
eVTG_HorizontalMoveSpeed2 = 7,
eVTG_SpeedKmh = 8,
eVTG_PositioningMode = 9, //optional
eVTG_CheckSum = 10,
};
//(GGA)GPS定位信息 Global Positioning System Fix Data
//$GPGGA,014434.70,3817.13334637,N,12139.72994196,E,4,07,1.5,6.571,M,8.942,M,0.7,0016*7B
struct XXGGA_Info_T {
double UTCTime; //UTC时间,格式为hhmmss.sss
double Latitude; //纬度,格式为ddmm.mmmm
char LatitudeHemi; //纬度半球,N或S
double Longitude; //经度,格式为dddmm.mmmm
char LongitudeHemi;//经度半球,E或W
uint16_t StatusIndicator;//GPS状态:0初始化,1单点定位,2码差分,3无效PPS,4固定解,5浮点解,6正在估算,7人工输入固定值,8模拟模式,9WAAS差分
size_t SatellitesCount; //使用卫星数量,从00到12
float HDOP; //HDOP-水平精度因子,0.5到99.9,一般认为HDOP越小,质量越好
double Altitude; //椭球高,-9999.9到9999.9米
char AltitudeUnit; //M指单位米
float GeoidHeight; //大地水准面高度异常差值,-9999.9到9999.9米
char GeoidHeightUnit; //M指单位米
int64_t DiffTemporal; //差分GPS数据期限(RTCM SC-104),最后设立RTCM传送的秒数量,如不是差分定位则为空
int16_t DiffStationId;//差分参考基站标号,从0000到1023
//char CheckSum[4]; //从$开始到*之间的所有ASCII码的异或校验
std::bitset<16> BitFlags;
};
//(GLL)定位地理信息 Geographic Position
struct XXGLL_Info_T {
double Latitude; //纬度ddmm.mmmm(度分)格式
char LatitudeHemi; //纬度半球N或S
double Longitude; //经度dddmm.mmmm(度分)格式
char LongitudeHemi;//经度半球E或W
int UTCTimeInt; //UTC时间,hhmmss(时分秒)格式
char FixStatus; //定位状态,A=有效定位,V=无效定位
char PositioningMode; //模式指示,仅NMEA0183 v3.00输出,A=自主定位,D=差分,E=估算,N=数据无效
//char CheckSum[4];
std::bitset<16> BitFlags;
};
//GSA 当前卫星信息 GPS DOP and Active Satellites (GSA)当前卫星信息
#define GSA_INFO_PRN_CNT 12
struct XXGSA_Info_T {
char Mode; //定位模式,A=自动手动2D/3D,M=手动2D/3D
uint16_t Type; //定位类型,1=未定位,2=2D定位,3=3D定位
int PRNList[GSA_INFO_PRN_CNT]; //PRN码-伪随机噪声码,第x信道正在使用的卫星PRN码编号
float PDOP; //accuracy PDOP综合位置精度因子,0.5-99.9
float HDOP; //HDOP水平精度因子0.5-99.9
float VDOP; //VDOP垂直精度因子0.5-99.9
//char CheckSum[4];
std::bitset<32> BitFlags;
};
//(GSV)可见卫星信息 可见卫星信息 GPS Satellites in View
struct XXGSV_Info_T {
uint8_t Ext_constellation; //UNKNOWN==0/GPS==1/SBAS==2/GLONASS==3/QZSS==4/BEIDOU==5/GALILEO==6
size_t ItemCount; //GSV语句的总数
int ItemSequence; //本句GSV的编号
int SatellitesCount; //可见卫星的总数,00~12,前面的0也将被传输
int PRNCode; //PRN码-伪随机噪声码,前面的0也将被传输;GPS:1-32,Beidou:1-37,GLONASS:1-24,Galileo:1-36,...
float SatelliteElevation;//卫星仰角,00~90度,前面的0也将被传输
float SatelliteAzimuth; //卫星方位角,000~359度,前面的0也将被传输
float SignalNoiseRatio; //信噪比,00~99dB,没有跟踪到卫星时为空,前面的0也将被传输
int PRNCode2; //按照每颗卫星进行循环显示,每条GSV语句最多可以显示4颗卫星的信息
float SatelliteElevation2;
float SatelliteAzimuth2;
float SignalNoiseRatio2;
int PRNCode3;
float SatelliteElevation3;
float SatelliteAzimuth3;
float SignalNoiseRatio3;
int PRNCode4;
float SatelliteElevation4;
float SatelliteAzimuth4;
float SignalNoiseRatio4;
//char CheckSum[4];
std::bitset<32> BitFlags;
};
// (RMC)推荐定位信息 Recommended Minimum Specific GPS/TRANSIT Data
//$GPRMC,200808.000,A,3114.4591,N,12118.0993,E,0.82,282.15,191220,,,A*61
struct XXRMC_Info_T {
double UTCTime; //UTC时间,hhmmss.sss格式,格林尼治时间;
char FixStatus; //状态,A=定位,V=未定位;当给GPS复位时为V,不输出速度,角度,时间数据;
double Latitude; //纬度ddmm.mmmm,度分格式
char LatitudeHemi; //纬度N或S
double Longitude; //经度dddmm.mmmm,度分格式
char LongitudeHemi; //经度E或W
float SpeedKnots; //速度,节,Knots
float Azimuth; //方位角,度 Azimuth/bearing
int UTCDate; //UTC日期,DDMMYY格式
float MagneticDeclination; //磁偏角,000-180度
char MagneticDeclinationDirection;//磁偏角方向,E或W
char PositioningMode; //模式指示,仅NMEA0183 v3.00输出,A=自主定位,D=差分,E=估算,N=数据无效
//char CheckSum[4];
std::bitset<16> BitFlags;
};
//(VTG)地面速度信息 Track Made Good and Ground Speed
struct XXVTG_Info_T {
float MovementAngleTN; //以真北为参考基准的地面航向,000~359度,前面的0也将被传输
char TrueNorthRef; //T
float MovementAngleMN; //以磁北为参考基准的地面航向,000~359度,前面的0也将被传输
char MagneticNorthRef; //M
float HorizontalMoveSpeedKn; //地面速率,000.0~999.9节,前面的0也将被传输
char SpeedKnots; //N
float HorizontalMoveSpeedKm; //地面速率,0000.0~1851.8Km/h,前面的0也将被传输
char SpeedKmh; //K
char PositioningMode; //模式指示,仅NMEA0183 v3.00输出,A=自主定位,D=差分,E=估算,N=数据无效
//char CheckSum[4];
std::bitset<16> BitFlags;
};
template <class T>
T stringToNumber(const std::string &sstr)
{
T number {};
std::istringstream iss {};
iss.str(sstr);
iss >> number; /* can auto remove leading 0 */
return number;
}
template <class T>
std::string toString(T &value)
{
std::ostringstream oss {};
oss << value;
return oss.str();
}
template <int BS_MAX_SIZE>
void bitsFlagSet(std::bitset<BS_MAX_SIZE> &bs, size_t pos)
{
bs.set(pos);
}
template <int BS_MAX_SIZE>
void bitsFlagReset(std::bitset<BS_MAX_SIZE> &bs, size_t pos)
{
bs.reset(pos);
}
template <int BS_MAX_SIZE>
void bitsFlagClear(std::bitset<BS_MAX_SIZE> &bs)
{
bs.reset();
}
template <int BS_MAX_SIZE>
bool bitsFlagTest(std::bitset<BS_MAX_SIZE> bs, size_t pos)
{
return bs.test(pos);
}
template <int BS_MAX_SIZE>
std::string bitsFlagToString(std::bitset<BS_MAX_SIZE> &bs)
{
return bs.to_string();
}
class GnssNmeaParser
{
public:
GnssNmeaParser();
~GnssNmeaParser();
int parse(const std::string &nmea);
int getNmeaLines(std::vector<std::string> &lines);
bool getGnssLocation(GpsLocation &gnssLocation);
bool getGnssSvStatus(GnssSvStatus &gnssSvStatus);
GpsUtcTime getUtcTime();
//bool getGpsSvStatus(GpsSvStatus &gpsSvStatus);
//bool getGpsStatus(GpsStatus &gpsStatus);
private:
int procGGA(XXGGA_Info_T &gga);
int procGLL(XXGLL_Info_T &gll);
int procGSA(std::vector<XXGSA_Info_T> &gsaVect);
int procGSV(std::vector<XXGSV_Info_T> &gsvVect);
int procRMC(XXRMC_Info_T &rmc);
int procVTG(XXVTG_Info_T &vtg);
/* convert latitude(ddmm.mmmm) and longitude(dddmm.mmmm) to degrees */
double latLongToDegree(const double dddmm_mmmm);
int gnssSvFlagUsedInFix(const int svid);
void updateUtcTime(const int ddmmyy, const double hhmmss_sss);
void updateLatLong(const double latitude, const char latHemi, const double longtitude, const char longHemi);
void updateAltitude(const double altitude);
void updateBearing(const float bearing);
void updateMagDec(const float magDec, const char magDecDir);
void updateAccuracy(const float pdop, const float hdop, const float vdop);
void updateSpeed(const float speed);
void updateGnssSvStatus(const std::vector<XXGSV_Info_T> &gsvVectInfoT);
void removeChecksum(std::string &str);
uint8_t getNConstellation(const std::string &nmeaHead);
bool startsWith(const std::string &src, const std::string &str);
bool endsWith(const std::string &src, const std::string &str);
std::string replace(const std::string &raw, const std::string &oldstr, const std::string &newstr);
size_t split(const std::string &line, const std::string &delim, std::vector<std::string> &vstr);
void reset();
std::vector<std::string> m_nmeaLines;
std::string m_nmeaLineSep = GNSS_NMEA_LINE_SEP;
std::string m_nmeaElementSep = GNSS_NMEA_ELEMENT_SEP;
std::vector<std::string> m_nmeaGGAvect;
std::vector<std::string> m_nmeaGLLvect;
std::vector<std::vector<std::string>> m_nmeaGSAvec2d;
std::vector<std::vector<std::string>> m_nmeaGSVvec2d;
std::vector<std::string> m_nmeaRMCvect;
std::vector<std::string> m_nmeaVTGvect;
XXGGA_Info_T m_ggaInfoT;
XXGLL_Info_T m_gllInfoT;
std::vector<XXGSA_Info_T> m_gsaVectInfoT;
std::vector<XXGSV_Info_T> m_gsvVectInfoT;
XXRMC_Info_T m_rmcInfoT;
XXVTG_Info_T m_vtgInfoT;
GpsUtcTime m_gnssUtcTime;
GpsLocation m_gnssLocation;
GnssSvStatus m_gnssSvStatus;
GpsStatus m_gpsStatus;
};
#endif // HAL_GNSS_V1_0_GNSSNMEAPARSER_H
解析.cpp实现文件
#include <log/log.h>
#include "GnssNmeaParser.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "GnssNmeaParserV1.0"
GnssNmeaParser::GnssNmeaParser()
{
m_nmeaLineSep = GNSS_NMEA_LINE_SEP;
m_nmeaElementSep = GNSS_NMEA_ELEMENT_SEP;
ALOGI("GnssNmeaParser created. %s", GNSS_NMEA_PARSER_VERSION);
reset();
}
GnssNmeaParser::~GnssNmeaParser()
{
reset();
}
int GnssNmeaParser::parse(const std::string &nmea)
{
reset();
int gpCount = 0;
if (0 == nmea.size()) {
return 0;
}
(void)split(nmea, m_nmeaLineSep, m_nmeaLines);
std::vector<std::string>::iterator vsit;
std::vector<std::string> nmeaGSAvect;
std::vector<std::string> nmeaGSVvect;
std::string line;
for (vsit = m_nmeaLines.begin(); vsit != m_nmeaLines.end(); vsit++) {
line = *vsit;
if (line.size() <= 6) {
//$GPxxx
continue;
}
removeChecksum(line);
gpCount += 1;
if (startsWith(line, "$GPGGA")) { //GGA
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
} else if (startsWith(line, "$GLGGA")) {
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
} else if (startsWith(line, "$BDGGA")) {
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
} else if (startsWith(line, "$GNGGA")) {
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
}
else if (startsWith(line, "$GPGLL")) { //GLL
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
} else if (startsWith(line, "$GLGLL")) {
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
} else if (startsWith(line, "$BDGLL")) {
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
} else if (startsWith(line, "$GNGLL")) {
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
}
else if (startsWith(line, "$GPGSA")) { //GSA
// may contain multi-line
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
} else if (startsWith(line, "$GLGSA")) {
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
} else if (startsWith(line, "$BDGSA")) {
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
} else if (startsWith(line, "$GNGSA")) {
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
}
else if (startsWith(line, "$GPGSV")) { //GSV
// may contain multi-line
(void)split(line, m_nmeaElementSep, nmeaGSVvect);
m_nmeaGSVvec2d.push_back(nmeaGSVvect);
} else if (startsWith(line, "$GLGSV")) {
(void)split(line, m_nmeaElementSep, nmeaGSVvect);
m_nmeaGSVvec2d.push_back(nmeaGSVvect);
} else if (startsWith(line, "$BDGSV")) {
(void)split(line, m_nmeaElementSep, nmeaGSVvect);
m_nmeaGSVvec2d.push_back(nmeaGSVvect);
}
else if (startsWith(line, "$GPRMC")) { //RMC
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
} else if (startsWith(line, "$GLRMC")) {
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
} else if (startsWith(line, "$BDRMC")) {
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
} else if (startsWith(line, "$GNRMC")) {
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
}
else if (startsWith(line, "$GPVTG")) { //VTG
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
} else if (startsWith(line, "$GLVTG")) {
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
} else if (startsWith(line, "$BDVTG")) {
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
} else if (startsWith(line, "$GNVTG")) {
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
}
else {
ALOGD("unkown line:%s", line.c_str());
}
}
(void)procGGA(m_ggaInfoT);
(void)procGLL(m_gllInfoT);
(void)procGSA(m_gsaVectInfoT);
(void)procGSV(m_gsvVectInfoT);
(void)procRMC(m_rmcInfoT);
(void)procVTG(m_vtgInfoT);
m_gnssLocation.size = sizeof(m_gnssLocation);
m_gnssSvStatus.size = sizeof(m_gnssSvStatus);
return gpCount;
}
int GnssNmeaParser::getNmeaLines(std::vector<std::string> &lines)
{
std::vector<std::string>::iterator vsit;
for (vsit = m_nmeaLines.begin(); vsit != m_nmeaLines.end(); vsit++) {
lines.push_back(*vsit+m_nmeaLineSep);
}
return lines.size();
}
int GnssNmeaParser::procGGA(XXGGA_Info_T &gga)
{
size_t vecSize = m_nmeaGGAvect.size();
if (vecSize != eGGA_CheckSum) {
ALOGD("%s invalid vector size:%zu, expected(%d)",
__func__, vecSize, eGGA_CheckSum);
return 0;
}
bitsFlagClear<16>(gga.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaGGAvect[i].length() != 0)
{
bitsFlagSet<16>(gga.BitFlags, i);
}
}
gga.UTCTime = stringToNumber<double>(m_nmeaGGAvect[eGGA_UTCTime]);
gga.Latitude = stringToNumber<double>(m_nmeaGGAvect[eGGA_Latitude]);
gga.LatitudeHemi = stringToNumber<char>(m_nmeaGGAvect[eGGA_LatitudeHemi]);
gga.Longitude = stringToNumber<double>(m_nmeaGGAvect[eGGA_Longitude]);
gga.LongitudeHemi = stringToNumber<char>(m_nmeaGGAvect[eGGA_LongitudeHemi]);
gga.StatusIndicator = stringToNumber<uint16_t>(m_nmeaGGAvect[eGGA_StatusIndicator]);
gga.SatellitesCount = stringToNumber<size_t>(m_nmeaGGAvect[eGGA_SatellitesCount]);
gga.HDOP = stringToNumber<float>(m_nmeaGGAvect[eGGA_HDOP]);
gga.Altitude = stringToNumber<double>(m_nmeaGGAvect[eGGA_Altitude]);
gga.AltitudeUnit = stringToNumber<char>(m_nmeaGGAvect[eGGA_AltitudeUnit]);
gga.GeoidHeight = stringToNumber<float>(m_nmeaGGAvect[eGGA_GeoidHeight]);
gga.GeoidHeightUnit = stringToNumber<char>(m_nmeaGGAvect[eGGA_GeoidHeightUnit]);
gga.DiffTemporal = stringToNumber<long>(m_nmeaGGAvect[eGGA_DiffTemporal]);
gga.DiffStationId = stringToNumber<int>(m_nmeaGGAvect[eGGA_DiffStationId]);
m_gpsStatus.size = sizeof(m_gpsStatus);
if (gga.StatusIndicator != 0) {
updateLatLong(gga.Latitude, gga.LatitudeHemi, gga.Longitude, gga.LongitudeHemi);
updateAltitude(gga.Altitude);
updateAccuracy(0.0f, gga.HDOP, 0.0f);
}
return m_nmeaGGAvect.size();
}
int GnssNmeaParser::procGLL(XXGLL_Info_T &gll)
{
size_t vecSize = m_nmeaGLLvect.size();
if ((vecSize != eGLL_CheckSum)
&& (vecSize != eGLL_CheckSum-1)) {
//PositioningMode is optional, only NMEA0183 v3.00 can provide PositioningMode
ALOGD("%s invalid vector size:%zu, expected(%d/%d)",
__func__, vecSize, eGLL_CheckSum, eGLL_CheckSum-1);
return 0;
}
bitsFlagClear<16>(gll.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaGLLvect[i].length() != 0)
{
bitsFlagSet<16>(gll.BitFlags, i);
}
}
gll.Latitude = stringToNumber<double>(m_nmeaGLLvect[eGLL_Latitude]);
gll.LatitudeHemi = stringToNumber<char>(m_nmeaGLLvect[eGLL_LatitudeHemi]);
gll.Longitude = stringToNumber<double>(m_nmeaGLLvect[eGLL_Longitude]);
gll.LongitudeHemi = stringToNumber<char>(m_nmeaGLLvect[eGLL_LongitudeHemi]);
gll.UTCTimeInt = stringToNumber<int>(m_nmeaGLLvect[eGLL_UTCTime]);
gll.FixStatus = stringToNumber<char>(m_nmeaGLLvect[eGLL_FixStatus]);
if (vecSize == eGLL_CheckSum) {
gll.PositioningMode = stringToNumber<char>(m_nmeaGLLvect[eGLL_PositioningMode]);//optional
}
if ((gll.FixStatus == 'A') && (gll.PositioningMode != 'N')) {
updateLatLong(gll.Latitude, gll.LatitudeHemi, gll.Longitude, gll.LongitudeHemi);
}
return m_nmeaGLLvect.size();
}
int GnssNmeaParser::procGSA(std::vector<XXGSA_Info_T> &gsaVect)
{
if (m_nmeaGSAvec2d.size() == 0) {
ALOGD("%s invalid vector size:%zu", __func__, m_nmeaGSAvec2d.size());
return 0;
}
std::vector<std::vector<std::string>>::iterator vvsit;
std::vector<std::string> nmeaGSAvect {};
XXGSA_Info_T gsa {};
int prnSn = 0;
size_t vecSize = 0;
std::string nmeaHeader;
for (vvsit = m_nmeaGSAvec2d.begin(); vvsit != m_nmeaGSAvec2d.end(); vvsit++) {
nmeaGSAvect = *vvsit;
(void)memset((void *)&gsa, 0, sizeof(gsa));
bitsFlagClear<32>(gsa.BitFlags);
vecSize = nmeaGSAvect.size();
if (vecSize != eGSA_CheckSum) {
ALOGI("%s invalid vector size:%zu, expected(%d)",
__func__, vecSize, eGSA_CheckSum);
continue;
}
for (int i = 1; i < (int)vecSize; i++)
{
if (nmeaGSAvect[i].length() != 0)
{
bitsFlagSet<32>(gsa.BitFlags, i);
}
}
nmeaHeader = (nmeaGSAvect[eGSA_Header]);
gsa.Mode = stringToNumber<char>(nmeaGSAvect[eGSA_Mode]);
gsa.Type = stringToNumber<uint16_t>(nmeaGSAvect[eGSA_Type]);
for (prnSn = 0; prnSn < GSA_INFO_PRN_CNT; prnSn++) {
gsa.PRNList[prnSn] = stringToNumber<int>(nmeaGSAvect[eGSA_PRN1+prnSn]);;
}
gsa.PDOP = stringToNumber<int>(nmeaGSAvect[eGSA_PDOP]);
gsa.HDOP = stringToNumber<int>(nmeaGSAvect[eGSA_HDOP]);
gsa.VDOP = stringToNumber<int>(nmeaGSAvect[eGSA_VDOP]);
gsaVect.push_back(gsa);
if ((gsa.Type <= 1)) {
ALOGD("%s Positioning Mode is %hu(1-untargeted,2-2D,3-3D)", __func__, gsa.Type);
} else {
updateAccuracy(gsa.PDOP, gsa.HDOP, gsa.VDOP);
}
}
return m_nmeaGSAvec2d.size();
}
int GnssNmeaParser::procGSV(std::vector<XXGSV_Info_T> &gsvVect)
{
if (m_nmeaGSVvec2d.size() == 0) {
ALOGD("%s invalid vector size:%zu", __func__, m_nmeaGSVvec2d.size());
return 0;
}
std::vector<std::vector<std::string>>::iterator vvsit;
std::vector<std::string> nmeaGSVvect {};
XXGSV_Info_T gsv {};
std::string nmeaHeader;
size_t vecSize = 0;
for (vvsit = m_nmeaGSVvec2d.begin(); vvsit != m_nmeaGSVvec2d.end(); vvsit++) {
nmeaGSVvect = *vvsit;
(void)memset((void *)&gsv, 0, sizeof(gsv));
bitsFlagClear<32>(gsv.BitFlags);
vecSize = nmeaGSVvect.size();
if ((0 != (vecSize % 4)) || (vecSize < eGSV_PRNCode)) {
ALOGI("%s invalid vector size:%zu, expected(8/12/16/20)", __func__, vecSize);
continue;
}
for (int i = 1; i < (int)vecSize; i++)
{
if (nmeaGSVvect[i].length() != 0)
{
bitsFlagSet<32>(gsv.BitFlags, i);
}
}
nmeaHeader = nmeaGSVvect[eGSV_Header];
gsv.Ext_constellation = getNConstellation(nmeaHeader);
gsv.ItemCount = stringToNumber<size_t>(nmeaGSVvect[eGSV_ItemCount]);
gsv.ItemSequence = stringToNumber<int>(nmeaGSVvect[eGSV_ItemSequence]);
gsv.SatellitesCount = stringToNumber<int>(nmeaGSVvect[eGSV_SatellitesCount]);
/* gsv slices count maybe 8/12/16/20 */
if (vecSize >= eGSV_PRNCode2) {
gsv.PRNCode = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode]);
gsv.SatelliteElevation = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation]);
gsv.SatelliteAzimuth = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth]);
gsv.SignalNoiseRatio = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio]);
}
if (vecSize >= eGSV_PRNCode3) {
gsv.PRNCode2 = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode2]);
gsv.SatelliteElevation2 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation2]);
gsv.SatelliteAzimuth2 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth2]);
gsv.SignalNoiseRatio2 = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio2]);
}
if (vecSize >= eGSV_PRNCode4) {
gsv.PRNCode3 = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode3]);
gsv.SatelliteElevation3 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation3]);
gsv.SatelliteAzimuth3 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth3]);
gsv.SignalNoiseRatio3 = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio3]);
}
if (vecSize == eGSV_CheckSum) {
gsv.PRNCode4 = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode4]);
gsv.SatelliteElevation4 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation4]);
gsv.SatelliteAzimuth4 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth4]);
gsv.SignalNoiseRatio4 = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio4]);
}
gsvVect.push_back(gsv);
}
updateGnssSvStatus(gsvVect);
return m_nmeaGSVvec2d.size();
}
int GnssNmeaParser::procRMC(XXRMC_Info_T &rmc)
{
size_t vecSize = m_nmeaRMCvect.size();
if ((vecSize != eRMC_CheckSum)
&& (vecSize != eRMC_CheckSum-1)) {
//PositioningMode is optional, only NMEA0183 v3.00 can provide PositioningMode
ALOGD("%s invalid vector size:%zu, expected(%d/%d)",
__func__, vecSize, eRMC_CheckSum, eRMC_CheckSum-1);
return 0;
}
bitsFlagClear<16>(rmc.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaRMCvect[i].length() != 0)
{
bitsFlagSet<16>(rmc.BitFlags, i);
}
}
rmc.UTCTime = stringToNumber<double>(m_nmeaRMCvect[eRMC_UTCTime]);
rmc.FixStatus = stringToNumber<char>(m_nmeaRMCvect[eRMC_FixStatus]);
rmc.Latitude = stringToNumber<double>(m_nmeaRMCvect[eRMC_Latitude]);
rmc.LatitudeHemi = stringToNumber<char>(m_nmeaRMCvect[eRMC_LatitudeHemi]);
rmc.Longitude = stringToNumber<double>(m_nmeaRMCvect[eRMC_Longitude]);
rmc.LongitudeHemi = stringToNumber<char>(m_nmeaRMCvect[eRMC_LongitudeHemi]);
rmc.SpeedKnots = stringToNumber<float>(m_nmeaRMCvect[eRMC_SpeedKnots]);
rmc.Azimuth = stringToNumber<float>(m_nmeaRMCvect[eRMC_Azimuth]);
rmc.UTCDate = stringToNumber<int>(m_nmeaRMCvect[eRMC_UTCDate]);
rmc.MagneticDeclination = stringToNumber<float>(m_nmeaRMCvect[eRMC_MagneticDeclination]);
rmc.MagneticDeclinationDirection = stringToNumber<char>(m_nmeaRMCvect[eRMC_MagneticDeclinationDirection]);
if (vecSize == eRMC_CheckSum) {
rmc.PositioningMode = stringToNumber<char>(m_nmeaRMCvect[eRMC_PositioningMode]);//optional
}
if (rmc.FixStatus == 'A') {
updateUtcTime(rmc.UTCDate, rmc.UTCTime);
updateLatLong(rmc.Latitude, rmc.LatitudeHemi, rmc.Longitude, rmc.LongitudeHemi);
updateBearing(rmc.Azimuth);
updateSpeed((1.852f * rmc.SpeedKnots / 3.6f));
updateMagDec(rmc.MagneticDeclination, rmc.MagneticDeclinationDirection);
} else if (rmc.FixStatus == 'V') {
ALOGW("%s FixStatus is V(A-targeted,V-untargeted)", __func__);
// UTCDate and UTCTime may be empty
//updateUtcTime(rmc.UTCDate, rmc.UTCTime);
updateLatLong(rmc.Latitude, rmc.LatitudeHemi, rmc.Longitude, rmc.LongitudeHemi);
//updateBearing(rmc.Azimuth);
} else {
//invalid data
ALOGD("%s invalid FixStatus(%c)", __func__, rmc.FixStatus);
}
return m_nmeaRMCvect.size();
}
int GnssNmeaParser::procVTG(XXVTG_Info_T &vtg)
{
size_t vecSize = m_nmeaVTGvect.size();
if ((vecSize != eVTG_CheckSum)
&& (vecSize != eVTG_CheckSum-1)) {
//PositioningMode is optional, only NMEA0183 v3.00 can provide PositioningMode
ALOGD("%s invalid vector size:%zu, expected(%d/%d)",
__func__, vecSize, eVTG_CheckSum, eVTG_CheckSum-1);
return 0;
}
bitsFlagClear<16>(vtg.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaVTGvect[i].length() != 0)
{
bitsFlagSet<16>(vtg.BitFlags, i);
}
}
vtg.MovementAngleTN = stringToNumber<float>(m_nmeaVTGvect[eVTG_MovementAngle]);
vtg.TrueNorthRef = stringToNumber<char>(m_nmeaVTGvect[eVTG_TrueNorthRef]);
vtg.MovementAngleMN = stringToNumber<float>(m_nmeaVTGvect[eVTG_MovementAngle2]);
vtg.MagneticNorthRef = stringToNumber<char>(m_nmeaVTGvect[eVTG_MagneticNorthRef]);
vtg.HorizontalMoveSpeedKn = stringToNumber<float>(m_nmeaVTGvect[eVTG_HorizontalMoveSpeed]);
vtg.SpeedKnots = stringToNumber<char>(m_nmeaVTGvect[eVTG_SpeedKnots]);
vtg.HorizontalMoveSpeedKm = stringToNumber<float>(m_nmeaVTGvect[eVTG_HorizontalMoveSpeed2]);
vtg.SpeedKmh = stringToNumber<char>(m_nmeaVTGvect[eVTG_SpeedKmh]);
if (vecSize == eVTG_CheckSum) {
vtg.PositioningMode = stringToNumber<char>(m_nmeaVTGvect[eVTG_PositioningMode]);//optional
}
if ((vtg.PositioningMode == 'A') || (vtg.PositioningMode == 'D')) {
updateSpeed(vtg.HorizontalMoveSpeedKm/3.6f);
}
return m_nmeaVTGvect.size();
}
void GnssNmeaParser::updateUtcTime(const int ddmmyy, const double hhmmss_sss)
{
//get utc diff
time_t time_now = time(NULL);
struct tm tm_local {};
struct tm tm_utc {};
long time_local_sec = 0;
long time_utc_sec = 0;
long utc_diff_sec = 0;
//get fixed time
struct tm tm_gnss {};
time_t time_fixed = 0;
int utc_year = 0;
int utc_month = 0;
int utc_day = 0;
int utc_hour = 0;
int utc_minute = 0;
int utc_seconds = 0;
int hhmmss = (int)hhmmss_sss;
int milliseconds = 0;
gmtime_r(&time_now, &tm_utc);
localtime_r(&time_now, &tm_local);
time_local_sec = tm_local.tm_sec +
60*(tm_local.tm_min +
60*(tm_local.tm_hour +
24*(tm_local.tm_yday +
365*tm_local.tm_year)));
time_utc_sec = tm_utc.tm_sec +
60*(tm_utc.tm_min +
60*(tm_utc.tm_hour +
24*(tm_utc.tm_yday +
365*tm_utc.tm_year)));
utc_diff_sec = time_local_sec - time_utc_sec;
utc_day = (ddmmyy / 100) / 100;
utc_month = (ddmmyy / 100) % 100;
utc_year = (ddmmyy % 100) + 2000;
utc_hour = ((hhmmss / 100) / 100);
utc_minute = ((hhmmss / 100) % 100);
utc_seconds = (hhmmss % 100);
//milliseconds = (int)((hhmmss_sss - hhmmss) * 1000); //will less precise
milliseconds = (int)((hhmmss_sss * 1000) - (hhmmss * 1000)); //Improve accuracy
tm_gnss.tm_hour = utc_hour;
tm_gnss.tm_min = utc_minute;
tm_gnss.tm_sec = utc_seconds;
tm_gnss.tm_year = utc_year - 1900;
tm_gnss.tm_mon = utc_month - 1;
tm_gnss.tm_mday = utc_day;
tm_gnss.tm_isdst = -1;
time_fixed = mktime(&tm_gnss) + utc_diff_sec;
m_gnssUtcTime = (long long)time_fixed * 1000 + milliseconds;
m_gnssLocation.timestamp = m_gnssUtcTime;
if ((0 == ddmmyy) || (0 == hhmmss)) {
ALOGW("%s invalid UTCDate=%d, UTCTime=%d", __func__, ddmmyy, hhmmss);
//use local stored utc time
time_fixed = mktime(&tm_utc) + utc_diff_sec;
m_gnssUtcTime = (long long)time_fixed * 1000;
m_gnssLocation.timestamp = m_gnssUtcTime;
}
}
void GnssNmeaParser::updateLatLong(const double latitude, const char latHemi, const double longtitude, const char longHemi)
{
double lat = latitude;
double lon = longtitude;
if (latHemi == 'S') {
lat = -lat;
}
if (longHemi == 'W') {
lon = -lon;
}
m_gnssLocation.flags |= GPS_LOCATION_HAS_LAT_LONG;
m_gnssLocation.latitude = latLongToDegree(lat);
m_gnssLocation.longitude = latLongToDegree(lon);
}
void GnssNmeaParser::updateAltitude(const double altitude)
{
double alt = altitude;
m_gnssLocation.flags |= GPS_LOCATION_HAS_ALTITUDE;
m_gnssLocation.altitude = alt;
}
void GnssNmeaParser::updateBearing(const float bearing)
{
float bea = bearing;
m_gnssLocation.flags |= GPS_LOCATION_HAS_BEARING;
m_gnssLocation.bearing = bea;
}
void GnssNmeaParser::updateMagDec(const float magDec, const char magDecDir)
{
(void)magDec;
(void)magDecDir;
}
void GnssNmeaParser::updateAccuracy(const float pdop, const float hdop, const float vdop)
{
/* GSA HDOP */
(void)pdop;
(void)vdop;
if ((0.1f <= hdop)) {
m_gnssLocation.flags |= GPS_LOCATION_HAS_HORIZONTAL_ACCURACY;
m_gnssLocation.accuracy = hdop;
}
}
void GnssNmeaParser::updateSpeed(const float speed)
{
float velocity = speed;
m_gnssLocation.flags |= GPS_LOCATION_HAS_SPEED;
m_gnssLocation.speed = velocity;
}
void GnssNmeaParser::updateGnssSvStatus(const std::vector<XXGSV_Info_T> &gsvVectInfoT)
{
std::vector<XXGSV_Info_T>::const_iterator vit;
int itemsCount = 0;
int itemSequence = 0;
int sateSeq = 0;
m_gnssSvStatus.size = sizeof(m_gnssSvStatus);
m_gnssSvStatus.num_svs = 0;
for (vit = gsvVectInfoT.begin(); vit != gsvVectInfoT.end(); vit++) {
itemsCount = vit->ItemCount;
itemSequence = vit->ItemSequence;
if ((sateSeq+3) > (GNSS_MAX_SVS-1)) {
/* preventing arrays from out of bounds */
ALOGW(" gnssSvStatus num more than GNSS_MAX_SVS:%d", GNSS_MAX_SVS);
break;
}
//m_gnssSvStatus.gnss_sv_list[sateSeq].size = sizeof(GnssSvInfo);
m_gnssSvStatus.gnss_sv_list[sateSeq].svid = vit->PRNCode;
m_gnssSvStatus.gnss_sv_list[sateSeq].elevation = vit->SatelliteElevation;
m_gnssSvStatus.gnss_sv_list[sateSeq].azimuth = vit->SatelliteAzimuth;
m_gnssSvStatus.gnss_sv_list[sateSeq].c_n0_dbhz = vit->SignalNoiseRatio;
m_gnssSvStatus.gnss_sv_list[sateSeq].flags = 0;
if (bitsFlagTest<32>((*vit).BitFlags, eGSV_SignalNoiseRatio)) {
//m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnss_sv_list[sateSeq].constellation = vit->Ext_constellation;
if (vit->PRNCode > 0) {
/* check and set flag whether available satellite */
m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= gnssSvFlagUsedInFix(vit->PRNCode);
/* increase visible satellites count */
sateSeq += 1;
}
//m_gnssSvStatus.gnss_sv_list[sateSeq].size = sizeof(GnssSvInfo);
m_gnssSvStatus.gnss_sv_list[sateSeq].svid = vit->PRNCode2;
m_gnssSvStatus.gnss_sv_list[sateSeq].elevation = vit->SatelliteElevation2;
m_gnssSvStatus.gnss_sv_list[sateSeq].azimuth = vit->SatelliteAzimuth2;
m_gnssSvStatus.gnss_sv_list[sateSeq].c_n0_dbhz = vit->SignalNoiseRatio2;
m_gnssSvStatus.gnss_sv_list[sateSeq].flags = 0;
if ( bitsFlagTest<32>(vit->BitFlags, eGSV_SignalNoiseRatio2) ) {
//m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnss_sv_list[sateSeq].constellation = vit->Ext_constellation;
if (vit->PRNCode2 > 0) {
m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= gnssSvFlagUsedInFix(vit->PRNCode2);
sateSeq += 1;
}
//m_gnssSvStatus.gnss_sv_list[sateSeq].size = sizeof(GnssSvInfo);
m_gnssSvStatus.gnss_sv_list[sateSeq].svid = vit->PRNCode3;
m_gnssSvStatus.gnss_sv_list[sateSeq].elevation = vit->SatelliteElevation3;
m_gnssSvStatus.gnss_sv_list[sateSeq].azimuth = vit->SatelliteAzimuth3;
m_gnssSvStatus.gnss_sv_list[sateSeq].c_n0_dbhz = vit->SignalNoiseRatio3;
m_gnssSvStatus.gnss_sv_list[sateSeq].flags = 0;
if (bitsFlagTest<32>(vit->BitFlags, eGSV_SignalNoiseRatio3)) {
//m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnss_sv_list[sateSeq].constellation = vit->Ext_constellation;
if (vit->PRNCode3 > 0) {
m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= gnssSvFlagUsedInFix(vit->PRNCode3);
sateSeq += 1;
}
//m_gnssSvStatus.gnss_sv_list[sateSeq].size = sizeof(GnssSvInfo);
m_gnssSvStatus.gnss_sv_list[sateSeq].svid = vit->PRNCode4;
m_gnssSvStatus.gnss_sv_list[sateSeq].elevation = vit->SatelliteElevation4;
m_gnssSvStatus.gnss_sv_list[sateSeq].azimuth = vit->SatelliteAzimuth4;
m_gnssSvStatus.gnss_sv_list[sateSeq].c_n0_dbhz = vit->SignalNoiseRatio4;
m_gnssSvStatus.gnss_sv_list[sateSeq].flags = 0;
if (bitsFlagTest<32>(vit->BitFlags, eGSV_SignalNoiseRatio4)) {
//m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnss_sv_list[sateSeq].constellation = vit->Ext_constellation;
if (vit->PRNCode4 > 0) {
m_gnssSvStatus.gnss_sv_list[sateSeq].flags |= gnssSvFlagUsedInFix(vit->PRNCode4);
sateSeq += 1;
}
}
m_gnssSvStatus.num_svs = sateSeq;
}
double GnssNmeaParser::latLongToDegree(const double dddmm_mmmm)
{
// eg.: 12031.0902 -> 120.51817(120+(31.0902/60.0=0.51817))
int ddd = (int)(dddmm_mmmm/100);
double mm_mmmm = dddmm_mmmm - (ddd*100.0);
double ddd_xxx = ddd + (mm_mmmm / 60.0);
return ddd_xxx;
}
int GnssNmeaParser::gnssSvFlagUsedInFix(const int svid) {
int fixed = 0;
int prnSn = 0;
std::vector<XXGSA_Info_T>::iterator gsaIt;
for (gsaIt = m_gsaVectInfoT.begin(); gsaIt != m_gsaVectInfoT.end(); gsaIt++) {
for (prnSn = 0; prnSn < GSA_INFO_PRN_CNT; prnSn++) {
if (svid == gsaIt->PRNList[prnSn]) {
fixed = GNSS_SV_FLAGS_USED_IN_FIX;
break;
}
}
}
return fixed;
}
bool GnssNmeaParser::getGnssLocation(GpsLocation &gnssLocation)
{
(void)memcpy(&gnssLocation, &m_gnssLocation, sizeof(m_gnssLocation));
return true;
}
bool GnssNmeaParser::getGnssSvStatus(GnssSvStatus &gnssSvStatus)
{
#if 1
int numSv = m_gnssSvStatus.num_svs;
ALOGD("getGnssSvStatus size:%zu, num_svs:%d", m_gnssSvStatus.size, m_gnssSvStatus.num_svs);
for(int tmp = 0; tmp < numSv; tmp++)
{
ALOGD("getGnssSvStatus (id=%d,elevation=%f,azimuth=%f,dbhz=%f,CX=%d,svFlag=0x%x)",
m_gnssSvStatus.gnss_sv_list[tmp].svid,
m_gnssSvStatus.gnss_sv_list[tmp].elevation,
m_gnssSvStatus.gnss_sv_list[tmp].azimuth,
m_gnssSvStatus.gnss_sv_list[tmp].c_n0_dbhz,
(int)m_gnssSvStatus.gnss_sv_list[tmp].constellation,
(int)m_gnssSvStatus.gnss_sv_list[tmp].flags);
}
#endif
(void)memcpy(&gnssSvStatus, &m_gnssSvStatus, sizeof(gnssSvStatus));
return true;
}
GpsUtcTime GnssNmeaParser::getUtcTime()
{
return m_gnssUtcTime;
}
void GnssNmeaParser::reset()
{
m_nmeaLines.clear();
m_nmeaGGAvect.clear();
m_nmeaGLLvect.clear();
m_nmeaGSAvec2d.clear();
m_nmeaGSVvec2d.clear();
m_nmeaRMCvect.clear();
m_nmeaVTGvect.clear();
m_gnssUtcTime = 0;
(void)memset(&m_ggaInfoT, 0, sizeof(m_ggaInfoT));
(void)memset(&m_gllInfoT, 0, sizeof(m_gllInfoT));
m_gsaVectInfoT.clear();
m_gsvVectInfoT.clear();
(void)memset(&m_rmcInfoT, 0, sizeof(m_rmcInfoT));
(void)memset(&m_vtgInfoT, 0, sizeof(m_vtgInfoT));
(void)memset(&m_gnssLocation, 0, sizeof(m_gnssLocation));
(void)memset(&m_gnssSvStatus, 0, sizeof(m_gnssSvStatus));
}
void GnssNmeaParser::removeChecksum(std::string &str)
{
// get rid of checksum at the end of the sentecne
// remove chars after *
size_t phit = 0;
phit = str.find("*");
if (std::string::npos != phit)
{
str.erase(phit);
}
}
uint8_t GnssNmeaParser::getNConstellation(const std::string &nmeaHead)
{
uint8_t constellation = GNSS_CONSTELLATION_UNKNOWN;
if (startsWith(nmeaHead, "$GP")) {
constellation = GNSS_CONSTELLATION_GPS;
} else if (startsWith(nmeaHead, "$GL")) {
constellation = GNSS_CONSTELLATION_GLONASS;
} else if (startsWith(nmeaHead, "$BD")) {
constellation = GNSS_CONSTELLATION_BEIDOU;
} else {
constellation = GNSS_CONSTELLATION_UNKNOWN;
}
return constellation;
}
bool GnssNmeaParser::startsWith(const std::string &src, const std::string &str)
{
int srcpos = 0;
int srclen = src.length();
int sublen = str.length();
if (srclen < sublen) {
return false;
}
return (0 == src.compare(srcpos, sublen, str));
}
bool GnssNmeaParser::endsWith(const std::string &src, const std::string &str)
{
int srcpos = 0;
int srclen = src.length();
int sublen = str.length();
if (srclen < sublen) {
return false;
}
srcpos = srclen - sublen;
return (0 == src.compare(srcpos, sublen, str));
}
std::string GnssNmeaParser::replace(const std::string &raw, const std::string &oldstr, const std::string &newstr) {
std::string res_string = raw;
size_t startpos = 0;
size_t retpos = 0;
while (std::string::npos != (retpos = res_string.find(oldstr, startpos)))
{
if (oldstr.size() == newstr.size()) {
(void)res_string.replace(retpos, oldstr.size(), newstr);
} else {
(void)res_string.erase(retpos, oldstr.size());
(void)res_string.insert(retpos, newstr);
}
startpos = retpos + oldstr.size();
}
return res_string;
}
size_t GnssNmeaParser::split(const std::string &line, const std::string &delim, std::vector<std::string> &vstr)
{
size_t pstart = 0;
size_t phit = 0;
std::string sstr;
size_t length = line.length();
vstr.clear();
for (;pstart <= length;)
{
phit = line.find(delim, pstart);
if (std::string::npos != phit)
{
/* find delim, get substr */
sstr = line.substr(pstart, phit-pstart);
vstr.push_back(sstr);
pstart = phit + delim.size();
} else {
/* not find delim, append remaining str and break */
vstr.push_back(line.substr(pstart));
break;
}
}
return vstr.size();
}
for Android Gnss V1.1
#ifndef HAL_GNSS_V1_0_GNSSNMEAPARSER_H
#define HAL_GNSS_V1_0_GNSSNMEAPARSER_H
#include <cstdio>
#include <iostream>
#include <sstream>
#include <bitset>
#include <vector>
#include <map>
#include <queue>
//#include <hardware/gps.h>
#include <android/hardware/gnss/1.1/IGnss.h>
#define GNSS_NMEA_LINE_SEP "\n"
#define GNSS_NMEA_ELEMENT_SEP ","
#define GNSS_NMEA_PARSER_VERSION "v1.0-20.0716"
using GnssSvFlags = ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvFlags;
using GnssStatusValue = ::android::hardware::gnss::V1_0::IGnssCallback::GnssStatusValue;
using GnssLocationFlags = android::hardware::gnss::V1_0::GnssLocationFlags;
using GnssMax = ::android::hardware::gnss::V1_0::GnssMax;
using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
using GnssConstellationType = ::android::hardware::gnss::V1_0::GnssConstellationType;
using GnssSvInfo = ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvInfo;
using GnssSvStatus = ::android::hardware::gnss::V1_0::IGnssCallback::GnssSvStatus;
using GnssUtcTime = ::android::hardware::gnss::V1_0::GnssUtcTime;
using GnssAidingData = ::android::hardware::gnss::V1_0::IGnss::GnssAidingData;
using GnssPositionMode = ::android::hardware::gnss::V1_0::IGnss::GnssPositionMode;
using GnssPositionRecurrence = ::android::hardware::gnss::V1_0::IGnss::GnssPositionRecurrence;
//GGA 定位信息
enum eGNSS_GGA_ITEM_T {
eGGA_Header = 0,
eGGA_UTCTime = 1,
eGGA_Latitude = 2,
eGGA_LatitudeHemi = 3,
eGGA_Longitude = 4,
eGGA_LongitudeHemi = 5,
eGGA_StatusIndicator = 6,
eGGA_SatellitesCount = 7,
eGGA_HDOP = 8,
eGGA_Altitude = 9,
eGGA_AltitudeUnit = 10,
eGGA_GeoidHeight = 11,
eGGA_GeoidHeightUnit = 12,
eGGA_DiffTemporal = 13,
eGGA_DiffStationId = 14,
eGGA_CheckSum = 15,
};
//GLL 定位地理信息
enum eGNSS_GLL_ITEM_T {
eGLL_Header = 0,
eGLL_Latitude = 1,
eGLL_LatitudeHemi = 2,
eGLL_Longitude = 3,
eGLL_LongitudeHemi = 4,
eGLL_UTCTime = 5,
eGLL_FixStatus = 6,
eGLL_PositioningMode = 7, //optional
eGLL_CheckSum = 8,
};
//GSA 当前卫星信息
enum eGNSS_GSA_ITEM_T {
eGSA_Header = 0,
eGSA_Mode = 1,
eGSA_Type = 2,
eGSA_PRN1 = 3,
eGSA_PRN2 = 4,
eGSA_PRN3 = 5,
eGSA_PRN4 = 6,
eGSA_PRN5 = 7,
eGSA_PRN6 = 8,
eGSA_PRN7 = 9,
eGSA_PRN8 = 10,
eGSA_PRN9 = 11,
eGSA_PRN10 = 12,
eGSA_PRN11 = 13,
eGSA_PRN12 = 14,
eGSA_PDOP = 15,
eGSA_HDOP = 16,
eGSA_VDOP = 17,
eGSA_CheckSum = 18,
};
//GSV 可见卫星信息
enum eGNSS_GSV_ITEM_T {
eGSV_Header = 0,
eGSV_ItemCount = 1,
eGSV_ItemSequence = 2,
eGSV_SatellitesCount = 3,
eGSV_PRNCode = 4,
eGSV_SatelliteElevation = 5,
eGSV_SatelliteAzimuth = 6,
eGSV_SignalNoiseRatio = 7,
eGSV_PRNCode2 = 8,
eGSV_SatelliteElevation2 = 9,
eGSV_SatelliteAzimuth2 = 10,
eGSV_SignalNoiseRatio2 = 11,
eGSV_PRNCode3 = 12,
eGSV_SatelliteElevation3 = 13,
eGSV_SatelliteAzimuth3 = 14,
eGSV_SignalNoiseRatio3 = 15,
eGSV_PRNCode4 = 16,
eGSV_SatelliteElevation4 = 17,
eGSV_SatelliteAzimuth4 = 18,
eGSV_SignalNoiseRatio4 = 19,
eGSV_CheckSum = 20,
};
// RMC
enum eGNSS_RMC_ITEM_T {
eRMC_Header = 0,
eRMC_UTCTime = 1,
eRMC_FixStatus = 2,
eRMC_Latitude = 3,
eRMC_LatitudeHemi = 4,
eRMC_Longitude = 5,
eRMC_LongitudeHemi = 6,
eRMC_SpeedKnots = 7,
eRMC_Azimuth = 8,
eRMC_UTCDate = 9,
eRMC_MagneticDeclination = 10,
eRMC_MagneticDeclinationDirection = 11,
eRMC_PositioningMode = 12, //optional
eRMC_CheckSum = 13,
};
//VTG 地面速度信息
enum eGNSS_VTG_ITEM_T {
eVTG_Header = 0,
eVTG_MovementAngle = 1,
eVTG_TrueNorthRef = 2,
eVTG_MovementAngle2 = 3,
eVTG_MagneticNorthRef = 4,
eVTG_HorizontalMoveSpeed = 5,
eVTG_SpeedKnots = 6,
eVTG_HorizontalMoveSpeed2 = 7,
eVTG_SpeedKmh = 8,
eVTG_PositioningMode = 9, //optional
eVTG_CheckSum = 10,
};
//(GGA)GPS定位信息 Global Positioning System Fix Data
//$GPGGA,014434.70,3817.13334637,N,12139.72994196,E,4,07,1.5,6.571,M,8.942,M,0.7,0016*7B
struct XXGGA_Info_T {
double UTCTime; //UTC时间,格式为hhmmss.sss
double Latitude; //纬度,格式为ddmm.mmmm
char LatitudeHemi; //纬度半球,N或S
double Longitude; //经度,格式为dddmm.mmmm
char LongitudeHemi;//经度半球,E或W
uint16_t StatusIndicator;//GPS状态:0初始化,1单点定位,2码差分,3无效PPS,4固定解,5浮点解,6正在估算,7人工输入固定值,8模拟模式,9WAAS差分
size_t SatellitesCount; //使用卫星数量,从00到12
float HDOP; //HDOP-水平精度因子,0.5到99.9,一般认为HDOP越小,质量越好
double Altitude; //椭球高,-9999.9到9999.9米
char AltitudeUnit; //M指单位米
float GeoidHeight; //大地水准面高度异常差值,-9999.9到9999.9米
char GeoidHeightUnit; //M指单位米
int64_t DiffTemporal; //差分GPS数据期限(RTCM SC-104),最后设立RTCM传送的秒数量,如不是差分定位则为空
int16_t DiffStationId;//差分参考基站标号,从0000到1023
//char CheckSum[4]; //从$开始到*之间的所有ASCII码的异或校验
std::bitset<16> BitFlags;
};
//(GLL)定位地理信息 Geographic Position
struct XXGLL_Info_T {
double Latitude; //纬度ddmm.mmmm(度分)格式
char LatitudeHemi; //纬度半球N或S
double Longitude; //经度dddmm.mmmm(度分)格式
char LongitudeHemi;//经度半球E或W
int UTCTimeInt; //UTC时间,hhmmss(时分秒)格式
char FixStatus; //定位状态,A=有效定位,V=无效定位
char PositioningMode; //模式指示,仅NMEA0183 v3.00输出,A=自主定位,D=差分,E=估算,N=数据无效
//char CheckSum[4];
std::bitset<16> BitFlags;
};
//GSA 当前卫星信息 GPS DOP and Active Satellites (GSA)当前卫星信息
#define GSA_INFO_PRN_CNT 12
struct XXGSA_Info_T {
char Mode; //定位模式,A=自动手动2D/3D,M=手动2D/3D
uint16_t Type; //定位类型,1=未定位,2=2D定位,3=3D定位
int PRNList[GSA_INFO_PRN_CNT]; //PRN码-伪随机噪声码,第x信道正在使用的卫星PRN码编号
float PDOP; //accuracy PDOP综合位置精度因子,0.5-99.9
float HDOP; //HDOP水平精度因子0.5-99.9
float VDOP; //VDOP垂直精度因子0.5-99.9
//char CheckSum[4];
std::bitset<32> BitFlags;
};
//(GSV)可见卫星信息 可见卫星信息 GPS Satellites in View
struct XXGSV_Info_T {
uint8_t Ext_constellation; //UNKNOWN==0/GPS==1/SBAS==2/GLONASS==3/QZSS==4/BEIDOU==5/GALILEO==6
size_t ItemCount; //GSV语句的总数
int ItemSequence; //本句GSV的编号
int SatellitesCount; //可见卫星的总数,00~12,前面的0也将被传输
int PRNCode; //PRN码-伪随机噪声码,前面的0也将被传输;GPS:1-32,Beidou:1-37,GLONASS:1-24,Galileo:1-36,...
float SatelliteElevation;//卫星仰角,00~90度,前面的0也将被传输
float SatelliteAzimuth; //卫星方位角,000~359度,前面的0也将被传输
float SignalNoiseRatio; //信噪比,00~99dB,没有跟踪到卫星时为空,前面的0也将被传输
int PRNCode2; //按照每颗卫星进行循环显示,每条GSV语句最多可以显示4颗卫星的信息
float SatelliteElevation2;
float SatelliteAzimuth2;
float SignalNoiseRatio2;
int PRNCode3;
float SatelliteElevation3;
float SatelliteAzimuth3;
float SignalNoiseRatio3;
int PRNCode4;
float SatelliteElevation4;
float SatelliteAzimuth4;
float SignalNoiseRatio4;
//char CheckSum[4];
std::bitset<32> BitFlags;
};
// (RMC)推荐定位信息 Recommended Minimum Specific GPS/TRANSIT Data
//$GPRMC,200808.000,A,3114.4591,N,12118.0993,E,0.82,282.15,191220,,,A*61
struct XXRMC_Info_T {
double UTCTime; //UTC时间,hhmmss.sss格式,格林尼治时间;
char FixStatus; //状态,A=定位,V=未定位;当给GPS复位时为V,不输出速度,角度,时间数据;
double Latitude; //纬度ddmm.mmmm,度分格式
char LatitudeHemi; //纬度N或S
double Longitude; //经度dddmm.mmmm,度分格式
char LongitudeHemi; //经度E或W
float SpeedKnots; //速度,节,Knots
float Azimuth; //方位角,度 Azimuth/bearing
int UTCDate; //UTC日期,DDMMYY格式
float MagneticDeclination; //磁偏角,000-180度
char MagneticDeclinationDirection;//磁偏角方向,E或W
char PositioningMode; //模式指示,仅NMEA0183 v3.00输出,A=自主定位,D=差分,E=估算,N=数据无效
//char CheckSum[4];
std::bitset<16> BitFlags;
};
//(VTG)地面速度信息 Track Made Good and Ground Speed
struct XXVTG_Info_T {
float MovementAngleTN; //以真北为参考基准的地面航向,000~359度,前面的0也将被传输
char TrueNorthRef; //T
float MovementAngleMN; //以磁北为参考基准的地面航向,000~359度,前面的0也将被传输
char MagneticNorthRef; //M
float HorizontalMoveSpeedKn; //地面速率,000.0~999.9节,前面的0也将被传输
char SpeedKnots; //N
float HorizontalMoveSpeedKm; //地面速率,0000.0~1851.8Km/h,前面的0也将被传输
char SpeedKmh; //K
char PositioningMode; //模式指示,仅NMEA0183 v3.00输出,A=自主定位,D=差分,E=估算,N=数据无效
//char CheckSum[4];
std::bitset<16> BitFlags;
};
template <class T>
T stringToNumber(const std::string &sstr)
{
T number {};
std::istringstream iss {};
iss.str(sstr);
iss >> number; /* can auto remove leading 0 */
return number;
}
template <class T>
std::string toString(T &value)
{
std::ostringstream oss {};
oss << value;
return oss.str();
}
template <int BS_MAX_SIZE>
void bitsFlagSet(std::bitset<BS_MAX_SIZE> &bs, size_t pos)
{
bs.set(pos);
}
template <int BS_MAX_SIZE>
void bitsFlagReset(std::bitset<BS_MAX_SIZE> &bs, size_t pos)
{
bs.reset(pos);
}
template <int BS_MAX_SIZE>
void bitsFlagClear(std::bitset<BS_MAX_SIZE> &bs)
{
bs.reset();
}
template <int BS_MAX_SIZE>
bool bitsFlagTest(std::bitset<BS_MAX_SIZE> bs, size_t pos)
{
return bs.test(pos);
}
template <int BS_MAX_SIZE>
std::string bitsFlagToString(std::bitset<BS_MAX_SIZE> &bs)
{
return bs.to_string();
}
class GnssNmeaParser
{
public:
GnssNmeaParser();
~GnssNmeaParser();
int parse(const std::string &nmea);
int getNmeaLines(std::vector<std::string> &lines);
bool getGnssLocation(GnssLocation &gnssLocation);
bool getGnssSvStatus(GnssSvStatus &gnssSvStatus);
GnssUtcTime getUtcTime();
private:
int procGGA(XXGGA_Info_T &gga);
int procGLL(XXGLL_Info_T &gll);
int procGSA(std::vector<XXGSA_Info_T> &gsaVect);
int procGSV(std::vector<XXGSV_Info_T> &gsvVect);
int procRMC(XXRMC_Info_T &rmc);
int procVTG(XXVTG_Info_T &vtg);
/* convert latitude(ddmm.mmmm) and longitude(dddmm.mmmm) to degrees */
double latLongToDegree(const double dddmm_mmmm);
int gnssSvFlagUsedInFix(const int svid);
void updateUtcTime(const int ddmmyy, const double hhmmss_sss);
void updateLatLong(const double latitude, const char latHemi, const double longtitude, const char longHemi);
void updateAltitude(const double altitude);
void updateBearing(const float bearing);
void updateMagDec(const float magDec, const char magDecDir);
void updateAccuracy(const float pdop, const float hdop, const float vdop);
void updateSpeed(const float speed);
void updateGnssSvStatus(const std::vector<XXGSV_Info_T> &gsvVectInfoT);
void removeChecksum(std::string &str);
uint8_t getNConstellation(const std::string &nmeaHead);
bool startsWith(const std::string &src, const std::string &str);
bool endsWith(const std::string &src, const std::string &str);
std::string replace(const std::string &raw, const std::string &oldstr, const std::string &newstr);
size_t split(const std::string &line, const std::string &delim, std::vector<std::string> &vstr);
void reset();
std::vector<std::string> m_nmeaLines;
std::string m_nmeaLineSep = GNSS_NMEA_LINE_SEP;
std::string m_nmeaElementSep = GNSS_NMEA_ELEMENT_SEP;
std::vector<std::string> m_nmeaGGAvect;
std::vector<std::string> m_nmeaGLLvect;
std::vector<std::vector<std::string>> m_nmeaGSAvec2d;
std::vector<std::vector<std::string>> m_nmeaGSVvec2d;
std::vector<std::string> m_nmeaRMCvect;
std::vector<std::string> m_nmeaVTGvect;
XXGGA_Info_T m_ggaInfoT;
XXGLL_Info_T m_gllInfoT;
std::vector<XXGSA_Info_T> m_gsaVectInfoT;
std::vector<XXGSV_Info_T> m_gsvVectInfoT;
XXRMC_Info_T m_rmcInfoT;
XXVTG_Info_T m_vtgInfoT;
GnssUtcTime m_gnssUtcTime;
GnssLocation m_gnssLocation;
GnssSvStatus m_gnssSvStatus;
//GnssStatusValue m_gnssStatus;
};
#endif // HAL_GNSS_V1_0_GNSSNMEAPARSER_H
#include <log/log.h>
#include "GnssNmeaParser.h"
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "GnssNmeaParserV1.1"
GnssNmeaParser::GnssNmeaParser()
{
m_nmeaLineSep = GNSS_NMEA_LINE_SEP;
m_nmeaElementSep = GNSS_NMEA_ELEMENT_SEP;
ALOGI("GnssNmeaParser created. %s", GNSS_NMEA_PARSER_VERSION);
reset();
}
GnssNmeaParser::~GnssNmeaParser()
{
reset();
}
int GnssNmeaParser::parse(const std::string &nmea)
{
reset();
int gpCount = 0;
if (0 == nmea.size()) {
return 0;
}
(void)split(nmea, m_nmeaLineSep, m_nmeaLines);
std::vector<std::string>::iterator vsit;
std::vector<std::string> nmeaGSAvect;
std::vector<std::string> nmeaGSVvect;
std::string line;
for (vsit = m_nmeaLines.begin(); vsit != m_nmeaLines.end(); vsit++) {
line = *vsit;
if (line.size() <= 6) {
//$GPxxx
continue;
}
removeChecksum(line);
gpCount += 1;
if (startsWith(line, "$GPGGA")) { //GGA
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
} else if (startsWith(line, "$GLGGA")) {
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
} else if (startsWith(line, "$BDGGA")) {
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
} else if (startsWith(line, "$GNGGA")) {
(void)split(line, m_nmeaElementSep, m_nmeaGGAvect);
}
else if (startsWith(line, "$GPGLL")) { //GLL
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
} else if (startsWith(line, "$GLGLL")) {
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
} else if (startsWith(line, "$BDGLL")) {
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
} else if (startsWith(line, "$GNGLL")) {
(void)split(line, m_nmeaElementSep, m_nmeaGLLvect);
}
else if (startsWith(line, "$GPGSA")) { //GSA
// may contain multi-line
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
} else if (startsWith(line, "$GLGSA")) {
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
} else if (startsWith(line, "$BDGSA")) {
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
} else if (startsWith(line, "$GNGSA")) {
(void)split(line, m_nmeaElementSep, nmeaGSAvect);
m_nmeaGSAvec2d.push_back(nmeaGSAvect);
}
else if (startsWith(line, "$GPGSV")) { //GSV
// may contain multi-line
(void)split(line, m_nmeaElementSep, nmeaGSVvect);
m_nmeaGSVvec2d.push_back(nmeaGSVvect);
} else if (startsWith(line, "$GLGSV")) {
(void)split(line, m_nmeaElementSep, nmeaGSVvect);
m_nmeaGSVvec2d.push_back(nmeaGSVvect);
} else if (startsWith(line, "$BDGSV")) {
(void)split(line, m_nmeaElementSep, nmeaGSVvect);
m_nmeaGSVvec2d.push_back(nmeaGSVvect);
}
else if (startsWith(line, "$GPRMC")) { //RMC
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
} else if (startsWith(line, "$GLRMC")) {
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
} else if (startsWith(line, "$BDRMC")) {
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
} else if (startsWith(line, "$GNRMC")) {
(void)split(line, m_nmeaElementSep, m_nmeaRMCvect);
}
else if (startsWith(line, "$GPVTG")) { //VTG
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
} else if (startsWith(line, "$GLVTG")) {
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
} else if (startsWith(line, "$BDVTG")) {
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
} else if (startsWith(line, "$GNVTG")) {
(void)split(line, m_nmeaElementSep, m_nmeaVTGvect);
}
else {
ALOGD("unkown line:%s", line.c_str());
}
}
(void)procGGA(m_ggaInfoT);
(void)procGLL(m_gllInfoT);
(void)procGSA(m_gsaVectInfoT);
(void)procGSV(m_gsvVectInfoT);
(void)procRMC(m_rmcInfoT);
(void)procVTG(m_vtgInfoT);
return gpCount;
}
int GnssNmeaParser::getNmeaLines(std::vector<std::string> &lines)
{
std::vector<std::string>::iterator vsit;
for (vsit = m_nmeaLines.begin(); vsit != m_nmeaLines.end(); vsit++) {
lines.push_back(*vsit+m_nmeaLineSep);
}
return lines.size();
}
int GnssNmeaParser::procGGA(XXGGA_Info_T &gga)
{
size_t vecSize = m_nmeaGGAvect.size();
if (vecSize != eGGA_CheckSum) {
ALOGD("%s invalid vector size:%zu, expected(%d)",
__func__, vecSize, eGGA_CheckSum);
return 0;
}
bitsFlagClear<16>(gga.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaGGAvect[i].length() != 0)
{
bitsFlagSet<16>(gga.BitFlags, i);
}
}
gga.UTCTime = stringToNumber<double>(m_nmeaGGAvect[eGGA_UTCTime]);
gga.Latitude = stringToNumber<double>(m_nmeaGGAvect[eGGA_Latitude]);
gga.LatitudeHemi = stringToNumber<char>(m_nmeaGGAvect[eGGA_LatitudeHemi]);
gga.Longitude = stringToNumber<double>(m_nmeaGGAvect[eGGA_Longitude]);
gga.LongitudeHemi = stringToNumber<char>(m_nmeaGGAvect[eGGA_LongitudeHemi]);
gga.StatusIndicator = stringToNumber<uint16_t>(m_nmeaGGAvect[eGGA_StatusIndicator]);
gga.SatellitesCount = stringToNumber<size_t>(m_nmeaGGAvect[eGGA_SatellitesCount]);
gga.HDOP = stringToNumber<float>(m_nmeaGGAvect[eGGA_HDOP]);
gga.Altitude = stringToNumber<double>(m_nmeaGGAvect[eGGA_Altitude]);
gga.AltitudeUnit = stringToNumber<char>(m_nmeaGGAvect[eGGA_AltitudeUnit]);
gga.GeoidHeight = stringToNumber<float>(m_nmeaGGAvect[eGGA_GeoidHeight]);
gga.GeoidHeightUnit = stringToNumber<char>(m_nmeaGGAvect[eGGA_GeoidHeightUnit]);
gga.DiffTemporal = stringToNumber<long>(m_nmeaGGAvect[eGGA_DiffTemporal]);
gga.DiffStationId = stringToNumber<int>(m_nmeaGGAvect[eGGA_DiffStationId]);
if (gga.StatusIndicator != 0) {
updateLatLong(gga.Latitude, gga.LatitudeHemi, gga.Longitude, gga.LongitudeHemi);
updateAltitude(gga.Altitude);
updateAccuracy(0.0f, gga.HDOP, 0.0f);
}
return m_nmeaGGAvect.size();
}
int GnssNmeaParser::procGLL(XXGLL_Info_T &gll)
{
size_t vecSize = m_nmeaGLLvect.size();
if ((vecSize != eGLL_CheckSum)
&& (vecSize != eGLL_CheckSum-1)) {
//PositioningMode is optional, only NMEA0183 v3.00 can provide PositioningMode
ALOGD("%s invalid vector size:%zu, expected(%d/%d)",
__func__, vecSize, eGLL_CheckSum, eGLL_CheckSum-1);
return 0;
}
bitsFlagClear<16>(gll.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaGLLvect[i].length() != 0)
{
bitsFlagSet<16>(gll.BitFlags, i);
}
}
gll.Latitude = stringToNumber<double>(m_nmeaGLLvect[eGLL_Latitude]);
gll.LatitudeHemi = stringToNumber<char>(m_nmeaGLLvect[eGLL_LatitudeHemi]);
gll.Longitude = stringToNumber<double>(m_nmeaGLLvect[eGLL_Longitude]);
gll.LongitudeHemi = stringToNumber<char>(m_nmeaGLLvect[eGLL_LongitudeHemi]);
gll.UTCTimeInt = stringToNumber<int>(m_nmeaGLLvect[eGLL_UTCTime]);
gll.FixStatus = stringToNumber<char>(m_nmeaGLLvect[eGLL_FixStatus]);
if (vecSize == eGLL_CheckSum) {
gll.PositioningMode = stringToNumber<char>(m_nmeaGLLvect[eGLL_PositioningMode]);//optional
}
if ((gll.FixStatus == 'A') && (gll.PositioningMode != 'N')) {
updateLatLong(gll.Latitude, gll.LatitudeHemi, gll.Longitude, gll.LongitudeHemi);
}
return m_nmeaGLLvect.size();
}
int GnssNmeaParser::procGSA(std::vector<XXGSA_Info_T> &gsaVect)
{
if (m_nmeaGSAvec2d.size() == 0) {
ALOGD("%s invalid vector size:%zu", __func__, m_nmeaGSAvec2d.size());
return 0;
}
std::vector<std::vector<std::string>>::iterator vvsit;
std::vector<std::string> nmeaGSAvect {};
XXGSA_Info_T gsa {};
int prnSn = 0;
size_t vecSize = 0;
std::string nmeaHeader;
for (vvsit = m_nmeaGSAvec2d.begin(); vvsit != m_nmeaGSAvec2d.end(); vvsit++) {
nmeaGSAvect = *vvsit;
(void)memset((void *)&gsa, 0, sizeof(gsa));
bitsFlagClear<32>(gsa.BitFlags);
vecSize = nmeaGSAvect.size();
if (vecSize != eGSA_CheckSum) {
ALOGI("%s invalid vector size:%zu, expected(%d)",
__func__, vecSize, eGSA_CheckSum);
continue;
}
for (int i = 1; i < (int)vecSize; i++)
{
if (nmeaGSAvect[i].length() != 0)
{
bitsFlagSet<32>(gsa.BitFlags, i);
}
}
nmeaHeader = (nmeaGSAvect[eGSA_Header]);
gsa.Mode = stringToNumber<char>(nmeaGSAvect[eGSA_Mode]);
gsa.Type = stringToNumber<uint16_t>(nmeaGSAvect[eGSA_Type]);
for (prnSn = 0; prnSn < GSA_INFO_PRN_CNT; prnSn++) {
gsa.PRNList[prnSn] = stringToNumber<int>(nmeaGSAvect[eGSA_PRN1+prnSn]);;
}
gsa.PDOP = stringToNumber<int>(nmeaGSAvect[eGSA_PDOP]);
gsa.HDOP = stringToNumber<int>(nmeaGSAvect[eGSA_HDOP]);
gsa.VDOP = stringToNumber<int>(nmeaGSAvect[eGSA_VDOP]);
gsaVect.push_back(gsa);
if ((gsa.Type <= 1)) {
ALOGD("%s Positioning Mode is %hu(1-untargeted,2-2D,3-3D)", __func__, gsa.Type);
} else {
updateAccuracy(gsa.PDOP, gsa.HDOP, gsa.VDOP);
}
}
return m_nmeaGSAvec2d.size();
}
int GnssNmeaParser::procGSV(std::vector<XXGSV_Info_T> &gsvVect)
{
if (m_nmeaGSVvec2d.size() == 0) {
ALOGD("%s invalid vector size:%zu", __func__, m_nmeaGSVvec2d.size());
return 0;
}
std::vector<std::vector<std::string>>::iterator vvsit;
std::vector<std::string> nmeaGSVvect {};
XXGSV_Info_T gsv {};
std::string nmeaHeader;
size_t vecSize = 0;
for (vvsit = m_nmeaGSVvec2d.begin(); vvsit != m_nmeaGSVvec2d.end(); vvsit++) {
nmeaGSVvect = *vvsit;
(void)memset((void *)&gsv, 0, sizeof(gsv));
bitsFlagClear<32>(gsv.BitFlags);
vecSize = nmeaGSVvect.size();
if ((0 != (vecSize % 4)) || (vecSize < eGSV_PRNCode)) {
ALOGI("%s invalid vector size:%zu, expected(8/12/16/20)", __func__, vecSize);
continue;
}
for (int i = 1; i < (int)vecSize; i++)
{
if (nmeaGSVvect[i].length() != 0)
{
bitsFlagSet<32>(gsv.BitFlags, i);
}
}
nmeaHeader = nmeaGSVvect[eGSV_Header];
gsv.Ext_constellation = getNConstellation(nmeaHeader);
gsv.ItemCount = stringToNumber<size_t>(nmeaGSVvect[eGSV_ItemCount]);
gsv.ItemSequence = stringToNumber<int>(nmeaGSVvect[eGSV_ItemSequence]);
gsv.SatellitesCount = stringToNumber<int>(nmeaGSVvect[eGSV_SatellitesCount]);
/* gsv slices count maybe 8/12/16/20 */
if (vecSize >= eGSV_PRNCode2) {
gsv.PRNCode = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode]);
gsv.SatelliteElevation = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation]);
gsv.SatelliteAzimuth = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth]);
gsv.SignalNoiseRatio = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio]);
}
if (vecSize >= eGSV_PRNCode3) {
gsv.PRNCode2 = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode2]);
gsv.SatelliteElevation2 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation2]);
gsv.SatelliteAzimuth2 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth2]);
gsv.SignalNoiseRatio2 = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio2]);
}
if (vecSize >= eGSV_PRNCode4) {
gsv.PRNCode3 = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode3]);
gsv.SatelliteElevation3 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation3]);
gsv.SatelliteAzimuth3 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth3]);
gsv.SignalNoiseRatio3 = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio3]);
}
if (vecSize == eGSV_CheckSum) {
gsv.PRNCode4 = stringToNumber<int>(nmeaGSVvect[eGSV_PRNCode4]);
gsv.SatelliteElevation4 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteElevation4]);
gsv.SatelliteAzimuth4 = stringToNumber<float>(nmeaGSVvect[eGSV_SatelliteAzimuth4]);
gsv.SignalNoiseRatio4 = stringToNumber<float>(nmeaGSVvect[eGSV_SignalNoiseRatio4]);
}
gsvVect.push_back(gsv);
}
updateGnssSvStatus(gsvVect);
return m_nmeaGSVvec2d.size();
}
int GnssNmeaParser::procRMC(XXRMC_Info_T &rmc)
{
size_t vecSize = m_nmeaRMCvect.size();
if ((vecSize != eRMC_CheckSum)
&& (vecSize != eRMC_CheckSum-1)) {
//PositioningMode is optional, only NMEA0183 v3.00 can provide PositioningMode
ALOGD("%s invalid vector size:%zu, expected(%d/%d)",
__func__, vecSize, eRMC_CheckSum, eRMC_CheckSum-1);
return 0;
}
bitsFlagClear<16>(rmc.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaRMCvect[i].length() != 0)
{
bitsFlagSet<16>(rmc.BitFlags, i);
}
}
rmc.UTCTime = stringToNumber<double>(m_nmeaRMCvect[eRMC_UTCTime]);
rmc.FixStatus = stringToNumber<char>(m_nmeaRMCvect[eRMC_FixStatus]);
rmc.Latitude = stringToNumber<double>(m_nmeaRMCvect[eRMC_Latitude]);
rmc.LatitudeHemi = stringToNumber<char>(m_nmeaRMCvect[eRMC_LatitudeHemi]);
rmc.Longitude = stringToNumber<double>(m_nmeaRMCvect[eRMC_Longitude]);
rmc.LongitudeHemi = stringToNumber<char>(m_nmeaRMCvect[eRMC_LongitudeHemi]);
rmc.SpeedKnots = stringToNumber<float>(m_nmeaRMCvect[eRMC_SpeedKnots]);
rmc.Azimuth = stringToNumber<float>(m_nmeaRMCvect[eRMC_Azimuth]);
rmc.UTCDate = stringToNumber<int>(m_nmeaRMCvect[eRMC_UTCDate]);
rmc.MagneticDeclination = stringToNumber<float>(m_nmeaRMCvect[eRMC_MagneticDeclination]);
rmc.MagneticDeclinationDirection = stringToNumber<char>(m_nmeaRMCvect[eRMC_MagneticDeclinationDirection]);
if (vecSize == eRMC_CheckSum) {
rmc.PositioningMode = stringToNumber<char>(m_nmeaRMCvect[eRMC_PositioningMode]);//optional
}
if (rmc.FixStatus == 'A') {
updateUtcTime(rmc.UTCDate, rmc.UTCTime);
updateLatLong(rmc.Latitude, rmc.LatitudeHemi, rmc.Longitude, rmc.LongitudeHemi);
updateBearing(rmc.Azimuth);
updateSpeed((1.852f * rmc.SpeedKnots / 3.6f));
updateMagDec(rmc.MagneticDeclination, rmc.MagneticDeclinationDirection);
} else if (rmc.FixStatus == 'V') {
ALOGW("%s FixStatus is V(A-targeted,V-untargeted)", __func__);
// UTCDate and UTCTime may be empty
//updateUtcTime(rmc.UTCDate, rmc.UTCTime);
updateLatLong(rmc.Latitude, rmc.LatitudeHemi, rmc.Longitude, rmc.LongitudeHemi);
//updateBearing(rmc.Azimuth);
} else {
//invalid data
ALOGD("%s invalid FixStatus(%c)", __func__, rmc.FixStatus);
}
return m_nmeaRMCvect.size();
}
int GnssNmeaParser::procVTG(XXVTG_Info_T &vtg)
{
size_t vecSize = m_nmeaVTGvect.size();
if ((vecSize != eVTG_CheckSum)
&& (vecSize != eVTG_CheckSum-1)) {
//PositioningMode is optional, only NMEA0183 v3.00 can provide PositioningMode
ALOGD("%s invalid vector size:%zu, expected(%d/%d)",
__func__, vecSize, eVTG_CheckSum, eVTG_CheckSum-1);
return 0;
}
bitsFlagClear<16>(vtg.BitFlags);
for (int i = 1; i < (int)vecSize; i++)
{
if (m_nmeaVTGvect[i].length() != 0)
{
bitsFlagSet<16>(vtg.BitFlags, i);
}
}
vtg.MovementAngleTN = stringToNumber<float>(m_nmeaVTGvect[eVTG_MovementAngle]);
vtg.TrueNorthRef = stringToNumber<char>(m_nmeaVTGvect[eVTG_TrueNorthRef]);
vtg.MovementAngleMN = stringToNumber<float>(m_nmeaVTGvect[eVTG_MovementAngle2]);
vtg.MagneticNorthRef = stringToNumber<char>(m_nmeaVTGvect[eVTG_MagneticNorthRef]);
vtg.HorizontalMoveSpeedKn = stringToNumber<float>(m_nmeaVTGvect[eVTG_HorizontalMoveSpeed]);
vtg.SpeedKnots = stringToNumber<char>(m_nmeaVTGvect[eVTG_SpeedKnots]);
vtg.HorizontalMoveSpeedKm = stringToNumber<float>(m_nmeaVTGvect[eVTG_HorizontalMoveSpeed2]);
vtg.SpeedKmh = stringToNumber<char>(m_nmeaVTGvect[eVTG_SpeedKmh]);
if (vecSize == eVTG_CheckSum) {
vtg.PositioningMode = stringToNumber<char>(m_nmeaVTGvect[eVTG_PositioningMode]);//optional
}
if ((vtg.PositioningMode == 'A') || (vtg.PositioningMode == 'D')) {
updateSpeed(vtg.HorizontalMoveSpeedKm/3.6f);
}
return m_nmeaVTGvect.size();
}
void GnssNmeaParser::updateUtcTime(const int ddmmyy, const double hhmmss_sss)
{
//get utc diff
time_t time_now = time(NULL);
struct tm tm_local {};
struct tm tm_utc {};
long time_local_sec = 0;
long time_utc_sec = 0;
long utc_diff_sec = 0;
//get fixed time
struct tm tm_gnss {};
time_t time_fixed = 0;
int utc_year = 0;
int utc_month = 0;
int utc_day = 0;
int utc_hour = 0;
int utc_minute = 0;
int utc_seconds = 0;
int hhmmss = (int)hhmmss_sss;
int milliseconds = 0;
gmtime_r(&time_now, &tm_utc);
localtime_r(&time_now, &tm_local);
time_local_sec = tm_local.tm_sec +
60*(tm_local.tm_min +
60*(tm_local.tm_hour +
24*(tm_local.tm_yday +
365*tm_local.tm_year)));
time_utc_sec = tm_utc.tm_sec +
60*(tm_utc.tm_min +
60*(tm_utc.tm_hour +
24*(tm_utc.tm_yday +
365*tm_utc.tm_year)));
utc_diff_sec = time_local_sec - time_utc_sec;
utc_day = (ddmmyy / 100) / 100;
utc_month = (ddmmyy / 100) % 100;
utc_year = (ddmmyy % 100) + 2000;
utc_hour = ((hhmmss / 100) / 100);
utc_minute = ((hhmmss / 100) % 100);
utc_seconds = (hhmmss % 100);
//milliseconds = (int)((hhmmss_sss - hhmmss) * 1000); //will less precise
milliseconds = (int)((hhmmss_sss * 1000) - (hhmmss * 1000)); //Improve accuracy
tm_gnss.tm_hour = utc_hour;
tm_gnss.tm_min = utc_minute;
tm_gnss.tm_sec = utc_seconds;
tm_gnss.tm_year = utc_year - 1900;
tm_gnss.tm_mon = utc_month - 1;
tm_gnss.tm_mday = utc_day;
tm_gnss.tm_isdst = -1;
time_fixed = mktime(&tm_gnss) + utc_diff_sec;
m_gnssUtcTime = (long long)time_fixed * 1000 + milliseconds;
m_gnssLocation.timestamp = m_gnssUtcTime;
if ((0 == ddmmyy) || (0 == hhmmss)) {
ALOGW("%s invalid UTCDate=%d, UTCTime=%d", __func__, ddmmyy, hhmmss);
//use local stored utc time
time_fixed = mktime(&tm_utc) + utc_diff_sec;
m_gnssUtcTime = (long long)time_fixed * 1000;
m_gnssLocation.timestamp = m_gnssUtcTime;
}
}
void GnssNmeaParser::updateLatLong(const double latitude, const char latHemi, const double longtitude, const char longHemi)
{
double lat = latitude;
double lon = longtitude;
if (latHemi == 'S') {
lat = -lat;
}
if (longHemi == 'W') {
lon = -lon;
}
m_gnssLocation.gnssLocationFlags |= GnssLocationFlags::HAS_LAT_LONG;
m_gnssLocation.latitudeDegrees = latLongToDegree(lat);
m_gnssLocation.longitudeDegrees = latLongToDegree(lon);
}
void GnssNmeaParser::updateAltitude(const double altitude)
{
double alt = altitude;
m_gnssLocation.gnssLocationFlags |= GnssLocationFlags::HAS_ALTITUDE;
m_gnssLocation.altitudeMeters = alt;
}
void GnssNmeaParser::updateBearing(const float bearing)
{
float bea = bearing;
m_gnssLocation.gnssLocationFlags |= GnssLocationFlags::HAS_BEARING;
m_gnssLocation.bearingDegrees = bea;
}
void GnssNmeaParser::updateMagDec(const float magDec, const char magDecDir)
{
(void)magDec;
(void)magDecDir;
}
void GnssNmeaParser::updateAccuracy(const float pdop, const float hdop, const float vdop)
{
/* GSA HDOP */
(void)pdop;
(void)vdop;
if ((0.1f <= hdop)) {
m_gnssLocation.gnssLocationFlags |= GnssLocationFlags::HAS_HORIZONTAL_ACCURACY;
m_gnssLocation.horizontalAccuracyMeters = hdop;
}
if ((0.1f <= vdop)) {
m_gnssLocation.gnssLocationFlags |= GnssLocationFlags::HAS_VERTICAL_ACCURACY;
m_gnssLocation.verticalAccuracyMeters = vdop;
}
}
void GnssNmeaParser::updateSpeed(const float speed)
{
float velocity = speed;
m_gnssLocation.gnssLocationFlags |= GnssLocationFlags::HAS_SPEED;
m_gnssLocation.speedMetersPerSec = velocity;
}
void GnssNmeaParser::updateGnssSvStatus(const std::vector<XXGSV_Info_T> &gsvVectInfoT)
{
std::vector<XXGSV_Info_T>::const_iterator vit;
int itemsCount = 0;
int itemSequence = 0;
int sateSeq = 0;
m_gnssSvStatus.numSvs = 0;
for (vit = gsvVectInfoT.begin(); vit != gsvVectInfoT.end(); vit++) {
itemsCount = vit->ItemCount;
itemSequence = vit->ItemSequence;
if ((sateSeq+3) > ((int)GnssMax::SVS_COUNT)-1) {
/* preventing arrays from out of bounds */
ALOGW("gnssSvStatus num more than SVS_COUNT:%d", GnssMax::SVS_COUNT);
break;
}
m_gnssSvStatus.gnssSvList[sateSeq].svid = vit->PRNCode;
m_gnssSvStatus.gnssSvList[sateSeq].elevationDegrees = vit->SatelliteElevation;
m_gnssSvStatus.gnssSvList[sateSeq].azimuthDegrees = vit->SatelliteAzimuth;
m_gnssSvStatus.gnssSvList[sateSeq].cN0Dbhz = vit->SignalNoiseRatio;
m_gnssSvStatus.gnssSvList[sateSeq].svFlag = 0;
if (bitsFlagTest<32>((*vit).BitFlags, eGSV_SignalNoiseRatio)) {
//m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= GnssSvFlags:HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnssSvList[sateSeq].constellation = (GnssConstellationType)vit->Ext_constellation;
if (vit->PRNCode > 0) {
/* check and set flag whether available satellite */
m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= gnssSvFlagUsedInFix(vit->PRNCode);
/* increase visible satellites count */
sateSeq += 1;
}
m_gnssSvStatus.gnssSvList[sateSeq].svid = vit->PRNCode2;
m_gnssSvStatus.gnssSvList[sateSeq].elevationDegrees = vit->SatelliteElevation2;
m_gnssSvStatus.gnssSvList[sateSeq].azimuthDegrees = vit->SatelliteAzimuth2;
m_gnssSvStatus.gnssSvList[sateSeq].cN0Dbhz = vit->SignalNoiseRatio2;
m_gnssSvStatus.gnssSvList[sateSeq].svFlag = 0;
if ( bitsFlagTest<32>(vit->BitFlags, eGSV_SignalNoiseRatio2) ) {
//m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= GnssSvFlags:HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnssSvList[sateSeq].constellation = (GnssConstellationType)vit->Ext_constellation;
if (vit->PRNCode2 > 0) {
m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= gnssSvFlagUsedInFix(vit->PRNCode2);
sateSeq += 1;
}
m_gnssSvStatus.gnssSvList[sateSeq].svid = vit->PRNCode3;
m_gnssSvStatus.gnssSvList[sateSeq].elevationDegrees = vit->SatelliteElevation3;
m_gnssSvStatus.gnssSvList[sateSeq].azimuthDegrees = vit->SatelliteAzimuth3;
m_gnssSvStatus.gnssSvList[sateSeq].cN0Dbhz = vit->SignalNoiseRatio3;
m_gnssSvStatus.gnssSvList[sateSeq].svFlag = 0;
if (bitsFlagTest<32>(vit->BitFlags, eGSV_SignalNoiseRatio3)) {
//m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= GnssSvFlags:HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnssSvList[sateSeq].constellation = (GnssConstellationType)vit->Ext_constellation;
if (vit->PRNCode3 > 0) {
m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= gnssSvFlagUsedInFix(vit->PRNCode3);
sateSeq += 1;
}
m_gnssSvStatus.gnssSvList[sateSeq].svid = vit->PRNCode4;
m_gnssSvStatus.gnssSvList[sateSeq].elevationDegrees = vit->SatelliteElevation4;
m_gnssSvStatus.gnssSvList[sateSeq].azimuthDegrees = vit->SatelliteAzimuth4;
m_gnssSvStatus.gnssSvList[sateSeq].cN0Dbhz = vit->SignalNoiseRatio4;
m_gnssSvStatus.gnssSvList[sateSeq].svFlag = 0;
if (bitsFlagTest<32>(vit->BitFlags, eGSV_SignalNoiseRatio4)) {
//m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= GnssSvFlags:HAS_CARRIER_FREQUENCY;
}
m_gnssSvStatus.gnssSvList[sateSeq].constellation = (GnssConstellationType)vit->Ext_constellation;
if (vit->PRNCode4 > 0) {
m_gnssSvStatus.gnssSvList[sateSeq].svFlag |= gnssSvFlagUsedInFix(vit->PRNCode4);
sateSeq += 1;
}
}
m_gnssSvStatus.numSvs = sateSeq;
}
double GnssNmeaParser::latLongToDegree(const double dddmm_mmmm)
{
// eg.: 12031.0902 -> 120.51817(120+(31.0902/60.0=0.51817))
int ddd = (int)(dddmm_mmmm/100);
double mm_mmmm = dddmm_mmmm - (ddd*100.0);
double ddd_xxx = ddd + (mm_mmmm / 60.0);
return ddd_xxx;
}
int GnssNmeaParser::gnssSvFlagUsedInFix(const int svid) {
int fixed = 0;
int prnSn = 0;
std::vector<XXGSA_Info_T>::iterator gsaIt;
for (gsaIt = m_gsaVectInfoT.begin(); gsaIt != m_gsaVectInfoT.end(); gsaIt++) {
for (prnSn = 0; prnSn < GSA_INFO_PRN_CNT; prnSn++) {
if (svid == gsaIt->PRNList[prnSn]) {
fixed = (int)GnssSvFlags::USED_IN_FIX;
break;
}
}
}
return fixed;
}
bool GnssNmeaParser::getGnssLocation(GnssLocation &gnssLocation)
{
(void)memcpy(&gnssLocation, &m_gnssLocation, sizeof(m_gnssLocation));
return true;
}
bool GnssNmeaParser::getGnssSvStatus(GnssSvStatus &gnssSvStatus)
{
#if 1
int numSv = m_gnssSvStatus.numSvs;
ALOGD("getGnssSvStatus numSvs:%d", m_gnssSvStatus.numSvs);
for(int tmp = 0; tmp < numSv; tmp++)
{
ALOGD("getGnssSvStatus (svid=%d,elevation=%f,azimuth=%f,dbhz=%f,CX=%d,svFlag=0x%x)",
m_gnssSvStatus.gnssSvList[tmp].svid,
m_gnssSvStatus.gnssSvList[tmp].elevationDegrees,
m_gnssSvStatus.gnssSvList[tmp].azimuthDegrees,
m_gnssSvStatus.gnssSvList[tmp].cN0Dbhz,
(int)m_gnssSvStatus.gnssSvList[tmp].constellation,
(int)m_gnssSvStatus.gnssSvList[tmp].svFlag);
}
#endif
(void)memcpy(&gnssSvStatus, &m_gnssSvStatus, sizeof(gnssSvStatus));
return true;
}
GnssUtcTime GnssNmeaParser::getUtcTime()
{
return m_gnssUtcTime;
}
void GnssNmeaParser::reset()
{
m_nmeaLines.clear();
m_nmeaGGAvect.clear();
m_nmeaGLLvect.clear();
m_nmeaGSAvec2d.clear();
m_nmeaGSVvec2d.clear();
m_nmeaRMCvect.clear();
m_nmeaVTGvect.clear();
m_gnssUtcTime = 0;
(void)memset(&m_ggaInfoT, 0, sizeof(m_ggaInfoT));
(void)memset(&m_gllInfoT, 0, sizeof(m_gllInfoT));
m_gsaVectInfoT.clear();
m_gsvVectInfoT.clear();
(void)memset(&m_rmcInfoT, 0, sizeof(m_rmcInfoT));
(void)memset(&m_vtgInfoT, 0, sizeof(m_vtgInfoT));
(void)memset(&m_gnssLocation, 0, sizeof(m_gnssLocation));
(void)memset(&m_gnssSvStatus, 0, sizeof(m_gnssSvStatus));
}
void GnssNmeaParser::removeChecksum(std::string &str)
{
// get rid of checksum at the end of the sentecne
// remove chars after *
size_t phit = 0;
phit = str.find("*");
if (std::string::npos != phit)
{
str.erase(phit);
}
}
uint8_t GnssNmeaParser::getNConstellation(const std::string &nmeaHead)
{
uint8_t constellation = (uint8_t)GnssConstellationType::UNKNOWN;
if (startsWith(nmeaHead, "$GP")) {
constellation = (uint8_t)GnssConstellationType::GPS;
} else if (startsWith(nmeaHead, "$GL")) {
constellation = (uint8_t)GnssConstellationType::GLONASS;
} else if (startsWith(nmeaHead, "$BD")) {
constellation = (uint8_t)GnssConstellationType::BEIDOU;
} else {
constellation = (uint8_t)GnssConstellationType::UNKNOWN;
}
return constellation;
}
bool GnssNmeaParser::startsWith(const std::string &src, const std::string &str)
{
int srcpos = 0;
int srclen = src.length();
int sublen = str.length();
if (srclen < sublen) {
return false;
}
return (0 == src.compare(srcpos, sublen, str));
}
bool GnssNmeaParser::endsWith(const std::string &src, const std::string &str)
{
int srcpos = 0;
int srclen = src.length();
int sublen = str.length();
if (srclen < sublen) {
return false;
}
srcpos = srclen - sublen;
return (0 == src.compare(srcpos, sublen, str));
}
std::string GnssNmeaParser::replace(const std::string &raw, const std::string &oldstr, const std::string &newstr) {
std::string res_string = raw;
size_t startpos = 0;
size_t retpos = 0;
while (std::string::npos != (retpos = res_string.find(oldstr, startpos)))
{
if (oldstr.size() == newstr.size()) {
(void)res_string.replace(retpos, oldstr.size(), newstr);
} else {
(void)res_string.erase(retpos, oldstr.size());
(void)res_string.insert(retpos, newstr);
}
startpos = retpos + oldstr.size();
}
return res_string;
}
size_t GnssNmeaParser::split(const std::string &line, const std::string &delim, std::vector<std::string> &vstr)
{
size_t pstart = 0;
size_t phit = 0;
std::string sstr;
size_t length = line.length();
vstr.clear();
for (;pstart <= length;)
{
phit = line.find(delim, pstart);
if (std::string::npos != phit)
{
/* find delim, get substr */
sstr = line.substr(pstart, phit-pstart);
vstr.push_back(sstr);
pstart = phit + delim.size();
} else {
/* not find delim, append remaining str and break */
vstr.push_back(line.substr(pstart));
break;
}
}
return vstr.size();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?