feat(BaseUI): show 'GPS Time Only' when GNSS has time but no position fix (#11361)
The position frame's drawGpsCoordinates() only distinguished 'No GPS present' / 'No GPS Lock' / coordinates, so a GNSS that had decoded valid time but no fix displayed identically to a cold chip. - GPSStatus: add per-acquisition hasTime flag (5th ctor param, accessor, matches() term, updateStatus() copy) - GPS::runOnce(): publish immediately on the gotTime rising edge so the flag reaches observers on the time-only path, which previously never published; done directly rather than via the end-of-loop block so fixHoldEnds is preserved and hold/power behavior is unchanged. Safe without a location: PositionModule ignores invalid positions. gotTime is already cleared on each GPS_ACTIVE entry, so the state is not sticky across acquisitions. - UIRenderer::drawGpsCoordinates(): the 'No GPS Lock' line becomes 'GPS Time Only' when time is valid. The drawGps() header renderer is intentionally untouched (its branches need separate de-clobbering work). Claude-Session: https://claude.ai/code/session_01CcrasD4QsatunDreANDgCx Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
2e958821f9
commit
512154ff97
3 files changed
+15
-5
No files matched your search
+7
-2
@@ -17,6 +17,7 @@ class GPSStatus : public Status
|
||||
|
||||
bool hasLock = false; // default to false, until we complete our first read
|
||||
bool isConnected = false; // Do we have a GPS we are talking to
|
||||
bool hasTime = false; // GPS has decoded a valid time this acquisition, even without a position fix
|
||||
|
||||
bool isPowerSaving = false; // Are we in power saving state
|
||||
|
||||
@@ -29,11 +30,12 @@ class GPSStatus : public Status
|
||||
GPSStatus() { statusType = STATUS_TYPE_GPS; }
|
||||
|
||||
// preferred method
|
||||
GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const meshtastic_Position &pos) : Status()
|
||||
GPSStatus(bool hasLock, bool isConnected, bool isPowerSaving, const meshtastic_Position &pos, bool hasTime = false) : Status()
|
||||
{
|
||||
this->hasLock = hasLock;
|
||||
this->isConnected = isConnected;
|
||||
this->isPowerSaving = isPowerSaving;
|
||||
this->hasTime = hasTime;
|
||||
|
||||
// all-in-one struct copy
|
||||
this->p = pos;
|
||||
@@ -50,6 +52,8 @@ class GPSStatus : public Status
|
||||
|
||||
bool getIsPowerSaving() const { return isPowerSaving; }
|
||||
|
||||
bool getHasTime() const { return hasTime; }
|
||||
|
||||
int32_t getLatitude() const
|
||||
{
|
||||
if (config.position.fixed_position) {
|
||||
@@ -91,7 +95,7 @@ class GPSStatus : public Status
|
||||
#ifdef GPS_DEBUG
|
||||
LOG_DEBUG("GPSStatus.match() new pos@%x to old pos@%x", newStatus->p.timestamp, p.timestamp);
|
||||
#endif
|
||||
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected ||
|
||||
return (newStatus->hasLock != hasLock || newStatus->isConnected != isConnected || newStatus->hasTime != hasTime ||
|
||||
newStatus->isPowerSaving != isPowerSaving || newStatus->p.latitude_i != p.latitude_i ||
|
||||
newStatus->p.longitude_i != p.longitude_i || newStatus->p.altitude != p.altitude ||
|
||||
newStatus->p.altitude_hae != p.altitude_hae || newStatus->p.PDOP != p.PDOP ||
|
||||
@@ -112,6 +116,7 @@ class GPSStatus : public Status
|
||||
initialized = true;
|
||||
hasLock = newStatus->hasLock;
|
||||
isConnected = newStatus->isConnected;
|
||||
hasTime = newStatus->hasTime;
|
||||
|
||||
p = newStatus->p;
|
||||
|
||||
|
||||
+7
-2
@@ -1446,7 +1446,7 @@ void GPS::publishUpdate()
|
||||
LOG_DEBUG("Publish pos@%x:2, hasVal=%d, Sats=%d, GPSlock=%d", p.timestamp, hasValidLocation, p.sats_in_view, hasLock());
|
||||
|
||||
// Notify any status instances that are observing us
|
||||
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p);
|
||||
const meshtastic::GPSStatus status = meshtastic::GPSStatus(hasValidLocation, isConnected(), isPowerSaving(), p, gotTime);
|
||||
newStatus.notifyObservers(&status);
|
||||
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||||
positionModule->handleNewPosition();
|
||||
@@ -1502,7 +1502,7 @@ int32_t GPS::runOnce()
|
||||
// gps_update_interval is faster than the position broadcast interval so there's a
|
||||
// fresh position ready when the device wants to broadcast one on the mesh.
|
||||
//
|
||||
// 1. Got a time for the first time --> set the time, don't publish.
|
||||
// 1. Got a time for the first time --> set the time, publish so the UI can show the time-only state.
|
||||
// 2. Got a lock for the first time
|
||||
// --> If gps_update_interval is <= 10s --> publishUpdate
|
||||
// --> Otherwise, hold for MIN(gps_update_interval - GPS_UPDATE_ALWAYS_ON_THRESHOLD_MS, 20s)
|
||||
@@ -1536,6 +1536,11 @@ int32_t GPS::runOnce()
|
||||
// 1. Got a time for the first time this cycle
|
||||
if (!gotTime && lookForTime()) { // Note: we count on this && short-circuiting and not resetting the RTC time
|
||||
gotTime = true;
|
||||
// Publish immediately (rather than via the block below, which would clear fixHoldEnds) so the
|
||||
// time-only state reaches the UI without waiting for a location. Safe without a valid location:
|
||||
// PositionModule::handleNewPosition ignores invalid positions.
|
||||
shouldPublish = true;
|
||||
publishUpdate();
|
||||
}
|
||||
|
||||
// 2. Got a lock for the first time, or 3. Got a lock after turning back on
|
||||
|
||||
@@ -582,7 +582,7 @@ void UIRenderer::drawGpsCoordinates(OLEDDisplay *display, int16_t x, int16_t y,
|
||||
}
|
||||
} else if (!gps->getHasLock() && !config.position.fixed_position) {
|
||||
if (strcmp(mode, "line1") == 0) {
|
||||
strcpy(displayLine, "No GPS Lock");
|
||||
strcpy(displayLine, gps->getHasTime() ? "GPS Time Only" : "No GPS Lock");
|
||||
display->drawString(x, y, displayLine);
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user