Limit repeater GPS acquisition and repair CI tests
This commit is contained in:
1 parent
4ba26ff4af
commit
fd920624a2
8 files changed
+84
-9
No files matched your search
@@ -20,6 +20,7 @@ jobs:
|
||||
- name: Install real crypto implementations for cross-language tests
|
||||
run: |
|
||||
python3 -m pip install platformio pycryptodome==3.23.0
|
||||
mkdir -p .pio/libdeps/management-test
|
||||
pio pkg install --global --library 'rweather/Crypto@0.4.0' --storage-dir .pio/libdeps/management-test
|
||||
- name: Verify protocol, encryption, scheduling and MQTT decoding
|
||||
run: python3 -B test/test_management_report.py -v
|
||||
|
||||
@@ -4288,6 +4288,10 @@ Companion reports `on` or `off`; infrastructure includes receiver details:
|
||||
- `off` when the GPS hardware is disabled
|
||||
- `on, {active|deactivated}, {fix|no fix}, {sat count} sats` when the GPS hardware is enabled
|
||||
|
||||
On repeaters, `gps off` cancels any acquisition already in progress. A later
|
||||
authorized location-telemetry request may wake the receiver, but only until its
|
||||
first valid fix is cached; the receiver then powers down again.
|
||||
|
||||
---
|
||||
|
||||
#### Sync this node's clock with GPS time
|
||||
|
||||
+17
-8
@@ -31,16 +31,25 @@ The cache behavior is:
|
||||
- Omit GPS from telemetry if there is no fix or if the cached fix is more than
|
||||
12 hours old.
|
||||
|
||||
When a telemetry request asks for location, GPS is kept on for 2 hours after the
|
||||
latest location request. During that hold window, later location telemetry
|
||||
requests can use fresh GPS data as soon as valid fixes are available.
|
||||
When a telemetry request asks for location, GPS is normally kept on for 2 hours
|
||||
after the latest location request. During that hold window, later location
|
||||
telemetry requests can use fresh GPS data as soon as valid fixes are available.
|
||||
|
||||
If GPS is manually enabled, it stays on and valid fixes continue to update the
|
||||
cache.
|
||||
|
||||
If no contact or ACL client can receive location telemetry, the scheduled
|
||||
2-hour refresh does not run. A real location telemetry request still turns GPS
|
||||
on for the 2-hour hold window, and manual GPS-on still keeps the cache updated.
|
||||
2-hour refresh does not run. A real location telemetry request can still turn
|
||||
GPS on, and manual GPS-on still keeps the cache updated.
|
||||
|
||||
## Repeater Nodes
|
||||
|
||||
Repeaters use a shorter on-demand policy when GPS is manually off. An authorized
|
||||
location-telemetry request wakes the receiver only when its cached position is
|
||||
stale. The first valid fix is cached and the receiver immediately powers down;
|
||||
the next request can return that fix without another wake. `gps off` also
|
||||
cancels an acquisition already in progress. An acquisition that never obtains a
|
||||
fix retains the normal 15-minute safety timeout.
|
||||
|
||||
## Companion/Client Nodes
|
||||
|
||||
@@ -55,6 +64,9 @@ Location telemetry is sent only when the requester's effective telemetry
|
||||
permissions include location. Those permissions are derived from the companion
|
||||
telemetry mode settings and contact flags.
|
||||
|
||||
No new phone app behavior is required. Existing clients see the existing GPS
|
||||
telemetry field when it is present.
|
||||
|
||||
The scheduled GPS cache refresh runs only when at least one stored contact has
|
||||
effective location telemetry access:
|
||||
|
||||
@@ -62,9 +74,6 @@ effective location telemetry access:
|
||||
- `location: allow flags` with at least one stored contact whose flags include
|
||||
location
|
||||
|
||||
No new phone app behavior is required. Existing clients see the existing GPS
|
||||
telemetry field when it is present.
|
||||
|
||||
## Sensor Nodes
|
||||
|
||||
Sensor telemetry access is controlled by:
|
||||
|
||||
@@ -204,6 +204,9 @@ void setup() {
|
||||
#endif
|
||||
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
// With GPS manually off, an authorized location telemetry request may wake
|
||||
// the receiver only until the first valid fix has been cached.
|
||||
sensors.setGpsTelemetryStopAfterFix(true);
|
||||
if (sensors.getLocationProvider() != NULL) {
|
||||
// Keep GPS awake for at most 10 minutes, then asleep for one day.
|
||||
sensors.getLocationProvider()->setPowerSavingProfile(600, 86400);
|
||||
|
||||
@@ -115,6 +115,18 @@ bool SensorManager::queryGpsTelemetry(uint8_t requester_permissions, CayenneLPP&
|
||||
gps_cache_altitude);
|
||||
return true;
|
||||
}
|
||||
if (gps_stop_after_fix && !gps_user_enabled) {
|
||||
// Repeaters acquire only when the cached position is stale. The request
|
||||
// returns without GPS while acquisition is in progress; the next request
|
||||
// can use the cached fix without waking the receiver again.
|
||||
if (!gpsTelemetryCacheFresh(now) && !gps_acquiring) {
|
||||
beginGpsTelemetryAcquisition(now);
|
||||
}
|
||||
if (!gpsTelemetryCacheFresh(now)) return false;
|
||||
telemetry.addGPS(TELEM_CHANNEL_SELF, gps_cache_lat, gps_cache_lon,
|
||||
gps_cache_altitude);
|
||||
return true;
|
||||
}
|
||||
gps_hold_until = now + GPS_TELEMETRY_HOLD_SEC * 1000UL;
|
||||
if (!telemetryGpsActive()) telemetryGpsStart();
|
||||
if (!gpsTelemetryCacheFresh(now) && !gps_acquiring) beginGpsTelemetryAcquisition(now);
|
||||
@@ -138,6 +150,11 @@ void SensorManager::processGpsTelemetryFix(float lat, float lon, float altitude,
|
||||
gps_stable_started_at = now;
|
||||
gps_stable_origin_lat = lat;
|
||||
gps_stable_origin_lon = lon;
|
||||
if (gps_stop_after_fix && !gps_user_enabled) {
|
||||
updateGpsTelemetryCache(lat, lon, altitude, now);
|
||||
finishGpsTelemetryAcquisition(now, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static const float STABLE_RADIUS_M2 =
|
||||
|
||||
@@ -18,6 +18,7 @@ class SensorManager {
|
||||
bool gps_location_access_available = false;
|
||||
bool gps_transport_available = true;
|
||||
bool gps_user_enabled = false;
|
||||
bool gps_stop_after_fix = false;
|
||||
bool gps_acquiring = false;
|
||||
bool gps_acquire_has_fix = false;
|
||||
float gps_cache_lat = 0;
|
||||
@@ -100,6 +101,13 @@ public:
|
||||
}
|
||||
virtual void loop() { }
|
||||
virtual void setTelemetryLocationAccessAvailable(bool available);
|
||||
void setGpsTelemetryStopAfterFix(bool enabled) {
|
||||
#if ENV_INCLUDE_GPS
|
||||
gps_stop_after_fix = enabled;
|
||||
#else
|
||||
(void)enabled;
|
||||
#endif
|
||||
}
|
||||
virtual int getNumSettings() const { return 0; }
|
||||
virtual const char* getSettingName(int i) const { return NULL; }
|
||||
virtual const char* getSettingValue(int i) const { return NULL; }
|
||||
|
||||
@@ -18,6 +18,9 @@ public:
|
||||
void setLocationAccessAvailable(bool available) {
|
||||
setTelemetryLocationAccessAvailable(available);
|
||||
}
|
||||
void setStopAfterFix(bool enabled) {
|
||||
setGpsTelemetryStopAfterFix(enabled);
|
||||
}
|
||||
void service(unsigned long now) { loopGpsTelemetry(now); }
|
||||
bool receiverRequired(unsigned long now) const {
|
||||
return gpsTelemetryReceiverRequired(now);
|
||||
@@ -103,6 +106,29 @@ TEST(GpsTransportOwnership, UserOffCancelsTelemetryAcquisitionAndHold) {
|
||||
EXPECT_EQ(1, sensors.starts);
|
||||
}
|
||||
|
||||
TEST(GpsTransportOwnership, RepeaterTelemetryStopsAfterFirstFix) {
|
||||
resetArduinoMock();
|
||||
TestGpsSensorManager sensors;
|
||||
CayenneLPP telemetry(64);
|
||||
|
||||
sensors.setStopAfterFix(true);
|
||||
EXPECT_FALSE(sensors.queryLocation(telemetry));
|
||||
ASSERT_TRUE(sensors.active);
|
||||
ASSERT_TRUE(sensors.receiverRequired(millis()));
|
||||
|
||||
sensors.acceptFix(47.61f, -122.33f, 125.0f, millis());
|
||||
EXPECT_FALSE(sensors.active);
|
||||
EXPECT_FALSE(sensors.receiverRequired(millis()));
|
||||
EXPECT_EQ(1, sensors.starts);
|
||||
EXPECT_EQ(1, sensors.stops);
|
||||
|
||||
// The next request receives the cached fix without another GPS wake.
|
||||
EXPECT_TRUE(sensors.queryLocation(telemetry));
|
||||
EXPECT_EQ(1, telemetry.gps_count);
|
||||
EXPECT_FALSE(sensors.active);
|
||||
EXPECT_EQ(1, sensors.starts);
|
||||
}
|
||||
|
||||
TEST(GpsTransportOwnership, LastGoodCacheSurvivesTemporaryUartOwnership) {
|
||||
resetArduinoMock();
|
||||
TestGpsSensorManager sensors;
|
||||
@@ -112,6 +138,9 @@ TEST(GpsTransportOwnership, LastGoodCacheSurvivesTemporaryUartOwnership) {
|
||||
sensors.acceptFix(47.61f, -122.33f, 125.0f, millis());
|
||||
g_mock_millis += 31000;
|
||||
sensors.acceptFix(47.61f, -122.33f, 125.0f, millis());
|
||||
// Non-repeater roles retain the normal two-hour request hold.
|
||||
EXPECT_TRUE(sensors.active);
|
||||
EXPECT_TRUE(sensors.receiverRequired(millis()));
|
||||
ASSERT_TRUE(sensors.queryLocation(telemetry));
|
||||
ASSERT_EQ(1, telemetry.gps_count);
|
||||
|
||||
|
||||
@@ -196,8 +196,12 @@ TEST(ManagementRouting, FloodForwardingDoesNotNeedAKeyAndStillHonorsFilters) {
|
||||
mesh.forwardFloods = true;
|
||||
mesh::Packet p;
|
||||
p.header = (PAYLOAD_TYPE_GRP_DATA << PH_TYPE_SHIFT) | ROUTE_TYPE_FLOOD;
|
||||
p.setPathHashSizeAndCount(1, 0); memcpy(p.payload, "MGR1", 4); p.payload[79] = 1;
|
||||
p.setPathHashSizeAndCount(1, 0);
|
||||
p.payload_len = mesh::management::floodSize(mesh::management::HEADER + mesh::management::TAG);
|
||||
memset(p.payload, 0, p.payload_len);
|
||||
memcpy(p.payload, "MGR1", 4);
|
||||
p.payload[79] = 1; // one page containing zero ACL entries
|
||||
ASSERT_TRUE(mesh::management::validPage(p.payload, p.payload_len, true));
|
||||
EXPECT_NE(ACTION_RELEASE, mesh.receivePacket(&p));
|
||||
EXPECT_FALSE(mesh.groupPacketObserved); // never delivered as decrypted channel data
|
||||
mesh.rejectFloods = true;
|
||||
|
||||
Reference in new issue
Block a user