Generate GAL NMEA sentences at AP side
Generate GAGSV sentence at AP side when NMEA Provider is set to AP in gps.conf Change-Id: I2cd436d61bab09386aaa813e85591e02f560b41e CRs-fixed: 1051996
This commit is contained in:
parent
2e3d64352b
commit
b707704985
2 changed files with 420 additions and 319 deletions
|
@ -123,6 +123,7 @@ typedef struct loc_eng_data_s
|
||||||
boolean generateNmea;
|
boolean generateNmea;
|
||||||
uint32_t gps_used_mask;
|
uint32_t gps_used_mask;
|
||||||
uint32_t glo_used_mask;
|
uint32_t glo_used_mask;
|
||||||
|
uint32_t gal_used_mask;
|
||||||
float hdop;
|
float hdop;
|
||||||
float pdop;
|
float pdop;
|
||||||
float vdop;
|
float vdop;
|
||||||
|
|
|
@ -34,6 +34,105 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <platform_lib_includes.h>
|
#include <platform_lib_includes.h>
|
||||||
|
|
||||||
|
#define GLONASS_SV_ID_OFFSET 64
|
||||||
|
#define MAX_SATELLITES_IN_USE 12
|
||||||
|
typedef struct loc_nmea_sv_meta_s
|
||||||
|
{
|
||||||
|
char talker[3];
|
||||||
|
GnssConstellationType svType;
|
||||||
|
uint32_t mask;
|
||||||
|
uint32_t svIdOffset;
|
||||||
|
} loc_nmea_sv_meta;
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
FUNCTION loc_eng_nmea_sv_meta_init
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Init loc_nmea_sv_meta passed in
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
NONE
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
Pointer to loc_nmea_sv_meta
|
||||||
|
|
||||||
|
SIDE EFFECTS
|
||||||
|
N/A
|
||||||
|
|
||||||
|
===========================================================================*/
|
||||||
|
static loc_nmea_sv_meta* loc_nmea_sv_meta_init(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
|
loc_nmea_sv_meta& sv_meta, GnssConstellationType svType, bool needCombine)
|
||||||
|
{
|
||||||
|
if (!loc_eng_data_p)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset(&sv_meta, 0, sizeof(sv_meta));
|
||||||
|
sv_meta.svType = svType;
|
||||||
|
sv_meta.talker[0] = 'G';
|
||||||
|
|
||||||
|
switch (svType)
|
||||||
|
{
|
||||||
|
case GNSS_CONSTELLATION_GPS:
|
||||||
|
sv_meta.talker[1] = 'P';
|
||||||
|
sv_meta.mask = loc_eng_data_p->gps_used_mask;
|
||||||
|
break;
|
||||||
|
case GNSS_CONSTELLATION_GLONASS:
|
||||||
|
sv_meta.talker[1] = 'L';
|
||||||
|
sv_meta.mask = loc_eng_data_p->glo_used_mask;
|
||||||
|
// GLONASS SV ids are from 65-96
|
||||||
|
sv_meta.svIdOffset = GLONASS_SV_ID_OFFSET;
|
||||||
|
break;
|
||||||
|
case GNSS_CONSTELLATION_GALILEO:
|
||||||
|
sv_meta.talker[1] = 'A';
|
||||||
|
sv_meta.mask = loc_eng_data_p->gal_used_mask;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOC_LOGE("NMEA Error unknow constellation type: %d", svType);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (needCombine &&
|
||||||
|
(loc_eng_data_p->gps_used_mask ? 1 : 0) +
|
||||||
|
(loc_eng_data_p->glo_used_mask ? 1 : 0) +
|
||||||
|
(loc_eng_data_p->gal_used_mask ? 1 : 0) > 1)
|
||||||
|
{
|
||||||
|
// If GPS, GLONASS, Galileo etc. are combined
|
||||||
|
// to obtain the reported position solution,
|
||||||
|
// talker shall be set to GN, to indicate that
|
||||||
|
// the satellites are used in a combined solution
|
||||||
|
sv_meta.talker[1] = 'N';
|
||||||
|
}
|
||||||
|
return &sv_meta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
FUNCTION loc_eng_nmea_count_bits
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Count how many bits are set in mask
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
NONE
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
Bits number set in mask
|
||||||
|
|
||||||
|
SIDE EFFECTS
|
||||||
|
N/A
|
||||||
|
|
||||||
|
===========================================================================*/
|
||||||
|
static uint32_t loc_eng_nmea_count_bits(uint32_t mask)
|
||||||
|
{
|
||||||
|
uint32_t count = 0;
|
||||||
|
while (mask)
|
||||||
|
{
|
||||||
|
if (mask & 1)
|
||||||
|
count++;
|
||||||
|
mask = mask >> 1;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
FUNCTION loc_eng_nmea_send
|
FUNCTION loc_eng_nmea_send
|
||||||
|
|
||||||
|
@ -96,6 +195,249 @@ int loc_eng_nmea_put_checksum(char *pNmea, int maxSize)
|
||||||
return (length + checksumLength + 1);
|
return (length + checksumLength + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
FUNCTION loc_eng_nmea_generate_GSA
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Generate NMEA GSA sentences generated based on position report
|
||||||
|
Currently below sentences are generated:
|
||||||
|
- $GPGSA : GPS DOP and active SVs
|
||||||
|
- $GLGSA : GLONASS DOP and active SVs
|
||||||
|
- $GAGSA : GALILEO DOP and active SVs
|
||||||
|
- $GNGSA : GNSS DOP and active SVs
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
NONE
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
Number of SVs used
|
||||||
|
|
||||||
|
SIDE EFFECTS
|
||||||
|
N/A
|
||||||
|
|
||||||
|
===========================================================================*/
|
||||||
|
uint32_t loc_eng_nmea_generate_GSA(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
|
const GpsLocationExtended &locationExtended,
|
||||||
|
char* sentence,
|
||||||
|
int bufSize,
|
||||||
|
loc_nmea_sv_meta* sv_meta_p)
|
||||||
|
{
|
||||||
|
if (!loc_eng_data_p || !sentence || bufSize <= 0 || !sv_meta_p)
|
||||||
|
{
|
||||||
|
LOC_LOGE("NMEA Error invalid arguments.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* pMarker = sentence;
|
||||||
|
int lengthRemaining = bufSize;
|
||||||
|
int length = 0;
|
||||||
|
|
||||||
|
uint32_t svUsedCount = 0;
|
||||||
|
uint32_t svUsedList[32] = {0};
|
||||||
|
|
||||||
|
char fixType = '\0';
|
||||||
|
|
||||||
|
const char* talker = sv_meta_p->talker;
|
||||||
|
uint32_t svIdOffset = sv_meta_p->svIdOffset;
|
||||||
|
uint32_t mask = sv_meta_p->mask;
|
||||||
|
|
||||||
|
for (uint8_t i = 1; mask > 0 && svUsedCount < 32; i++)
|
||||||
|
{
|
||||||
|
if (mask & 1)
|
||||||
|
svUsedList[svUsedCount++] = i + svIdOffset;
|
||||||
|
mask = mask >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (svUsedCount == 0 && GNSS_CONSTELLATION_GPS != sv_meta_p->svType)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (svUsedCount == 0)
|
||||||
|
fixType = '1'; // no fix
|
||||||
|
else if (svUsedCount <= 3)
|
||||||
|
fixType = '2'; // 2D fix
|
||||||
|
else
|
||||||
|
fixType = '3'; // 3D fix
|
||||||
|
|
||||||
|
// Start printing the sentence
|
||||||
|
// Format: $--GSA,a,x,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,p.p,h.h,v.v*cc
|
||||||
|
// a : Mode : A : Automatic, allowed to automatically switch 2D/3D
|
||||||
|
// x : Fixtype : 1 (no fix), 2 (2D fix), 3 (3D fix)
|
||||||
|
// xx : 12 SV ID
|
||||||
|
// p.p : Position DOP (Dilution of Precision)
|
||||||
|
// h.h : Horizontal DOP
|
||||||
|
// v.v : Vertical DOP
|
||||||
|
// cc : Checksum value
|
||||||
|
length = snprintf(pMarker, lengthRemaining, "$%sGSA,A,%c,", talker, fixType);
|
||||||
|
|
||||||
|
if (length < 0 || length >= lengthRemaining)
|
||||||
|
{
|
||||||
|
LOC_LOGE("NMEA Error in string formatting");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pMarker += length;
|
||||||
|
lengthRemaining -= length;
|
||||||
|
|
||||||
|
// Add first 12 satellite IDs
|
||||||
|
for (uint8_t i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
if (i < svUsedCount)
|
||||||
|
length = snprintf(pMarker, lengthRemaining, "%02d,", svUsedList[i]);
|
||||||
|
else
|
||||||
|
length = snprintf(pMarker, lengthRemaining, ",");
|
||||||
|
|
||||||
|
if (length < 0 || length >= lengthRemaining)
|
||||||
|
{
|
||||||
|
LOC_LOGE("NMEA Error in string formatting");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
pMarker += length;
|
||||||
|
lengthRemaining -= length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the position/horizontal/vertical DOP values
|
||||||
|
if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
|
||||||
|
{ // dop is in locationExtended, (QMI)
|
||||||
|
length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
|
||||||
|
locationExtended.pdop,
|
||||||
|
locationExtended.hdop,
|
||||||
|
locationExtended.vdop);
|
||||||
|
}
|
||||||
|
else if (loc_eng_data_p->pdop > 0 && loc_eng_data_p->hdop > 0 && loc_eng_data_p->vdop > 0)
|
||||||
|
{ // dop was cached from sv report (RPC)
|
||||||
|
length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
|
||||||
|
loc_eng_data_p->pdop,
|
||||||
|
loc_eng_data_p->hdop,
|
||||||
|
loc_eng_data_p->vdop);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // no dop
|
||||||
|
length = snprintf(pMarker, lengthRemaining, ",,");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sentence is ready, add checksum and broadcast */
|
||||||
|
length = loc_eng_nmea_put_checksum(sentence, bufSize);
|
||||||
|
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
||||||
|
|
||||||
|
return svUsedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
FUNCTION loc_eng_nmea_generate_GSV
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Generate NMEA GSV sentences generated based on sv report
|
||||||
|
Currently below sentences are generated:
|
||||||
|
- $GPGSV: GPS Satellites in View
|
||||||
|
- $GNGSV: GLONASS Satellites in View
|
||||||
|
- $GAGSV: GALILEO Satellites in View
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
NONE
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
NONE
|
||||||
|
|
||||||
|
SIDE EFFECTS
|
||||||
|
N/A
|
||||||
|
|
||||||
|
===========================================================================*/
|
||||||
|
void loc_eng_nmea_generate_GSV(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
|
const GnssSvStatus &svStatus,
|
||||||
|
char* sentence,
|
||||||
|
int bufSize,
|
||||||
|
loc_nmea_sv_meta* sv_meta_p)
|
||||||
|
{
|
||||||
|
if (!loc_eng_data_p || !sentence || bufSize <= 0)
|
||||||
|
{
|
||||||
|
LOC_LOGE("NMEA Error invalid argument.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* pMarker = sentence;
|
||||||
|
int lengthRemaining = bufSize;
|
||||||
|
int length = 0;
|
||||||
|
int sentenceCount = 0;
|
||||||
|
int sentenceNumber = 1;
|
||||||
|
int svNumber = 1;
|
||||||
|
|
||||||
|
const char* talker = sv_meta_p->talker;
|
||||||
|
uint32_t svIdOffset = sv_meta_p->svIdOffset;
|
||||||
|
uint32_t mask = sv_meta_p->mask;
|
||||||
|
uint32_t svCount = loc_eng_nmea_count_bits(mask);
|
||||||
|
|
||||||
|
|
||||||
|
if (svCount <= 0)
|
||||||
|
{
|
||||||
|
// no svs in view, so just send a blank $--GSV sentence
|
||||||
|
snprintf(sentence, lengthRemaining, "$%sGSV,1,1,0,", talker);
|
||||||
|
length = loc_eng_nmea_put_checksum(sentence, bufSize);
|
||||||
|
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
svNumber = 1;
|
||||||
|
sentenceNumber = 1;
|
||||||
|
sentenceCount = svCount / 4 + (svCount % 4 != 0);
|
||||||
|
|
||||||
|
while (sentenceNumber <= sentenceCount)
|
||||||
|
{
|
||||||
|
pMarker = sentence;
|
||||||
|
lengthRemaining = bufSize;
|
||||||
|
|
||||||
|
length = snprintf(pMarker, lengthRemaining, "$%sGSV,%d,%d,%02d",
|
||||||
|
talker, sentenceCount, sentenceNumber, svCount);
|
||||||
|
|
||||||
|
if (length < 0 || length >= lengthRemaining)
|
||||||
|
{
|
||||||
|
LOC_LOGE("NMEA Error in string formatting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pMarker += length;
|
||||||
|
lengthRemaining -= length;
|
||||||
|
|
||||||
|
for (int i=0; (svNumber <= svStatus.num_svs) && (i < 4); svNumber++)
|
||||||
|
{
|
||||||
|
if (sv_meta_p->svType == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
||||||
|
{
|
||||||
|
length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,",
|
||||||
|
svStatus.gnss_sv_list[svNumber - 1].svid,
|
||||||
|
(int)(0.5 + svStatus.gnss_sv_list[svNumber - 1].elevation), //float to int
|
||||||
|
(int)(0.5 + svStatus.gnss_sv_list[svNumber - 1].azimuth)); //float to int
|
||||||
|
|
||||||
|
if (length < 0 || length >= lengthRemaining)
|
||||||
|
{
|
||||||
|
LOC_LOGE("NMEA Error in string formatting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pMarker += length;
|
||||||
|
lengthRemaining -= length;
|
||||||
|
|
||||||
|
if (svStatus.gnss_sv_list[svNumber - 1].c_n0_dbhz > 0)
|
||||||
|
{
|
||||||
|
length = snprintf(pMarker, lengthRemaining,"%02d",
|
||||||
|
(int)(0.5 + svStatus.gnss_sv_list[svNumber - 1].c_n0_dbhz)); //float to int
|
||||||
|
|
||||||
|
if (length < 0 || length >= lengthRemaining)
|
||||||
|
{
|
||||||
|
LOC_LOGE("NMEA Error in string formatting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pMarker += length;
|
||||||
|
lengthRemaining -= length;
|
||||||
|
}
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
length = loc_eng_nmea_put_checksum(sentence, bufSize);
|
||||||
|
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
||||||
|
sentenceNumber++;
|
||||||
|
|
||||||
|
} //while
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
FUNCTION loc_eng_nmea_generate_pos
|
FUNCTION loc_eng_nmea_generate_pos
|
||||||
|
|
||||||
|
@ -103,10 +445,12 @@ DESCRIPTION
|
||||||
Generate NMEA sentences generated based on position report
|
Generate NMEA sentences generated based on position report
|
||||||
Currently below sentences are generated within this function:
|
Currently below sentences are generated within this function:
|
||||||
- $GPGSA : GPS DOP and active SVs
|
- $GPGSA : GPS DOP and active SVs
|
||||||
- $GNGSA : GLONASS DOP and active SVs
|
- $GLGSA : GLONASS DOP and active SVs
|
||||||
- $GPVTG : Track made good and ground speed
|
- $GAGSA : GALILEO DOP and active SVs
|
||||||
- $GPRMC : Recommended minimum navigation information
|
- $GNGSA : GNSS DOP and active SVs
|
||||||
- $GPGGA : Time, position and fix related data
|
- $--VTG : Track made good and ground speed
|
||||||
|
- $--RMC : Recommended minimum navigation information
|
||||||
|
- $--GGA : Time, position and fix related data
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
NONE
|
NONE
|
||||||
|
@ -144,174 +488,49 @@ void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
int utcMSeconds = (location.gpsLocation.timestamp)%1000;
|
int utcMSeconds = (location.gpsLocation.timestamp)%1000;
|
||||||
|
|
||||||
if (generate_nmea) {
|
if (generate_nmea) {
|
||||||
// ------------------
|
char talker[3] = {'G', 'P', '\0'};
|
||||||
// ------$GPGSA------
|
|
||||||
// ------------------
|
|
||||||
|
|
||||||
uint32_t svUsedCount = 0;
|
uint32_t svUsedCount = 0;
|
||||||
uint32_t svUsedList[32] = {0};
|
uint32_t count = 0;
|
||||||
uint32_t mask = loc_eng_data_p->gps_used_mask;
|
loc_nmea_sv_meta sv_meta;
|
||||||
for (uint8_t i = 1; mask > 0 && svUsedCount < 32; i++)
|
// -------------------
|
||||||
|
// ---$GPGSA/$GNGSA---
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
count = loc_eng_nmea_generate_GSA(loc_eng_data_p, locationExtended, sentence, sizeof(sentence),
|
||||||
|
loc_nmea_sv_meta_init(loc_eng_data_p, sv_meta, GNSS_CONSTELLATION_GPS, true));
|
||||||
|
if (count > 0)
|
||||||
{
|
{
|
||||||
if (mask & 1)
|
svUsedCount += count;
|
||||||
svUsedList[svUsedCount++] = i;
|
talker[1] = sv_meta.talker[1];
|
||||||
mask = mask >> 1;
|
|
||||||
}
|
}
|
||||||
// clear the cache so they can't be used again
|
|
||||||
loc_eng_data_p->gps_used_mask = 0;
|
|
||||||
|
|
||||||
char fixType;
|
// -------------------
|
||||||
if (svUsedCount == 0)
|
// ---$GLGSA/$GNGSA---
|
||||||
fixType = '1'; // no fix
|
// -------------------
|
||||||
else if (svUsedCount <= 3)
|
|
||||||
fixType = '2'; // 2D fix
|
|
||||||
else
|
|
||||||
fixType = '3'; // 3D fix
|
|
||||||
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GPGSA,A,%c,", fixType);
|
count = loc_eng_nmea_generate_GSA(loc_eng_data_p, locationExtended, sentence, sizeof(sentence),
|
||||||
|
loc_nmea_sv_meta_init(loc_eng_data_p, sv_meta, GNSS_CONSTELLATION_GLONASS, true));
|
||||||
if (length < 0 || length >= lengthRemaining)
|
if (count > 0)
|
||||||
{
|
{
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
svUsedCount += count;
|
||||||
return;
|
talker[1] = sv_meta.talker[1];
|
||||||
}
|
}
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 12; i++) // only the first 12 sv go in sentence
|
// -------------------
|
||||||
|
// ---$GAGSA/$GNGSA---
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
count = loc_eng_nmea_generate_GSA(loc_eng_data_p, locationExtended, sentence, sizeof(sentence),
|
||||||
|
loc_nmea_sv_meta_init(loc_eng_data_p, sv_meta, GNSS_CONSTELLATION_GALILEO, true));
|
||||||
|
if (count > 0)
|
||||||
{
|
{
|
||||||
if (i < svUsedCount)
|
svUsedCount += count;
|
||||||
length = snprintf(pMarker, lengthRemaining, "%02d,", svUsedList[i]);
|
talker[1] = sv_meta.talker[1];
|
||||||
else
|
|
||||||
length = snprintf(pMarker, lengthRemaining, ",");
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
|
// -------------------
|
||||||
{ // dop is in locationExtended, (QMI)
|
// ------$--VTG-------
|
||||||
length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
|
// -------------------
|
||||||
locationExtended.pdop,
|
|
||||||
locationExtended.hdop,
|
|
||||||
locationExtended.vdop);
|
|
||||||
}
|
|
||||||
else if (loc_eng_data_p->pdop > 0 && loc_eng_data_p->hdop > 0 && loc_eng_data_p->vdop > 0)
|
|
||||||
{ // dop was cached from sv report (RPC)
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
|
|
||||||
loc_eng_data_p->pdop,
|
|
||||||
loc_eng_data_p->hdop,
|
|
||||||
loc_eng_data_p->vdop);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // no dop
|
|
||||||
length = snprintf(pMarker, lengthRemaining, ",,");
|
|
||||||
}
|
|
||||||
|
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
|
||||||
|
|
||||||
// ------------------
|
|
||||||
// ------$GNGSA------
|
|
||||||
// ------------------
|
|
||||||
uint32_t gloUsedCount = 0;
|
|
||||||
uint32_t gloUsedList[32] = {0};
|
|
||||||
|
|
||||||
// Reset locals for GNGSA sentence generation
|
|
||||||
pMarker = sentence;
|
|
||||||
lengthRemaining = sizeof(sentence);
|
|
||||||
mask = loc_eng_data_p->glo_used_mask;
|
|
||||||
fixType = '\0';
|
|
||||||
|
|
||||||
// Parse the glonass sv mask, and fetch glo sv ids
|
|
||||||
// Mask corresponds to the offset.
|
|
||||||
// GLONASS SV ids are from 65-96
|
|
||||||
const int GLONASS_SV_ID_OFFSET = 64;
|
|
||||||
for (uint8_t i = 1; mask > 0 && gloUsedCount < 32; i++)
|
|
||||||
{
|
|
||||||
if (mask & 1)
|
|
||||||
gloUsedList[gloUsedCount++] = i + GLONASS_SV_ID_OFFSET;
|
|
||||||
mask = mask >> 1;
|
|
||||||
}
|
|
||||||
// clear the cache so they can't be used again
|
|
||||||
loc_eng_data_p->glo_used_mask = 0;
|
|
||||||
|
|
||||||
if (gloUsedCount == 0)
|
|
||||||
fixType = '1'; // no fix
|
|
||||||
else if (gloUsedCount <= 3)
|
|
||||||
fixType = '2'; // 2D fix
|
|
||||||
else
|
|
||||||
fixType = '3'; // 3D fix
|
|
||||||
|
|
||||||
// Start printing the sentence
|
|
||||||
// Format: $--GSA,a,x,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,xx,p.p,h.h,v.v*cc
|
|
||||||
// GNGSA : for glonass SVs
|
|
||||||
// a : Mode : A : Automatic, allowed to automatically switch 2D/3D
|
|
||||||
// x : Fixtype : 1 (no fix), 2 (2D fix), 3 (3D fix)
|
|
||||||
// xx : 12 SV ID
|
|
||||||
// p.p : Position DOP (Dilution of Precision)
|
|
||||||
// h.h : Horizontal DOP
|
|
||||||
// v.v : Vertical DOP
|
|
||||||
// cc : Checksum value
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GNGSA,A,%c,", fixType);
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
|
|
||||||
// Add first 12 GLONASS satellite IDs
|
|
||||||
for (uint8_t i = 0; i < 12; i++)
|
|
||||||
{
|
|
||||||
if (i < gloUsedCount)
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "%02d,", gloUsedList[i]);
|
|
||||||
else
|
|
||||||
length = snprintf(pMarker, lengthRemaining, ",");
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the position/horizontal/vertical DOP values
|
|
||||||
if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
|
|
||||||
{ // dop is in locationExtended, (QMI)
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
|
|
||||||
locationExtended.pdop,
|
|
||||||
locationExtended.hdop,
|
|
||||||
locationExtended.vdop);
|
|
||||||
}
|
|
||||||
else if (loc_eng_data_p->pdop > 0 && loc_eng_data_p->hdop > 0 && loc_eng_data_p->vdop > 0)
|
|
||||||
{ // dop was cached from sv report (RPC)
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "%.1f,%.1f,%.1f",
|
|
||||||
loc_eng_data_p->pdop,
|
|
||||||
loc_eng_data_p->hdop,
|
|
||||||
loc_eng_data_p->vdop);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // no dop
|
|
||||||
length = snprintf(pMarker, lengthRemaining, ",,");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sentence is ready, add checksum and broadcast */
|
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
|
||||||
|
|
||||||
// ------------------
|
|
||||||
// ------$GPVTG------
|
|
||||||
// ------------------
|
|
||||||
|
|
||||||
pMarker = sentence;
|
pMarker = sentence;
|
||||||
lengthRemaining = sizeof(sentence);
|
lengthRemaining = sizeof(sentence);
|
||||||
|
@ -328,11 +547,11 @@ void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
magTrack -= 360.0;
|
magTrack -= 360.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GPVTG,%.1lf,T,%.1lf,M,", location.gpsLocation.bearing, magTrack);
|
length = snprintf(pMarker, lengthRemaining, "$%sVTG,%.1lf,T,%.1lf,M,", talker, location.gpsLocation.bearing, magTrack);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GPVTG,,T,,M,");
|
length = snprintf(pMarker, lengthRemaining, "$%sVTG,,T,,M,", talker);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
if (length < 0 || length >= lengthRemaining)
|
||||||
|
@ -373,15 +592,15 @@ void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
||||||
|
|
||||||
// ------------------
|
// -------------------
|
||||||
// ------$GPRMC------
|
// ------$--RMC-------
|
||||||
// ------------------
|
// -------------------
|
||||||
|
|
||||||
pMarker = sentence;
|
pMarker = sentence;
|
||||||
lengthRemaining = sizeof(sentence);
|
lengthRemaining = sizeof(sentence);
|
||||||
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GPRMC,%02d%02d%02d.%02d,A," ,
|
length = snprintf(pMarker, lengthRemaining, "$%sRMC,%02d%02d%02d.%02d,A," ,
|
||||||
utcHours, utcMinutes, utcSeconds,utcMSeconds/10);
|
talker, utcHours, utcMinutes, utcSeconds,utcMSeconds/10);
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
if (length < 0 || length >= lengthRemaining)
|
||||||
{
|
{
|
||||||
|
@ -526,15 +745,15 @@ void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
||||||
|
|
||||||
// ------------------
|
// -------------------
|
||||||
// ------$GPGGA------
|
// ------$--GGA-------
|
||||||
// ------------------
|
// -------------------
|
||||||
|
|
||||||
pMarker = sentence;
|
pMarker = sentence;
|
||||||
lengthRemaining = sizeof(sentence);
|
lengthRemaining = sizeof(sentence);
|
||||||
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GPGGA,%02d%02d%02d.%02d," ,
|
length = snprintf(pMarker, lengthRemaining, "$%sGGA,%02d%02d%02d.%02d," ,
|
||||||
utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
|
talker, utcHours, utcMinutes, utcSeconds, utcMSeconds/10);
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
if (length < 0 || length >= lengthRemaining)
|
||||||
{
|
{
|
||||||
|
@ -601,6 +820,9 @@ void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
else
|
else
|
||||||
gpsQuality = '2'; // 2 means DGPS fix
|
gpsQuality = '2'; // 2 means DGPS fix
|
||||||
|
|
||||||
|
// Number of satellites in use, 00-12
|
||||||
|
if (svUsedCount > MAX_SATELLITES_IN_USE)
|
||||||
|
svUsedCount = MAX_SATELLITES_IN_USE;
|
||||||
if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
|
if (locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_DOP)
|
||||||
{ // dop is in locationExtended, (QMI)
|
{ // dop is in locationExtended, (QMI)
|
||||||
length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,",
|
length = snprintf(pMarker, lengthRemaining, "%c,%02d,%.1f,",
|
||||||
|
@ -657,6 +879,10 @@ void loc_eng_nmea_generate_pos(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
||||||
|
|
||||||
|
// clear the cache so they can't be used again
|
||||||
|
loc_eng_data_p->gps_used_mask = 0;
|
||||||
|
loc_eng_data_p->glo_used_mask = 0;
|
||||||
|
loc_eng_data_p->gal_used_mask = 0;
|
||||||
}
|
}
|
||||||
//Send blank NMEA reports for non-final fixes
|
//Send blank NMEA reports for non-final fixes
|
||||||
else {
|
else {
|
||||||
|
@ -719,13 +945,12 @@ void loc_eng_nmea_generate_sv(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
int sentenceCount = 0;
|
int sentenceCount = 0;
|
||||||
int sentenceNumber = 1;
|
int sentenceNumber = 1;
|
||||||
int svNumber = 1;
|
int svNumber = 1;
|
||||||
int gpsCount = 0;
|
|
||||||
int glnCount = 0;
|
|
||||||
|
|
||||||
//Count GPS SVs for saparating GPS from GLONASS and throw others
|
//Count GPS SVs for saparating GPS from GLONASS and throw others
|
||||||
|
|
||||||
loc_eng_data_p->gps_used_mask = 0;
|
loc_eng_data_p->gps_used_mask = 0;
|
||||||
loc_eng_data_p->glo_used_mask = 0;
|
loc_eng_data_p->glo_used_mask = 0;
|
||||||
|
loc_eng_data_p->gal_used_mask = 0;
|
||||||
for(svNumber=1; svNumber <= svCount; svNumber++) {
|
for(svNumber=1; svNumber <= svCount; svNumber++) {
|
||||||
if (GNSS_CONSTELLATION_GPS == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
if (GNSS_CONSTELLATION_GPS == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
||||||
{
|
{
|
||||||
|
@ -735,7 +960,6 @@ void loc_eng_nmea_generate_sv(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
{
|
{
|
||||||
loc_eng_data_p->gps_used_mask |= (1 << (svStatus.gnss_sv_list[svNumber - 1].svid - 1));
|
loc_eng_data_p->gps_used_mask |= (1 << (svStatus.gnss_sv_list[svNumber - 1].svid - 1));
|
||||||
}
|
}
|
||||||
gpsCount++;
|
|
||||||
}
|
}
|
||||||
else if (GNSS_CONSTELLATION_GLONASS == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
else if (GNSS_CONSTELLATION_GLONASS == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
||||||
{
|
{
|
||||||
|
@ -745,164 +969,40 @@ void loc_eng_nmea_generate_sv(loc_eng_data_s_type *loc_eng_data_p,
|
||||||
{
|
{
|
||||||
loc_eng_data_p->glo_used_mask |= (1 << (svStatus.gnss_sv_list[svNumber - 1].svid - 1));
|
loc_eng_data_p->glo_used_mask |= (1 << (svStatus.gnss_sv_list[svNumber - 1].svid - 1));
|
||||||
}
|
}
|
||||||
glnCount++;
|
}
|
||||||
|
else if (GNSS_CONSTELLATION_GALILEO == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
||||||
|
{
|
||||||
|
// cache the used in fix mask, as it will be needed to send $GAGSA
|
||||||
|
// during the position report
|
||||||
|
if (GNSS_SV_FLAGS_USED_IN_FIX == (svStatus.gnss_sv_list[svNumber - 1].flags & GNSS_SV_FLAGS_USED_IN_FIX))
|
||||||
|
{
|
||||||
|
loc_eng_data_p->gal_used_mask |= (1 << (svStatus.gnss_sv_list[svNumber - 1].svid - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loc_nmea_sv_meta sv_meta;
|
||||||
// ------------------
|
// ------------------
|
||||||
// ------$GPGSV------
|
// ------$GPGSV------
|
||||||
// ------------------
|
// ------------------
|
||||||
|
|
||||||
if (gpsCount <= 0)
|
loc_eng_nmea_generate_GSV(loc_eng_data_p, svStatus, sentence, sizeof(sentence),
|
||||||
{
|
loc_nmea_sv_meta_init(loc_eng_data_p, sv_meta, GNSS_CONSTELLATION_GPS, false));
|
||||||
// no svs in view, so just send a blank $GPGSV sentence
|
|
||||||
strlcpy(sentence, "$GPGSV,1,1,0,", sizeof(sentence));
|
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
svNumber = 1;
|
|
||||||
sentenceNumber = 1;
|
|
||||||
sentenceCount = gpsCount/4 + (gpsCount % 4 != 0);
|
|
||||||
|
|
||||||
while (sentenceNumber <= sentenceCount)
|
|
||||||
{
|
|
||||||
pMarker = sentence;
|
|
||||||
lengthRemaining = sizeof(sentence);
|
|
||||||
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GPGSV,%d,%d,%02d",
|
|
||||||
sentenceCount, sentenceNumber, gpsCount);
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
|
|
||||||
for (int i=0; (svNumber <= svCount) && (i < 4); svNumber++)
|
|
||||||
{
|
|
||||||
if (GNSS_CONSTELLATION_GPS == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
|
||||||
{
|
|
||||||
length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,",
|
|
||||||
svStatus.gnss_sv_list[svNumber-1].svid,
|
|
||||||
(int)(0.5 + svStatus.gnss_sv_list[svNumber-1].elevation), //float to int
|
|
||||||
(int)(0.5 + svStatus.gnss_sv_list[svNumber-1].azimuth)); //float to int
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
|
|
||||||
if (svStatus.gnss_sv_list[svNumber-1].c_n0_dbhz > 0)
|
|
||||||
{
|
|
||||||
length = snprintf(pMarker, lengthRemaining,"%02d",
|
|
||||||
(int)(0.5 + svStatus.gnss_sv_list[svNumber-1].c_n0_dbhz)); //float to int
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
|
||||||
sentenceNumber++;
|
|
||||||
|
|
||||||
} //while
|
|
||||||
|
|
||||||
} //if
|
|
||||||
|
|
||||||
// ------------------
|
// ------------------
|
||||||
// ------$GLGSV------
|
// ------$GLGSV------
|
||||||
// ------------------
|
// ------------------
|
||||||
|
|
||||||
if (glnCount <= 0)
|
loc_eng_nmea_generate_GSV(loc_eng_data_p, svStatus, sentence, sizeof(sentence),
|
||||||
{
|
loc_nmea_sv_meta_init(loc_eng_data_p, sv_meta, GNSS_CONSTELLATION_GLONASS, false));
|
||||||
// no svs in view, so just send a blank $GLGSV sentence
|
|
||||||
strlcpy(sentence, "$GLGSV,1,1,0,", sizeof(sentence));
|
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
svNumber = 1;
|
|
||||||
sentenceNumber = 1;
|
|
||||||
sentenceCount = glnCount/4 + (glnCount % 4 != 0);
|
|
||||||
|
|
||||||
while (sentenceNumber <= sentenceCount)
|
// ------------------
|
||||||
{
|
// ------$GAGSV------
|
||||||
pMarker = sentence;
|
// ------------------
|
||||||
lengthRemaining = sizeof(sentence);
|
|
||||||
|
|
||||||
length = snprintf(pMarker, lengthRemaining, "$GLGSV,%d,%d,%02d",
|
loc_eng_nmea_generate_GSV(loc_eng_data_p, svStatus, sentence, sizeof(sentence),
|
||||||
sentenceCount, sentenceNumber, glnCount);
|
loc_nmea_sv_meta_init(loc_eng_data_p, sv_meta, GNSS_CONSTELLATION_GALILEO, false));
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
|
|
||||||
for (int i=0; (svNumber <= svCount) && (i < 4); svNumber++)
|
|
||||||
{
|
|
||||||
if (GNSS_CONSTELLATION_GLONASS == svStatus.gnss_sv_list[svNumber - 1].constellation)
|
|
||||||
{
|
|
||||||
|
|
||||||
length = snprintf(pMarker, lengthRemaining,",%02d,%02d,%03d,",
|
|
||||||
svStatus.gnss_sv_list[svNumber - 1].svid,
|
|
||||||
(int)(0.5 + svStatus.gnss_sv_list[svNumber - 1].elevation), //float to int
|
|
||||||
(int)(0.5 + svStatus.gnss_sv_list[svNumber - 1].azimuth)); //float to int
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
|
|
||||||
if (svStatus.gnss_sv_list[svNumber - 1].c_n0_dbhz > 0)
|
|
||||||
{
|
|
||||||
length = snprintf(pMarker, lengthRemaining,"%02d",
|
|
||||||
(int)(0.5 + svStatus.gnss_sv_list[svNumber - 1].c_n0_dbhz)); //float to int
|
|
||||||
|
|
||||||
if (length < 0 || length >= lengthRemaining)
|
|
||||||
{
|
|
||||||
LOC_LOGE("NMEA Error in string formatting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pMarker += length;
|
|
||||||
lengthRemaining -= length;
|
|
||||||
}
|
|
||||||
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
length = loc_eng_nmea_put_checksum(sentence, sizeof(sentence));
|
|
||||||
loc_eng_nmea_send(sentence, length, loc_eng_data_p);
|
|
||||||
sentenceNumber++;
|
|
||||||
|
|
||||||
} //while
|
|
||||||
|
|
||||||
}//if
|
|
||||||
|
|
||||||
// For RPC, the DOP are sent during sv report, so cache them
|
// For RPC, the DOP are sent during sv report, so cache them
|
||||||
// now to be sent during position report.
|
// now to be sent during position report.
|
||||||
|
|
Loading…
Reference in a new issue