Protocol updates

This commit is contained in:
leviathan
2026-02-11 21:59:30 -05:00
parent 0767850a6f
commit 9e2565c1fc
30 changed files with 772 additions and 507 deletions
+82 -62
View File
@@ -1,11 +1,12 @@
//! Fiat V0 protocol decoder/encoder
//!
//! Ported from protopirate's fiat_v0.c
//! Aligned with ProtoPirate reference: `REFERENCES/ProtoPirate/protocols/fiat_v0.c` (Flipper).
//! Decode/encode logic (preamble, gap, Manchester, data/btn extraction, upload waveform) matches reference.
//!
//! Protocol characteristics:
//! - Differential Manchester encoding: 200/400µs timing
//! - 64-bit data (cnt:32 | serial:32) + 6-bit button
//! - 150 preamble pairs, 800µs gap, 3 bursts
//! - 150 preamble pairs (count LOW pulses), 800µs gap, 3 bursts
use super::{DecodedSignal, ProtocolDecoder, ProtocolTiming};
use crate::duration_diff;
@@ -16,21 +17,21 @@ const TE_LONG: u32 = 400;
const TE_DELTA: u32 = 100;
#[allow(dead_code)]
const MIN_COUNT_BIT: usize = 64;
const PREAMBLE_PAIRS: u16 = 150;
const PREAMBLE_PAIRS: u16 = 150; // 0x96 in reference
const GAP_US: u32 = 800;
const TOTAL_BURSTS: u8 = 3;
const INTER_BURST_GAP: u32 = 25000;
/// Manchester decoder states
/// Manchester state machine states (matches Flipper's manchester_decoder.h, same as Ford V0)
#[derive(Debug, Clone, Copy, PartialEq)]
enum ManchesterState {
Mid0,
Mid1,
Start0,
Start1,
Mid0 = 0,
Mid1 = 1,
Start0 = 2,
Start1 = 3,
}
/// Decoder states
/// Decoder states (matches protopirate's FiatV0DecoderStep)
#[derive(Debug, Clone, Copy, PartialEq)]
enum DecoderStep {
Reset,
@@ -68,37 +69,46 @@ impl FiatV0Decoder {
}
}
/// Manchester advance - returns decoded bit or None
fn manchester_advance(&mut self, is_short: bool, is_high: bool) -> Option<bool> {
let event = match (is_short, is_high) {
(true, true) => 0,
(true, false) => 1,
(false, true) => 2,
(false, false) => 3,
};
/// Manchester state machine (same as Ford V0 / Flipper manchester_decoder).
/// Event: 0=ShortLow, 1=ShortHigh, 2=LongLow, 3=LongHigh.
fn manchester_advance(&mut self, event: u8) -> Option<bool> {
let (new_state, emit) = match (self.manchester_state, event) {
(ManchesterState::Mid0, 0) => (ManchesterState::Mid0, false),
(ManchesterState::Mid0, 1) => (ManchesterState::Start1, true),
(ManchesterState::Mid0, 2) => (ManchesterState::Mid0, false),
(ManchesterState::Mid0, 3) => (ManchesterState::Mid1, true),
let (new_state, output) = match (self.manchester_state, event) {
(ManchesterState::Mid0, 0) | (ManchesterState::Mid1, 0) => {
(ManchesterState::Start1, None)
}
(ManchesterState::Mid0, 1) | (ManchesterState::Mid1, 1) => {
(ManchesterState::Start0, None)
}
(ManchesterState::Start1, 1) => (ManchesterState::Mid1, Some(true)),
(ManchesterState::Start1, 3) => (ManchesterState::Start0, Some(true)),
(ManchesterState::Start0, 0) => (ManchesterState::Mid0, Some(false)),
(ManchesterState::Start0, 2) => (ManchesterState::Start1, Some(false)),
_ => (ManchesterState::Mid1, None),
(ManchesterState::Mid1, 0) => (ManchesterState::Start0, true),
(ManchesterState::Mid1, 1) => (ManchesterState::Mid1, false),
(ManchesterState::Mid1, 2) => (ManchesterState::Mid0, true),
(ManchesterState::Mid1, 3) => (ManchesterState::Mid1, false),
(ManchesterState::Start0, 0) => (ManchesterState::Mid0, false),
(ManchesterState::Start0, 1) => (ManchesterState::Mid0, false),
(ManchesterState::Start0, 2) => (ManchesterState::Mid0, false),
(ManchesterState::Start0, 3) => (ManchesterState::Mid1, false),
(ManchesterState::Start1, 0) => (ManchesterState::Mid0, false),
(ManchesterState::Start1, 1) => (ManchesterState::Mid1, false),
(ManchesterState::Start1, 2) => (ManchesterState::Mid0, false),
(ManchesterState::Start1, 3) => (ManchesterState::Mid1, false),
_ => (ManchesterState::Mid1, false),
};
self.manchester_state = new_state;
output
if emit {
Some((event & 1) == 1)
} else {
None
}
}
fn manchester_reset(&mut self) {
self.manchester_state = ManchesterState::Mid1;
}
/// Add bit to accumulator; at 64 bits extract serial/cnt and clear data (bit_count unchanged in reference).
fn add_manchester_bit(&mut self, bit: bool) {
let new_bit = if bit { 1u32 } else { 0u32 };
let carry = (self.data_low >> 31) & 1;
@@ -162,6 +172,7 @@ impl ProtocolDecoder for FiatV0Decoder {
fn feed(&mut self, level: bool, duration: u32) -> Option<DecodedSignal> {
match self.step {
// Reset: wait for short HIGH (matches reference)
DecoderStep::Reset => {
if !level {
return None;
@@ -177,50 +188,60 @@ impl ProtocolDecoder for FiatV0Decoder {
}
}
// Preamble: only process LOW pulses (reference: if(level) return). Count short LOWs; gap = 800µs LOW.
DecoderStep::Preamble => {
// Count short pulses in preamble, look for gap
if duration_diff!(duration, TE_SHORT) < TE_DELTA {
if level {
return None;
}
let short_ok = duration_diff!(duration, TE_SHORT) < TE_DELTA;
let gap_ok = duration_diff!(duration, GAP_US) < TE_DELTA;
if short_ok {
self.preamble_count += 1;
self.te_last = duration;
} else if self.preamble_count >= PREAMBLE_PAIRS {
// Check for gap
if duration_diff!(duration, GAP_US) < TE_DELTA {
} else {
if self.preamble_count >= PREAMBLE_PAIRS && gap_ok {
self.step = DecoderStep::Data;
self.preamble_count = 0;
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.te_last = duration;
return None;
} else {
self.step = DecoderStep::Reset;
}
} else {
self.step = DecoderStep::Reset;
}
}
// Data: Manchester events — short first, then long (matches reference)
DecoderStep::Data => {
let is_short = duration_diff!(duration, TE_SHORT) < TE_DELTA;
let is_long = duration_diff!(duration, TE_LONG) < TE_DELTA;
let short_diff = duration_diff!(duration, TE_SHORT);
let long_diff = duration_diff!(duration, TE_LONG);
if is_short || is_long {
if let Some(bit) = self.manchester_advance(is_short, level) {
self.add_manchester_bit(bit);
if self.bit_count > 0x46 {
self.btn = ((self.data_low << 1) | 1) as u8;
let result = self.parse_data();
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.step = DecoderStep::Reset;
return Some(result);
}
let event = if short_diff < TE_DELTA {
if level { 0 } else { 1 }
} else if long_diff < TE_DELTA {
if level { 2 } else { 3 }
} else {
self.te_last = duration;
if duration > TE_LONG * 3 {
self.step = DecoderStep::Reset;
}
return None;
};
if let Some(bit) = self.manchester_advance(event) {
self.add_manchester_bit(bit);
if self.bit_count > 0x46 {
self.btn = ((self.data_low << 1) | 1) as u8;
let result = self.parse_data();
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.step = DecoderStep::Reset;
return Some(result);
}
} else if duration > TE_LONG * 3 {
// End of signal
self.step = DecoderStep::Reset;
}
self.te_last = duration;
@@ -249,14 +270,13 @@ impl ProtocolDecoder for FiatV0Decoder {
signal.push(LevelDuration::new(false, INTER_BURST_GAP));
}
// Preamble
// Preamble: 150 HIGH-LOW pairs; last LOW is gap (matches reference get_upload)
for i in 0..PREAMBLE_PAIRS {
signal.push(LevelDuration::new(true, TE_SHORT));
if i < PREAMBLE_PAIRS - 1 {
signal.push(LevelDuration::new(false, TE_SHORT));
} else {
signal.push(LevelDuration::new(false, GAP_US));
}
signal.push(LevelDuration::new(
false,
if i == PREAMBLE_PAIRS - 1 { GAP_US } else { TE_SHORT },
));
}
// First bit (bit 63)