better working signals
This commit is contained in:
+24
-11
@@ -15,11 +15,12 @@ use crate::duration_diff;
|
||||
|
||||
const TE_SHORT: u32 = 250;
|
||||
const TE_LONG: u32 = 500;
|
||||
const TE_DELTA: u32 = 100;
|
||||
const TE_DELTA: u32 = 200; // Wider tolerance for HackRF software demodulation (was 100)
|
||||
const MIN_COUNT_BIT: usize = 64;
|
||||
const TOTAL_BURSTS: u8 = 6;
|
||||
const PREAMBLE_PAIRS: usize = 4;
|
||||
const GAP_US: u32 = 3500;
|
||||
const GAP_TOLERANCE: u32 = 1500; // Wide gap tolerance for software demodulator
|
||||
|
||||
// CRC matrix for Ford V0 — GF(2) matrix multiplication
|
||||
// Copied directly from protopirate's ford_v0.c
|
||||
@@ -552,13 +553,16 @@ impl ProtocolDecoder for FordV0Decoder {
|
||||
// ─── Step 3: PreambleCheck — count preamble pairs or transition to gap ───
|
||||
DecoderStep::PreambleCheck => {
|
||||
if level {
|
||||
if duration_diff!(duration, TE_LONG) < TE_DELTA {
|
||||
// Long HIGH: another preamble pair
|
||||
let short_diff = duration_diff!(duration, TE_SHORT);
|
||||
let long_diff = duration_diff!(duration, TE_LONG);
|
||||
|
||||
if long_diff < TE_DELTA && long_diff <= short_diff {
|
||||
// Long HIGH (closer to TE_LONG): another preamble pair
|
||||
self.header_count += 1;
|
||||
self.te_last = duration;
|
||||
self.step = DecoderStep::Preamble;
|
||||
} else if duration_diff!(duration, TE_SHORT) < TE_DELTA {
|
||||
// Short HIGH: end of preamble, transition to gap
|
||||
} else if short_diff < TE_DELTA {
|
||||
// Short HIGH (closer to TE_SHORT): end of preamble, transition to gap
|
||||
self.step = DecoderStep::Gap;
|
||||
} else {
|
||||
self.step = DecoderStep::Reset;
|
||||
@@ -568,24 +572,33 @@ impl ProtocolDecoder for FordV0Decoder {
|
||||
|
||||
// ─── Step 4: Gap — wait for ~3500µs LOW gap ───
|
||||
DecoderStep::Gap => {
|
||||
if !level && duration_diff!(duration, GAP_US) < 250 {
|
||||
if !level && duration_diff!(duration, GAP_US) < GAP_TOLERANCE {
|
||||
// Gap detected, start data collection
|
||||
// First bit is implicitly 1 (matches protopirate)
|
||||
self.decode_data = 1;
|
||||
self.bit_count = 1;
|
||||
self.step = DecoderStep::Data;
|
||||
} else if !level && duration > GAP_US + 250 {
|
||||
} else if !level && duration > GAP_US + GAP_TOLERANCE {
|
||||
self.step = DecoderStep::Reset;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Step 5: Data — Manchester decode 80 bits ───
|
||||
DecoderStep::Data => {
|
||||
// Map level+duration to Manchester event
|
||||
// Flipper convention: level=true (HIGH) → Low event, level=false (LOW) → High event
|
||||
let event = if duration_diff!(duration, TE_SHORT) < TE_DELTA {
|
||||
// Map level+duration to Manchester event using NEAREST-MATCH.
|
||||
// With TE_DELTA=200, SHORT(250) and LONG(500) ranges overlap at 300–450µs.
|
||||
// First-match would always pick SHORT for overlapping durations, causing
|
||||
// bit errors and CRC failure. Nearest-match picks the closer timing.
|
||||
//
|
||||
// Tie-break favors LONG (strict < for short_diff) because asymmetric
|
||||
// demodulation compresses LOWs towards the midpoint (375µs) — these are
|
||||
// actually LONG pulses that got shortened by threshold bias.
|
||||
let short_diff = duration_diff!(duration, TE_SHORT);
|
||||
let long_diff = duration_diff!(duration, TE_LONG);
|
||||
|
||||
let event = if short_diff < TE_DELTA && short_diff < long_diff {
|
||||
if level { 0 } else { 1 } // ShortLow / ShortHigh
|
||||
} else if duration_diff!(duration, TE_LONG) < TE_DELTA {
|
||||
} else if long_diff < TE_DELTA {
|
||||
if level { 2 } else { 3 } // LongLow / LongHigh
|
||||
} else {
|
||||
self.step = DecoderStep::Reset;
|
||||
|
||||
+40
-17
@@ -15,7 +15,7 @@ use crate::duration_diff;
|
||||
|
||||
const TE_SHORT: u32 = 800;
|
||||
const TE_LONG: u32 = 1600;
|
||||
const TE_DELTA: u32 = 200;
|
||||
const TE_DELTA: u32 = 300;
|
||||
#[allow(dead_code)]
|
||||
const MIN_COUNT_BIT: usize = 64;
|
||||
|
||||
@@ -115,6 +115,19 @@ impl SubaruDecoder {
|
||||
((hi as u16) << 8) | (lo as u16)
|
||||
}
|
||||
|
||||
/// Add a level+duration to the signal, merging with the previous entry
|
||||
/// if it has the same level. This prevents consecutive same-level pulses
|
||||
/// which would silently merge during HackRF transmission.
|
||||
fn add_level(signal: &mut Vec<LevelDuration>, level: bool, duration: u32) {
|
||||
if let Some(last) = signal.last_mut() {
|
||||
if last.level == level {
|
||||
*last = LevelDuration::new(level, last.duration_us + duration);
|
||||
return;
|
||||
}
|
||||
}
|
||||
signal.push(LevelDuration::new(level, duration));
|
||||
}
|
||||
|
||||
/// Process the decoded data
|
||||
fn process_data(&self) -> Option<DecodedSignal> {
|
||||
if self.bit_count < 64 {
|
||||
@@ -160,7 +173,7 @@ impl ProtocolDecoder for SubaruDecoder {
|
||||
}
|
||||
|
||||
fn supported_frequencies(&self) -> &[u32] {
|
||||
&[433_920_000]
|
||||
&[433_920_000, 315_000_000] // 433.92 MHz (EU/AU) and 315 MHz (US/JP)
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
@@ -284,38 +297,48 @@ impl ProtocolDecoder for SubaruDecoder {
|
||||
let key = decoded.data;
|
||||
let mut signal = Vec::with_capacity(512);
|
||||
|
||||
// Generate 3 bursts
|
||||
// Generate 3 bursts.
|
||||
//
|
||||
// IMPORTANT: Uses add_level() to merge adjacent same-level pulses.
|
||||
// The HackRF transmitter generates IQ samples sequentially from the
|
||||
// LevelDuration list, so consecutive same-level pairs silently merge
|
||||
// and corrupt timing. For example, the last preamble LOW (1600µs) +
|
||||
// gap LOW (2800µs) would become a single 4400µs LOW without merging.
|
||||
for burst in 0..3 {
|
||||
if burst > 0 {
|
||||
signal.push(LevelDuration::new(false, 25000));
|
||||
// Inter-burst silence
|
||||
Self::add_level(&mut signal, false, 25000);
|
||||
}
|
||||
|
||||
// Preamble: 80 long HIGH/LOW pairs
|
||||
for _ in 0..80 {
|
||||
signal.push(LevelDuration::new(true, TE_LONG));
|
||||
signal.push(LevelDuration::new(false, TE_LONG));
|
||||
// Preamble: 79 full pairs + 80th HIGH only.
|
||||
// The gap LOW replaces the 80th preamble LOW.
|
||||
for i in 0..80 {
|
||||
Self::add_level(&mut signal, true, TE_LONG);
|
||||
if i < 79 {
|
||||
Self::add_level(&mut signal, false, TE_LONG);
|
||||
}
|
||||
}
|
||||
|
||||
// Gap
|
||||
signal.push(LevelDuration::new(false, GAP_US));
|
||||
// Gap (replaces the 80th preamble LOW)
|
||||
Self::add_level(&mut signal, false, GAP_US);
|
||||
|
||||
// Sync
|
||||
signal.push(LevelDuration::new(true, SYNC_US));
|
||||
signal.push(LevelDuration::new(false, TE_LONG));
|
||||
Self::add_level(&mut signal, true, SYNC_US);
|
||||
Self::add_level(&mut signal, false, TE_LONG);
|
||||
|
||||
// Data: 64 bits (MSB first)
|
||||
// Short HIGH = 1, Long HIGH = 0
|
||||
for bit in (0..64).rev() {
|
||||
if (key >> bit) & 1 == 1 {
|
||||
signal.push(LevelDuration::new(true, TE_SHORT));
|
||||
Self::add_level(&mut signal, true, TE_SHORT);
|
||||
} else {
|
||||
signal.push(LevelDuration::new(true, TE_LONG));
|
||||
Self::add_level(&mut signal, true, TE_LONG);
|
||||
}
|
||||
signal.push(LevelDuration::new(false, TE_SHORT));
|
||||
Self::add_level(&mut signal, false, TE_SHORT);
|
||||
}
|
||||
|
||||
// End marker
|
||||
signal.push(LevelDuration::new(false, TE_LONG * 2));
|
||||
// End-of-burst gap (extends the last data LOW)
|
||||
Self::add_level(&mut signal, false, TE_LONG * 2);
|
||||
}
|
||||
|
||||
Some(signal)
|
||||
|
||||
+62
-52
@@ -21,14 +21,14 @@ use crate::radio::demodulator::LevelDuration;
|
||||
// Type 3/4 timing (used as default for ProtocolTiming)
|
||||
const TE_SHORT: u32 = 500;
|
||||
const TE_LONG: u32 = 1000;
|
||||
const TE_DELTA: u32 = 80;
|
||||
const TE_DELTA: u32 = 150; // Wider tolerance for HackRF software demodulation (was 80)
|
||||
#[allow(dead_code)]
|
||||
const MIN_COUNT_BIT: usize = 80;
|
||||
|
||||
// Type 1/2 timing
|
||||
const TE_SHORT_12: u32 = 300;
|
||||
const TE_LONG_12: u32 = 600;
|
||||
const TE_DELTA_12: u32 = 79;
|
||||
const TE_DELTA_12: u32 = 120; // Wider tolerance for HackRF (was 79)
|
||||
|
||||
// TEA constants
|
||||
const TEA_DELTA: u32 = 0x9E3779B9;
|
||||
@@ -982,15 +982,20 @@ impl ProtocolDecoder for VagDecoder {
|
||||
|
||||
DecoderStep::Preamble2 => {
|
||||
if !level {
|
||||
// Low pulse - check if matches 500µs
|
||||
let diff = if duration > TE_SHORT { duration - TE_SHORT } else { TE_SHORT - duration };
|
||||
if diff < TE_DELTA {
|
||||
let prev_diff = if self.te_last > TE_SHORT {
|
||||
self.te_last - TE_SHORT
|
||||
} else {
|
||||
TE_SHORT - self.te_last
|
||||
};
|
||||
if prev_diff < TE_DELTA {
|
||||
// Low pulse during preamble. With HackRF software demodulation,
|
||||
// the LOW pulses can be severely shortened by threshold asymmetry.
|
||||
// Instead of requiring LOWs to be ~500µs, accept any LOW that's
|
||||
// short enough to be part of a preamble pair. We rely primarily
|
||||
// on the HIGH pulse timing for validation.
|
||||
let prev_high_diff = if self.te_last > TE_SHORT {
|
||||
self.te_last - TE_SHORT
|
||||
} else {
|
||||
TE_SHORT - self.te_last
|
||||
};
|
||||
if prev_high_diff < TE_DELTA {
|
||||
// Previous HIGH was valid. Accept LOWs up to 2*TE_SHORT
|
||||
// (covers both symmetric and asymmetric demodulation).
|
||||
if duration < TE_SHORT * 2 {
|
||||
self.te_last = duration;
|
||||
self.header_count += 1;
|
||||
return None;
|
||||
@@ -1000,44 +1005,44 @@ impl ProtocolDecoder for VagDecoder {
|
||||
return None;
|
||||
}
|
||||
|
||||
// High pulse after sufficient preamble
|
||||
// High pulse — check for preamble continuation or sync transition
|
||||
if self.header_count < 41 {
|
||||
// Not enough preamble yet — keep counting if this HIGH is ~500µs
|
||||
let hi_diff = if duration > TE_SHORT { duration - TE_SHORT } else { TE_SHORT - duration };
|
||||
if hi_diff < TE_DELTA {
|
||||
self.te_last = duration;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check for 1000µs sync HIGH
|
||||
// Sufficient preamble — check for 1000µs sync HIGH
|
||||
let diff = if duration > TE_LONG { duration - TE_LONG } else { TE_LONG - duration };
|
||||
if diff > TE_DELTA_12 {
|
||||
if diff <= TE_DELTA {
|
||||
self.te_last = duration;
|
||||
self.step = DecoderStep::Sync2A;
|
||||
return None;
|
||||
}
|
||||
|
||||
let prev_diff = if self.te_last > TE_SHORT {
|
||||
self.te_last - TE_SHORT
|
||||
} else {
|
||||
TE_SHORT - self.te_last
|
||||
};
|
||||
if prev_diff > TE_DELTA_12 {
|
||||
// Not sync — might be another preamble HIGH
|
||||
let hi_diff = if duration > TE_SHORT { duration - TE_SHORT } else { TE_SHORT - duration };
|
||||
if hi_diff < TE_DELTA {
|
||||
self.te_last = duration;
|
||||
return None;
|
||||
}
|
||||
|
||||
self.te_last = duration;
|
||||
self.step = DecoderStep::Sync2A;
|
||||
// Neither preamble nor sync — reset
|
||||
self.step = DecoderStep::Reset;
|
||||
}
|
||||
|
||||
DecoderStep::Sync2A => {
|
||||
if !level {
|
||||
// Sync LOW after 1000µs HIGH. Accept LOWs within TE_DELTA of
|
||||
// TE_SHORT, or any short LOW from asymmetric demodulation.
|
||||
let diff = if duration > TE_SHORT { duration - TE_SHORT } else { TE_SHORT - duration };
|
||||
if diff < TE_DELTA {
|
||||
let prev_diff = if self.te_last > TE_LONG {
|
||||
self.te_last - TE_LONG
|
||||
} else {
|
||||
TE_LONG - self.te_last
|
||||
};
|
||||
if prev_diff < TE_DELTA {
|
||||
self.te_last = duration;
|
||||
self.step = DecoderStep::Sync2B;
|
||||
return None;
|
||||
}
|
||||
if diff < TE_DELTA || duration < TE_SHORT {
|
||||
self.te_last = duration;
|
||||
self.step = DecoderStep::Sync2B;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
self.step = DecoderStep::Reset;
|
||||
@@ -1045,6 +1050,7 @@ impl ProtocolDecoder for VagDecoder {
|
||||
|
||||
DecoderStep::Sync2B => {
|
||||
if level {
|
||||
// Expect ~750µs HIGH sync pulse
|
||||
let diff = if duration > 750 { duration - 750 } else { 750 - duration };
|
||||
if diff < TE_DELTA {
|
||||
self.te_last = duration;
|
||||
@@ -1057,26 +1063,26 @@ impl ProtocolDecoder for VagDecoder {
|
||||
|
||||
DecoderStep::Sync2C => {
|
||||
if !level {
|
||||
// Expect ~750µs LOW sync pulse, but accept shorter from
|
||||
// asymmetric demodulation (as low as ~200µs)
|
||||
let diff = if duration > 750 { duration - 750 } else { 750 - duration };
|
||||
if diff <= TE_DELTA_12 {
|
||||
let prev_diff = if self.te_last > 750 {
|
||||
self.te_last - 750
|
||||
} else {
|
||||
750 - self.te_last
|
||||
};
|
||||
if prev_diff <= TE_DELTA_12 {
|
||||
self.mid_count += 1;
|
||||
self.step = DecoderStep::Sync2B;
|
||||
let prev_diff = if self.te_last > 750 {
|
||||
self.te_last - 750
|
||||
} else {
|
||||
750 - self.te_last
|
||||
};
|
||||
if (diff <= TE_DELTA || duration < 750) && prev_diff <= TE_DELTA {
|
||||
self.mid_count += 1;
|
||||
self.step = DecoderStep::Sync2B;
|
||||
|
||||
if self.mid_count == 3 {
|
||||
self.data_low = 1;
|
||||
self.data_high = 0;
|
||||
self.bit_count = 1;
|
||||
self.manchester_advance(ManchesterEvent::Reset);
|
||||
self.step = DecoderStep::Data2;
|
||||
}
|
||||
return None;
|
||||
if self.mid_count == 3 {
|
||||
self.data_low = 1;
|
||||
self.data_high = 0;
|
||||
self.bit_count = 1;
|
||||
self.manchester_advance(ManchesterEvent::Reset);
|
||||
self.step = DecoderStep::Data2;
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
self.step = DecoderStep::Reset;
|
||||
@@ -1084,9 +1090,13 @@ impl ProtocolDecoder for VagDecoder {
|
||||
|
||||
DecoderStep::Data2 => {
|
||||
// Determine Manchester event for Type 3/4 (500/1000µs)
|
||||
let event = if duration >= 380 && duration <= 620 {
|
||||
// Use nearest-match with wider tolerance for HackRF demodulation.
|
||||
let short_diff = if duration > TE_SHORT { duration - TE_SHORT } else { TE_SHORT - duration };
|
||||
let long_diff = if duration > TE_LONG { duration - TE_LONG } else { TE_LONG - duration };
|
||||
|
||||
let event = if short_diff <= TE_DELTA && short_diff <= long_diff {
|
||||
Some(if level { ManchesterEvent::ShortLow } else { ManchesterEvent::ShortHigh })
|
||||
} else if duration >= 880 && duration <= 1120 {
|
||||
} else if long_diff <= TE_DELTA {
|
||||
Some(if level { ManchesterEvent::LongLow } else { ManchesterEvent::LongHigh })
|
||||
} else {
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user