Validate beacon power without stranding saved settings
This commit is contained in:
1 parent
adbeb2d007
commit
d5cc73c43d
15 files changed
+662
-7
No files matched your search
@@ -94,6 +94,9 @@ public:
|
||||
virtual bool supportsMeshtext() const { return false; }
|
||||
virtual bool supportsEthernetTunnel() const { return false; }
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
// Check the requested antenna power at the prospective beacon frequency.
|
||||
// Validation must not retune the radio or alter its current power setting.
|
||||
virtual bool validateBeaconPower(float, int8_t) const { return false; }
|
||||
virtual RadioParamApplyResult prepareBeaconTransmit(const RadioProfileParams&, int8_t) {
|
||||
return RadioParamApplyResult::FAILED;
|
||||
}
|
||||
|
||||
+1
-2
@@ -3,7 +3,6 @@
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
|
||||
#include <helpers/BeaconFrames.h>
|
||||
#include <helpers/radiolib/RadioPowerLimits.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace mesh {
|
||||
@@ -12,7 +11,7 @@ bool Mesh::validateTextBeacon(const BeaconSlot& slot) const {
|
||||
if (!beacon::validText(slot.text) || slot.hops > 7
|
||||
|| !RadioProfiles::valid(slot.radio)
|
||||
|| !RadioProfiles::safePreamble(slot.radio, slot.radio.preamble ? slot.radio.preamble : 32)
|
||||
|| slot.power < -9 || !isLoRaTxPowerValid(slot.power, slot.radio.freq)
|
||||
|| !_radio->validateBeaconPower(slot.radio.freq, slot.power)
|
||||
|| !_radio->validateProfile(slot.radio)) return false;
|
||||
if (slot.radio.protocol == RadioProfileProtocol::MeshCore) return true;
|
||||
#if MESH_ENABLE_MESHTEXT_WIRE
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <Mesh.h>
|
||||
#include <helpers/FilePresence.h>
|
||||
#include <helpers/MeshtextChat.h>
|
||||
#include <helpers/UTF8Helpers.h>
|
||||
#include <Arduino.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
@@ -75,12 +76,15 @@ bool decodeSlot(const uint8_t bytes[RecordSize], BeaconSlot& slot) {
|
||||
slot.power = int8_t(bytes[13]); slot.preset = bytes[14]; slot.hops = bytes[15];
|
||||
slot.enabled = true;
|
||||
memcpy(slot.text, bytes + 17, BeaconSlot::TextCapacity);
|
||||
const size_t text_length = strlen(slot.text);
|
||||
// Reject noncanonical trailing data instead of carrying hidden text bytes.
|
||||
for (size_t i = strlen(slot.text) + 1; i < BeaconSlot::TextCapacity; ++i)
|
||||
for (size_t i = text_length + 1; i < BeaconSlot::TextCapacity; ++i)
|
||||
if (slot.text[i]) return false;
|
||||
for (const unsigned char* c = reinterpret_cast<const unsigned char*>(slot.text); *c; ++c)
|
||||
if (*c < 32 || *c == 127) return false;
|
||||
return isfinite(slot.radio.freq) && isfinite(slot.radio.bw)
|
||||
return validUtf8PrefixLength(slot.text, text_length) == text_length
|
||||
&& RadioProfiles::valid(slot.radio)
|
||||
&& RadioProfiles::safePreamble(slot.radio, slot.radio.preamble ? slot.radio.preamble : 32)
|
||||
&& (slot.radio.protocol != RadioProfileProtocol::Meshtext
|
||||
|| (slot.preset <= uint8_t(mt::Preset::LongSlow) && slot.radio.preamble == 16));
|
||||
}
|
||||
@@ -218,7 +222,9 @@ BeaconManager::ReadResult BeaconManager::readConfig(
|
||||
}
|
||||
crc = crcUpdate(crc, bytes, sizeof(bytes));
|
||||
BeaconSlot slot;
|
||||
if (!decodeSlot(bytes, slot) || (slot.enabled && (!mesh_ || !mesh_->validateTextBeacon(slot)))
|
||||
// Disk validity is independent of the current board's radio capabilities.
|
||||
// Preserve unsupported slots so an upgrade can still query/repair them.
|
||||
if (!decodeSlot(bytes, slot)
|
||||
|| (slot.enabled && slot.radio.protocol == RadioProfileProtocol::Meshtext && !header[6]))
|
||||
valid = false;
|
||||
if (output) output[i] = slot;
|
||||
@@ -403,7 +409,9 @@ void BeaconManager::loop(uint32_t now) {
|
||||
if (hour > 0 && handled_hour_ != hour) {
|
||||
const unsigned index = unsigned((hour - 1) % SlotCount);
|
||||
BeaconSlot& slot = slots_[index];
|
||||
if (!slot.enabled) handled_hour_ = hour;
|
||||
// A retained slot may be unsupported by this board or firmware. Skip it
|
||||
// before allocating a durable Meshtext packet ID or entering the TX queue.
|
||||
if (!slot.enabled || !mesh_->validateTextBeacon(slot)) handled_hour_ = hour;
|
||||
else {
|
||||
uint64_t guard = last_send_ && elapsed_ - last_send_ < HourMillis
|
||||
? HourMillis - (elapsed_ - last_send_) : 0;
|
||||
|
||||
@@ -139,6 +139,12 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
bool checkBeaconOutputPower(float frequency_mhz, int8_t dbm) const override {
|
||||
(void)frequency_mhz;
|
||||
return dbm >= _min_dbm && dbm <= _max_dbm;
|
||||
}
|
||||
#endif
|
||||
// Emit a gain-control code. Override for a PA driven by PWM or an external
|
||||
// DAC instead of the MCU's own.
|
||||
virtual void writeGainControl(uint8_t code) {
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "RadioLibWrappers.h"
|
||||
#include "RadioInterruptEvents.h"
|
||||
#include "RadioProfileChip.h"
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
#include "RadioPowerLimits.h"
|
||||
#endif
|
||||
#include <new>
|
||||
#if defined(ESP32_PLATFORM)
|
||||
#include <esp_heap_caps.h>
|
||||
@@ -559,6 +562,39 @@ mesh::RadioParamApplyResult RadioLibWrapper::tuneProfile(uint8_t profile) {
|
||||
}
|
||||
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
bool RadioLibWrapper::validateBeaconPower(float frequency_mhz, int8_t power) const {
|
||||
return isfinite(frequency_mhz) && mesh::isLoRaTxPowerValid(power, frequency_mhz)
|
||||
&& checkBeaconOutputPower(frequency_mhz, power);
|
||||
}
|
||||
|
||||
bool RadioLibWrapper::checkBeaconOutputPower(float frequency_mhz, int8_t power) const {
|
||||
(void)frequency_mhz;
|
||||
#if MESH_RADIO_PROFILE_CHIP == 1276
|
||||
// SX127x's setter automatically selects RFO below 2 dBm. Its two-argument
|
||||
// checker assumes PA_BOOST, so use the same selection as setOutputPower().
|
||||
return static_cast<SX1276*>(_radio)->checkOutputPower(power, nullptr, power < 2)
|
||||
== RADIOLIB_ERR_NONE;
|
||||
#elif MESH_RADIO_PROFILE_CHIP == 1272
|
||||
return static_cast<SX1272*>(_radio)->checkOutputPower(power, nullptr, power < 2)
|
||||
== RADIOLIB_ERR_NONE;
|
||||
#elif MESH_RADIO_PROFILE_CHIP == 1121
|
||||
// RadioLib's checker uses its current band. Validate the prospective band
|
||||
// without changing the cached frequency or triggering a hardware retune.
|
||||
if (frequency_mhz > 1000.0f) return power >= -18 && power <= 13;
|
||||
#ifdef LR1121_FORCE_HP_PA
|
||||
return power >= -9 && power <= 22;
|
||||
#else
|
||||
return power >= -17 && power <= 22;
|
||||
#endif
|
||||
#elif MESH_RADIO_PROFILE_CHIP == 2021
|
||||
return mesh::lr2021::isHighBand(frequency_mhz)
|
||||
? power >= -19 && power <= 12 : power >= -9 && power <= 22;
|
||||
#else
|
||||
// These RadioLib checkers inspect configuration only; no SPI is performed.
|
||||
return _radio->checkOutputPower(power, nullptr) == RADIOLIB_ERR_NONE;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t RadioLibWrapper::getBeaconAirtime(const mesh::RadioProfileParams& p, int length) {
|
||||
if (length <= 0 || length > MAX_TRANS_UNIT || !validateProfile(p)) return 0;
|
||||
const uint16_t preamble = p.protocol == mesh::RadioProfileProtocol::Meshtext
|
||||
@@ -596,7 +632,8 @@ mesh::RadioParamApplyResult RadioLibWrapper::prepareBeaconTransmit(
|
||||
_hil_beacon_tx_frequency_mhz = 0;
|
||||
if (!mesh::hilTransmitFrequencyAllowed(p.freq)) return Result::FAILED;
|
||||
#endif
|
||||
if (!_params_valid || !_dbm_valid || !getBeaconAirtime(p, MAX_TRANS_UNIT)) return Result::FAILED;
|
||||
if (!_params_valid || !_dbm_valid || !getBeaconAirtime(p, MAX_TRANS_UNIT)
|
||||
|| !validateBeaconPower(p.freq, power)) return Result::FAILED;
|
||||
if (isCalibratingNoiseFloor()) return Result::BUSY;
|
||||
|
||||
beginProfileRetune(isInRecvMode() && !_rx_ps_armed && !_rx_ps_enabled);
|
||||
|
||||
@@ -272,6 +272,11 @@ protected:
|
||||
virtual int16_t applyCachedTxPower(int8_t dbm) {
|
||||
return _radio->setOutputPower(dbm);
|
||||
}
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
// External amplifiers override this in antenna dBm. The public capability
|
||||
// still checks the board's explicit limits before consulting this hook.
|
||||
virtual bool checkBeaconOutputPower(float frequency_mhz, int8_t dbm) const;
|
||||
#endif
|
||||
virtual bool applyRxBoostedGainMode(bool) { return false; }
|
||||
virtual int16_t enterCarrierWave() { return _radio->transmitDirect(); }
|
||||
virtual bool validateMorseFrequency(float frequency_mhz) const {
|
||||
@@ -409,6 +414,7 @@ public:
|
||||
mesh::RadioParamApplyResult prepareTransmitProfile(uint8_t profile) override;
|
||||
mesh::RadioParamApplyResult prepareTransmitProfile(uint8_t profile, bool reply_rx_override) override;
|
||||
#if MESH_ENABLE_TX_BEACONS
|
||||
bool validateBeaconPower(float frequency_mhz, int8_t power) const override;
|
||||
mesh::RadioParamApplyResult prepareBeaconTransmit(const mesh::RadioProfileParams& params,
|
||||
int8_t power) override;
|
||||
mesh::RadioParamApplyResult restoreBeaconReceive() override;
|
||||
|
||||
Reference in new issue
Block a user