protocol work

This commit is contained in:
KaraZajac
2026-02-18 21:24:34 -05:00
parent 05078ba961
commit 8ef3b98634
5 changed files with 127 additions and 393 deletions
+23 -10
View File
@@ -4,6 +4,13 @@
//! Each decoder processes level+duration pairs from the demodulator and optionally supports
//! encoding (replay). Shared pieces: [common], [keeloq_common], [keys], [aut64].
//!
//! **Decoder selection (vs ProtoPirate)**
//! ProtoPirate calls `subghz_receiver_decode(receiver, level, duration)` for each pulse; the
//! Flipper SDK receiver (not in REFERENCES) feeds all registered decoders. There is no
//! preamble-based decoder selection in the scene—only the decoder's own feed() logic (e.g. VAG
//! Reset/Preamble1/Preamble2). We do the same: feed every pulse to all decoders that support the
//! file frequency; whoever returns a valid frame is reported. No extra preamble filtering.
//!
//! **Manchester decoding**: Ford, Fiat, and common each have separate Manchester state machines
//! (FordV0ManchesterState, FiatV0ManchesterState, CommonManchesterState in common.rs). They are
//! not reused across protocols. Event conventions match the reference per protocol (e.g. Kia V5
@@ -95,10 +102,10 @@ impl ProtocolRegistry {
Box::new(kia_v3_v4::KiaV3V4Decoder::new()),
Box::new(kia_v5::KiaV5Decoder::new()),
Box::new(kia_v6::KiaV6Decoder::new()),
// Other protocols (Ford before Subaru so 250/500µs Ford keyfobs decode as Ford)
// VAG before Ford/Subaru so 500/1000µs VAG streams decode as VAG (ProtoPirate order has VAG after Ford/Subaru but Flipper likely feeds all decoders; KAT uses first-match so VAG must be tried earlier)
Box::new(vag::VagDecoder::new()),
Box::new(ford_v0::FordV0Decoder::new()),
Box::new(subaru::SubaruDecoder::new()),
Box::new(vag::VagDecoder::new()),
Box::new(fiat_v0::FiatV0Decoder::new()),
Box::new(suzuki::SuzukiDecoder::new()),
Box::new(scher_khan::ScherKhanDecoder::new()),
@@ -160,7 +167,9 @@ impl ProtocolRegistry {
let level = if invert_level { !pair.level } else { pair.level };
let duration_us = pair.duration_us;
let mut hit = None;
// Feed this pulse to all decoders that support this frequency (Flipper-style).
// Whoever actually produces a valid frame is reported; decoder order no longer decides.
let mut hits: Vec<(String, DecodedSignal)> = Vec::new();
for decoder in &mut self.decoders {
let freq_supported = decoder
.supported_frequencies()
@@ -177,11 +186,10 @@ impl ProtocolRegistry {
.protocol_display_name
.as_deref()
.unwrap_or_else(|| decoder.name());
hit = Some((name.to_string(), decoded));
break;
hits.push((name.to_string(), decoded));
}
}
if let Some((name, decoded)) = hit {
if let Some((name, decoded)) = hits.into_iter().next() {
let segment: Vec<LevelDuration> = pairs[segment_start..=i]
.iter()
.map(|p| LevelDuration::new(p.level, p.duration_us))
@@ -212,6 +220,8 @@ impl ProtocolRegistry {
let level = if invert_level { !pair.level } else { pair.level };
let duration_us = pair.duration_us;
// Feed this pulse to all decoders; report first valid frame (Flipper-style).
let mut hits: Vec<(String, DecodedSignal)> = Vec::new();
for decoder in &mut self.decoders {
let freq_supported = decoder
.supported_frequencies()
@@ -227,12 +237,15 @@ impl ProtocolRegistry {
if let Some(decoded) = decoder.feed(level, duration_us) {
let name = decoded
.protocol_display_name
.as_deref()
.unwrap_or_else(|| decoder.name());
return Some((name.to_string(), decoded));
.protocol_display_name
.as_deref()
.unwrap_or_else(|| decoder.name());
hits.push((name.to_string(), decoded));
}
}
if let Some((name, decoded)) = hits.into_iter().next() {
return Some((name.to_string(), decoded));
}
}
None
+17 -9
View File
@@ -18,6 +18,7 @@ use super::{ProtocolDecoder, ProtocolTiming, DecodedSignal};
use super::aut64;
use super::keys;
use crate::radio::demodulator::LevelDuration;
use tracing;
// Type 3/4 timing (used as default for ProtocolTiming)
const TE_SHORT: u32 = 500;
@@ -30,7 +31,8 @@ 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 = 80; // Preamble1/Data1 (ref vag.c 79/80)
#[allow(dead_code)]
const TE_DELTA_12: u32 = 80; // Preamble1/Data1 (ref vag.c 79/80); preamble now uses REF_PREAMBLE1_TOL
// Reference-aligned deltas (vag.c VAG_NEAR / VAG_TOL_300 79, VAG_TOL_500 120)
const REF_RESET_DELTA: u32 = 79; // Reset: 300±79, 500±79 for Preamble2
@@ -38,6 +40,8 @@ const REF_PREAMBLE_SYNC: u32 = 80; // Preamble2 counting: 500±80
const REF_SYNC2_AB_DELTA: u32 = 79; // Sync2A/Sync2B: 500/1000/750±79 (ref VAG_NEAR(..., 79))
const REF_SYNC2C_DELTA: u32 = 79; // Sync2C: 750±79
const REF_GAP1_DELTA: u32 = 79; // Preamble1→Data1 gap 600µs ±79 (ref check_gap1)
// Real-world Type 1/2: preamble often ~280380µs; ref uses 79/80
const REF_PREAMBLE1_TOL: u32 = 100; // 300±100 for Type 1/2 preamble lock/count
// TEA constants
const TEA_DELTA: u32 = 0x9E3779B9;
@@ -842,9 +846,9 @@ impl ProtocolDecoder for VagDecoder {
if !level {
return None;
}
// Matches vag.c: duration < 300 and (300-duration)<=79 -> Preamble1; else (duration-300)<=79 -> Preamble1; else (duration-300)>79 and 500±79 -> Preamble2
// Matches vag.c: duration < 300 and (300-duration)<=tol -> Preamble1; else (duration-300)<=tol -> Preamble1; else 500±79 -> Preamble2. Use REF_PREAMBLE1_TOL for Type 1/2 lock.
if duration < TE_SHORT_12 {
if (TE_SHORT_12 - duration) > REF_RESET_DELTA {
if (TE_SHORT_12 - duration) > REF_PREAMBLE1_TOL {
return None;
}
// init_pattern1
@@ -857,8 +861,8 @@ impl ProtocolDecoder for VagDecoder {
self.vag_type = VagType::Unknown;
self.te_last = duration;
self.manchester_advance(ManchesterEvent::Reset);
} else if duration.wrapping_sub(TE_SHORT_12) <= REF_RESET_DELTA {
// Fall-through to init_pattern1 in ref (duration 300..380)
} else if duration.wrapping_sub(TE_SHORT_12) <= REF_PREAMBLE1_TOL {
// Fall-through to init_pattern1 in ref (duration 300..300+tol)
self.step = DecoderStep::Preamble1;
self.data_low = 0;
self.data_high = 0;
@@ -900,14 +904,14 @@ impl ProtocolDecoder for VagDecoder {
TE_SHORT_12 - duration
};
// Reference: (300-duration)<=79 or (duration-300)<80 -> count pair (check_preamble1_prev)
if te_diff < TE_DELTA_12 {
// Reference: (300-duration) or (duration-300) within tol -> count pair. Use REF_PREAMBLE1_TOL for real-world jitter.
if te_diff <= REF_PREAMBLE1_TOL {
let prev_diff = if self.te_last > TE_SHORT_12 {
self.te_last - TE_SHORT_12
} else {
TE_SHORT_12 - self.te_last
};
if prev_diff <= REF_RESET_DELTA {
if prev_diff <= REF_PREAMBLE1_TOL {
self.te_last = duration;
self.header_count += 1;
return None;
@@ -930,7 +934,7 @@ impl ProtocolDecoder for VagDecoder {
} else {
TE_SHORT_12 - self.te_last
};
if prev_diff <= REF_RESET_DELTA {
if prev_diff <= REF_PREAMBLE1_TOL {
self.step = DecoderStep::Data1;
return None;
}
@@ -1005,6 +1009,10 @@ impl ProtocolDecoder for VagDecoder {
self.data_count_bit = 80;
self.parse_data();
tracing::debug!(
"VAG Data1 decode: 80 bits, decrypted={} (report regardless of key)",
self.decrypted
);
let result = self.build_decoded_signal();
self.data_low = 0;