Files
KAT/src/protocols/vag.rs
T
leviathan 655f019469 v1.0.0
2026-02-13 22:00:42 -05:00

1201 lines
43 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! VAG (VW/Audi/Seat/Skoda) protocol decoder/encoder
//!
//! Aligned with ProtoPirate reference: `REFERENCES/ProtoPirate/protocols/vag.c` and `vag.h`.
//! Decoder steps (VAGDecoderStepReset/Preamble1/Data1/Preamble2/Sync2A/B/C/Data2), Type 1/2/3/4
//! parse (vag_parse_data, vag_aut64_decrypt, vag_tea_decrypt), dispatch (0x2A/0x1C/0x46 and
//! 0x2B/0x1D/0x47), and encoder (vag_encoder_build_type1/2/3_4) match the reference.
//!
//! **Timing**: Reference uses VAG_TOL_300 (79) and VAG_TOL_500 (120). Reset/Preamble1 use 300±79/80;
//! Preamble1→Data1 gap 600µs ±79; Data1 short 300±79/80, long 600±79/80; end-of-data gap 6000µs
//! (accept diff < 4000). Preamble2 count 500±80; Sync2A 500/1000µs ±79; Sync2B 750µs ±79;
//! Sync2C 750µs ±79; Data2 short 500±120 (380620µs), long 1000±120 (8801120µs).
//!
//! **Protocol**: Manchester, 80 bits (key1 64 + key2 16). Type 1/2: 300/600µs, prefix 0xAF3F/0xAF1C.
//! Type 3/4: 500µs, 45 preamble pairs, sync 1000+500 then 3×750µs; key1/key2 not inverted.
//! Button names match reference (vag_button_name): Unlock/Lock/Boot.
use super::{ProtocolDecoder, ProtocolTiming, DecodedSignal};
use super::aut64;
use super::keys;
use crate::radio::demodulator::LevelDuration;
// Type 3/4 timing (used as default for ProtocolTiming)
const TE_SHORT: u32 = 500;
const TE_LONG: u32 = 1000;
#[allow(dead_code)]
const TE_DELTA: u32 = 80; // ref vag.c (Type 3/4); exposed via timing()
#[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 = 80; // Preamble1/Data1 (ref vag.c 79/80)
// 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
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)
// TEA constants
const TEA_DELTA: u32 = 0x9E3779B9;
const TEA_ROUNDS: usize = 32;
/// TEA key schedule for VAG (vag.c vag_tea_key_schedule; VAG_TEA_DELTA 0x9E3779B9, 32 rounds)
static TEA_KEY_SCHEDULE: [u32; 4] = [0x0B46502D, 0x5E253718, 0x2BF93A19, 0x622C1206];
/// Manchester states
#[derive(Debug, Clone, Copy, PartialEq)]
enum ManchesterState {
Mid0,
Mid1,
Start0,
Start1,
}
/// Manchester event types
#[derive(Debug, Clone, Copy)]
enum ManchesterEvent {
ShortHigh,
ShortLow,
LongHigh,
LongLow,
Reset,
}
/// Decoder states (matches protopirate's VAGDecoderStep)
#[derive(Debug, Clone, Copy, PartialEq)]
enum DecoderStep {
Reset,
Preamble1,
Data1,
Preamble2,
Sync2A,
Sync2B,
Sync2C,
Data2,
}
/// VAG sub-type
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum VagType {
Unknown = 0,
Type1 = 1, // AUT64, 300µs
Type2 = 2, // TEA, 300µs
Type3 = 3, // AUT64, 500µs, auto-detect key
Type4 = 4, // AUT64, 500µs, key 2
}
/// VAG protocol decoder
pub struct VagDecoder {
step: DecoderStep,
manchester_state: ManchesterState,
data_low: u32,
data_high: u32,
bit_count: usize,
key1_low: u32,
key1_high: u32,
key2_low: u32,
key2_high: u32,
te_last: u32,
header_count: u16,
mid_count: u8,
vag_type: VagType,
// Decoded fields
serial: u32,
cnt: u32,
btn: u8,
check_byte: u8,
key_idx: u8,
decrypted: bool,
data_count_bit: usize,
}
impl VagDecoder {
pub fn new() -> Self {
Self {
step: DecoderStep::Reset,
manchester_state: ManchesterState::Mid1,
data_low: 0,
data_high: 0,
bit_count: 0,
key1_low: 0,
key1_high: 0,
key2_low: 0,
key2_high: 0,
te_last: 0,
header_count: 0,
mid_count: 0,
vag_type: VagType::Unknown,
serial: 0,
cnt: 0,
btn: 0,
check_byte: 0,
key_idx: 0xFF,
decrypted: false,
data_count_bit: 0,
}
}
/// Manchester state machine advance
fn manchester_advance(&mut self, event: ManchesterEvent) -> Option<bool> {
match event {
ManchesterEvent::Reset => {
self.manchester_state = ManchesterState::Mid1;
None
}
ManchesterEvent::ShortHigh => {
let (new_state, output) = match self.manchester_state {
ManchesterState::Mid0 | ManchesterState::Mid1 => (ManchesterState::Start1, None),
ManchesterState::Start0 => (ManchesterState::Mid0, Some(false)),
_ => (ManchesterState::Mid1, None),
};
self.manchester_state = new_state;
output
}
ManchesterEvent::ShortLow => {
let (new_state, output) = match self.manchester_state {
ManchesterState::Mid0 | ManchesterState::Mid1 => (ManchesterState::Start0, None),
ManchesterState::Start1 => (ManchesterState::Mid1, Some(true)),
_ => (ManchesterState::Mid1, None),
};
self.manchester_state = new_state;
output
}
ManchesterEvent::LongHigh => {
let (new_state, output) = match self.manchester_state {
ManchesterState::Start0 => (ManchesterState::Start1, Some(false)),
_ => (ManchesterState::Mid1, None),
};
self.manchester_state = new_state;
output
}
ManchesterEvent::LongLow => {
let (new_state, output) = match self.manchester_state {
ManchesterState::Start1 => (ManchesterState::Start0, Some(true)),
_ => (ManchesterState::Mid1, None),
};
self.manchester_state = new_state;
output
}
}
}
/// Push a bit into the shift register
fn push_bit(&mut self, bit: bool) {
let carry = (self.data_low >> 31) & 1;
self.data_low = (self.data_low << 1) | (if bit { 1 } else { 0 });
self.data_high = (self.data_high << 1) | carry;
self.bit_count += 1;
}
/// TEA decrypt (matches vag.c vag_tea_decrypt)
fn tea_decrypt(v0: &mut u32, v1: &mut u32, key_schedule: &[u32; 4]) {
let mut sum = TEA_DELTA.wrapping_mul(TEA_ROUNDS as u32);
for _ in 0..TEA_ROUNDS {
*v1 = v1.wrapping_sub(
((*v0 << 4) ^ (*v0 >> 5)).wrapping_add(*v0)
^ sum.wrapping_add(key_schedule[((sum >> 11) & 3) as usize]),
);
sum = sum.wrapping_sub(TEA_DELTA);
*v0 = v0.wrapping_sub(
((*v1 << 4) ^ (*v1 >> 5)).wrapping_add(*v1)
^ sum.wrapping_add(key_schedule[(sum & 3) as usize]),
);
}
}
/// TEA encrypt (matches vag.c vag_tea_encrypt)
fn tea_encrypt(v0: &mut u32, v1: &mut u32, key_schedule: &[u32; 4]) {
let mut sum: u32 = 0;
for _ in 0..TEA_ROUNDS {
*v0 = v0.wrapping_add(
((*v1 << 4) ^ (*v1 >> 5)).wrapping_add(*v1)
^ sum.wrapping_add(key_schedule[(sum & 3) as usize]),
);
sum = sum.wrapping_add(TEA_DELTA);
*v1 = v1.wrapping_add(
((*v0 << 4) ^ (*v0 >> 5)).wrapping_add(*v0)
^ sum.wrapping_add(key_schedule[((sum >> 11) & 3) as usize]),
);
}
}
/// Type 1/2 dispatch check (vag.c vag_dispatch_type_1_2)
fn dispatch_type_1_2(dispatch: u8) -> bool {
dispatch == 0x2A || dispatch == 0x1C || dispatch == 0x46
}
/// Type 3/4 dispatch check (vag.c vag_dispatch_type_3_4)
fn dispatch_type_3_4(dispatch: u8) -> bool {
dispatch == 0x2B || dispatch == 0x1D || dispatch == 0x47
}
/// Validate decrypted block button (vag.c vag_button_valid)
fn button_valid(dec: &[u8]) -> bool {
let dec_byte = dec[7];
let dec_btn = (dec_byte >> 4) & 0xF;
if dec_btn == 1 || dec_btn == 2 || dec_btn == 4 {
return true;
}
if dec_byte == 0 {
return true;
}
false
}
/// Decrypted button vs dispatch (vag.c vag_button_matches)
fn button_matches(dec: &[u8], dispatch_byte: u8) -> bool {
let expected_btn = (dispatch_byte >> 4) & 0xF;
let dec_btn = (dec[7] >> 4) & 0xF;
if dec_btn == expected_btn {
return true;
}
if dec[7] == 0 && expected_btn == 2 {
return true;
}
false
}
/// Fill decoded fields from decrypted block (vag.c vag_fill_from_decrypted)
fn fill_from_decrypted(&mut self, dec: &[u8], dispatch_byte: u8) {
let serial_raw = (dec[0] as u32)
| ((dec[1] as u32) << 8)
| ((dec[2] as u32) << 16)
| ((dec[3] as u32) << 24);
self.serial = (serial_raw << 24)
| ((serial_raw & 0xFF00) << 8)
| ((serial_raw >> 8) & 0xFF00)
| (serial_raw >> 24);
self.cnt = (dec[4] as u32) | ((dec[5] as u32) << 8) | ((dec[6] as u32) << 16);
self.btn = (dec[7] >> 4) & 0xF;
self.check_byte = dispatch_byte;
self.decrypted = true;
}
/// Try AUT64 decryption with a specific key index
fn try_aut64_decrypt(block: &mut [u8], key_index: usize) -> bool {
let store = keys::get_keystore();
if let Some(key) = store.get_vag_key((key_index + 1) as u8) {
aut64::aut64_decrypt(key, block);
true
} else {
false
}
}
/// Parse key1/key2 and decrypt by type (vag.c vag_parse_data)
fn parse_data(&mut self) {
self.decrypted = false;
self.serial = 0;
self.cnt = 0;
self.btn = 0;
let dispatch_byte = (self.key2_low & 0xFF) as u8;
let key2_high_byte = ((self.key2_low >> 8) & 0xFF) as u8;
// Build key1 bytes from key1_high/key1_low
let mut key1_bytes = [0u8; 8];
key1_bytes[0] = (self.key1_high >> 24) as u8;
key1_bytes[1] = (self.key1_high >> 16) as u8;
key1_bytes[2] = (self.key1_high >> 8) as u8;
key1_bytes[3] = self.key1_high as u8;
key1_bytes[4] = (self.key1_low >> 24) as u8;
key1_bytes[5] = (self.key1_low >> 16) as u8;
key1_bytes[6] = (self.key1_low >> 8) as u8;
key1_bytes[7] = self.key1_low as u8;
let _type_byte = key1_bytes[0];
// Build encrypted block (bytes 1-7 of key1 + key2 high byte)
let mut block = [0u8; 8];
block[0] = key1_bytes[1];
block[1] = key1_bytes[2];
block[2] = key1_bytes[3];
block[3] = key1_bytes[4];
block[4] = key1_bytes[5];
block[5] = key1_bytes[6];
block[6] = key1_bytes[7];
block[7] = key2_high_byte;
match self.vag_type {
VagType::Type1 => {
if !Self::dispatch_type_1_2(dispatch_byte) {
return;
}
// Try all 3 AUT64 keys
for key_idx in 0..3 {
let mut block_copy = block;
if !Self::try_aut64_decrypt(&mut block_copy, key_idx) {
continue;
}
if Self::button_valid(&block_copy) {
self.serial = ((block_copy[0] as u32) << 24)
| ((block_copy[1] as u32) << 16)
| ((block_copy[2] as u32) << 8)
| (block_copy[3] as u32);
self.cnt = (block_copy[4] as u32)
| ((block_copy[5] as u32) << 8)
| ((block_copy[6] as u32) << 16);
self.btn = block_copy[7];
self.check_byte = dispatch_byte;
self.key_idx = key_idx as u8;
self.decrypted = true;
return;
}
}
}
VagType::Type2 => {
if !Self::dispatch_type_1_2(dispatch_byte) {
return;
}
let mut v0 = ((block[0] as u32) << 24)
| ((block[1] as u32) << 16)
| ((block[2] as u32) << 8)
| (block[3] as u32);
let mut v1 = ((block[4] as u32) << 24)
| ((block[5] as u32) << 16)
| ((block[6] as u32) << 8)
| (block[7] as u32);
Self::tea_decrypt(&mut v0, &mut v1, &TEA_KEY_SCHEDULE);
let tea_dec = [
(v0 >> 24) as u8,
(v0 >> 16) as u8,
(v0 >> 8) as u8,
v0 as u8,
(v1 >> 24) as u8,
(v1 >> 16) as u8,
(v1 >> 8) as u8,
v1 as u8,
];
if !Self::button_matches(&tea_dec, dispatch_byte) {
return;
}
self.fill_from_decrypted(&tea_dec, dispatch_byte);
self.key_idx = 0xFF;
}
VagType::Type3 => {
// Try key 2 first, then key 1, then key 0
let mut block_copy = block;
if Self::try_aut64_decrypt(&mut block_copy, 2) && Self::button_valid(&block_copy) {
self.vag_type = VagType::Type4;
self.key_idx = 2;
self.fill_from_decrypted(&block_copy, dispatch_byte);
return;
}
block_copy = block;
if Self::try_aut64_decrypt(&mut block_copy, 1) && Self::button_valid(&block_copy) {
self.key_idx = 1;
self.fill_from_decrypted(&block_copy, dispatch_byte);
return;
}
block_copy = block;
if Self::try_aut64_decrypt(&mut block_copy, 0) && Self::button_valid(&block_copy) {
self.key_idx = 0;
self.fill_from_decrypted(&block_copy, dispatch_byte);
return;
}
}
VagType::Type4 => {
if !Self::dispatch_type_3_4(dispatch_byte) {
return;
}
let mut block_copy = block;
if !Self::try_aut64_decrypt(&mut block_copy, 2) {
return;
}
if !Self::button_matches(&block_copy, dispatch_byte) {
return;
}
self.key_idx = 2;
self.fill_from_decrypted(&block_copy, dispatch_byte);
}
VagType::Unknown => {}
}
}
/// Get vehicle name from type byte
#[allow(dead_code)]
fn get_vehicle_name(type_byte: u8) -> &'static str {
match type_byte {
0x00 => "VW Passat",
0xC0 => "VW",
0xC1 => "Audi",
0xC2 => "Seat",
0xC3 => "Skoda",
_ => "VAG",
}
}
/// Get button name (matches vag.c vag_button_name: Unlock/Lock/Boot)
#[allow(dead_code)]
fn get_button_name(btn: u8) -> &'static str {
match btn {
1 | 0x10 => "Unlock",
2 | 0x20 => "Lock",
4 | 0x40 => "Boot",
_ => "Unknown",
}
}
/// Build encoder output from decoded signal (uses decoded + extra; extra = vag_type | (key_idx<<8))
fn encode_signal(&self, decoded: &DecodedSignal) -> Option<Vec<LevelDuration>> {
let extra = match decoded.extra {
Some(e) => e,
None => return None,
};
let vag_type_num = (extra & 0xFF) as u8;
let vag_type = match vag_type_num {
1 => VagType::Type1,
2 => VagType::Type2,
3 => VagType::Type3,
4 => VagType::Type4,
_ => return None,
};
let key_idx = ((extra >> 8) & 0xFF) as u8;
match vag_type {
VagType::Type1 => Self::encode_type1(decoded, key_idx),
VagType::Type2 => Self::encode_type2(decoded),
VagType::Type3 | VagType::Type4 => Self::encode_type3_4(decoded, vag_type, key_idx),
_ => None,
}
}
/// Encode Type 1 (300µs, AUT64)
fn encode_type1(decoded: &DecodedSignal, key_idx: u8) -> Option<Vec<LevelDuration>> {
let mut upload = Vec::with_capacity(700);
let serial = decoded.serial.unwrap_or(0);
let btn = decoded.button.unwrap_or(0);
let cnt = decoded.counter.unwrap_or(0) as u32;
let type_byte = (decoded.data >> 56) as u8;
let btn_byte = btn;
let dispatch = Self::get_dispatch_byte(btn_byte, 1);
// Build plaintext block
let mut block = [0u8; 8];
block[0] = (serial >> 24) as u8;
block[1] = (serial >> 16) as u8;
block[2] = (serial >> 8) as u8;
block[3] = serial as u8;
block[4] = cnt as u8;
block[5] = (cnt >> 8) as u8;
block[6] = (cnt >> 16) as u8;
block[7] = btn_byte;
// Encrypt with AUT64
let key_idx = if key_idx != 0xFF { key_idx as usize } else { 0 };
let store = keys::get_keystore();
if let Some(key) = store.get_vag_key((key_idx + 1) as u8) {
aut64::aut64_encrypt(key, &mut block);
} else {
return None;
}
drop(store);
// Build key values
let key1_high = ((type_byte as u32) << 24)
| ((block[0] as u32) << 16)
| ((block[1] as u32) << 8)
| (block[2] as u32);
let key1_low = ((block[3] as u32) << 24)
| ((block[4] as u32) << 16)
| ((block[5] as u32) << 8)
| (block[6] as u32);
let key2 = (((block[7] as u16) << 8) | (dispatch as u16)) & 0xFFFF;
// Preamble: 220 cycles of 300µs HIGH/LOW
for _ in 0..220 {
upload.push(LevelDuration::new(true, 300));
upload.push(LevelDuration::new(false, 300));
}
upload.push(LevelDuration::new(false, 300));
upload.push(LevelDuration::new(true, 300));
// Prefix: 0xAF3F (16 bits, Manchester)
let prefix: u16 = 0xAF3F;
Self::encode_manchester_16(&mut upload, prefix, 300);
// Key1: 64 bits inverted, Manchester encoded
let key1 = ((key1_high as u64) << 32) | (key1_low as u64);
let key1_inv = !key1;
Self::encode_manchester_64(&mut upload, key1_inv, 300);
// Key2: 16 bits inverted, Manchester encoded
let key2_inv = !key2;
Self::encode_manchester_16(&mut upload, key2_inv, 300);
// Gap
upload.push(LevelDuration::new(false, 6000));
Some(upload)
}
/// Encode Type 2 (300µs, TEA)
fn encode_type2(decoded: &DecodedSignal) -> Option<Vec<LevelDuration>> {
let mut upload = Vec::with_capacity(700);
let serial = decoded.serial.unwrap_or(0);
let btn = decoded.button.unwrap_or(0);
let cnt = decoded.counter.unwrap_or(0) as u32;
let type_byte = (decoded.data >> 56) as u8;
let btn_byte = Self::btn_to_byte(btn, 2);
let dispatch = Self::get_dispatch_byte(btn_byte, 2);
// Build plaintext block
let mut block = [0u8; 8];
block[0] = (serial >> 24) as u8;
block[1] = (serial >> 16) as u8;
block[2] = (serial >> 8) as u8;
block[3] = serial as u8;
block[4] = cnt as u8;
block[5] = (cnt >> 8) as u8;
block[6] = (cnt >> 16) as u8;
block[7] = btn_byte;
// Encrypt with TEA
let mut v0 = ((block[0] as u32) << 24)
| ((block[1] as u32) << 16)
| ((block[2] as u32) << 8)
| (block[3] as u32);
let mut v1 = ((block[4] as u32) << 24)
| ((block[5] as u32) << 16)
| ((block[6] as u32) << 8)
| (block[7] as u32);
Self::tea_encrypt(&mut v0, &mut v1, &TEA_KEY_SCHEDULE);
let enc_block = [
(v0 >> 24) as u8, (v0 >> 16) as u8, (v0 >> 8) as u8, v0 as u8,
(v1 >> 24) as u8, (v1 >> 16) as u8, (v1 >> 8) as u8, v1 as u8,
];
let key1_high = ((type_byte as u32) << 24)
| ((enc_block[0] as u32) << 16)
| ((enc_block[1] as u32) << 8)
| (enc_block[2] as u32);
let key1_low = ((enc_block[3] as u32) << 24)
| ((enc_block[4] as u32) << 16)
| ((enc_block[5] as u32) << 8)
| (enc_block[6] as u32);
let key2 = (((enc_block[7] as u16) << 8) | (dispatch as u16)) & 0xFFFF;
// Preamble
for _ in 0..220 {
upload.push(LevelDuration::new(true, 300));
upload.push(LevelDuration::new(false, 300));
}
upload.push(LevelDuration::new(false, 300));
upload.push(LevelDuration::new(true, 300));
// Prefix: 0xAF1C (16 bits, Manchester)
let prefix: u16 = 0xAF1C;
Self::encode_manchester_16(&mut upload, prefix, 300);
// Key1: 64 bits inverted
let key1 = ((key1_high as u64) << 32) | (key1_low as u64);
let key1_inv = !key1;
Self::encode_manchester_64(&mut upload, key1_inv, 300);
// Key2: 16 bits inverted
let key2_inv = !key2;
Self::encode_manchester_16(&mut upload, key2_inv, 300);
// Gap
upload.push(LevelDuration::new(false, 6000));
Some(upload)
}
/// Encode Type 3/4 (500µs, AUT64)
fn encode_type3_4(decoded: &DecodedSignal, vag_type: VagType, key_idx: u8) -> Option<Vec<LevelDuration>> {
let mut upload = Vec::with_capacity(600);
let vag_type_num = vag_type as u8;
let serial = decoded.serial.unwrap_or(0);
let btn = decoded.button.unwrap_or(0);
let cnt = decoded.counter.unwrap_or(0) as u32;
let type_byte = (decoded.data >> 56) as u8;
let btn_byte = Self::btn_to_byte(btn, vag_type_num);
let dispatch = Self::get_dispatch_byte(btn_byte, vag_type_num);
let mut block = [0u8; 8];
block[0] = (serial >> 24) as u8;
block[1] = (serial >> 16) as u8;
block[2] = (serial >> 8) as u8;
block[3] = serial as u8;
block[4] = cnt as u8;
block[5] = (cnt >> 8) as u8;
block[6] = (cnt >> 16) as u8;
block[7] = btn_byte;
let key_idx = if key_idx != 0xFF {
key_idx as usize
} else if vag_type == VagType::Type4 { 2 } else { 1 };
let store = keys::get_keystore();
if let Some(key) = store.get_vag_key((key_idx + 1) as u8) {
aut64::aut64_encrypt(key, &mut block);
} else {
return None;
}
drop(store);
let key1_high = ((type_byte as u32) << 24)
| ((block[0] as u32) << 16)
| ((block[1] as u32) << 8)
| (block[2] as u32);
let key1_low = ((block[3] as u32) << 24)
| ((block[4] as u32) << 16)
| ((block[5] as u32) << 8)
| (block[6] as u32);
let key2 = (((block[7] as u16) << 8) | (dispatch as u16)) & 0xFFFF;
let key1 = ((key1_high as u64) << 32) | (key1_low as u64);
// Two repeats
for _ in 0..2 {
// Preamble: 45 cycles of 500µs HIGH/LOW
for _ in 0..45 {
upload.push(LevelDuration::new(true, 500));
upload.push(LevelDuration::new(false, 500));
}
// Sync: 1000µs HIGH, 500µs LOW
upload.push(LevelDuration::new(true, 1000));
upload.push(LevelDuration::new(false, 500));
// Mid sync: 3 cycles of 750µs HIGH/LOW
for _ in 0..3 {
upload.push(LevelDuration::new(true, 750));
upload.push(LevelDuration::new(false, 750));
}
// Key1: 64 bits (NOT inverted for Type 3/4)
for i in (0..64).rev() {
let bit = (key1 >> i) & 1 == 1;
if bit {
upload.push(LevelDuration::new(true, 500));
upload.push(LevelDuration::new(false, 500));
} else {
upload.push(LevelDuration::new(false, 500));
upload.push(LevelDuration::new(true, 500));
}
}
// Key2: 16 bits
for i in (0..16).rev() {
let bit = (key2 >> i) & 1 == 1;
if bit {
upload.push(LevelDuration::new(true, 500));
upload.push(LevelDuration::new(false, 500));
} else {
upload.push(LevelDuration::new(false, 500));
upload.push(LevelDuration::new(true, 500));
}
}
// Gap
upload.push(LevelDuration::new(false, 10000));
}
Some(upload)
}
/// Dispatch byte from button and type (vag.c vag_get_dispatch_byte)
fn get_dispatch_byte(btn: u8, vag_type: u8) -> u8 {
if vag_type == 1 || vag_type == 2 {
match btn {
0x20 | 2 => 0x2A,
0x40 | 4 => 0x46,
0x10 | 1 => 0x1C,
_ => 0x2A,
}
} else {
match btn {
0x20 | 2 => 0x2B,
0x40 | 4 => 0x47,
0x10 | 1 => 0x1D,
_ => 0x2B,
}
}
}
/// Convert button code to byte for encoding (matches vag.c vag_btn_to_byte)
fn btn_to_byte(btn: u8, vag_type: u8) -> u8 {
if vag_type == 1 {
btn
} else {
match btn {
1 => 0x10,
2 => 0x20,
4 => 0x40,
_ => btn, // ref default: return btn
}
}
}
/// Encode 16 bits in Manchester at given half-period
fn encode_manchester_16(upload: &mut Vec<LevelDuration>, data: u16, te: u32) {
for i in (0..16).rev() {
let bit = (data >> i) & 1 == 1;
if bit {
upload.push(LevelDuration::new(true, te));
upload.push(LevelDuration::new(false, te));
} else {
upload.push(LevelDuration::new(false, te));
upload.push(LevelDuration::new(true, te));
}
}
}
/// Encode 64 bits in Manchester at given half-period
fn encode_manchester_64(upload: &mut Vec<LevelDuration>, data: u64, te: u32) {
for i in (0..64).rev() {
let bit = (data >> i) & 1 == 1;
if bit {
upload.push(LevelDuration::new(true, te));
upload.push(LevelDuration::new(false, te));
} else {
upload.push(LevelDuration::new(false, te));
upload.push(LevelDuration::new(true, te));
}
}
}
/// Build DecodedSignal from internal state (sets extra when decrypted for encode-from-capture)
fn build_decoded_signal(&self) -> DecodedSignal {
let key1 = ((self.key1_high as u64) << 32) | (self.key1_low as u64);
let extra = if self.decrypted {
Some((self.vag_type as u8 as u64) | ((self.key_idx as u64) << 8))
} else {
None
};
DecodedSignal {
serial: if self.decrypted { Some(self.serial) } else { None },
button: if self.decrypted { Some(self.btn) } else { None },
counter: if self.decrypted { Some((self.cnt & 0xFFFF) as u16) } else { None },
crc_valid: self.decrypted,
data: key1,
data_count_bit: self.data_count_bit,
encoder_capable: self.decrypted,
extra,
}
}
}
impl ProtocolDecoder for VagDecoder {
fn name(&self) -> &'static str {
"VAG"
}
fn timing(&self) -> ProtocolTiming {
ProtocolTiming {
te_short: TE_SHORT,
te_long: TE_LONG,
te_delta: TE_DELTA,
min_count_bit: MIN_COUNT_BIT,
}
}
fn supported_frequencies(&self) -> &[u32] {
&[433_920_000, 434_420_000]
}
fn reset(&mut self) {
self.step = DecoderStep::Reset;
self.manchester_state = ManchesterState::Mid1;
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.header_count = 0;
self.mid_count = 0;
self.vag_type = VagType::Unknown;
self.te_last = 0;
self.decrypted = false;
self.serial = 0;
self.cnt = 0;
self.btn = 0;
self.check_byte = 0;
self.key_idx = 0xFF;
}
fn feed(&mut self, level: bool, duration: u32) -> Option<DecodedSignal> {
match self.step {
DecoderStep::Reset => {
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
if duration < TE_SHORT_12 {
if (TE_SHORT_12 - duration) > REF_RESET_DELTA {
return None;
}
// init_pattern1
self.step = DecoderStep::Preamble1;
self.data_low = 0;
self.data_high = 0;
self.header_count = 0;
self.mid_count = 0;
self.bit_count = 0;
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)
self.step = DecoderStep::Preamble1;
self.data_low = 0;
self.data_high = 0;
self.header_count = 0;
self.mid_count = 0;
self.bit_count = 0;
self.vag_type = VagType::Unknown;
self.te_last = duration;
self.manchester_advance(ManchesterEvent::Reset);
} else {
// (duration - 300) > 79: check 500±79 for Preamble2
let diff = if duration < TE_SHORT {
TE_SHORT - duration
} else {
duration - TE_SHORT
};
if diff <= REF_RESET_DELTA {
self.step = DecoderStep::Preamble2;
self.data_low = 0;
self.data_high = 0;
self.header_count = 0;
self.mid_count = 0;
self.bit_count = 0;
self.vag_type = VagType::Unknown;
self.te_last = duration;
self.manchester_advance(ManchesterEvent::Reset);
}
}
}
DecoderStep::Preamble1 => {
if level {
return None;
}
let te_diff = if duration > TE_SHORT_12 {
duration - TE_SHORT_12
} else {
TE_SHORT_12 - duration
};
if te_diff < TE_DELTA_12 {
// Check previous pulse
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 <= TE_DELTA_12 {
self.te_last = duration;
self.header_count += 1;
return None;
}
self.step = DecoderStep::Reset;
return None;
}
// Check for gap (end of preamble): 600µs ±79, te_last 300±79 (ref check_gap1)
if self.header_count >= 201 {
let gap_diff = if duration > TE_LONG_12 {
duration - TE_LONG_12
} else {
TE_LONG_12 - duration
};
if gap_diff <= REF_GAP1_DELTA {
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 {
self.step = DecoderStep::Data1;
return None;
}
}
}
self.step = DecoderStep::Reset;
}
DecoderStep::Data1 => {
if self.bit_count < 96 {
// Determine Manchester event
let short_diff = if duration > TE_SHORT_12 {
duration - TE_SHORT_12
} else {
TE_SHORT_12 - duration
};
let long_diff = if duration > TE_LONG_12 {
duration - TE_LONG_12
} else {
TE_LONG_12 - duration
};
let event = if short_diff <= TE_DELTA_12 {
Some(if level { ManchesterEvent::ShortLow } else { ManchesterEvent::ShortHigh })
} else if long_diff <= TE_DELTA_12 {
Some(if level { ManchesterEvent::LongLow } else { ManchesterEvent::LongHigh })
} else {
None
};
if let Some(evt) = event {
if let Some(bit_value) = self.manchester_advance(evt) {
self.push_bit(bit_value);
// Check for type identifier at bit 15
if self.bit_count == 15 {
if self.data_low == 0x2F3F && self.data_high == 0 {
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.vag_type = VagType::Type1;
} else if self.data_low == 0x2F1C && self.data_high == 0 {
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.vag_type = VagType::Type2;
}
} else if self.bit_count == 64 {
self.key1_low = !self.data_low;
self.key1_high = !self.data_high;
self.data_low = 0;
self.data_high = 0;
}
}
return None;
}
}
// End-of-data gap: 6000µs, accept within 4000µs (matches vag.c check_gap1_data)
if !level {
let gap_diff = if duration > 6000 {
duration - 6000
} else {
6000 - duration
};
if gap_diff < 4000 && self.bit_count == 80 {
self.key2_low = (!self.data_low) & 0xFFFF;
self.key2_high = 0;
self.data_count_bit = 80;
self.parse_data();
let result = self.build_decoded_signal();
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.step = DecoderStep::Reset;
return Some(result);
}
}
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.step = DecoderStep::Reset;
}
DecoderStep::Preamble2 => {
// Matches vag.c: LOW 500±80 and te_last 500±80 to count; then header_count>=41, HIGH 1000±79 and te_last 500±79 -> Sync2A
if !level {
let diff = if duration < TE_SHORT {
TE_SHORT - duration
} else {
duration - TE_SHORT
};
if diff < REF_PREAMBLE_SYNC {
let prev_diff = if self.te_last < TE_SHORT {
TE_SHORT - self.te_last
} else {
self.te_last - TE_SHORT
};
if prev_diff < REF_PREAMBLE_SYNC {
self.te_last = duration;
self.header_count += 1;
return None;
}
}
self.step = DecoderStep::Reset;
return None;
}
if self.header_count < 41 {
return None;
}
let diff = if duration < TE_LONG {
TE_LONG - duration
} else {
duration - TE_LONG
};
if diff > REF_RESET_DELTA {
return None;
}
let prev_diff = if self.te_last < TE_SHORT {
TE_SHORT - self.te_last
} else {
self.te_last - TE_SHORT
};
if prev_diff > REF_RESET_DELTA {
return None;
}
self.te_last = duration;
self.step = DecoderStep::Sync2A;
}
DecoderStep::Sync2A => {
// Matches vag.c: LOW 500±79 and te_last 1000±79 -> Sync2B (VAG_NEAR(..., 79))
if !level {
let diff = if duration < TE_SHORT {
TE_SHORT - duration
} else {
duration - TE_SHORT
};
if diff <= REF_SYNC2_AB_DELTA {
let prev_diff = if self.te_last < TE_LONG {
TE_LONG - self.te_last
} else {
self.te_last - TE_LONG
};
if prev_diff <= REF_SYNC2_AB_DELTA {
self.te_last = duration;
self.step = DecoderStep::Sync2B;
return None;
}
}
}
self.step = DecoderStep::Reset;
}
DecoderStep::Sync2B => {
// Matches vag.c: HIGH 750±79 -> Sync2C (VAG_NEAR(duration, 750, 79))
if level {
let diff = if duration < 750 {
750 - duration
} else {
duration - 750
};
if diff <= REF_SYNC2_AB_DELTA {
self.te_last = duration;
self.step = DecoderStep::Sync2C;
return None;
}
}
self.step = DecoderStep::Reset;
}
DecoderStep::Sync2C => {
// Matches vag.c: LOW 750±79 and te_last 750±79 (diff<=79), mid_count++; at 3 -> Data2
if !level {
let diff = if duration < 750 {
750 - duration
} else {
duration - 750
};
if diff <= REF_SYNC2C_DELTA {
let prev_diff = if self.te_last < 750 {
750 - self.te_last
} else {
self.te_last - 750
};
if prev_diff <= REF_SYNC2C_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;
}
}
}
self.step = DecoderStep::Reset;
}
DecoderStep::Data2 => {
// Matches vag.c: short 380-620µs, long 880-1120µs
let event = if duration >= 380 && duration <= 620 {
Some(if level { ManchesterEvent::ShortLow } else { ManchesterEvent::ShortHigh })
} else if duration >= 880 && duration <= 1120 {
Some(if level { ManchesterEvent::LongLow } else { ManchesterEvent::LongHigh })
} else {
None
};
if let Some(evt) = event {
if let Some(bit_value) = self.manchester_advance(evt) {
self.push_bit(bit_value);
if self.bit_count == 64 {
self.key1_low = self.data_low;
self.key1_high = self.data_high;
self.data_low = 0;
self.data_high = 0;
}
}
}
// Check for completion at 80 bits
if self.bit_count == 80 {
self.key2_low = self.data_low & 0xFFFF;
self.key2_high = 0;
self.data_count_bit = 80;
self.vag_type = VagType::Type3;
self.parse_data();
let result = self.build_decoded_signal();
self.data_low = 0;
self.data_high = 0;
self.bit_count = 0;
self.step = DecoderStep::Reset;
return Some(result);
}
}
}
None
}
fn supports_encoding(&self) -> bool {
true
}
fn encode(&self, decoded: &DecodedSignal, _button: u8) -> Option<Vec<LevelDuration>> {
self.encode_signal(decoded)
}
}
impl Default for VagDecoder {
fn default() -> Self {
Self::new()
}
}