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:
Jonathan Bennett
2026-08-10 02:39:40 +00:00
committed by GitHub
co-authored by Claude
parent 2e958821f9
commit 512154ff97
3 changed files with 15 additions and 5 deletions
+7 -2
View File
@@ -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;