Correct Morse human spacing and harden speed qualification
Run Unit Tests / nrf52-companion-smoke (push) Canceled after 0s
Run Unit Tests / nrf52-sensor-smoke (push) Canceled after 0s
Run Unit Tests / esp32-sensor-smoke (push) Canceled after 0s
Run Unit Tests / management-reports (push) Canceled after 0s
Run Unit Tests / stm32-companion-smoke (push) Canceled after 0s
Run Unit Tests / bootloader-version (push) Canceled after 0s
Run Unit Tests / test (push) Canceled after 0s
Run Unit Tests / hosted-doc-links (push) Canceled after 0s
Build and deploy Docs site to GitHub Pages / github-pages (push) Canceled after 0s
Run Unit Tests / nrf52-companion-smoke (push) Canceled after 0s
Run Unit Tests / nrf52-sensor-smoke (push) Canceled after 0s
Run Unit Tests / esp32-sensor-smoke (push) Canceled after 0s
Run Unit Tests / management-reports (push) Canceled after 0s
Run Unit Tests / stm32-companion-smoke (push) Canceled after 0s
Run Unit Tests / bootloader-version (push) Canceled after 0s
Run Unit Tests / test (push) Canceled after 0s
Run Unit Tests / hosted-doc-links (push) Canceled after 0s
Build and deploy Docs site to GitHub Pages / github-pages (push) Canceled after 0s
This commit is contained in:
1 parent
378925638b
commit
af08c02a00
23 files changed
+1194
-34
No files matched your search
+36
-1
@@ -209,10 +209,11 @@ inline bool handleMorseCommand(Radio* radio, const char* command,
|
||||
const bool speed = length == 9 && !strncmp(key, "morse.wpm", 9);
|
||||
#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
|
||||
const bool hil_timing = length == 16 && !strncmp(key, "morse.hil.timing", 16);
|
||||
const bool hil_squelch = length == 17 && !strncmp(key, "morse.hil.squelch", 17);
|
||||
#endif
|
||||
if (!base && !frequency && !speed
|
||||
#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
|
||||
&& !hil_timing
|
||||
&& !hil_timing && !hil_squelch
|
||||
#endif
|
||||
) return false;
|
||||
if (!radio || (!radio->supportsMorseTx()
|
||||
@@ -225,6 +226,40 @@ inline bool handleMorseCommand(Radio* radio, const char* command,
|
||||
}
|
||||
const char* args = cli::skipRecentRepeaterSpaces(key + length);
|
||||
#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
|
||||
if (hil_squelch) {
|
||||
#if MESH_ENABLE_MORSE_RX
|
||||
if (!radio->supportsMorseRx()) {
|
||||
snprintf(reply, capacity, "Error: Morse RX unsupported on this radio");
|
||||
return true;
|
||||
}
|
||||
if (query) {
|
||||
if (*args) snprintf(reply, capacity, "Error: unexpected argument");
|
||||
else if (isnan(morseHilSquelch())) snprintf(reply, capacity, "> auto; volatile HIL RX only");
|
||||
else snprintf(reply, capacity, "> %.3f dBm; volatile HIL RX only", morseHilSquelch());
|
||||
return true;
|
||||
}
|
||||
if (!setting) {
|
||||
snprintf(reply, capacity, "Error: use get/set morse.hil.squelch auto|-160..0");
|
||||
return true;
|
||||
}
|
||||
if (radio->isCarrierWaveActive() || radio->isMorseTxActive() || radio->isMorseRxActive()
|
||||
|| !radio->isInRecvMode() || radio->isReceiving()) {
|
||||
snprintf(reply, capacity, "Error: radio busy; HIL squelch changes require idle RX");
|
||||
return true;
|
||||
}
|
||||
float value = NAN;
|
||||
if ((strcmp(args, "auto") && (!cli::parseDecimalStrict(args, value)
|
||||
|| !isfinite(value))) || !setMorseHilSquelch(value)) {
|
||||
snprintf(reply, capacity, "Error: use morse.hil.squelch auto or -160..0 dBm");
|
||||
return true;
|
||||
}
|
||||
if (isnan(value)) snprintf(reply, capacity, "OK - HIL Morse squelch auto; volatile RX only");
|
||||
else snprintf(reply, capacity, "OK - HIL Morse squelch %.3f dBm; volatile RX only", value);
|
||||
#else
|
||||
snprintf(reply, capacity, "Error: Morse RX unsupported on this radio");
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
if (hil_timing) {
|
||||
if (query) {
|
||||
if (*args) snprintf(reply, capacity, "Error: unexpected argument");
|
||||
|
||||
+36
-5
@@ -23,6 +23,22 @@
|
||||
|
||||
namespace mesh {
|
||||
|
||||
#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
|
||||
// Volatile bench squelch, not a saved setting or a production noise model.
|
||||
// AUTO retains the complete adaptive detector; a finite floor lets controlled
|
||||
// RF tests reject measured quiet-envelope excursions before they become keys.
|
||||
inline float& morseHilSquelchStorage() {
|
||||
static float value = NAN;
|
||||
return value;
|
||||
}
|
||||
inline float morseHilSquelch() { return morseHilSquelchStorage(); }
|
||||
inline bool setMorseHilSquelch(float value) {
|
||||
if (!isnan(value) && (!isfinite(value) || value < -160.0f || value > 0.0f)) return false;
|
||||
morseHilSquelchStorage() = value;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
enum class MorseRxResult : uint8_t {
|
||||
Started, Stopped, Busy, Unsupported, InvalidFrequency, Overlap,
|
||||
InvalidSpeed, InvalidDuration, Failed
|
||||
@@ -129,6 +145,10 @@ public:
|
||||
#endif
|
||||
static_assert(ReceiverBitRateKbps >= 0.6f && ReceiverBitRateKbps <= 300.0f,
|
||||
"HIL GFSK receiver clock must remain in the supported range");
|
||||
#if defined(MESH_MORSE_HIL_PRODUCTION_RF) && MESH_MORSE_HIL_PRODUCTION_RF
|
||||
static_assert(ReceiverBitRateKbps == 1.2f,
|
||||
"Production-equivalent HIL requires the shipping Morse receiver clock");
|
||||
#endif
|
||||
static constexpr uint32_t MinDurationMillis = 1000UL;
|
||||
static constexpr uint32_t MaxDurationMillis = 300000UL;
|
||||
static constexpr uint32_t NoiseLearningMillis = 500UL;
|
||||
@@ -267,6 +287,16 @@ public:
|
||||
if (provisional_fall < 5.0f) provisional_fall = 5.0f;
|
||||
if (threshold < _signal - provisional_fall) threshold = _signal - provisional_fall;
|
||||
}
|
||||
#if defined(MESH_MORSE_HIL) && MESH_MORSE_HIL
|
||||
const float squelch = morseHilSquelch();
|
||||
if (isfinite(squelch)) {
|
||||
// Bound both edges with the same three-dB hysteresis. This prevents a
|
||||
// quiet pre-key from absorbing the following real dot; nothing is
|
||||
// removed from, or rewritten in, the decoded transcript afterwards.
|
||||
const float floor = squelch - (_keyed ? 3.0f : 0.0f);
|
||||
if (threshold < floor) threshold = floor;
|
||||
}
|
||||
#endif
|
||||
const bool raw_keyed = rssi_dbm >= threshold;
|
||||
if (!_keyed && !raw_keyed && !_candidate_valid) {
|
||||
// Drift slowly while quiet; follow a lower floor faster without letting
|
||||
@@ -402,12 +432,13 @@ private:
|
||||
// longer physical gaps and remain distinguishable at the nominal timing.
|
||||
const uint16_t nominal_q5 = uint16_t(uint32_t(_nominal_unit) * UnitScale);
|
||||
const uint16_t gap_unit_q5 = _unit_q5 < nominal_q5 ? _unit_q5 : nominal_q5;
|
||||
// Ordinary +/-20% gap jitter still separates an intra-letter gap (<=1.2
|
||||
// units) from a letter gap (>=2.4), and letters (<=3.6) from words (>=5.6).
|
||||
// Keep some margin at 2.25/5.5 units rather than merging shortened gaps.
|
||||
// Use the ordinary 1/3 and 3/7 gap midpoints. +/-20% human jitter leaves
|
||||
// intra-letter gaps <=1.2, letter gaps >=2.4/<=3.6 and word gaps >=5.6.
|
||||
// The 2/5 boundaries also leave room for a biased RF falling edge to
|
||||
// shorten a gap; 2.25/5.5 merged measured ordinary human-timing words.
|
||||
// This is not automatic Farnsworth-spacing or unknown-speed acquisition.
|
||||
if (gap * 4UL * UnitScale >= uint32_t(gap_unit_q5) * 9UL && !_letter_flushed) flushLetter();
|
||||
if (gap * 2UL * UnitScale >= uint32_t(gap_unit_q5) * 11UL && !_word_flushed && _letter_flushed) {
|
||||
if (gap * UnitScale >= uint32_t(gap_unit_q5) * 2UL && !_letter_flushed) flushLetter();
|
||||
if (gap * UnitScale >= uint32_t(gap_unit_q5) * 5UL && !_word_flushed && _letter_flushed) {
|
||||
append(' ');
|
||||
_word_flushed = true;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,19 @@ namespace mesh {
|
||||
static_assert(MESH_MORSE_MAX_WPM >= 1 && MESH_MORSE_MAX_WPM <= 255,
|
||||
"Morse WPM must fit the command/API byte");
|
||||
|
||||
#if defined(MESH_MORSE_HIL_PRODUCTION_RF) && MESH_MORSE_HIL_PRODUCTION_RF
|
||||
// Compile-time evidence that a production-equivalent RF comparison did not
|
||||
// accidentally inherit the faster bench tuple through PlatformIO's flags.
|
||||
#if !defined(MESH_MORSE_HIL) || !MESH_MORSE_HIL \
|
||||
|| MESH_MORSE_HIL_WARM_TX != 0 || MESH_MORSE_HIL_RSSI_WINDOW != 0 \
|
||||
|| MESH_MORSE_HIL_PA_RAMP_US != 3400 \
|
||||
|| MESH_MORSE_HIL_SAMPLE_INTERVAL_MS != 2 \
|
||||
|| MESH_MORSE_HIL_FAST_OFF_DEBOUNCE != 0 \
|
||||
|| MESH_MORSE_HIL_PACKET_GATING != 0
|
||||
#error "Production-equivalent HIL requires the shipping Morse RF settings"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum class MorseTxResult : uint8_t {
|
||||
Started, Stopped, Busy, Unsupported, InvalidFrequency, Overlap,
|
||||
InvalidText, InvalidSpeed, TooLong, Failed
|
||||
|
||||
Reference in new issue
Block a user