Files
MeshCore/src/helpers/MorseSettings.h
T
mikecarper ca9caece53 Add bounded Morse receive and negotiated RS232 autosleep
Add native narrow-band CW capture, ACK-first remote sessions, retained LoRa-readable pages, checked restoration and transport-safe progress. Add stock-compatible negotiated heartbeat/autosleep and recovery. Include host regressions and identity-bound HIL runners; keep unverified faster tuning HIL-only and document outstanding hardware validation.
2026-10-13 01:24:39 -07:00

76 lines
2.6 KiB
C++

#pragma once
#include <helpers/IdentityStore.h>
#include <helpers/MorseTx.h>
#include <stddef.h>
#include <stdint.h>
namespace mesh {
struct MorseSettings {
// A distinct TX-only channel. Neither packet-radio profile is modified.
uint32_t frequency_khz = 902100;
uint8_t wpm = MorseTx::DefaultWpm;
float frequencyMHz() const { return float(frequency_khz) / 1000.0f; }
};
constexpr uint32_t MorseMinFrequencyKHz = 100000;
constexpr uint32_t MorseMaxFrequencyKHz = 1000000;
constexpr uint8_t MorseMinWpm = MorseTx::MinWpm;
constexpr uint8_t MorseMaxWpm = MorseTx::MaxWpm;
constexpr size_t MorseSettingsImageSize = 12;
inline bool validMorseSettings(const MorseSettings& prefs) {
return prefs.frequency_khz >= MorseMinFrequencyKHz
&& prefs.frequency_khz <= MorseMaxFrequencyKHz
&& prefs.wpm >= MorseMinWpm && prefs.wpm <= MorseMaxWpm;
}
inline uint32_t morseSettingsCRC(const uint8_t* data, size_t size) {
uint32_t crc = 0xffffffffUL;
while (size--) {
crc ^= *data++;
for (uint8_t bit = 0; bit < 8; ++bit)
crc = (crc >> 1) ^ ((crc & 1U) ? 0xedb88320UL : 0);
}
return crc;
}
inline void encodeMorseSettings(const MorseSettings& prefs,
uint8_t (&image)[MorseSettingsImageSize]) {
image[0] = 'M'; image[1] = 'C'; image[2] = 1; image[3] = prefs.wpm;
for (unsigned i = 0; i < 4; ++i)
image[4 + i] = uint8_t(prefs.frequency_khz >> (i * 8));
const uint32_t crc = morseSettingsCRC(image, 8);
for (unsigned i = 0; i < 4; ++i) image[8 + i] = uint8_t(crc >> (i * 8));
}
inline bool decodeMorseSettings(const uint8_t* image, size_t size,
MorseSettings& prefs) {
if (!image || size != MorseSettingsImageSize || image[0] != 'M'
|| image[1] != 'C' || image[2] != 1) return false;
uint32_t frequency = 0, crc = 0;
for (unsigned i = 0; i < 4; ++i) {
frequency |= uint32_t(image[4 + i]) << (i * 8);
crc |= uint32_t(image[8 + i]) << (i * 8);
}
MorseSettings candidate;
candidate.frequency_khz = frequency;
candidate.wpm = image[3];
if (crc != morseSettingsCRC(image, 8) || !validMorseSettings(candidate))
return false;
prefs = candidate;
return true;
}
// Independent checked storage leaves legacy node/Companion layouts intact.
// Defaults and saved settings never begin transmitting automatically.
bool loadMorseSettings(FILESYSTEM* fs);
const MorseSettings& morseSettings();
// A missing fresh store is ready with defaults. Unreadable/corrupt saved
// frequency must not silently become the default transmit frequency.
bool morseSettingsUsable();
bool saveMorseSettings(const MorseSettings& candidate);
} // namespace mesh