133 lines
4.9 KiB
C++
133 lines
4.9 KiB
C++
#include "CommonCLI.h"
|
|
#include "CheckedSettingsFile.h"
|
|
#include <MeshCore.h>
|
|
#if defined(NRF52_PLATFORM) && defined(NRF52_POWER_MANAGEMENT)
|
|
#include "NRF52VoltagePolicy.h"
|
|
#endif
|
|
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
|
|
#include "AtomicFileWriter.h"
|
|
#else
|
|
#include "ContactFileTransaction.h"
|
|
#endif
|
|
|
|
namespace {
|
|
const char* const BATTERY_FORWARD_PATH = "/battery_forward";
|
|
|
|
bool readBatteryForwarding(FILESYSTEM* fs, const char* path,
|
|
mesh::batteryforward::Settings& settings) {
|
|
uint8_t bytes[mesh::batteryforward::RecordSize];
|
|
return mesh::storage::readFixedSettingsFile(fs, path, bytes, sizeof(bytes))
|
|
&& mesh::batteryforward::decode(bytes, sizeof(bytes), settings);
|
|
}
|
|
}
|
|
|
|
void CommonCLI::loadBatteryForwarding(FILESYSTEM* fs) {
|
|
_battery_forward_fs = fs;
|
|
_battery_forward_settings = mesh::batteryforward::Settings{};
|
|
_battery_forward_state = mesh::batteryforward::State{};
|
|
#if defined(ESP32_PLATFORM) || defined(RP2040_PLATFORM)
|
|
if (!mesh::ContactFileTransaction::recover(fs, BATTERY_FORWARD_PATH)) {
|
|
_battery_forward_fs = nullptr;
|
|
return;
|
|
}
|
|
#endif
|
|
mesh::batteryforward::Settings loaded;
|
|
if (readBatteryForwarding(fs, BATTERY_FORWARD_PATH, loaded)
|
|
|| readBatteryForwarding(fs, "/battery_forward.bak", loaded))
|
|
_battery_forward_settings = loaded;
|
|
}
|
|
|
|
bool CommonCLI::saveBatteryForwarding(const mesh::batteryforward::Settings& settings) {
|
|
if (!_battery_forward_fs || !mesh::batteryforward::validSettings(settings)) return false;
|
|
uint8_t bytes[mesh::batteryforward::RecordSize];
|
|
mesh::batteryforward::encode(bytes, settings);
|
|
#if defined(NRF52_PLATFORM)
|
|
return mesh::storage::writeCheckedSettingsFile(_battery_forward_fs, BATTERY_FORWARD_PATH,
|
|
bytes, sizeof(bytes)) == mesh::AtomicFileWriter::Outcome::Committed;
|
|
#else
|
|
#if defined(STM32_PLATFORM)
|
|
mesh::AtomicFileWriter writer(_battery_forward_fs, BATTERY_FORWARD_PATH);
|
|
#else
|
|
mesh::ContactFileTransaction writer(_battery_forward_fs, BATTERY_FORWARD_PATH);
|
|
#endif
|
|
if (!writer || writer.write(bytes, sizeof(bytes)) != sizeof(bytes) || !writer.commit()) return false;
|
|
uint8_t verified[sizeof(bytes)];
|
|
return mesh::storage::readFixedSettingsFile(_battery_forward_fs, BATTERY_FORWARD_PATH,
|
|
verified, sizeof(verified)) && memcmp(bytes, verified, sizeof(bytes)) == 0;
|
|
#endif
|
|
}
|
|
|
|
uint16_t CommonCLI::batteryEmptyMv() const {
|
|
#if defined(NRF52_PLATFORM) && defined(NRF52_POWER_MANAGEMENT)
|
|
return mesh::power::configuredEmpty();
|
|
#else
|
|
#ifdef BATT_MIN_MILLIVOLTS
|
|
const uint16_t compiled = BATT_MIN_MILLIVOLTS;
|
|
#else
|
|
const uint16_t compiled = 3000;
|
|
#endif
|
|
return _battery_forward_settings.emptyMv ? _battery_forward_settings.emptyMv : compiled;
|
|
#endif
|
|
}
|
|
|
|
uint16_t CommonCLI::batteryFullMv() const {
|
|
#if defined(NRF52_PLATFORM) && defined(NRF52_POWER_MANAGEMENT)
|
|
return mesh::power::configuredFull();
|
|
#else
|
|
#ifdef BATT_MAX_MILLIVOLTS
|
|
const uint16_t compiled = BATT_MAX_MILLIVOLTS;
|
|
#else
|
|
const uint16_t compiled = 4200;
|
|
#endif
|
|
return _battery_forward_settings.fullMv ? _battery_forward_settings.fullMv : compiled;
|
|
#endif
|
|
}
|
|
|
|
uint8_t CommonCLI::batteryPercent(uint16_t mv) const {
|
|
return mesh::batteryforward::percent(mv, batteryEmptyMv(), batteryFullMv());
|
|
}
|
|
|
|
bool CommonCLI::batteryAllowsTransmit(const mesh::Packet* packet) const {
|
|
// Explicit relay ownership survives path stripping and retry clones. Own
|
|
// replies and OTA session traffic are not inferred from radio routing flags.
|
|
return !packet || !packet->forwarded || batteryAllowsForward(packet->isRouteFlood());
|
|
}
|
|
|
|
bool CommonCLI::batteryAllowsForward(bool flood) const {
|
|
// Receive/transmit admission can run before CommonCLI::loop(), including
|
|
// the first packet after boot or a long MCU sleep. Never use a stale gate.
|
|
loopBatteryForwarding();
|
|
return _battery_forward_state.allows(flood);
|
|
}
|
|
|
|
void CommonCLI::loopBatteryForwarding(bool force) const {
|
|
if (!force && !_battery_forward_settings.enabled) return;
|
|
const uint32_t now = millis();
|
|
if (!force && !_battery_forward_state.due(now)) return;
|
|
const uint16_t mv = _board->getBattMilliVolts();
|
|
_battery_forward_state.update(now, mv, batteryPercent(mv),
|
|
mesh::batteryforward::validEndpoints(batteryEmptyMv(), batteryFullMv()),
|
|
_battery_forward_settings);
|
|
}
|
|
|
|
bool CommonCLI::handleBatteryForwardingCommand(const char* command, char* reply) {
|
|
if (strncmp(command, "get battery.forward", 19) == 0) {
|
|
const char* tail = command + 19;
|
|
while (*tail == ' ' || *tail == '\t') ++tail;
|
|
if (!*tail) loopBatteryForwarding(true);
|
|
}
|
|
bool saved = false;
|
|
const bool handled = mesh::batteryforward::handleCommand(_battery_forward_settings,
|
|
_battery_forward_state, batteryEmptyMv(), batteryFullMv(),
|
|
#if defined(NRF52_PLATFORM) && defined(NRF52_POWER_MANAGEMENT)
|
|
true,
|
|
#else
|
|
false,
|
|
#endif
|
|
command, reply, 157, [this, &saved](const mesh::batteryforward::Settings& candidate) {
|
|
return saved = saveBatteryForwarding(candidate);
|
|
});
|
|
if (saved) loopBatteryForwarding(true);
|
|
return handled;
|
|
}
|