Fix Companion device power saving
This commit is contained in:
1 parent
b8d274c90e
commit
843d309e2b
16 files changed
+1959
-1821
No files matched your search
@@ -333,6 +333,10 @@ void DataStore::loadPrefsInt(const char *filename, CompanionNodePrefs& _prefs, d
|
||||
file.read((uint8_t *)&_prefs.rx_ps_sleep_us, sizeof(_prefs.rx_ps_sleep_us)); // 131
|
||||
file.read((uint8_t *)&_prefs.rx_ps_level, sizeof(_prefs.rx_ps_level)); // 135
|
||||
file.read((uint8_t *)&_prefs.rx_ps_preamble, sizeof(_prefs.rx_ps_preamble)); // 136
|
||||
if (file.available() >= (int)sizeof(_prefs.powersaving_enabled)) {
|
||||
file.read((uint8_t *)&_prefs.powersaving_enabled,
|
||||
sizeof(_prefs.powersaving_enabled)); // 137
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
@@ -395,6 +399,8 @@ bool DataStore::savePrefs(const CompanionNodePrefs& _prefs, double node_lat, dou
|
||||
sizeof(_prefs.rx_ps_level)) == sizeof(_prefs.rx_ps_level); // 135
|
||||
success = success && file.write((uint8_t *)&_prefs.rx_ps_preamble,
|
||||
sizeof(_prefs.rx_ps_preamble)) == sizeof(_prefs.rx_ps_preamble); // 136
|
||||
success = success && file.write((uint8_t *)&_prefs.powersaving_enabled,
|
||||
sizeof(_prefs.powersaving_enabled)) == sizeof(_prefs.powersaving_enabled); // 137
|
||||
|
||||
#if defined(NRF52_PLATFORM)
|
||||
success = file.commit(success);
|
||||
|
||||
@@ -1355,6 +1355,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
|
||||
_prefs.rx_ps_preamble = RXPS_FIXED_PREAMBLE;
|
||||
_prefs.rx_ps_rx_us = RX_POWERSAVING_DEFAULT_RX_US;
|
||||
_prefs.rx_ps_sleep_us = RX_POWERSAVING_DEFAULT_SLEEP_US;
|
||||
_prefs.powersaving_enabled = 0;
|
||||
recalcRxPowerSavingFromLevel(_prefs.rx_ps_level, _prefs.sf, _prefs.bw,
|
||||
_prefs.rx_ps_preamble, &_prefs.rx_ps_rx_us,
|
||||
&_prefs.rx_ps_sleep_us);
|
||||
@@ -1437,6 +1438,7 @@ void MyMesh::begin(bool has_display) {
|
||||
_prefs.radio_fem_rxgain = constrain(_prefs.radio_fem_rxgain, 0, 1);
|
||||
_prefs.radio_fem_txgain = constrain(_prefs.radio_fem_txgain, 0, 1);
|
||||
_prefs.rx_powersaving_enabled = constrain(_prefs.rx_powersaving_enabled, 0, 1);
|
||||
_prefs.powersaving_enabled = constrain(_prefs.powersaving_enabled, 0, 1);
|
||||
_prefs.rx_ps_level = constrain(_prefs.rx_ps_level, 0, 10);
|
||||
if (_prefs.rx_ps_preamble != 16 && _prefs.rx_ps_preamble != 32) {
|
||||
_prefs.rx_ps_preamble = 0;
|
||||
@@ -1883,9 +1885,11 @@ void MyMesh::getNodeSnapshot(WebConfigServer::NodeSnapshot& s) {
|
||||
s.rx_ps_preamble = _prefs.rx_ps_preamble;
|
||||
s.rx_ps_rx_us = _prefs.rx_ps_rx_us;
|
||||
s.rx_ps_sleep_us = _prefs.rx_ps_sleep_us;
|
||||
s.power_saving = _prefs.powersaving_enabled;
|
||||
s.repeat = _prefs.client_repeat != 0;
|
||||
s.capabilities = WebConfigServer::CAP_LOCATION | WebConfigServer::CAP_AIRTIME
|
||||
| WebConfigServer::CAP_RX_DELAY | WebConfigServer::CAP_RX_GAIN;
|
||||
| WebConfigServer::CAP_RX_DELAY | WebConfigServer::CAP_RX_GAIN
|
||||
| WebConfigServer::CAP_POWER_SAVING;
|
||||
if (board.canControlLoRaFemLna()) {
|
||||
s.capabilities |= WebConfigServer::CAP_FEM_RX_GAIN;
|
||||
}
|
||||
@@ -2069,6 +2073,10 @@ void MyMesh::execCommand(char* cmd, char* reply) {
|
||||
applyAndSaveRxPowerSaving(value, reply);
|
||||
return;
|
||||
}
|
||||
if (strcmp(key, "powersaving") == 0) {
|
||||
applyAndSavePowerSaving(value, reply);
|
||||
return;
|
||||
}
|
||||
if (strcmp(key, "radio.fem.rxgain") == 0) {
|
||||
bool enabled;
|
||||
if (!wcParseBool(value, enabled)) {
|
||||
@@ -3507,6 +3515,24 @@ bool MyMesh::applyAndSaveFemTxGain(bool enabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MyMesh::applyAndSavePowerSaving(const char* value, char* reply) {
|
||||
bool enabled;
|
||||
if (strcmp(value, "on") == 0) {
|
||||
enabled = true;
|
||||
} else if (strcmp(value, "off") == 0) {
|
||||
enabled = false;
|
||||
} else {
|
||||
strcpy(reply, "Error: use powersaving on or powersaving off");
|
||||
return false;
|
||||
}
|
||||
|
||||
_prefs.powersaving_enabled = enabled ? 1 : 0;
|
||||
sensors.setPowerSavingEnabled(enabled);
|
||||
savePrefs();
|
||||
snprintf(reply, 160, "OK - powersaving %s", enabled ? "on" : "off");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MyMesh::applyAndSaveRxPowerSaving(const char* value, char* reply) {
|
||||
if (!radio_driver.supportsRxPowerSaving()) {
|
||||
strcpy(reply, "Error: RX power saving unsupported");
|
||||
@@ -4395,6 +4421,14 @@ void MyMesh::handleTerminalCommand(char* command) {
|
||||
}
|
||||
} else if (strncmp(command, "import ", 7) == 0) {
|
||||
importTerminalCard(command + 7);
|
||||
} else if (strcmp(command, "powersaving") == 0
|
||||
|| strcmp(command, "get powersaving") == 0) {
|
||||
Serial.printf(" powersaving %s\r\n",
|
||||
_prefs.powersaving_enabled ? "on" : "off");
|
||||
} else if (strncmp(command, "powersaving ", 12) == 0) {
|
||||
char reply[160];
|
||||
applyAndSavePowerSaving(command + 12, reply);
|
||||
Serial.printf(" %s\r\n", reply);
|
||||
} else if (strcmp(command, "get radio.fem.rxgain") == 0) {
|
||||
if (!board.canControlLoRaFemLna()) {
|
||||
Serial.print(" ERROR: FEM RX gain control is unsupported on this board\r\n");
|
||||
@@ -4411,7 +4445,11 @@ void MyMesh::handleTerminalCommand(char* command) {
|
||||
}
|
||||
} else if (strncmp(command, "set ", 4) == 0) {
|
||||
const char* config = command + 4;
|
||||
if (strncmp(config, "af ", 3) == 0) {
|
||||
if (strncmp(config, "powersaving ", 12) == 0) {
|
||||
char reply[160];
|
||||
applyAndSavePowerSaving(config + 12, reply);
|
||||
Serial.printf(" %s\r\n", reply);
|
||||
} else if (strncmp(config, "af ", 3) == 0) {
|
||||
_prefs.airtime_factor = constrain((float)atof(config + 3), 0.0f, 9.0f);
|
||||
savePrefs();
|
||||
Serial.print(" OK\r\n");
|
||||
@@ -4472,6 +4510,7 @@ void MyMesh::handleTerminalCommand(char* command) {
|
||||
} else if (strcmp(command, "help") == 0) {
|
||||
Serial.print("Commands:\r\n");
|
||||
Serial.print(" set {name|lat|lon|freq|tx|af} {value}\r\n");
|
||||
Serial.print(" powersaving [on|off]\r\n");
|
||||
Serial.print(" get radio.fem.rxgain\r\n");
|
||||
Serial.print(" set radio.fem.rxgain <on|off>\r\n");
|
||||
Serial.print(" get radio.fem.txgain\r\n");
|
||||
|
||||
@@ -278,6 +278,7 @@ private:
|
||||
void checkSerialInterface();
|
||||
bool applyAndSaveFemRxGain(bool enabled);
|
||||
bool applyAndSaveFemTxGain(bool enabled);
|
||||
bool applyAndSavePowerSaving(const char* value, char* reply);
|
||||
bool applyAndSaveRxPowerSaving(const char* value, char* reply);
|
||||
#ifdef ENABLE_USB_INTERFACE
|
||||
ContactInfo* getTerminalRecipient();
|
||||
|
||||
@@ -44,6 +44,7 @@ struct CompanionNodePrefs { // persisted to file
|
||||
uint32_t rx_ps_sleep_us; // sleep window in microseconds
|
||||
uint8_t rx_ps_level; // 0=manual timings, 1..10=level-derived
|
||||
uint8_t rx_ps_preamble; // 0=auto from SF, otherwise 16 or 32
|
||||
uint8_t powersaving_enabled; // device CPU/GPS idle power saving
|
||||
|
||||
// Keep the upstream repeat API while retaining the existing binary prefs
|
||||
// layout used by this branch.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "MyMesh.h"
|
||||
|
||||
#ifdef ESP32_PLATFORM
|
||||
#include "esp_pm.h"
|
||||
#include "esp_bt.h"
|
||||
#endif
|
||||
|
||||
@@ -122,6 +121,74 @@ MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store
|
||||
|
||||
/* END GLOBAL OBJECTS */
|
||||
|
||||
#ifdef ESP32_PLATFORM
|
||||
static int8_t applied_power_saving = -1;
|
||||
static int8_t attempted_power_saving = -1;
|
||||
static unsigned long power_saving_retry_at = 0;
|
||||
|
||||
static uint32_t companionNominalCpuMhz() {
|
||||
#ifdef ESP32_CPU_FREQ
|
||||
return ESP32_CPU_FREQ;
|
||||
#else
|
||||
return F_CPU / 1000000UL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool applyCompanionPowerSaving(bool enabled) {
|
||||
const uint32_t nominal_mhz = companionNominalCpuMhz();
|
||||
const uint32_t target_mhz = enabled && nominal_mhz > 80 ? 80 : nominal_mhz;
|
||||
if (!setCpuFrequencyMhz(target_mhz)) {
|
||||
Serial.printf("Device power saving failed: CPU %lu MHz is unsupported\r\n",
|
||||
(unsigned long)target_mhz);
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(BLE_PIN_CODE) && !CONFIG_IDF_TARGET_ESP32C6
|
||||
esp_err_t bt_result = enabled ? esp_bt_sleep_enable()
|
||||
: esp_bt_sleep_disable();
|
||||
if (bt_result != ESP_OK) {
|
||||
Serial.printf("Bluetooth sleep %s failed: %s\r\n",
|
||||
enabled ? "enable" : "disable",
|
||||
esp_err_to_name(bt_result));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIFI_SSID
|
||||
#if defined(BLE_PIN_CODE)
|
||||
// WiFi modem sleep is required for WiFi/BLE coexistence in Full Companion.
|
||||
WiFi.setSleep(true);
|
||||
#else
|
||||
WiFi.setSleep(enabled);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Serial.printf("Device power saving %s: CPU %lu MHz\r\n",
|
||||
enabled ? "on" : "off", (unsigned long)target_mhz);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void serviceCompanionPowerSaving(bool force = false) {
|
||||
const int8_t requested = the_mesh.getNodePrefs()->powersaving_enabled ? 1 : 0;
|
||||
if (!force && applied_power_saving == requested) return;
|
||||
|
||||
const unsigned long now = millis();
|
||||
if (!force && attempted_power_saving == requested
|
||||
&& power_saving_retry_at != 0
|
||||
&& (int32_t)(now - power_saving_retry_at) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
attempted_power_saving = requested;
|
||||
if (applyCompanionPowerSaving(requested != 0)) {
|
||||
applied_power_saving = requested;
|
||||
power_saving_retry_at = 0;
|
||||
} else {
|
||||
power_saving_retry_at = now + 5000;
|
||||
if (power_saving_retry_at == 0) power_saving_retry_at = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_USB_INTERFACE)
|
||||
static char usb_terminal_line[MAX_TRANS_UNIT * 2 + 32];
|
||||
static size_t usb_terminal_line_len = 0;
|
||||
@@ -664,12 +731,12 @@ void setup() {
|
||||
the_mesh.startInterface(interface_manager);
|
||||
sensors.begin();
|
||||
|
||||
#if ENV_INCLUDE_GPS == 1 && defined(BLE_PIN_CODE)
|
||||
// BLE companions keep GPS duty cycling enabled by default: at most 10
|
||||
// minutes awake, followed by 5 minutes asleep.
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
// Device power saving applies a 10-minute awake, 5-minute sleep GPS cycle.
|
||||
if (sensors.getLocationProvider() != NULL) {
|
||||
sensors.getLocationProvider()->setPowerSavingProfile(600, 300);
|
||||
sensors.setPowerSavingEnabled(true);
|
||||
sensors.setPowerSavingEnabled(
|
||||
the_mesh.getNodePrefs()->powersaving_enabled != 0);
|
||||
}
|
||||
#endif
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
@@ -683,34 +750,7 @@ void setup() {
|
||||
board.onBootComplete();
|
||||
|
||||
#ifdef ESP32_PLATFORM
|
||||
#if !CONFIG_IDF_TARGET_ESP32C6
|
||||
// Enable BLE sleep
|
||||
esp_err_t errBLESleep = esp_bt_sleep_enable();
|
||||
if (errBLESleep == ESP_OK) {
|
||||
Serial.println("Bluetooth sleep enabled successfully");
|
||||
} else {
|
||||
Serial.printf("Bluetooth sleep enable failed: %s\n", esp_err_to_name(errBLESleep));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
esp_pm_config_esp32c3_t pm_config;
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
esp_pm_config_esp32s3_t pm_config;
|
||||
#elif CONFIG_IDF_TARGET_ESP32
|
||||
esp_pm_config_esp32_t pm_config;
|
||||
#elif CONFIG_IDF_TARGET_ESP32C6
|
||||
esp_pm_config_t pm_config;
|
||||
#endif
|
||||
|
||||
// Configure Power Management
|
||||
pm_config = { .max_freq_mhz = 80, .min_freq_mhz = 40, .light_sleep_enable = true };
|
||||
esp_err_t errPM = esp_pm_configure(&pm_config);
|
||||
if (errPM == ESP_OK) {
|
||||
Serial.println("Power Management configured successfully");
|
||||
} else {
|
||||
Serial.printf("Power Management failed to configure: %d\r\n", errPM);
|
||||
}
|
||||
serviceCompanionPowerSaving(true);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -744,9 +784,14 @@ void loop() {
|
||||
external_watchdog.loop();
|
||||
#endif
|
||||
|
||||
#ifdef ESP32_PLATFORM
|
||||
serviceCompanionPowerSaving();
|
||||
#endif
|
||||
|
||||
// USB power alone (for example, a wall charger) must not disable power
|
||||
// saving. Stay awake only while a computer has an active USB data session.
|
||||
bool can_sleep = !the_mesh.hasPendingWork();
|
||||
bool can_sleep = the_mesh.getNodePrefs()->powersaving_enabled
|
||||
&& !the_mesh.hasPendingWork();
|
||||
#if defined(NRF52_PLATFORM)
|
||||
can_sleep = can_sleep && !board.isUsbHostConnected();
|
||||
#endif
|
||||
|
||||
Reference in new issue
Block a user