mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-23 09:42:34 +00:00
properly reset CAD offset when needed
This commit is contained in:
1 parent
ce6e71067d
commit
69cc148fbe
12 files changed
+249
-44
No files matched your search
@@ -53,7 +53,7 @@ LoRaRadioBase::LoRaRadioBase(const struct device *lora_dev, MainBoard &board,
|
||||
_sample_rssi(0), _sample_channel_quiet(false), _sample_fresh(false),
|
||||
_rx_entry_cyc(0),
|
||||
_rssi_bursts(0), _rssi_spread_sum(0), _rssi_degenerate(0),
|
||||
_cad_auto(false), _cad_offset(0), _probe_interval_s(0),
|
||||
_cad_auto(false), _cad_offset(0), _cad_temp_offset(0), _probe_interval_s(0),
|
||||
_cad_busycap_pct(0), _cad_pending_level(INT8_MIN),
|
||||
_cad_pending_deadline_ms(0),
|
||||
_cad_last_probe_ms(0), _cad_last_decay_ms(0),
|
||||
@@ -583,7 +583,8 @@ void LoRaRadioBase::reconfigureWithParams(float freq, float bw, uint8_t sf, uint
|
||||
reconfigure();
|
||||
}
|
||||
|
||||
void LoRaRadioBase::setRadioOverride(float freq, float bw, uint8_t sf, uint8_t cr)
|
||||
void LoRaRadioBase::setRadioOverride(float freq, float bw, uint8_t sf, uint8_t cr,
|
||||
bool visiting_new_preset)
|
||||
{
|
||||
_override_freq = freq;
|
||||
_override_bw = bw;
|
||||
@@ -591,6 +592,19 @@ void LoRaRadioBase::setRadioOverride(float freq, float bw, uint8_t sf, uint8_t c
|
||||
_override_cr = cr;
|
||||
_has_radio_override = true;
|
||||
reconfigure();
|
||||
|
||||
/* Visit a new preset at its own base detPeak. The learned offset belongs
|
||||
* to the preset it was measured on and the base table it addresses is
|
||||
* per-SF/per-bandwidth, so carrying it across programs a threshold nobody
|
||||
* measured (SF7->SF12 is 5 counts on SX126x, 16 on LR11xx). A freeze
|
||||
* changes nothing on air, so it keeps the offset that is already right.
|
||||
*
|
||||
* _cad_offset is left untouched — not snapshotted — so the configured
|
||||
* preset gets its offset back verbatim in clearRadioOverride(), and no
|
||||
* visitor value can reach prefs in between. Adaptation is suspended for
|
||||
* the duration; see cadMaintenance(). */
|
||||
_cad_temp_offset = visiting_new_preset ? 0 : _cad_offset;
|
||||
hwCadSetPeakOffset(cadEffectiveOffset());
|
||||
}
|
||||
|
||||
void LoRaRadioBase::clearRadioOverride()
|
||||
@@ -600,6 +614,7 @@ void LoRaRadioBase::clearRadioOverride()
|
||||
}
|
||||
_has_radio_override = false;
|
||||
reconfigure();
|
||||
hwCadSetPeakOffset(cadEffectiveOffset());
|
||||
}
|
||||
|
||||
void LoRaRadioBase::startReceive()
|
||||
@@ -1650,7 +1665,11 @@ void LoRaRadioBase::setCadParams(bool auto_enabled, int8_t offset,
|
||||
? (uint32_t)probe_interval_s * 1000U
|
||||
: (uint32_t)CONFIG_ZEPHCORE_NOISE_FLOOR_INTERVAL_MS;
|
||||
|
||||
hwCadSetPeakOffset(_cad_offset);
|
||||
/* Effective, not _cad_offset: applyCadPrefs() reaches here from ordinary
|
||||
* `set cad.*` commands, which an operator can issue while a `tempradio`
|
||||
* window is open. Programming the configured offset then would put the
|
||||
* visited preset back on a threshold that does not belong to it. */
|
||||
hwCadSetPeakOffset(cadEffectiveOffset());
|
||||
|
||||
LOG_INF("cad: auto=%d offset=%d base=%u measure_interval=%ums busycap=%u%%",
|
||||
(int)auto_enabled, (int)offset, (unsigned)base,
|
||||
@@ -1666,6 +1685,15 @@ void LoRaRadioBase::resetCadStats()
|
||||
{
|
||||
memset(_cad_stats, 0, sizeof(_cad_stats));
|
||||
_cad_probe_rr = 0;
|
||||
|
||||
/* Drop any probe still in flight with the table it belongs to.
|
||||
* cadMaintenance() books a verdict into whatever stats exist when it
|
||||
* resolves, not the ones that were current when it was armed — so a
|
||||
* probe left pending across reconfigure() writes an old-preset sample
|
||||
* into the fresh table, and across `set cad.reset` writes a pre-reset
|
||||
* sample into a table the operator just cleared. */
|
||||
_cad_pending_level = INT8_MIN;
|
||||
_cad_pending_deadline_ms = 0;
|
||||
}
|
||||
|
||||
void LoRaRadioBase::decayCadStats()
|
||||
@@ -1868,16 +1896,26 @@ bool LoRaRadioBase::cadRelaxOnTxStarvation()
|
||||
*
|
||||
* One step at a time, never a jump to base: on a genuinely congested
|
||||
* site the operator's sensitive setting may be almost right, and the
|
||||
* smallest change that restores transmission is the one to make. */
|
||||
if (_cad_offset >= cadLevelMaxEff()) {
|
||||
* smallest change that restores transmission is the one to make.
|
||||
*
|
||||
* This one safety DOES run during a temporary override — unlike the
|
||||
* staircase, which cadMaintenance() suspends there. A node muted for
|
||||
* the length of a `tempradio` window, or until the reboot a `set radio`
|
||||
* is waiting for, is muted for real. It steps the visitor's offset, so
|
||||
* the recovery lasts exactly as long as the visit and still cannot reach
|
||||
* prefs: getCadOffset() keeps reporting the configured value. */
|
||||
int8_t &off = _has_radio_override ? _cad_temp_offset : _cad_offset;
|
||||
|
||||
if (off >= cadLevelMaxEff()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_cad_offset++;
|
||||
hwCadSetPeakOffset(_cad_offset);
|
||||
LOG_WRN("cad: TX starvation override -> offset %d (auto=%d) — LBT was "
|
||||
off++;
|
||||
hwCadSetPeakOffset(cadEffectiveOffset());
|
||||
LOG_WRN("cad: TX starvation override -> offset %d (auto=%d%s) — LBT was "
|
||||
"refusing every transmit",
|
||||
(int)_cad_offset, (int)_cad_auto);
|
||||
(int)off, (int)_cad_auto,
|
||||
_has_radio_override ? ", temp preset" : "");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1887,6 +1925,21 @@ void LoRaRadioBase::cadMaintenance()
|
||||
return;
|
||||
}
|
||||
|
||||
/* Nothing to learn on a preset the node is only visiting: the statistics
|
||||
* would describe that preset, and every mover of _cad_offset below is
|
||||
* persisted by Dispatcher::maintenanceLoop() -> onCadOffsetChanged() ->
|
||||
* prefs, so letting the staircase run inside a `tempradio` window would
|
||||
* write a visitor's offset to flash and leave it there after the revert.
|
||||
* The chip runs at the visited preset's own base (setRadioOverride).
|
||||
*
|
||||
* The pending sample is dropped rather than carried: it was taken under
|
||||
* the other preset, and consuming it after the revert would admit a
|
||||
* probe on a quiet verdict that is a whole interval stale. */
|
||||
if (_has_radio_override) {
|
||||
_sample_fresh = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int64_t now = k_uptime_get();
|
||||
|
||||
/* Periodic decay keeps the stats fresh (and counters bounded). */
|
||||
@@ -2150,6 +2203,9 @@ int LoRaRadioBase::formatCadStatus(char *buf, int cap)
|
||||
* Header: a:on o:1 pk:22(b21/4s) sp:0.9/84%(312) bc:25%
|
||||
* a auto on/off o offset pk operating peak
|
||||
* b family base 4s symbols bc busy cap
|
||||
* a:tmp a temporary radio override is running a preset the node is
|
||||
* only visiting: adaptation is suspended and o/pk describe that
|
||||
* visit, not the configured preset (see setRadioOverride).
|
||||
* sp RSSI burst quality: mean spread in dB across the median-of-N
|
||||
* reads, the share of bursts whose spread was 0, and the burst
|
||||
* count. The count is not decoration: a share without its
|
||||
@@ -2190,10 +2246,12 @@ int LoRaRadioBase::formatCadStatus(char *buf, int cap)
|
||||
* still gets the mean and the share, which is the actual verdict. */
|
||||
bool room_for_count = (cap >= 200);
|
||||
|
||||
const int eff_off = cadEffectiveOffset();
|
||||
|
||||
n += snprintf(buf + n, cap > n ? cap - n : 0,
|
||||
"a:%s o:%d pk:%d(b%u/4s) sp:%u.%u/%u%%",
|
||||
_cad_auto ? "on" : "off", (int)_cad_offset,
|
||||
(int)base + _cad_offset, base,
|
||||
_has_radio_override ? "tmp" : (_cad_auto ? "on" : "off"),
|
||||
eff_off, (int)base + eff_off, base,
|
||||
spread_mean10 / 10U, spread_mean10 % 10U, degen_pct);
|
||||
if (room_for_count) {
|
||||
/* bursts(ok reads/busy reads/abandoned bursts/dc-blocked) — the
|
||||
@@ -2232,7 +2290,7 @@ int LoRaRadioBase::formatCadStatus(char *buf, int cap)
|
||||
* every rung printed is a real one and `pk` below is what the chip got. */
|
||||
const int lmin = cadLevelMinEff();
|
||||
const int lmax = cadLevelMaxEff();
|
||||
int cur = _cad_offset;
|
||||
int cur = eff_off;
|
||||
if (cur < lmin) cur = lmin;
|
||||
if (cur > lmax) cur = lmax;
|
||||
int lo = cur - 1, hi = cur + 1;
|
||||
|
||||
@@ -41,7 +41,17 @@ public:
|
||||
* _prefs. Used by tempradio so the saved prefs survive intact and
|
||||
* concurrent savePrefs() calls don't poison flash. clearRadioOverride()
|
||||
* reverts to whatever _prefs holds at that moment. */
|
||||
void setRadioOverride(float freq, float bw, uint8_t sf, uint8_t cr);
|
||||
/* visiting_new_preset = the override moves the radio onto a preset it
|
||||
* was not already running (`tempradio`), so the learned detPeak offset
|
||||
* does not apply there and the visit starts at that preset's own base.
|
||||
* Pass false when the override exists only to HOLD the radio on the
|
||||
* preset it is already running while _prefs move ahead of it
|
||||
* (freezeRadioParams, i.e. `set radio` / `set freq` + reboot): nothing
|
||||
* changed on air, so the offset that was learned for it keeps running
|
||||
* until the reboot re-reads prefs. Either way CAD adaptation is
|
||||
* suspended while the override is up — see cadMaintenance(). */
|
||||
void setRadioOverride(float freq, float bw, uint8_t sf, uint8_t cr,
|
||||
bool visiting_new_preset = true);
|
||||
void clearRadioOverride();
|
||||
bool hasRadioOverride() const { return _has_radio_override; }
|
||||
int recvRaw(uint8_t *bytes, int sz) override;
|
||||
@@ -388,6 +398,22 @@ protected:
|
||||
CadLevelStats _cad_stats[CAD_NUM_LEVELS];
|
||||
bool _cad_auto; /* staircase acts on the stats */
|
||||
int8_t _cad_offset; /* operating detPeak offset (levels) */
|
||||
/* The offset in force while a temporary radio override is active, i.e.
|
||||
* on a preset the node is only visiting (`tempradio`, and the frozen
|
||||
* old preset a `set radio` leaves running until reboot). detPeak's base
|
||||
* table is per-SF and per-bandwidth, so the offset learned for the
|
||||
* configured preset addresses a different ladder there — on the LR11xx
|
||||
* the SF7->SF12 base step alone is 16 counts. Kept separate rather than
|
||||
* saved-and-restored so _cad_offset never moves during the visit, which
|
||||
* is what keeps it out of prefs: Dispatcher::maintenanceLoop() persists
|
||||
* any change it sees in getCadOffset(). */
|
||||
int8_t _cad_temp_offset;
|
||||
/* The offset the chip is actually programmed with. Every hwCadSetPeakOffset()
|
||||
* goes through this; getCadOffset() deliberately does not, because that is
|
||||
* the value the app persists. */
|
||||
int8_t cadEffectiveOffset() const {
|
||||
return _has_radio_override ? _cad_temp_offset : _cad_offset;
|
||||
}
|
||||
uint16_t _probe_interval_s; /* 0 = CAD probing disabled; drives _measure_interval_ms */
|
||||
uint8_t _cad_busycap_pct; /* airtime cap: max % TX deferred (0 = off) */
|
||||
/* A CAD_RX probe awaiting its terminal event. _cad_pending_level is the
|
||||
|
||||
@@ -2809,13 +2809,21 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
|
||||
bw >= 7000 && bw <= 500000 &&
|
||||
sf >= 5 && sf <= 12 &&
|
||||
cr >= 5 && cr <= 8) {
|
||||
/* Coding rate is deliberately not in this test:
|
||||
* it changes airtime, not the channel or the
|
||||
* per-SF/per-bandwidth detPeak base, so it does
|
||||
* not invalidate the learned CAD offset. */
|
||||
bool preset_changed =
|
||||
prefs.freq != (float)freq / 1000.0f ||
|
||||
prefs.bw != (float)bw / 1000.0f ||
|
||||
prefs.sf != sf;
|
||||
prefs.freq = (float)freq / 1000.0f;
|
||||
prefs.bw = (float)bw / 1000.0f;
|
||||
prefs.sf = sf;
|
||||
prefs.cr = cr;
|
||||
prefs.client_repeat = repeat;
|
||||
_store->savePrefs(prefs);
|
||||
if (_radio_reconfig_cb) _radio_reconfig_cb();
|
||||
if (_radio_reconfig_cb) _radio_reconfig_cb(preset_changed);
|
||||
LOG_INF("SET_RADIO_PARAMS: client_repeat=%d", repeat);
|
||||
sendPacketOk();
|
||||
} else {
|
||||
@@ -2832,7 +2840,7 @@ bool CompanionMesh::handleProtocolFrame(const uint8_t *data, size_t len)
|
||||
if (power >= -9 && power <= MAX_LORA_TX_POWER) {
|
||||
prefs.tx_power_dbm = power;
|
||||
_store->savePrefs(prefs);
|
||||
if (_radio_reconfig_cb) _radio_reconfig_cb();
|
||||
if (_radio_reconfig_cb) _radio_reconfig_cb(false);
|
||||
sendPacketOk();
|
||||
} else {
|
||||
sendPacketError(ERR_ILLEGAL_ARG);
|
||||
|
||||
@@ -85,8 +85,10 @@ typedef size_t (*WriteFrameCallback)(const uint8_t *data, size_t len);
|
||||
/* Battery millivolt read callback */
|
||||
typedef uint16_t (*GetBatteryCallback)(void);
|
||||
|
||||
/* Radio reconfigure callback */
|
||||
typedef void (*RadioReconfigureCallback)(void);
|
||||
/* Radio reconfigure callback. preset_changed = the channel or the modem
|
||||
* config moved (freq/bw/sf), not just TX power — the adaptive-CAD state is
|
||||
* tied to those and has to be reset with them (see main_companion). */
|
||||
typedef void (*RadioReconfigureCallback)(bool preset_changed);
|
||||
|
||||
/* BLE PIN change callback */
|
||||
typedef void (*PinChangeCallback)(uint32_t new_pin);
|
||||
|
||||
@@ -1199,7 +1199,10 @@ void RepeaterMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint8_
|
||||
void RepeaterMesh::freezeRadioParams(float freq, float bw, uint8_t sf, uint8_t cr) {
|
||||
auto& radio = getRadioDriver(_radio);
|
||||
if (!radio.hasRadioOverride()) {
|
||||
radio.setRadioOverride(freq, bw, sf, cr);
|
||||
/* Holds the radio on the preset it is ALREADY running while _prefs
|
||||
* move ahead of it, so the learned CAD offset still applies — see
|
||||
* setRadioOverride(). */
|
||||
radio.setRadioOverride(freq, bw, sf, cr, /*visiting_new_preset=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -903,7 +903,10 @@ void RoomServerMesh::applyTempRadioParams(float freq, float bw, uint8_t sf, uint
|
||||
void RoomServerMesh::freezeRadioParams(float freq, float bw, uint8_t sf, uint8_t cr) {
|
||||
auto& radio = getRadioDriver(_radio);
|
||||
if (!radio.hasRadioOverride()) {
|
||||
radio.setRadioOverride(freq, bw, sf, cr);
|
||||
/* Holds the radio on the preset it is ALREADY running while _prefs
|
||||
* move ahead of it, so the learned CAD offset still applies — see
|
||||
* setRadioOverride(). */
|
||||
radio.setRadioOverride(freq, bw, sf, cr, /*visiting_new_preset=*/false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,41 @@ void CommonCLI::savePrefs() {
|
||||
_callbacks->savePrefs();
|
||||
}
|
||||
|
||||
/* Drop everything the adaptive-CAD controller has learned.
|
||||
*
|
||||
* Called both by `set cad.reset` and by every command that moves the radio to a
|
||||
* different preset, because such a change invalidates all three pieces at once:
|
||||
* detPeak's base table is per-SF and per-bandwidth, so the ladder the offset
|
||||
* addresses is re-based under it (SF7->SF12 is 5 counts on SX126x and 16 on the
|
||||
* LR11xx), and the per-level statistics that justified the offset describe a
|
||||
* preset that is no longer on air. Re-converging from the new preset's own
|
||||
* base costs an hour or two; carrying a stale offset across can leave the node
|
||||
* either transmitting over live receptions or unable to transmit at all.
|
||||
*
|
||||
* The operating offset lives in two places — _prefs->cad_offset, and _cad_offset
|
||||
* inside the radio, which applyCadPrefs() reloads through setCadParams().
|
||||
*
|
||||
* preset_pending = the caller has already written the NEW freq/bw/sf/cr to
|
||||
* _prefs but the radio is still running the OLD preset (frozen by
|
||||
* freezeRadioParams until the reboot the caller is about to ask for).
|
||||
* applyCadPrefs() stamps cad_base from the RUNNING radio, i.e. the preset being
|
||||
* left, so that stamp has to be cleared again afterwards: a stale anchor in
|
||||
* flash is precisely what makes setCadParams() re-anchor a freshly reset offset
|
||||
* by (old_base - new_base) on the next boot, which is the bug this reset
|
||||
* exists to avoid. 0 means "no anchor recorded", which that re-anchor
|
||||
* deliberately treats as a no-op, and the next boot re-stamps it.
|
||||
*/
|
||||
void CommonCLI::resetCadState(bool preset_pending) {
|
||||
_prefs->cad_offset = cliDefaults()->cad_offset;
|
||||
_prefs->cad_base = 0;
|
||||
_callbacks->resetCadStats();
|
||||
_callbacks->applyCadPrefs();
|
||||
if (preset_pending) {
|
||||
_prefs->cad_base = 0;
|
||||
}
|
||||
savePrefs();
|
||||
}
|
||||
|
||||
uint8_t CommonCLI::buildAdvertData(uint8_t node_type, uint8_t* app_data) {
|
||||
if (_prefs->advert_loc_policy == ADVERT_LOC_NONE) {
|
||||
AdvertDataBuilder builder(node_type, _prefs->node_name);
|
||||
@@ -851,19 +886,12 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
* FROM wherever the staircase had already walked detPeak, with no
|
||||
* evidence left to justify sitting there — the opposite of a reset,
|
||||
* and useless for the one job this command has (recovering after a
|
||||
* base-table change). The operating offset lives in two places:
|
||||
* _prefs->cad_offset, and _cad_offset inside the radio, which
|
||||
* applyCadPrefs() reloads through setCadParams(). */
|
||||
_prefs->cad_offset = cliDefaults()->cad_offset;
|
||||
/* Clear the recorded base too. applyCadPrefs() below re-stamps it
|
||||
* from the radio, so a reset always leaves offset and base
|
||||
* describing the same configuration -- leaving a stale base here
|
||||
* would make the NEXT base-table change re-anchor a freshly reset
|
||||
* offset away from zero. */
|
||||
_prefs->cad_base = 0;
|
||||
_callbacks->resetCadStats();
|
||||
_callbacks->applyCadPrefs();
|
||||
savePrefs();
|
||||
* base-table change).
|
||||
*
|
||||
* preset_pending = false: the radio is running the preset this
|
||||
* reset is for, so the base applyCadPrefs() stamps is the right
|
||||
* one to keep. */
|
||||
resetCadState(false);
|
||||
snprintf(reply, CLI_REPLY_SIZE,
|
||||
"OK - CAD probe stats cleared, detPeak offset reset to %d",
|
||||
(int)_prefs->cad_offset);
|
||||
@@ -1006,7 +1034,17 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
_prefs->cr = cr;
|
||||
_callbacks->savePrefs();
|
||||
_callbacks->freezeRadioParams(old_freq, old_bw, old_sf, old_cr);
|
||||
strcpy(reply, "OK - reboot to apply");
|
||||
/* Anything that moves the channel or the detPeak base table
|
||||
* invalidates the learned CAD offset and every statistic
|
||||
* behind it — see resetCadState(). Coding rate does neither
|
||||
* (it changes airtime, not the threshold or the band), so a
|
||||
* cr-only edit keeps a converged offset. */
|
||||
if (freq != old_freq || bw != old_bw || sf != old_sf) {
|
||||
resetCadState(true);
|
||||
strcpy(reply, "OK - reboot to apply (CAD reset)");
|
||||
} else {
|
||||
strcpy(reply, "OK - reboot to apply");
|
||||
}
|
||||
} else {
|
||||
strcpy(reply, "Error: freq 150-2500, bw 7-500, sf 5-12, cr 5-8, or default");
|
||||
}
|
||||
@@ -1163,7 +1201,14 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
|
||||
* back; freeze the running radio on the old freq until reboot,
|
||||
* mirroring the "set radio" handler above. */
|
||||
_callbacks->freezeRadioParams(old_freq, _prefs->bw, _prefs->sf, _prefs->cr);
|
||||
strcpy(reply, "OK - reboot to apply");
|
||||
/* New channel, new interference: the offset and the statistics
|
||||
* behind it were learned somewhere else. See resetCadState(). */
|
||||
if (f != old_freq) {
|
||||
resetCadState(true);
|
||||
strcpy(reply, "OK - reboot to apply (CAD reset)");
|
||||
} else {
|
||||
strcpy(reply, "OK - reboot to apply");
|
||||
}
|
||||
} else {
|
||||
strcpy(reply, "Error: range 150-2500 MHz, or default");
|
||||
}
|
||||
|
||||
@@ -149,4 +149,11 @@ public:
|
||||
|
||||
void handleCommand(uint32_t sender_timestamp, const char* command, char* reply);
|
||||
uint8_t buildAdvertData(uint8_t node_type, uint8_t* app_data);
|
||||
|
||||
/* Full adaptive-CAD reset: the learned detPeak offset, the probe statistics
|
||||
* that justified it, and the recorded base anchor, all dropped together.
|
||||
* Public so the companion's app-driven radio change (CMD_SET_RADIO_PARAMS,
|
||||
* which applies live rather than at reboot) can reach the same code path
|
||||
* instead of open-coding it. See the definition for `preset_pending`. */
|
||||
void resetCadState(bool preset_pending);
|
||||
};
|
||||
@@ -673,11 +673,6 @@ static uint16_t get_battery_mv(void)
|
||||
return zephyr_board.getBattMilliVolts();
|
||||
}
|
||||
|
||||
static void radio_reconfigure(void)
|
||||
{
|
||||
lora_radio.reconfigure();
|
||||
}
|
||||
|
||||
static mesh::ZephyrMillisecondClock ms_clock;
|
||||
static mesh::ZephyrRNG zephyr_rng;
|
||||
static mesh::SimpleMeshTables mesh_tables;
|
||||
@@ -886,6 +881,24 @@ static ClientACL companion_acl; /* unused by CommonCLI but required by construc
|
||||
static CommonCLI companion_cli(zephyr_board, rtc_clock, companion_acl,
|
||||
&companion_mesh.prefs, &companion_cli_cbs);
|
||||
|
||||
/* Radio reconfigure, reached from the app protocol (CMD_SET_RADIO_PARAMS /
|
||||
* CMD_SET_RADIO_TX_POWER). Defined here rather than up with the other radio
|
||||
* callbacks because it needs companion_cli, which needs the mesh and the
|
||||
* datastore — same reason save_prefs_to_flash() sits below them.
|
||||
*
|
||||
* Unlike the CLI's `set radio`, this path applies LIVE: there is no reboot and
|
||||
* no frozen old preset, so by the time the CAD reset runs the radio is already
|
||||
* on the new one and the base it stamps is the right one to keep — hence
|
||||
* preset_pending = false. */
|
||||
static void radio_reconfigure(bool preset_changed)
|
||||
{
|
||||
lora_radio.reconfigure();
|
||||
|
||||
if (preset_changed) {
|
||||
companion_cli.resetCadState(false);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ZEPHCORE_AUTO_SHUTDOWN_MILLIVOLTS) && \
|
||||
CONFIG_ZEPHCORE_AUTO_SHUTDOWN_MILLIVOLTS > 0
|
||||
#define ZEPHCORE_HAS_AUTO_SHUTDOWN 1
|
||||
|
||||
Reference in new issue
Block a user