mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-30 11:54:25 +00:00
218 lines
7.1 KiB
C++
218 lines
7.1 KiB
C++
#include "CardputerSensorManager.h"
|
|
|
|
namespace {
|
|
const uint32_t STANDBY_RENEW_MS = 60UL * 60UL * 1000UL;
|
|
bool due(uint32_t now, uint32_t deadline) {
|
|
return static_cast<int32_t>(now - deadline) >= 0;
|
|
}
|
|
}
|
|
|
|
#if ENV_INCLUDE_GPS
|
|
void CardputerSensorManager::armGpsPowerSavingCycle() {
|
|
if (!powersaving_enabled || !_location->getGPSPowerSaving()) return;
|
|
_location->syncTimeForPowerSavingCycle();
|
|
_location->setNextGPSOn(0);
|
|
_location->setNextSleep();
|
|
// The provider uses zero as "no deadline", including at millis rollover.
|
|
if (static_cast<uint32_t>(_location->getNextGPSOff()) == 0) _location->setNextGPSOff(1);
|
|
}
|
|
|
|
void CardputerSensorManager::start_gps() {
|
|
if (!gps_serial_open || gps_active) return;
|
|
gps_standby(false);
|
|
gps_active = true;
|
|
// Do not turn a retained pre-sleep fix into a new telemetry observation.
|
|
// Receiver startup is asynchronous; the normal bounded parser polls it.
|
|
_location->clearPositionFix();
|
|
_location->begin();
|
|
next_gps_update = millis();
|
|
if (!_location->getGPSPowerSaving()) _location->syncTimeForPowerSavingCycle();
|
|
armGpsPowerSavingCycle();
|
|
}
|
|
|
|
void CardputerSensorManager::stop_gps() {
|
|
if (!gps_active) return;
|
|
gps_standby(true);
|
|
gps_active = false;
|
|
_location->stopTimeSync();
|
|
_location->setNextGPSOff(0);
|
|
if (powersaving_enabled && _location->getGPSPowerSaving()
|
|
&& isGpsTelemetryUserEnabled()) _location->setNextWake();
|
|
else _location->setNextGPSOn(0);
|
|
_location->stop();
|
|
}
|
|
#endif
|
|
|
|
void CardputerSensorManager::gps_standby(bool active) {
|
|
// CASIC protocol sections CAS10/CAS12: hot start and standby for at most
|
|
// 65535 seconds. The provider's MicroNMEA sender generates the checksum.
|
|
#if ENV_INCLUDE_GPS
|
|
_location->sendSentence(active ? "$PCAS12,65535" : "$PCAS10,0");
|
|
#else
|
|
// GPS-free roles still have a powered physical receiver. Keep it in standby
|
|
// without linking a parser/provider or advertising a GPS firmware feature.
|
|
Serial1.print(active ? "$PCAS12,65535*1E\r\n" : "$PCAS10,0*1C\r\n");
|
|
#endif
|
|
standby_renew_at = static_cast<uint32_t>(millis()) + STANDBY_RENEW_MS;
|
|
}
|
|
|
|
bool CardputerSensorManager::begin() {
|
|
if (gps_serial_open) return true;
|
|
// Existing board macros name the cap's RX/TX nets; setPins takes MCU RX/TX.
|
|
Serial1.setPins(PIN_GPS_TX, PIN_GPS_RX);
|
|
Serial1.begin(GPS_BAUD_RATE);
|
|
gps_serial_open = true;
|
|
gps_active = false;
|
|
#if ENV_INCLUDE_GPS
|
|
_location->setGPSPowerSaving(false);
|
|
_location->stopTimeSync();
|
|
_location->stop();
|
|
#endif
|
|
// A fixed cap powers GNSS at boot even when the saved preference is off.
|
|
// Silence it explicitly; UART traffic during startup is not a user choice.
|
|
gps_standby(true);
|
|
#if !CARDPUTER_ADV_UI
|
|
#if ENV_INCLUDE_GPS
|
|
// The fixed cap uses command-based standby. Keep the generic manager's GPS
|
|
// discovery/transport permanently blocked: it must not reset or reopen this
|
|
// UART independently. Its environmental discovery and telemetry stay intact.
|
|
CardputerSensorBase::gps_serial_transport_blocked = true;
|
|
#endif
|
|
return CardputerSensorBase::begin();
|
|
#else
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
bool CardputerSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP &telemetry) {
|
|
// Shared cache, permissions, bounded acquisition and manual-off cancellation.
|
|
#if !CARDPUTER_ADV_UI
|
|
return CardputerSensorBase::querySensors(requester_permissions, telemetry);
|
|
#elif ENV_INCLUDE_GPS
|
|
queryGpsTelemetry(requester_permissions, telemetry);
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void CardputerSensorManager::loop() {
|
|
if (!gps_serial_open) return;
|
|
#if !CARDPUTER_ADV_UI && (ENV_INCLUDE_GPS || defined(ENV_INCLUDE_BME680_BSEC))
|
|
// Generic GPS discovery is blocked and its gps_detected/active remain false.
|
|
// This services external BSEC sensors and the one shared GPS telemetry cache.
|
|
CardputerSensorBase::loop();
|
|
#endif
|
|
const uint32_t now = millis();
|
|
#if ENV_INCLUDE_GPS
|
|
#if CARDPUTER_ADV_UI
|
|
loopGpsTelemetry(now);
|
|
#endif
|
|
if (powersaving_enabled && isGpsTelemetryUserEnabled()
|
|
&& !isTrackerGpsModeEnabled() && _location->getGPSPowerSaving()) {
|
|
const uint32_t next_off = _location->getNextGPSOff();
|
|
const uint32_t next_on = _location->getNextGPSOn();
|
|
if (gps_active && !gpsTelemetryReceiverRequired(now)
|
|
&& ((next_off != 0 && due(now, next_off)) || !_location->waitingTimeSync())) {
|
|
stop_gps();
|
|
} else if (!gps_active && ((next_on != 0 && due(now, next_on))
|
|
|| _location->waitingTimeSync())) {
|
|
start_gps();
|
|
}
|
|
}
|
|
#endif
|
|
if (!gps_active) {
|
|
// CAS12 eventually wakes on its own. Renew off/standby without changing
|
|
// saved intent or creating a GPS telemetry/clock acquisition.
|
|
if (due(now, standby_renew_at)) gps_standby(true);
|
|
return;
|
|
}
|
|
#if ENV_INCLUDE_GPS
|
|
_location->loop();
|
|
if (due(now, next_gps_update)) {
|
|
if (_location->isValid()) {
|
|
node_lat = static_cast<double>(_location->getLatitude()) / 1000000.0;
|
|
node_lon = static_cast<double>(_location->getLongitude()) / 1000000.0;
|
|
node_altitude = static_cast<double>(_location->getAltitude()) / 1000.0;
|
|
processGpsTelemetryFix(node_lat, node_lon, node_altitude, now);
|
|
}
|
|
next_gps_update = now + getGpsUpdateIntervalMillis();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
int CardputerSensorManager::getNumSettings() const {
|
|
return CardputerSensorBase::getNumSettings()
|
|
#if ENV_INCLUDE_GPS
|
|
+ 1
|
|
#endif
|
|
;
|
|
}
|
|
|
|
const char *CardputerSensorManager::getSettingName(int i) const {
|
|
#if ENV_INCLUDE_GPS
|
|
if (i == 0) return "gps";
|
|
--i;
|
|
#endif
|
|
return CardputerSensorBase::getSettingName(i);
|
|
}
|
|
|
|
const char *CardputerSensorManager::getSettingValue(int i) const {
|
|
#if ENV_INCLUDE_GPS
|
|
if (i == 0) return isGpsTelemetryUserEnabled() ? "1" : "0";
|
|
--i;
|
|
#endif
|
|
return CardputerSensorBase::getSettingValue(i);
|
|
}
|
|
|
|
bool CardputerSensorManager::setSettingValue(const char *name, const char *value) {
|
|
if (!name || !value) return false;
|
|
#if ENV_INCLUDE_GPS
|
|
if (strcmp(name, "gps") == 0) {
|
|
const bool enabled = strcmp(value, "0") != 0;
|
|
const bool was_active = gps_active;
|
|
_location->setGPSPowerSaving(enabled && powersaving_enabled);
|
|
setGpsTelemetryUserEnabled(enabled);
|
|
if (enabled && powersaving_enabled && was_active) armGpsPowerSavingCycle();
|
|
if (!enabled) {
|
|
_location->stopTimeSync();
|
|
_location->setNextGPSOn(0);
|
|
_location->setNextGPSOff(0);
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
const bool accepted = CardputerSensorBase::setSettingValue(name, value);
|
|
#if ENV_INCLUDE_GPS
|
|
if (accepted && strcmp(name, "gps_interval") == 0) next_gps_update = millis();
|
|
#endif
|
|
return accepted;
|
|
}
|
|
|
|
void CardputerSensorManager::setPowerSavingEnabled(bool enabled) {
|
|
#if ENV_INCLUDE_GPS
|
|
if (powersaving_enabled == enabled) return;
|
|
powersaving_enabled = enabled;
|
|
if (isTrackerGpsModeEnabled()) {
|
|
_location->setGPSPowerSaving(false);
|
|
return;
|
|
}
|
|
const bool user_enabled = isGpsTelemetryUserEnabled();
|
|
_location->setGPSPowerSaving(enabled && user_enabled);
|
|
if (!user_enabled) return;
|
|
if (!gps_active) start_gps();
|
|
else if (enabled) armGpsPowerSavingCycle();
|
|
#else
|
|
CardputerSensorBase::setPowerSavingEnabled(enabled);
|
|
#endif
|
|
}
|
|
|
|
void CardputerSensorManager::shutdownGpsTransportForDeepSleep() {
|
|
if (!gps_serial_open) return;
|
|
#if ENV_INCLUDE_GPS
|
|
stop_gps();
|
|
#else
|
|
gps_standby(true);
|
|
#endif
|
|
Serial1.end();
|
|
gps_serial_open = false;
|
|
}
|