[fix](trx-wefax): add phasing timeout fallback to receiving
PhasingDetector is strict (needs 10 phasing lines with low pulse- position variance). On real-world signals with noise, tuning error, or non-standard phasing, it can fail to converge — leaving the state machine wedged in Phasing forever after a successful APT start detection. Add a ~30 s timeout: if phasing alignment doesn't lock after PHASING_TIMEOUT_LINES worth of samples, fall through to Receiving with phase_offset=0 and verified=false. The correlation verifier then decides whether the content is real imagery (commit, eventually save) or not (drop, back to Idle). The image will be horizontally misaligned since we never locked phase, but it's better than a stuck state that produces nothing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -58,6 +58,13 @@ const VERIFY_HIGH_CORR_STREAK: u32 = 5;
|
||||
/// to Idle without saving anything.
|
||||
const VERIFY_TIMEOUT_LINES: u32 = 40;
|
||||
|
||||
/// Maximum number of scan-line-equivalent sample windows to wait for phasing
|
||||
/// lock before falling through to Receiving (unverified). Typical WEFAX
|
||||
/// phasing lasts ~30 s; if the phasing detector hasn't converged by then
|
||||
/// we give up on alignment and let the correlation verifier decide whether
|
||||
/// the content that follows is a real image. At 120 LPM this is ~30 s.
|
||||
const PHASING_TIMEOUT_LINES: u32 = 60;
|
||||
|
||||
/// WEFAX decoder output event.
|
||||
#[derive(Debug)]
|
||||
pub enum WefaxEvent {
|
||||
@@ -118,6 +125,11 @@ pub struct WefaxDecoder {
|
||||
/// Rolling count of consecutive well-correlated lines, used to confirm
|
||||
/// an unverified reception.
|
||||
high_corr_streak: u32,
|
||||
/// Number of luminance samples processed while in `State::Phasing`.
|
||||
/// When this exceeds the equivalent of `PHASING_TIMEOUT_LINES` lines,
|
||||
/// the decoder falls through to Receiving (unverified) so a noisy or
|
||||
/// partial phasing signal doesn't wedge the state machine.
|
||||
phasing_samples: u64,
|
||||
/// Current rig dial frequency in Hz (for image filenames).
|
||||
freq_hz: u64,
|
||||
/// Current rig mode name (for image filenames).
|
||||
@@ -147,6 +159,7 @@ impl WefaxDecoder {
|
||||
low_corr_lines: 0,
|
||||
verified: false,
|
||||
high_corr_streak: 0,
|
||||
phasing_samples: 0,
|
||||
freq_hz: 0,
|
||||
mode: String::new(),
|
||||
}
|
||||
@@ -285,6 +298,20 @@ impl WefaxDecoder {
|
||||
if let Some(ref mut phasing) = self.phasing {
|
||||
if let Some(offset) = phasing.process(&luminance) {
|
||||
events.push(self.transition_to_receiving(ioc, lpm, offset, true));
|
||||
} else {
|
||||
// Phasing timeout: if alignment doesn't converge in
|
||||
// ~PHASING_TIMEOUT_LINES lines, fall through to
|
||||
// Receiving (unverified) and let the correlation
|
||||
// verifier decide.
|
||||
self.phasing_samples += luminance.len() as u64;
|
||||
let spl = WefaxConfig::samples_per_line(lpm, INTERNAL_RATE) as u64;
|
||||
if self.phasing_samples >= spl * PHASING_TIMEOUT_LINES as u64 {
|
||||
debug!(
|
||||
ioc,
|
||||
lpm, "WEFAX: phasing timeout — falling through to receiving"
|
||||
);
|
||||
events.push(self.transition_to_receiving(ioc, lpm, 0, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -440,6 +467,7 @@ impl WefaxDecoder {
|
||||
self.low_corr_lines = 0;
|
||||
self.verified = false;
|
||||
self.high_corr_streak = 0;
|
||||
self.phasing_samples = 0;
|
||||
events
|
||||
}
|
||||
|
||||
@@ -489,6 +517,7 @@ impl WefaxDecoder {
|
||||
self.tone_detector.reset();
|
||||
self.phasing = Some(PhasingDetector::new(lpm, INTERNAL_RATE));
|
||||
self.demodulator.reset();
|
||||
self.phasing_samples = 0;
|
||||
self.state = State::Phasing { ioc, lpm };
|
||||
self.state_event("Phasing", ioc, lpm)
|
||||
}
|
||||
@@ -526,6 +555,7 @@ impl WefaxDecoder {
|
||||
self.low_corr_lines = 0;
|
||||
self.verified = false;
|
||||
self.high_corr_streak = 0;
|
||||
self.phasing_samples = 0;
|
||||
}
|
||||
|
||||
fn finalize_image(&mut self, ioc: u16, lpm: u16) -> Vec<WefaxEvent> {
|
||||
|
||||
Reference in New Issue
Block a user