mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-15 20:49:53 +00:00
- gps: servers honour gps_enabled at boot (was lost on reboot; zc.gps_set upgrades older prefs to on once); sleep lock only while acquiring; gps off works on boards without a power line (UART sleep); UI toggles and fixes handled on the main thread; configure only after a good init; observer parks its GPS; one interval clamp (clampGpsInterval); one nav-mode knob (room servers on Air530Z now stationary); GNSS UARTE from DT - gps: split into ZephyrGPSManager / gps_power / gps_module_cfg (+gps_internal.h); dead driver branches, gps_get_diag, sats_* removed - clock: ZephyrRTCClock writes the hardware RTC itself (clkreboot now resets it); MESH_EVENT_RTC_SAVE gone - power: one power-off path (zephcore_power_off, ZephyrBoard::powerOff), poweroff/shutdown CLI, get pwrmgt.*, crash record kept across reboot, battery reading cached 10 s, fuel gauge on the current API - telemetry: upstream SensorManager + CayenneLPP (rounded to nearest), one builder for all roles; per-sensor channels, MCU temp always, guest gating and inverse mask on servers; sensor list/get/set work; BME280/BMP280 also probed at 0x77 - CLI: gps in upstream's form, get gps detail, gps sync
151 lines
5.0 KiB
C++
151 lines
5.0 KiB
C++
/*
|
|
* SPDX-License-Identifier: MIT
|
|
* CompanionCLICallbacks: the companion's side of CommonCLI (prefs, identity,
|
|
* radio, GPS, stats). main_companion owns the instance and the CommonCLI.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <helpers/CommonCLI.h>
|
|
#include <helpers/StatsFormatHelper.h>
|
|
#include <ZephyrDataStore.h>
|
|
#include <ZephyrBoard.h>
|
|
#include <adapters/radio/LoRaRadio.h>
|
|
#include "CompanionMesh.h"
|
|
|
|
class CompanionCLICallbacks : public CommonCLICallbacks {
|
|
ZephyrDataStore& _store;
|
|
CompanionMesh& _mesh;
|
|
mesh::LoRaRadio& _radio;
|
|
mesh::ZephyrBoard& _board;
|
|
mesh::MillisecondClock& _ms;
|
|
mesh::PacketManager& _pool;
|
|
bool (*_tx_idle)(void);
|
|
|
|
public:
|
|
/* tx_idle: the transport has sent everything queued (main_companion
|
|
* knows the pending reply and which transport is active). */
|
|
CompanionCLICallbacks(ZephyrDataStore& store, CompanionMesh& mesh, mesh::LoRaRadio& radio,
|
|
mesh::ZephyrBoard& board, mesh::MillisecondClock& ms,
|
|
mesh::PacketManager& pool, bool (*tx_idle)(void))
|
|
: _store(store), _mesh(mesh), _radio(radio), _board(board), _ms(ms), _pool(pool),
|
|
_tx_idle(tx_idle) {}
|
|
|
|
void savePrefs() override {
|
|
_store.savePrefs(_mesh.prefs);
|
|
}
|
|
const char* getFirmwareVer() override { return FIRMWARE_VERSION; }
|
|
const char* getBuildDate() override { return FIRMWARE_BUILD_DATE; }
|
|
const char* getRole() override { return "companion"; }
|
|
/* CLI `erase`: the factory reset, which keeps the volume marked as ours
|
|
* so the next boot does not format it a second time. */
|
|
bool formatFileSystem() override { return _store.factoryReset(); }
|
|
|
|
/* Same path as the app's advert command; delay_millis is unused. */
|
|
void sendSelfAdvertisement(int delay_millis, bool flood) override {
|
|
(void)delay_millis;
|
|
_mesh.sendSelfAdvert(flood);
|
|
}
|
|
void updateAdvertTimer() override {}
|
|
void updateFloodAdvertTimer() override {}
|
|
|
|
/* Reboot gate: true once the app has everything we owe it, including a
|
|
* held-back v-contact ack, so a `reboot` typed there waits for its ack. */
|
|
bool transportTxIdle() override {
|
|
return !_mesh.vcontactConfirmPending() && _tx_idle();
|
|
}
|
|
|
|
/* No log file on a companion. */
|
|
void setLoggingOn(bool enable) override { (void)enable; }
|
|
void eraseLogFile() override {}
|
|
void dumpLogFile() override {}
|
|
|
|
/* No runtime TX-power API in the LoRa driver; log only, as the repeater. */
|
|
void setTxPower(int8_t power_dbm) override {
|
|
LOG_INF("TX power %d dBm requested (reboot to apply)", power_dbm);
|
|
}
|
|
|
|
bool setRxBoostedGain(bool enable) override {
|
|
return _radio.setRxBoost(enable);
|
|
}
|
|
|
|
bool setFemRxGain(bool enable) override {
|
|
return _radio.setFemRxEnable(enable);
|
|
}
|
|
|
|
bool configSideDetectors(const uint8_t* sfs, uint8_t num) override {
|
|
return _radio.configSideDetectors(sfs, num);
|
|
}
|
|
|
|
/* Adaptive CAD */
|
|
int formatFreqErrorStatus(char* buf, int cap) override {
|
|
return _radio.formatFreqErrorStatus(buf, cap);
|
|
}
|
|
int formatCadStatus(char* buf, int cap) override {
|
|
return _radio.formatCadStatus(buf, cap);
|
|
}
|
|
void applyCadPrefs() override {
|
|
_radio.setCadParams(_mesh.prefs.cad_auto != 0,
|
|
_mesh.prefs.cad_offset,
|
|
_mesh.prefs.probe_interval,
|
|
_mesh.prefs.cad_busycap,
|
|
_mesh.prefs.cad_base);
|
|
_mesh.prefs.cad_offset = _radio.getCadOffset();
|
|
_mesh.prefs.cad_base = _radio.cadBasePeak();
|
|
}
|
|
void resetCadStats() override {
|
|
_radio.resetCadStats();
|
|
}
|
|
|
|
mesh::LocalIdentity& getSelfId() override { return _mesh.self_id; }
|
|
|
|
void saveIdentity(const mesh::LocalIdentity& new_id) override {
|
|
_mesh.self_id = new_id;
|
|
_store.saveMainIdentity(new_id);
|
|
}
|
|
|
|
void clearStats() override {
|
|
_radio.resetStats();
|
|
_radio.resetDutyCycleTimeoutRestarts();
|
|
_mesh.resetStats();
|
|
}
|
|
|
|
/* Duty-cycle false-preamble re-arm count. Without these the
|
|
* CommonCLICallbacks default answers 0 forever, so `get dc.restarts`
|
|
* read clean on every companion regardless of what the radio was doing
|
|
* — and the companion is the role the duty cycle actually runs in.
|
|
* Mirrors RepeaterMesh::getDutyCycleTimeoutRestarts(). */
|
|
uint32_t getDutyCycleTimeoutRestarts() const override {
|
|
return _radio.getDutyCycleTimeoutRestarts();
|
|
}
|
|
|
|
void resetDutyCycleTimeoutRestarts() override {
|
|
_radio.resetDutyCycleTimeoutRestarts();
|
|
}
|
|
|
|
/* Temp radio params — deferred; stub for now. */
|
|
void applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_t cr,
|
|
int timeout_mins) override {
|
|
(void)freq; (void)bw; (void)sf; (void)cr; (void)timeout_mins;
|
|
}
|
|
|
|
MeshTimeSync* getMeshTimeSync() override {
|
|
return _mesh.getMeshTimeSync();
|
|
}
|
|
|
|
/* stats-core / stats-radio / stats-packets, as the repeater prints them. */
|
|
void formatStatsReply(char* reply) override {
|
|
StatsFormatHelper::formatCoreStats(reply, _board, _ms,
|
|
_mesh.getErrFlags(), &_pool);
|
|
}
|
|
void formatRadioStatsReply(char* reply) override {
|
|
StatsFormatHelper::formatRadioStats(reply, &_radio, _radio,
|
|
_mesh.getTotalAirTime(), _mesh.getReceiveAirTime());
|
|
}
|
|
void formatPacketStatsReply(char* reply) override {
|
|
StatsFormatHelper::formatPacketStats(reply, _radio,
|
|
_mesh.getNumSentFlood(), _mesh.getNumSentDirect(),
|
|
_mesh.getNumRecvFlood(), _mesh.getNumRecvDirect());
|
|
}
|
|
};
|