mirror of
https://github.com/meshtastic/firmware.git
synced 2025-05-09 23:02:00 +00:00
use Position struct for GPS data
This commit is contained in:
parent
7d267e8027
commit
70b80e600d
@ -202,11 +202,13 @@ void GPS::publishUpdate()
|
|||||||
if (shouldPublish) {
|
if (shouldPublish) {
|
||||||
shouldPublish = false;
|
shouldPublish = false;
|
||||||
|
|
||||||
DEBUG_MSG("publishing GPS lock=%d\n", hasLock());
|
// In debug logs, identify position by @timestamp:stage (stage 2 = publish)
|
||||||
|
DEBUG_MSG("publishing pos@%x:2, hasVal=%d, GPSlock=%d\n",
|
||||||
|
p.pos_timestamp, hasValidLocation, hasLock());
|
||||||
|
|
||||||
// Notify any status instances that are observing us
|
// Notify any status instances that are observing us
|
||||||
const meshtastic::GPSStatus status =
|
const meshtastic::GPSStatus status =
|
||||||
meshtastic::GPSStatus(hasValidLocation, isConnected(), latitude, longitude, altitude, dop, heading, numSatellites);
|
meshtastic::GPSStatus(hasValidLocation, isConnected(), p);
|
||||||
newStatus.notifyObservers(&status);
|
newStatus.notifyObservers(&status);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -244,6 +246,7 @@ int32_t GPS::runOnce()
|
|||||||
|
|
||||||
bool gotLoc = lookForLocation();
|
bool gotLoc = lookForLocation();
|
||||||
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
|
if (gotLoc && !hasValidLocation) { // declare that we have location ASAP
|
||||||
|
DEBUG_MSG("hasValidLocation RISING EDGE\n");
|
||||||
hasValidLocation = true;
|
hasValidLocation = true;
|
||||||
shouldPublish = true;
|
shouldPublish = true;
|
||||||
}
|
}
|
||||||
@ -260,6 +263,10 @@ int32_t GPS::runOnce()
|
|||||||
|
|
||||||
if (tooLong) {
|
if (tooLong) {
|
||||||
// we didn't get a location during this ack window, therefore declare loss of lock
|
// we didn't get a location during this ack window, therefore declare loss of lock
|
||||||
|
if (hasValidLocation) {
|
||||||
|
DEBUG_MSG("hasValidLocation FALLING EDGE (last read: %d)\n", gotLoc);
|
||||||
|
}
|
||||||
|
p = Position_init_default;
|
||||||
hasValidLocation = false;
|
hasValidLocation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,10 @@ class GPS : private concurrency::OSThread
|
|||||||
private:
|
private:
|
||||||
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
|
uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastWhileActiveMsec = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hasValidLocation - indicates that the position variables contain a complete
|
||||||
|
* GPS location, valid and fresh (< gps_update_interval + gps_attempt_time)
|
||||||
|
*/
|
||||||
bool hasValidLocation = false; // default to false, until we complete our first read
|
bool hasValidLocation = false; // default to false, until we complete our first read
|
||||||
|
|
||||||
bool isAwake = false; // true if we want a location right now
|
bool isAwake = false; // true if we want a location right now
|
||||||
@ -39,14 +43,7 @@ class GPS : private concurrency::OSThread
|
|||||||
/** If !0 we will attempt to connect to the GPS over I2C */
|
/** If !0 we will attempt to connect to the GPS over I2C */
|
||||||
static uint8_t i2cAddress;
|
static uint8_t i2cAddress;
|
||||||
|
|
||||||
int32_t latitude = 0, longitude = 0; // as an int mult by 1e-7 to get value as double
|
Position p = Position_init_default;
|
||||||
int32_t altitude = 0;
|
|
||||||
uint32_t dop = 0; // Diminution of position; PDOP where possible (UBlox), HDOP otherwise (TinyGPS) in 10^2 units (needs
|
|
||||||
// scaling before use)
|
|
||||||
uint32_t heading = 0; // Heading of motion, in degrees * 10^-5
|
|
||||||
|
|
||||||
int32_t geoidal_height = 0; // geoidal separation, in meters!
|
|
||||||
time_t pos_timestamp = 0; // positional timestamp from GPS solution
|
|
||||||
|
|
||||||
GPS() : concurrency::OSThread("GPS") {}
|
GPS() : concurrency::OSThread("GPS") {}
|
||||||
|
|
||||||
|
@ -95,6 +95,17 @@ bool NMEAGPS::lookForLocation()
|
|||||||
if (! hasLock())
|
if (! hasLock())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
#ifdef GPS_EXTRAVERBOSE
|
||||||
|
DEBUG_MSG("AGE: LOC=%d FIX=%d DATE=%d TIME=%d\n",
|
||||||
|
reader.location.age(),
|
||||||
|
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||||
|
gsafixtype.age(),
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
reader.date.age(), reader.time.age());
|
||||||
|
#endif // GPS_EXTRAVERBOSE
|
||||||
|
|
||||||
// check if a complete GPS solution set is available for reading
|
// check if a complete GPS solution set is available for reading
|
||||||
// tinyGPSDatum::age() also includes isValid() test
|
// tinyGPSDatum::age() also includes isValid() test
|
||||||
// FIXME
|
// FIXME
|
||||||
@ -105,7 +116,7 @@ bool NMEAGPS::lookForLocation()
|
|||||||
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
|
(reader.time.age() < GPS_SOL_EXPIRY_MS) &&
|
||||||
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
|
(reader.date.age() < GPS_SOL_EXPIRY_MS)))
|
||||||
{
|
{
|
||||||
// DEBUG_MSG("SOME data is TOO OLD\n");
|
DEBUG_MSG("SOME data is TOO OLD\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +124,7 @@ bool NMEAGPS::lookForLocation()
|
|||||||
if (! reader.location.isUpdated())
|
if (! reader.location.isUpdated())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Start reading the data
|
// We know the solution is fresh and valid, so just read the data
|
||||||
auto loc = reader.location.value();
|
auto loc = reader.location.value();
|
||||||
|
|
||||||
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
|
// Some GPSes (Air530) seem to send a zero longitude when the current fix is bogus
|
||||||
@ -123,27 +134,34 @@ bool NMEAGPS::lookForLocation()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
|
||||||
|
|
||||||
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
// Dilution of precision (an accuracy metric) is reported in 10^2 units, so we need to scale down when we use it
|
||||||
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||||
dop = TinyGPSPlus::parseDecimal(gsapdop.value());
|
p.HDOP = reader.hdop.value();
|
||||||
|
p.PDOP = TinyGPSPlus::parseDecimal(gsapdop.value());
|
||||||
|
DEBUG_MSG("PDOP=%d, HDOP=%d\n", dop, reader.hdop.value());
|
||||||
#else
|
#else
|
||||||
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
|
// FIXME! naive PDOP emulation (assumes VDOP==HDOP)
|
||||||
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
|
// correct formula is PDOP = SQRT(HDOP^2 + VDOP^2)
|
||||||
dop = 1.41 * reader.hdop.value();
|
p.HDOP = reader.hdop.value();
|
||||||
|
p.PDOP = 1.41 * reader.hdop.value();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Discard incomplete or erroneous readings
|
// Discard incomplete or erroneous readings
|
||||||
if (dop == 0)
|
if (reader.hdop.value() == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
latitude = toDegInt(loc.lat);
|
p.latitude_i = toDegInt(loc.lat);
|
||||||
longitude = toDegInt(loc.lng);
|
p.longitude_i = toDegInt(loc.lng);
|
||||||
|
|
||||||
geoidal_height = reader.geoidHeight.meters();
|
p.alt_geoid_sep = reader.geoidHeight.meters();
|
||||||
#ifdef GPS_ALTITUDE_HAE
|
p.altitude_hae = reader.altitude.meters() + p.alt_geoid_sep;
|
||||||
altitude = reader.altitude.meters() + geoidal_height;
|
p.altitude = reader.altitude.meters();
|
||||||
#else
|
|
||||||
altitude = reader.altitude.meters();
|
p.fix_quality = fixQual;
|
||||||
|
#ifndef TINYGPS_OPTION_NO_CUSTOM_FIELDS
|
||||||
|
p.fix_type = fixType;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// positional timestamp
|
// positional timestamp
|
||||||
@ -155,16 +173,16 @@ bool NMEAGPS::lookForLocation()
|
|||||||
t.tm_mon = reader.date.month() - 1;
|
t.tm_mon = reader.date.month() - 1;
|
||||||
t.tm_year = reader.date.year() - 1900;
|
t.tm_year = reader.date.year() - 1900;
|
||||||
t.tm_isdst = false;
|
t.tm_isdst = false;
|
||||||
pos_timestamp = mktime(&t);
|
p.pos_timestamp = mktime(&t);
|
||||||
|
|
||||||
// Nice to have, if available
|
// Nice to have, if available
|
||||||
if (reader.satellites.isUpdated()) {
|
if (reader.satellites.isUpdated()) {
|
||||||
setNumSatellites(reader.satellites.value());
|
p.sats_in_view = reader.satellites.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reader.course.isUpdated() && reader.course.isValid()) {
|
if (reader.course.isUpdated() && reader.course.isValid()) {
|
||||||
if (reader.course.value() < 36000) { // sanity check
|
if (reader.course.value() < 36000) { // sanity check
|
||||||
heading = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
|
p.ground_track = reader.course.value() * 1e3; // Scale the heading (in degrees * 10^-2) to match the expected degrees * 10^-5
|
||||||
} else {
|
} else {
|
||||||
DEBUG_MSG("BOGUS course.value() REJECTED: %d\n",
|
DEBUG_MSG("BOGUS course.value() REJECTED: %d\n",
|
||||||
reader.course.value());
|
reader.course.value());
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#define PDOP_INVALID 9999
|
#define PDOP_INVALID 9999
|
||||||
|
|
||||||
|
// #define UBX_MODE_NMEA
|
||||||
|
|
||||||
extern RadioConfig radioConfig;
|
extern RadioConfig radioConfig;
|
||||||
|
|
||||||
UBloxGPS::UBloxGPS() {}
|
UBloxGPS::UBloxGPS() {}
|
||||||
@ -48,12 +50,22 @@ bool UBloxGPS::setupGPS()
|
|||||||
delay(500);
|
delay(500);
|
||||||
|
|
||||||
if (isConnected()) {
|
if (isConnected()) {
|
||||||
|
#ifdef UBX_MODE_NMEA
|
||||||
|
DEBUG_MSG("Connected to UBLOX GPS, downgrading to NMEA mode\n");
|
||||||
|
DEBUG_MSG("- GPS errors below are related and safe to ignore\n");
|
||||||
|
#else
|
||||||
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
DEBUG_MSG("Connected to UBLOX GPS successfully\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!setUBXMode())
|
if (!setUBXMode())
|
||||||
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
RECORD_CRITICALERROR(CriticalErrorCode_UBloxInitFailed); // Don't halt the boot if saving the config fails, but do report the bug
|
||||||
|
|
||||||
|
#ifdef UBX_MODE_NMEA
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
return true;
|
return true;
|
||||||
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -61,6 +73,17 @@ bool UBloxGPS::setupGPS()
|
|||||||
|
|
||||||
bool UBloxGPS::setUBXMode()
|
bool UBloxGPS::setUBXMode()
|
||||||
{
|
{
|
||||||
|
#ifdef UBX_MODE_NMEA
|
||||||
|
if (_serial_gps) {
|
||||||
|
ublox.setUART1Output(COM_TYPE_NMEA, 1000);
|
||||||
|
}
|
||||||
|
if (i2cAddress) {
|
||||||
|
ublox.setI2COutput(COM_TYPE_NMEA, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // pretend initialization failed to force NMEA mode
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_serial_gps) {
|
if (_serial_gps) {
|
||||||
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
|
if (!ublox.setUART1Output(COM_TYPE_UBX, 1000)) // Use native API
|
||||||
return false;
|
return false;
|
||||||
@ -119,7 +142,6 @@ bool UBloxGPS::factoryReset()
|
|||||||
void UBloxGPS::whileActive()
|
void UBloxGPS::whileActive()
|
||||||
{
|
{
|
||||||
ublox.flushPVT(); // reset ALL freshness flags first
|
ublox.flushPVT(); // reset ALL freshness flags first
|
||||||
|
|
||||||
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
|
ublox.getT(maxWait()); // ask for new time data - hopefully ready when we come back
|
||||||
|
|
||||||
// Ask for a new position fix - hopefully it will have results ready by next time
|
// Ask for a new position fix - hopefully it will have results ready by next time
|
||||||
@ -177,6 +199,7 @@ bool UBloxGPS::lookForLocation()
|
|||||||
ublox.moduleQueried.longitude &&
|
ublox.moduleQueried.longitude &&
|
||||||
ublox.moduleQueried.altitude &&
|
ublox.moduleQueried.altitude &&
|
||||||
ublox.moduleQueried.pDOP &&
|
ublox.moduleQueried.pDOP &&
|
||||||
|
ublox.moduleQueried.SIV &&
|
||||||
ublox.moduleQueried.gpsDay))
|
ublox.moduleQueried.gpsDay))
|
||||||
{
|
{
|
||||||
// Not ready? No problem! We'll try again later.
|
// Not ready? No problem! We'll try again later.
|
||||||
@ -188,6 +211,7 @@ bool UBloxGPS::lookForLocation()
|
|||||||
DEBUG_MSG("FixType=%d\n", fixType);
|
DEBUG_MSG("FixType=%d\n", fixType);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// check if GPS has an acceptable lock
|
// check if GPS has an acceptable lock
|
||||||
if (! hasLock()) {
|
if (! hasLock()) {
|
||||||
ublox.flushPVT(); // reset ALL freshness flags
|
ublox.flushPVT(); // reset ALL freshness flags
|
||||||
@ -217,11 +241,7 @@ bool UBloxGPS::lookForLocation()
|
|||||||
|
|
||||||
time_t tmp_ts = mktime(&t);
|
time_t tmp_ts = mktime(&t);
|
||||||
|
|
||||||
// SIV number is nice-to-have if it's available
|
// FIXME - can opportunistically attempt to set RTC from GPS timestamp?
|
||||||
if (ublox.moduleQueried.SIV) {
|
|
||||||
uint16_t gSIV = ublox.getSIV(0);
|
|
||||||
setNumSatellites(gSIV);
|
|
||||||
}
|
|
||||||
|
|
||||||
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
// bogus lat lon is reported as 0 or 0 (can be bogus just for one)
|
||||||
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
// Also: apparently when the GPS is initially reporting lock it can output a bogus latitude > 90 deg!
|
||||||
@ -232,16 +252,18 @@ bool UBloxGPS::lookForLocation()
|
|||||||
|
|
||||||
// only if entire dataset is valid, update globals from temp vars
|
// only if entire dataset is valid, update globals from temp vars
|
||||||
if (foundLocation) {
|
if (foundLocation) {
|
||||||
longitude = tmp_lon;
|
p.location_source = Position_LocSource_LOCSRC_GPS_INTERNAL;
|
||||||
latitude = tmp_lat;
|
p.longitude_i = tmp_lon;
|
||||||
#ifdef GPS_ALTITUDE_HAE
|
p.latitude_i = tmp_lat;
|
||||||
altitude = tmp_alt_hae / 1000;
|
p.altitude = tmp_alt_msl / 1000;
|
||||||
#else
|
p.altitude_hae = tmp_alt_hae / 1000;
|
||||||
altitude = tmp_alt_msl / 1000;
|
p.alt_geoid_sep = (tmp_alt_hae - tmp_alt_msl) / 1000;
|
||||||
#endif
|
p.pos_timestamp = tmp_ts;
|
||||||
geoidal_height = (tmp_alt_hae - tmp_alt_msl) / 1000;
|
p.PDOP = tmp_dop;
|
||||||
pos_timestamp = tmp_ts;
|
p.fix_type = fixType;
|
||||||
dop = tmp_dop;
|
p.sats_in_view = ublox.getSIV(0);
|
||||||
|
// In debug logs, identify position by @timestamp:stage (stage 1 = birth)
|
||||||
|
DEBUG_MSG("lookForLocation() new pos@%x:1\n", tmp_ts);
|
||||||
} else {
|
} else {
|
||||||
// INVALID solution - should never happen
|
// INVALID solution - should never happen
|
||||||
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
|
DEBUG_MSG("Invalid location lat/lon/hae/dop %d/%d/%d/%d - discarded\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user