Restore GPS control shutdown for externally started receivers

This commit is contained in:
mikecarper committed 2026-10-15 23:34:34 -07:00
1 parent 36ec9b8bd3
commit e0f46a5014
4 files changed
+42 -6

No files matched your search

@@ -146,14 +146,16 @@ public :
void stop() override {
_stop_calls++;
if (!_started) return;
_started = false;
// RAK discovery and board code can power GPS without begin(). Always
// force the control pins off; only release a claim acquired here.
if (_pin_en != -1) {
digitalWrite(_pin_en, !GPS_EN_ACTIVE);
}
if (_pin_reset != -1) {
digitalWrite(_pin_reset, GPS_RESET_ACTIVE);
}
if (!_started) return;
_started = false;
release();
}
+26
View File
@@ -1,6 +1,7 @@
#include <helpers/sensors/EnvironmentSensorManager.h>
#include <helpers/sensors/I2CAddressClaimPolicy.h>
#include <helpers/sensors/NmeaSentenceProbe.h>
#include <helpers/sensors/MicroNMEALocationProvider.h>
#include <cassert>
#include <cstring>
#include <cstdio>
@@ -421,6 +422,30 @@ static void dedicated() {
#endif
}
static void dedicatedProviderStop() {
#if defined(PIN_GPS_EN) && PIN_GPS_EN >= 0
fresh();
const int reset_pin=7;
MicroNMEALocationProvider location(Serial1,nullptr,reset_pin,PIN_GPS_EN);
EnvironmentSensorManager sensors(location);
Serial1.nmea(); assert(sensors.begin());
assert(sensors.isGPSDetected()&&sensors.isGpsPowered());
// RAK discovery controls power directly, without provider.begin(). Match
// NRF52Board::shutdownPeripherals(), which stops the selected provider.
sensors.getLocationProvider()->stop();
assert(digitalRead(PIN_GPS_EN)==!PIN_GPS_EN_ACTIVE);
assert(digitalRead(reset_pin)==GPS_RESET_ACTIVE);
// A repeated stop must still force safe pins if another owner woke GPS.
digitalWrite(PIN_GPS_EN,PIN_GPS_EN_ACTIVE);
digitalWrite(reset_pin,!GPS_RESET_ACTIVE);
sensors.getLocationProvider()->stop();
assert(digitalRead(PIN_GPS_EN)==!PIN_GPS_EN_ACTIVE);
assert(digitalRead(reset_pin)==GPS_RESET_ACTIVE);
#else
assert(false&&"dedicated provider scenario requires a separate enable pin");
#endif
}
static void terminalStorage() {
SensorManager unknown;
assert(!unknown.canRemoveSharedStoragePowerForDeepSleep());
@@ -469,6 +494,7 @@ int main(int argc,char** argv) {
else if(!std::strcmp(argv[1],"wake_bus_failure")) i2c(false,4);
else if(!std::strcmp(argv[1],"initial_config_failure")) initialConfigFailure();
else if(!std::strcmp(argv[1],"dedicated")) dedicated();
else if(!std::strcmp(argv[1],"dedicated_provider_stop")) dedicatedProviderStop();
else if(!std::strcmp(argv[1],"terminal_storage")) terminalStorage();
else assert(false&&"unknown scenario");
}
+9 -2
View File
@@ -476,12 +476,19 @@ int main() {
Stream serial; RefCountedDigitalPin rail(5); rail.begin();
MicroNMEALocationProvider gps(serial, nullptr, 7, 6, &rail);
gps.stop(); assert(digitalRead(5)==LOW);
rail.claim(); // An external owner powers a receiver never begun here.
for (unsigned attempt=0; attempt<2; ++attempt) {
digitalWrite(6, HIGH); digitalWrite(7, HIGH);
gps.stop();
assert(digitalRead(5)==HIGH && digitalRead(6)==LOW && digitalRead(7)==LOW);
}
rail.release(); assert(digitalRead(5)==LOW);
for (unsigned cycle=0; cycle<300; ++cycle) {
rail.claim(); // Another peripheral owns the same supply.
gps.begin(); gps.begin();
assert(digitalRead(5)==HIGH && digitalRead(6)==HIGH);
assert(digitalRead(5)==HIGH && digitalRead(6)==HIGH && digitalRead(7)==HIGH);
gps.stop(); gps.stop();
assert(digitalRead(5)==HIGH && digitalRead(6)==LOW);
assert(digitalRead(5)==HIGH && digitalRead(6)==LOW && digitalRead(7)==LOW);
rail.release(); assert(digitalRead(5)==LOW);
}
}
+3 -2
View File
@@ -9,7 +9,7 @@ import os
import subprocess
import tempfile
import unittest
from test_gps_upstream_adaptations import ARDUINO, CAYENNE, MESH
from test_gps_upstream_adaptations import ARDUINO, CAYENNE, MESH, NMEA, RTC
from test_replay_reset_integration import extract_braced
ROOT = Path(__file__).resolve().parents[1]
@@ -111,6 +111,7 @@ inline void digitalWrite(int pin,int value){assert(pin>=0&&pin<64);pin_values[pi
inline int digitalRead(int pin){assert(pin>=0&&pin<64);return pin_values[pin];}
''')
for name, content in {"Arduino.h": arduino, "Mesh.h": MESH, "CayenneLPP.h": CAYENNE,
"MicroNMEA.h": NMEA, "RTClib.h": RTC,
"Wire.h": "#pragma once\nclass TwoWire {};\ninline TwoWire Wire;\n"}.items():
(work / name).write_text(content, encoding="utf-8")
cpp, binary = work / "lifecycle.cpp", work / "lifecycle"
@@ -186,7 +187,7 @@ class RakGpsPowerTests(unittest.TestCase):
def test_actual_dedicated_gps_control_isolated_from_shared_slot_power(self):
for active in (0, 1):
with self.subTest(active_level=active):
compile_lifecycle(self, ("dedicated",),
compile_lifecycle(self, ("dedicated", "dedicated_provider_stop"),
("-DRAK_4631", "-DPIN_GPS_EN=14", f"-DPIN_GPS_EN_ACTIVE={active}"))
def test_actual_boot_policy_protects_storage_and_poe_even_when_gps_is_not_compiled(self):