GPS NMEA: generate proper nmea during leap second transition
During leap second transition, the hour, minute and seconds displayed need to be in the format of 23:59:60 to denote the extra leap second Change-Id: Ice7c6f934b1251990ba26e2b7e399554a2862eb4 CRs-fixed: 2335188
This commit is contained in:
parent
9b0abcc59d
commit
730abcc3d4
3 changed files with 120 additions and 7 deletions
|
@ -1920,9 +1920,6 @@ GnssAdapter::updateClientsEventMask()
|
||||||
mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT;
|
mask |= LOC_API_ADAPTER_BIT_NMEA_1HZ_REPORT;
|
||||||
updateNmeaMask(mNmeaMask | LOC_NMEA_MASK_DEBUG_V02);
|
updateNmeaMask(mNmeaMask | LOC_NMEA_MASK_DEBUG_V02);
|
||||||
}
|
}
|
||||||
if (it->second.locationSystemInfoCb != nullptr) {
|
|
||||||
mask |= LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1952,6 +1949,9 @@ GnssAdapter::updateClientsEventMask()
|
||||||
mask |= LOC_API_ADAPTER_BIT_REQUEST_WIFI;
|
mask |= LOC_API_ADAPTER_BIT_REQUEST_WIFI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// need to register for leap second info
|
||||||
|
// for proper nmea generation
|
||||||
|
mask |= LOC_API_ADAPTER_BIT_LOC_SYSTEM_INFO;
|
||||||
updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
|
updateEvtMask(mask, LOC_REGISTRATION_MASK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3012,7 +3012,8 @@ GnssAdapter::reportPosition(const UlpLocation& ulpLocation,
|
||||||
(LOC_RELIABILITY_NOT_SET == locationExtended.horizontal_reliability));
|
(LOC_RELIABILITY_NOT_SET == locationExtended.horizontal_reliability));
|
||||||
uint8_t generate_nmea = (reported && status != LOC_SESS_FAILURE && !blank_fix);
|
uint8_t generate_nmea = (reported && status != LOC_SESS_FAILURE && !blank_fix);
|
||||||
std::vector<std::string> nmeaArraystr;
|
std::vector<std::string> nmeaArraystr;
|
||||||
loc_nmea_generate_pos(ulpLocation, locationExtended, generate_nmea, nmeaArraystr);
|
loc_nmea_generate_pos(ulpLocation, locationExtended, mLocSystemInfo,
|
||||||
|
generate_nmea, nmeaArraystr);
|
||||||
stringstream ss;
|
stringstream ss;
|
||||||
for (auto sentence : nmeaArraystr) {
|
for (auto sentence : nmeaArraystr) {
|
||||||
ss << sentence;
|
ss << sentence;
|
||||||
|
@ -3292,7 +3293,22 @@ GnssAdapter::reportLocationSystemInfo(const LocationSystemInfo & locationSystemI
|
||||||
// may come at different time
|
// may come at different time
|
||||||
if (locationSystemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) {
|
if (locationSystemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) {
|
||||||
mLocSystemInfo.systemInfoMask |= LOCATION_SYS_INFO_LEAP_SECOND;
|
mLocSystemInfo.systemInfoMask |= LOCATION_SYS_INFO_LEAP_SECOND;
|
||||||
mLocSystemInfo.leapSecondSysInfo = locationSystemInfo.leapSecondSysInfo;
|
|
||||||
|
const LeapSecondSystemInfo &srcLeapSecondSysInfo = locationSystemInfo.leapSecondSysInfo;
|
||||||
|
LeapSecondSystemInfo &dstLeapSecondSysInfo = mLocSystemInfo.leapSecondSysInfo;
|
||||||
|
if (srcLeapSecondSysInfo.leapSecondInfoMask &
|
||||||
|
LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT) {
|
||||||
|
dstLeapSecondSysInfo.leapSecondInfoMask |=
|
||||||
|
LEAP_SECOND_SYS_INFO_CURRENT_LEAP_SECONDS_BIT;
|
||||||
|
dstLeapSecondSysInfo.leapSecondCurrent = srcLeapSecondSysInfo.leapSecondCurrent;
|
||||||
|
}
|
||||||
|
// once leap second change event is complete, modem may send up event invalidate the leap second
|
||||||
|
// change info while AP is still processing report during leap second transition
|
||||||
|
// so, we choose to keep this info around even though it is old
|
||||||
|
if (srcLeapSecondSysInfo.leapSecondInfoMask & LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT) {
|
||||||
|
dstLeapSecondSysInfo.leapSecondInfoMask |= LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT;
|
||||||
|
dstLeapSecondSysInfo.leapSecondChangeInfo = srcLeapSecondSysInfo.leapSecondChangeInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// we received new info, inform client of the newly received info
|
// we received new info, inform client of the newly received info
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
|
|
||||||
#define GLONASS_SV_ID_OFFSET 64
|
#define GLONASS_SV_ID_OFFSET 64
|
||||||
#define MAX_SATELLITES_IN_USE 12
|
#define MAX_SATELLITES_IN_USE 12
|
||||||
|
#define MSEC_IN_ONE_WEEK 604800000ULL
|
||||||
|
#define UTC_GPS_OFFSET_MSECS 315964800000ULL
|
||||||
|
|
||||||
// GNSS system id according to NMEA spec
|
// GNSS system id according to NMEA spec
|
||||||
#define SYSTEM_ID_GPS 1
|
#define SYSTEM_ID_GPS 1
|
||||||
|
@ -605,6 +607,79 @@ static void loc_nmea_generate_GSV(const GnssSvNotification &svNotify,
|
||||||
} //while
|
} //while
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*===========================================================================
|
||||||
|
FUNCTION getUtcTimeWithLeapSecondTransition
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
This function returns true if the position report is generated during
|
||||||
|
leap second transition period. If not, then the utc timestamp returned
|
||||||
|
will be set to the timestamp in the position report. If it is,
|
||||||
|
then the utc timestamp returned will need to take into account
|
||||||
|
of the leap second transition so that proper calendar year/month/date
|
||||||
|
can be calculated from the returned utc timestamp.
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
NONE
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
true: position report is generated in leap second transition period.
|
||||||
|
|
||||||
|
SIDE EFFECTS
|
||||||
|
N/A
|
||||||
|
|
||||||
|
===========================================================================*/
|
||||||
|
bool getUtcTimeWithLeapSecondTransition(const UlpLocation &location,
|
||||||
|
const GpsLocationExtended &locationExtended,
|
||||||
|
const LocationSystemInfo &systemInfo,
|
||||||
|
LocGpsUtcTime &utcPosTimestamp) {
|
||||||
|
bool inTransition = false;
|
||||||
|
|
||||||
|
// position report is not generated during leap second transition,
|
||||||
|
// we can use the UTC timestamp from position report as is
|
||||||
|
utcPosTimestamp = location.gpsLocation.timestamp;
|
||||||
|
|
||||||
|
// Check whether we are in leap second transition.
|
||||||
|
// If so, per NMEA spec, we need to display the extra second in format of 23:59:60
|
||||||
|
// with year/month/date not getting advanced.
|
||||||
|
if ((locationExtended.flags & GPS_LOCATION_EXTENDED_HAS_GPS_TIME) &&
|
||||||
|
((systemInfo.systemInfoMask & LOCATION_SYS_INFO_LEAP_SECOND) &&
|
||||||
|
(systemInfo.leapSecondSysInfo.leapSecondInfoMask &
|
||||||
|
LEAP_SECOND_SYS_INFO_LEAP_SECOND_CHANGE_BIT))) {
|
||||||
|
|
||||||
|
const LeapSecondChangeInfo &leapSecondChangeInfo =
|
||||||
|
systemInfo.leapSecondSysInfo.leapSecondChangeInfo;
|
||||||
|
const GnssSystemTimeStructType &gpsTimestampLsChange =
|
||||||
|
leapSecondChangeInfo.gpsTimestampLsChange;
|
||||||
|
|
||||||
|
uint64_t gpsTimeLsChange = gpsTimestampLsChange.systemWeek * MSEC_IN_ONE_WEEK +
|
||||||
|
gpsTimestampLsChange.systemMsec;
|
||||||
|
uint64_t gpsTimePosReport = locationExtended.gpsTime.gpsWeek * MSEC_IN_ONE_WEEK +
|
||||||
|
locationExtended.gpsTime.gpsTimeOfWeekMs;
|
||||||
|
// we are only dealing with positive leap second change, as negative
|
||||||
|
// leap second change has never occurred and should not occur in future
|
||||||
|
if (leapSecondChangeInfo.leapSecondsAfterChange >
|
||||||
|
leapSecondChangeInfo.leapSecondsBeforeChange) {
|
||||||
|
// leap second adjustment is always 1 second at a time. It can happen
|
||||||
|
// every quarter end and up to four times per year.
|
||||||
|
if ((gpsTimePosReport >= gpsTimeLsChange) &&
|
||||||
|
(gpsTimePosReport < (gpsTimeLsChange + 1000))) {
|
||||||
|
inTransition = true;
|
||||||
|
utcPosTimestamp = gpsTimeLsChange + UTC_GPS_OFFSET_MSECS -
|
||||||
|
leapSecondChangeInfo.leapSecondsBeforeChange * 1000;
|
||||||
|
|
||||||
|
// we substract 1000 milli-seconds from UTC timestmap in order to calculate the
|
||||||
|
// proper year, month and date during leap second transtion.
|
||||||
|
// Let us give an example, assuming leap second transition is scheduled on 2019,
|
||||||
|
// Dec 31st mid night. When leap second transition is happening,
|
||||||
|
// instead of outputting the time as 2020, Jan, 1st, 00 hour, 00 min, and 00 sec.
|
||||||
|
// The time need to be displayed as 2019, Dec, 31st, 23 hour, 59 min and 60 sec.
|
||||||
|
utcPosTimestamp -= 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inTransition;
|
||||||
|
}
|
||||||
|
|
||||||
/*===========================================================================
|
/*===========================================================================
|
||||||
FUNCTION loc_nmea_generate_pos
|
FUNCTION loc_nmea_generate_pos
|
||||||
|
|
||||||
|
@ -631,11 +706,19 @@ SIDE EFFECTS
|
||||||
===========================================================================*/
|
===========================================================================*/
|
||||||
void loc_nmea_generate_pos(const UlpLocation &location,
|
void loc_nmea_generate_pos(const UlpLocation &location,
|
||||||
const GpsLocationExtended &locationExtended,
|
const GpsLocationExtended &locationExtended,
|
||||||
|
const LocationSystemInfo &systemInfo,
|
||||||
unsigned char generate_nmea,
|
unsigned char generate_nmea,
|
||||||
std::vector<std::string> &nmeaArraystr)
|
std::vector<std::string> &nmeaArraystr)
|
||||||
{
|
{
|
||||||
ENTRY_LOG();
|
ENTRY_LOG();
|
||||||
time_t utcTime(location.gpsLocation.timestamp/1000);
|
|
||||||
|
LocGpsUtcTime utcPosTimestamp = 0;
|
||||||
|
bool inLsTransition = false;
|
||||||
|
|
||||||
|
inLsTransition = getUtcTimeWithLeapSecondTransition
|
||||||
|
(location, locationExtended, systemInfo, utcPosTimestamp);
|
||||||
|
|
||||||
|
time_t utcTime(utcPosTimestamp/1000);
|
||||||
tm * pTm = gmtime(&utcTime);
|
tm * pTm = gmtime(&utcTime);
|
||||||
if (NULL == pTm) {
|
if (NULL == pTm) {
|
||||||
LOC_LOGE("gmtime failed");
|
LOC_LOGE("gmtime failed");
|
||||||
|
@ -653,7 +736,19 @@ void loc_nmea_generate_pos(const UlpLocation &location,
|
||||||
int utcMinutes = pTm->tm_min;
|
int utcMinutes = pTm->tm_min;
|
||||||
int utcSeconds = pTm->tm_sec;
|
int utcSeconds = pTm->tm_sec;
|
||||||
int utcMSeconds = (location.gpsLocation.timestamp)%1000;
|
int utcMSeconds = (location.gpsLocation.timestamp)%1000;
|
||||||
loc_sv_cache_info sv_cache_info = {};
|
|
||||||
|
if (inLsTransition) {
|
||||||
|
// During leap second transition, we need to display the extra
|
||||||
|
// leap second of hour, minute, second as (23:59:60)
|
||||||
|
utcHours = 23;
|
||||||
|
utcMinutes = 59;
|
||||||
|
utcSeconds = 60;
|
||||||
|
// As UTC timestamp is freezing during leap second transition,
|
||||||
|
// retrieve milli-seconds portion from GPS timestamp.
|
||||||
|
utcMSeconds = locationExtended.gpsTime.gpsTimeOfWeekMs % 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
loc_sv_cache_info sv_cache_info = {};
|
||||||
|
|
||||||
if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) {
|
if (GPS_LOCATION_EXTENDED_HAS_GNSS_SV_USED_DATA & locationExtended.flags) {
|
||||||
sv_cache_info.gps_used_mask =
|
sv_cache_info.gps_used_mask =
|
||||||
|
@ -667,6 +762,7 @@ void loc_nmea_generate_pos(const UlpLocation &location,
|
||||||
sv_cache_info.bds_used_mask =
|
sv_cache_info.bds_used_mask =
|
||||||
(uint32_t)locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask;
|
(uint32_t)locationExtended.gnss_sv_used_ids.qzss_sv_used_ids_mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (generate_nmea) {
|
if (generate_nmea) {
|
||||||
char talker[3] = {'G', 'P', '\0'};
|
char talker[3] = {'G', 'P', '\0'};
|
||||||
uint32_t svUsedCount = 0;
|
uint32_t svUsedCount = 0;
|
||||||
|
|
|
@ -40,6 +40,7 @@ void loc_nmea_generate_sv(const GnssSvNotification &svNotify,
|
||||||
|
|
||||||
void loc_nmea_generate_pos(const UlpLocation &location,
|
void loc_nmea_generate_pos(const UlpLocation &location,
|
||||||
const GpsLocationExtended &locationExtended,
|
const GpsLocationExtended &locationExtended,
|
||||||
|
const LocationSystemInfo &systemInfo,
|
||||||
unsigned char generate_nmea,
|
unsigned char generate_nmea,
|
||||||
std::vector<std::string> &nmeaArraystr);
|
std::vector<std::string> &nmeaArraystr);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue