[fix](trx-wefax): remove idle phasing fallback detection
Phasing-only signals (no APT start tone) should not trigger image decoding. Only APT start tones and signal-level variance detection can start reception. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -65,9 +65,6 @@ pub struct WefaxDecoder {
|
|||||||
demodulator: FmDiscriminator,
|
demodulator: FmDiscriminator,
|
||||||
tone_detector: ToneDetector,
|
tone_detector: ToneDetector,
|
||||||
phasing: Option<PhasingDetector>,
|
phasing: Option<PhasingDetector>,
|
||||||
/// Fallback phasing detector that runs in Idle state to catch ongoing
|
|
||||||
/// transmissions when the APT start tone was missed.
|
|
||||||
idle_phasing: Option<PhasingDetector>,
|
|
||||||
slicer: Option<LineSlicer>,
|
slicer: Option<LineSlicer>,
|
||||||
image: Option<ImageAssembler>,
|
image: Option<ImageAssembler>,
|
||||||
/// Total sample counter for timestamps.
|
/// Total sample counter for timestamps.
|
||||||
@@ -87,7 +84,6 @@ pub struct WefaxDecoder {
|
|||||||
|
|
||||||
impl WefaxDecoder {
|
impl WefaxDecoder {
|
||||||
pub fn new(input_sample_rate: u32, config: WefaxConfig) -> Self {
|
pub fn new(input_sample_rate: u32, config: WefaxConfig) -> Self {
|
||||||
let default_lpm = config.lpm.unwrap_or(120);
|
|
||||||
Self {
|
Self {
|
||||||
resampler: Resampler::new(input_sample_rate),
|
resampler: Resampler::new(input_sample_rate),
|
||||||
demodulator: FmDiscriminator::new(
|
demodulator: FmDiscriminator::new(
|
||||||
@@ -96,7 +92,6 @@ impl WefaxDecoder {
|
|||||||
config.deviation_hz,
|
config.deviation_hz,
|
||||||
),
|
),
|
||||||
tone_detector: ToneDetector::new(INTERNAL_RATE),
|
tone_detector: ToneDetector::new(INTERNAL_RATE),
|
||||||
idle_phasing: Some(PhasingDetector::new(default_lpm, INTERNAL_RATE)),
|
|
||||||
config,
|
config,
|
||||||
state: State::Idle,
|
state: State::Idle,
|
||||||
phasing: None,
|
phasing: None,
|
||||||
@@ -155,20 +150,15 @@ impl WefaxDecoder {
|
|||||||
match self.state.clone() {
|
match self.state.clone() {
|
||||||
State::Idle => {
|
State::Idle => {
|
||||||
// Look for APT start tone first.
|
// Look for APT start tone first.
|
||||||
let mut got_start = false;
|
|
||||||
for result in &tone_results {
|
for result in &tone_results {
|
||||||
if let Some(tone) = result.tone {
|
if let Some(tone) = result.tone {
|
||||||
match tone {
|
match tone {
|
||||||
AptTone::Start576 => {
|
AptTone::Start576 => {
|
||||||
self.idle_phasing = None;
|
|
||||||
events.push(self.transition_to_start_detected(576));
|
events.push(self.transition_to_start_detected(576));
|
||||||
got_start = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
AptTone::Start288 => {
|
AptTone::Start288 => {
|
||||||
self.idle_phasing = None;
|
|
||||||
events.push(self.transition_to_start_detected(288));
|
events.push(self.transition_to_start_detected(288));
|
||||||
got_start = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
AptTone::Stop => {} // Ignore stop in idle.
|
AptTone::Stop => {} // Ignore stop in idle.
|
||||||
@@ -176,26 +166,7 @@ impl WefaxDecoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback 1: try phasing detection on luminance to catch
|
// Fallback: detect active WEFAX signal by luminance variance.
|
||||||
// ongoing transmissions where the start tone was missed.
|
|
||||||
if !got_start {
|
|
||||||
if let Some(ref mut idle_ph) = self.idle_phasing {
|
|
||||||
if let Some(offset) = idle_ph.process(&luminance) {
|
|
||||||
let ioc = self.config.ioc.unwrap_or(576);
|
|
||||||
let lpm = self.config.lpm.unwrap_or(120);
|
|
||||||
self.reception_start_ms = Some(
|
|
||||||
std::time::SystemTime::now()
|
|
||||||
.duration_since(std::time::UNIX_EPOCH)
|
|
||||||
.unwrap_or_default()
|
|
||||||
.as_millis() as i64,
|
|
||||||
);
|
|
||||||
self.idle_phasing = None;
|
|
||||||
events.push(self.transition_to_receiving(ioc, lpm, offset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback 2: detect active WEFAX signal by luminance variance.
|
|
||||||
// Like fldigi's "strong image signal" detection — if we see
|
// Like fldigi's "strong image signal" detection — if we see
|
||||||
// sustained modulated signal, auto-start receiving with defaults.
|
// sustained modulated signal, auto-start receiving with defaults.
|
||||||
if self.state == State::Idle {
|
if self.state == State::Idle {
|
||||||
@@ -230,7 +201,6 @@ impl WefaxDecoder {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.as_millis() as i64,
|
.as_millis() as i64,
|
||||||
);
|
);
|
||||||
self.idle_phasing = None;
|
|
||||||
self.signal_detect_buf.clear();
|
self.signal_detect_buf.clear();
|
||||||
events.push(self.transition_to_receiving(ioc, lpm, 0));
|
events.push(self.transition_to_receiving(ioc, lpm, 0));
|
||||||
break;
|
break;
|
||||||
@@ -334,13 +304,11 @@ impl WefaxDecoder {
|
|||||||
}
|
}
|
||||||
_ => Vec::new(),
|
_ => Vec::new(),
|
||||||
};
|
};
|
||||||
let default_lpm = self.config.lpm.unwrap_or(120);
|
|
||||||
self.state = State::Idle;
|
self.state = State::Idle;
|
||||||
self.resampler.reset();
|
self.resampler.reset();
|
||||||
self.demodulator.reset();
|
self.demodulator.reset();
|
||||||
self.tone_detector.reset();
|
self.tone_detector.reset();
|
||||||
self.phasing = None;
|
self.phasing = None;
|
||||||
self.idle_phasing = Some(PhasingDetector::new(default_lpm, INTERNAL_RATE));
|
|
||||||
self.slicer = None;
|
self.slicer = None;
|
||||||
self.image = None;
|
self.image = None;
|
||||||
self.sample_count = 0;
|
self.sample_count = 0;
|
||||||
@@ -409,13 +377,11 @@ impl WefaxDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn transition_to_idle(&mut self) {
|
fn transition_to_idle(&mut self) {
|
||||||
let default_lpm = self.config.lpm.unwrap_or(120);
|
|
||||||
self.state = State::Idle;
|
self.state = State::Idle;
|
||||||
self.phasing = None;
|
self.phasing = None;
|
||||||
self.slicer = None;
|
self.slicer = None;
|
||||||
// image is kept until finalize_image is called or next reception starts.
|
// image is kept until finalize_image is called or next reception starts.
|
||||||
self.tone_detector.reset();
|
self.tone_detector.reset();
|
||||||
self.idle_phasing = Some(PhasingDetector::new(default_lpm, INTERNAL_RATE));
|
|
||||||
self.signal_detect_count = 0;
|
self.signal_detect_count = 0;
|
||||||
self.signal_detect_buf.clear();
|
self.signal_detect_buf.clear();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user