This commit is contained in:
leviathan
2026-02-13 22:00:42 -05:00
parent b306ff0574
commit 655f019469
35 changed files with 768 additions and 52 deletions
+24
View File
@@ -0,0 +1,24 @@
# KAT Protocol Documentation
This folder describes how each keyfob protocol supported by KAT works. Each document corresponds to a decoder/encoder in `src/protocols/`.
**Capture/encode model:** Decoded signals expose optional `extra` (e.g. VAG: vag_type + key_idx). When present, the app stores it in `Capture.data_extra` so retransmit can encode from the capture without decoder instance state. See [vag.md](vag.md) for the VAG encode-from-capture flow.
| Protocol | Rust module | Doc |
|----------|-------------|-----|
| Kia V0 | `kia_v0.rs` | [kia_v0.md](kia_v0.md) |
| Kia V1 | `kia_v1.rs` | [kia_v1.md](kia_v1.md) |
| Kia V2 | `kia_v2.rs` | [kia_v2.md](kia_v2.md) |
| Kia V3/V4 | `kia_v3_v4.rs` | [kia_v3_v4.md](kia_v3_v4.md) |
| Kia V5 | `kia_v5.rs` | [kia_v5.md](kia_v5.md) |
| Kia V6 | `kia_v6.rs` | [kia_v6.md](kia_v6.md) |
| Ford V0 | `ford_v0.rs` | [ford_v0.md](ford_v0.md) |
| Subaru | `subaru.rs` | [subaru.md](subaru.md) |
| VAG | `vag.rs` | [vag.md](vag.md) |
| Fiat V0 | `fiat_v0.rs` | [fiat_v0.md](fiat_v0.md) |
| Suzuki | `suzuki.rs` | [suzuki.md](suzuki.md) |
| Scher-Khan | `scher_khan.rs` | [scher_khan.md](scher_khan.md) |
| Star Line | `star_line.rs` | [star_line.md](star_line.md) |
| PSA | `psa.rs` | [psa.md](psa.md) |
Implementations are aligned with the ProtoPirate reference in `REFERENCES/ProtoPirate/protocols/`.
+40
View File
@@ -0,0 +1,40 @@
# Fiat V0 Protocol
**Rust module:** `src/protocols/fiat_v0.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/fiat_v0.c` (older reference)
## Overview
Fiat V0 uses differential Manchester. Preamble: count short pulses (HIGH or LOW, 200 µs ±100); when count ≥ 150 (0x96), accept 800 µs LOW gap and enter Data. Data: 64 bits (serial = data_low, cnt = data_high) then 7 more bits; complete when bit_count > 0x46 with btn = (data_low << 1) | 1; 71 bits total. Encoder: 150 preamble pairs, last LOW = 800 µs gap; 64 data bits then 6 button bits (btn >> 1); end marker te_short×8 LOW.
## Timing
| Parameter | Value | Notes |
|------------|--------|--------------|
| Short | 200 µs | ±100 µs |
| Long | 400 µs | ±100 µs |
| Preamble | ≥150 short pulses | |
| Gap | 800 µs | ±100 µs |
| Min bits | 71 | |
## Encoding
Differential Manchester; 6 button bits sent as btn >> 1; end marker 200×8 µs LOW.
## Frame Layout (71 bits)
- 64 bits: serial (data_low), counter (data_high).
- 7 bits more; button = (data_low << 1) | 1 (decoded).
## Decoder Steps
1. **Reset** — Count short (200 µs) HIGH or LOW; when count ≥ 150 and LOW gap ~800 µs → Data.
2. **Data** — Manchester decode; at > 0x46 bits set btn = (data_low << 1) | 1, return 71-bit decode.
## Encoder
Supported; 3 bursts, 25 ms inter-burst gap; 150 preamble pairs; 800 µs gap; 64 + 6 button bits; end marker.
## Frequencies
433.92 MHz.
+44
View File
@@ -0,0 +1,44 @@
# Ford V0 Protocol
**Rust module:** `src/protocols/ford_v0.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/ford_v0.c`
## Overview
Ford V0 uses Manchester encoding at 250/500 µs. 80 bits total: 64-bit key1 + 16-bit key2. CRC is computed via GF(2) matrix multiplication (CRC matrix in code). BS (byte) and “BS magic” are used for encoding and validation. 6 bursts; 4 preamble pairs per burst; 3500 µs gap before data. Flipper-style Manchester: level true → ShortLow/LongLow, level false → ShortHigh/LongHigh.
## Timing
| Parameter | Value | Notes |
|------------|--------|--------------------|
| Short | 250 µs | ±100 µs (te_delta) |
| Long | 500 µs | ±100 µs |
| Gap | 3500 µs| ±250 µs |
| Min bits | 64 | (key1); 80 total |
## Encoding
Manchester: short/low, short/high, long/low, long/high map to events 03; state machine emits data bits. First bit after gap is implicit 1; then 79 more bits from Manchester (64 for key1, 16 for key2). key1/key2 sent inverted (~key1, ~key2).
## Frame Layout (80 bits)
- **key1 (64 bits):** header byte, serial, button, counter, XOR/parity and mixed nibbles (see decode_ford_v0 in code).
- **key2 (16 bits):** BS (high byte), CRC (low byte) XOR 0x80.
CRC is matrix-based over key1 bytes and BS byte; received CRC is key2 low byte XOR 0x80.
## Decoder Steps
1. **Reset** — Short HIGH (250 µs) or long HIGH (500 µs) → Preamble (allows re-sync mid-preamble).
2. **Preamble** — LOW long (500 µs) → PreambleCheck.
3. **PreambleCheck** — HIGH long → header_count++, back to Preamble; HIGH short → Gap.
4. **Gap** — LOW ~3500 µs (±250) → Data, set first bit to 1, bit_count=1.
5. **Data** — Manchester events (short/long × level); add_bit (two 64-bit registers, C-style); at 64 bits form key1 = ~combined, clear; at 80 bits key2 = ~low 16, decode_ford_v0, verify CRC, return.
## Encoder
Supported. Builds 6 bursts: short-long, 4 preamble pairs, short-long, gap, then Manchester 80 bits (key1 then key2, inverted). Inter-burst gap long×100.
## Frequencies
315 MHz, 433.92 MHz.
+45
View File
@@ -0,0 +1,45 @@
# Kia V0 Protocol
**Rust module:** `src/protocols/kia_v0.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/kia_v0.c`
## Overview
Kia V0 is a PWM keyfob protocol: short pulse = 0, long pulse = 1. No Manchester encoding. 61 bits per frame (1 sync bit + 60 data bits). CRC8 over bits 855; polynomial 0x7F, init 0x00.
## Timing
| Parameter | Value | Notes |
|------------|--------|--------------------|
| Short (0) | 250 µs | ±100 µs (te_delta) |
| Long (1) | 500 µs | ±100 µs |
| Min bits | 61 | |
## Frame Layout (61 bits)
- **Sync:** 1 bit (the long-long pattern also counts as first data bit = 1).
- **Data:** 60 bits MSB first:
- Bits 5659: 4-bit prefix (often preserved from capture).
- Bits 4055: 16-bit counter.
- Bits 1239: 28-bit serial.
- Bits 811: 4-bit button.
- Bits 07: 8-bit CRC (over bits 855, 6 bytes).
## Decoder Steps
1. **Reset** — Wait for short HIGH (250 µs ±100).
2. **CheckPreamble** — Count preamble: alternating short pulses; on LOW, if shortshort pair then `header_count++`; if longlong and `header_count > 15` → go to SaveDuration, add first bit 1.
3. **SaveDuration** — On HIGH: if duration ≥ 500 + 200 µs (end marker), check `decode_count_bit == 61` and return decode; else store duration and go to CheckDuration. On LOW → Reset.
4. **CheckDuration** — On LOW: shortshort → add bit 0, back to SaveDuration; longlong → add bit 1, back to SaveDuration; else Reset.
## Encoder
- 2 bursts; inter-burst gap 25000 µs.
- 32 alternating short (250 µs) preamble pairs.
- Sync: long HIGH, long LOW (500 µs each).
- Data: 59 bits sent (mask 1ULL << (58 - bit_num)), i.e. bits 58 down to 0 (per reference).
- End marker: long × 2 (1000 µs HIGH).
## Frequencies
433.92 MHz.
+41
View File
@@ -0,0 +1,41 @@
# Kia V1 Protocol
**Rust module:** `src/protocols/kia_v1.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/kia_v1.c`
## Overview
Kia V1 uses Manchester encoding at 800/1600 µs. 57 bits total: 32 serial + 8 button + 12 counter + 4 CRC. Long preamble (~90 long pairs). CRC4 with offset rules (cnt_high 0 vs ≥ 6).
## Timing
| Parameter | Value | Notes |
|-----------|---------|---------|
| Short | 800 µs | ±200 µs |
| Long | 1600 µs | ±200 µs |
| Min bits | 57 | |
## Encoding
Manchester: symbol duration short or long; bit value from transition direction.
## Frame Layout (57 bits)
- 32 bits: serial
- 8 bits: button
- 12 bits: counter
- 4 bits: CRC4 (checksum with offset rules)
## Decoder Steps
1. **Reset** — Wait for long pulse (preamble).
2. **CheckPreamble** — Count long pairs until enough; then transition to data.
3. **DecodeData** — Manchester decode; at 57 bits validate CRC4 and return.
## Encoder
Supported; builds preamble and Manchester-encoded 57-bit frame.
## Frequencies
433.92 MHz.
+38
View File
@@ -0,0 +1,38 @@
# Kia V2 Protocol
**Rust module:** `src/protocols/kia_v2.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/kia_v2.c`
## Overview
Kia V2 uses Manchester encoding at 500/1000 µs. 53 bits: 32 serial + 4 button + 12 counter + 4 CRC, plus start bit. Long preamble of 252 long pairs. CRC4 (XOR nibbles + offset 1).
## Timing
| Parameter | Value | Notes |
|-----------|---------|---------|
| Short | 500 µs | ±150 µs |
| Long | 1000 µs | ±150 µs |
| Min bits | 53 | |
## Encoding
Manchester encoding; bit value from short/long and transition.
## Frame Layout (53 bits)
- Start bit + 32 serial + 4 button + 12 counter (byte-swapped) + 4 CRC.
## Decoder Steps
1. **Reset** — Wait for preamble (long pulses).
2. **CheckPreamble** — Count 252 long pairs.
3. **CollectRawBits** — Manchester decode; at 53 bits validate CRC4 and return.
## Encoder
Supported; preamble and Manchester 53-bit frame.
## Frequencies
433.92 MHz.
+42
View File
@@ -0,0 +1,42 @@
# Kia V3/V4 Protocol
**Rust module:** `src/protocols/kia_v3_v4.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/kia_v3_v4.c`
## Overview
Kia V3 and V4 use PWM (short = 0, long = 1) with KeeLoq encryption. 68 bits: 8 bytes encrypted + 4 bits CRC. Short preamble of 16 pairs; sync 1200 µs (V4: long HIGH, V3: long LOW). KeeLoq uses the KIA manufacturer key from the keystore (type 10).
## Timing
| Parameter | Value | Notes |
|------------|---------|---------|
| Short (0) | 400 µs | ±150 µs |
| Long (1) | 800 µs | ±150 µs |
| Sync | 1200 µs | |
| Min bits | 68 | |
## Frame Layout (68 bits)
- Preamble: 16 short/long pairs.
- Sync: 1200 µs (polarity distinguishes V3 vs V4).
- 64 raw bits (8 bytes) then 4 CRC bits.
- 64 bits are KeeLoq-encrypted; decrypt with KIA MF key to get serial/button/counter.
## Decoder Steps
1. **Reset** — Wait for preamble.
2. **CheckPreamble** — Count 16 pairs; detect sync polarity (V3 vs V4).
3. **CollectRawBits** — Collect 68 bits (64 + 4 CRC); KeeLoq-decrypt 64 bits, validate CRC4, extract fields.
## Encoder
Supported; 3 bursts, 10 s inter-burst gap; preamble, sync, encrypted payload + CRC.
## Frequencies
433.92 MHz.
## Keystore
Requires KIA manufacturer key (keystore type 10, `kia_mf_key`). Loaded from embedded blob or keystore.ini.
+43
View File
@@ -0,0 +1,43 @@
# Kia V5 Protocol
**Rust module:** `src/protocols/kia_v5.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/kia_v5.c`
## Overview
Kia V5 uses Manchester encoding at 400/800 µs with **opposite polarity** to V1/V2: level true → ShortHigh, level false → ShortLow. 64 data bits + 3-bit CRC (67 bits on air). Preamble: 40+ short/long pairs; then LONG HIGH (sync), SHORT LOW (alignment), then Manchester data. Counter is encrypted with a custom mixer cipher using the KIA V5 key (YEK); serial/button from YEK.
## Timing
| Parameter | Value | Notes |
|-----------|--------|---------|
| Short | 400 µs | ±150 µs |
| Long | 800 µs | ±150 µs |
| Min bits | 64 | (+ 3 CRC) |
## Encoding
Manchester with V5 polarity (level ? ShortHigh : ShortLow).
## Frame Layout
- Preamble (40+ pairs) → sync (long HIGH) → alignment (short LOW) → 64 Manchester bits → 3 CRC bits.
- 64-bit key (YEK) = bit-reverse of stored value; serial/button/counter extracted from YEK; counter half is mixer-decrypted with keystore V5 key.
## Decoder Steps
1. **Reset** — Wait for preamble.
2. **CheckPreamble** — Count pairs; detect sync and alignment.
3. **Data** — Manchester decode 67 bits; extract YEK, mixer-decode counter, validate CRC.
## Encoder
Decode-only in KAT (reference has encoder under ENABLE_EMULATE_FEATURE).
## Frequencies
433.92 MHz.
## Keystore
Requires KIA V5 mixer key (keystore type 13, `kia_v5_key`). Used for mixer decryption of counter.
+47
View File
@@ -0,0 +1,47 @@
# Kia V6 Protocol
**Rust module:** `src/protocols/kia_v6.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/kia_v6.c`
## Overview
Kia V6 uses Manchester encoding at 200/400 µs (level convention inverted vs Flipper). 144 bits in three parts: part1 (64) + part2 (64) + part3 (16); each part stored inverted. Long preamble of 601 pairs; sync bits 1,1,0,1 then data. AES-128 decryption with key derived from KIA V6 A and B keystores (types 11 and 12) and XOR masks.
## Timing
| Parameter | Value | Notes |
|-----------|--------|---------|
| Short | 200 µs | ±100 µs |
| Long | 400 µs | ±100 µs |
| Preamble | 601 pairs | |
| Min bits | 144 | |
## Encoding
Manchester (event mapping 0/2/4/6 for level convention). Three 64/64/16-bit segments, each inverted when stored.
## Frame Layout (144 bits)
- Part1: 64 bits (inverted)
- Part2: 64 bits (inverted)
- Part3: 16 bits (inverted)
AES-128 decrypt with key = f(keystore_a, keystore_b, XOR_MASK_LOW, XOR_MASK_HIGH). Serial/button/counter and CRC extracted after decryption.
## Decoder Steps
1. **Reset** — Wait for preamble.
2. **CheckPreamble** — Count 601 pairs; detect sync pattern 1,1,0,1.
3. **Data** — Manchester decode 144 bits; invert segments; AES-128 decrypt; validate CRC8; return fields.
## Encoder
Decode-only in KAT (no encoder in reference).
## Frequencies
433.92 MHz.
## Keystore
Requires KIA V6 A and B keys (keystore types 11 and 12: `kia_v6_a_key`, `kia_v6_b_key`). XOR masks applied to derive AES key.
+44
View File
@@ -0,0 +1,44 @@
# PSA (Peugeot/Citroën) Protocol
**Rust module:** `src/protocols/psa.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/psa.c`
## Overview
PSA uses Manchester at 250/500 µs symbol (125/250 µs sub-symbol for preamble). 128 bits total: key1 (64) + validation (16) + key2/rest (48); decode uses key1 + 16-bit validation. TEA decrypt/encrypt with fixed key schedules; mode 0x23 adds an XOR layer. Two modes: seed 0x23 (TEA + XOR), seed 0xF3/0x36 (TEA, BF2 key schedule).
## Timing
| Parameter | Value | Notes |
|------------|--------|---------|
| Symbol short | 250 µs | ±100 µs |
| Symbol long | 500 µs | ±100 µs |
| Preamble | 125/250 µs sub-symbols | |
| Min bits | 128 | |
## Encoding
Manchester; preamble uses 125/250 µs; then 250/500 µs symbols. TEA encrypt; mode 0x23 adds XOR.
## Frame Layout (128 bits)
- key1: 64 bits
- validation: 16 bits
- key2/rest: 48 bits
TEA decrypt key1 (and validation); mode 0x23: XOR with BF1 key schedule; mode 0x36: TEA with BF2 key schedule. Serial/button/counter extracted from decrypted key1.
## Decoder Steps
1. **WaitEdge** — Wait for edge/preamble.
2. **CountPattern** — Count preamble pattern (125/250 µs).
3. **DecodeManchester** — Manchester decode 128 bits; TEA decrypt; apply mode (0x23 XOR or 0x36); extract fields.
4. **End** — End marker (e.g. 1000 µs); return decode.
## Encoder
Supported; preamble, Manchester 128 bits, TEA (+ XOR for 0x23).
## Frequencies
433.92 MHz.
+40
View File
@@ -0,0 +1,40 @@
# Scher-Khan Protocol
**Rust module:** `src/protocols/scher_khan.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/scher_khan.c`
## Overview
Scher-Khan is decode-only. PWM: 750 µs = 0, 1100 µs = 1; preamble uses 2× short then alternating. Variable bit count (35, 51, 57, 63, 64, 81, 82); only 51-bit format is parsed for serial/button/counter. Reference: phreakerclub.com/72.
## Timing
| Parameter | Value | Notes |
|-----------|---------|---------|
| Short (0) | 750 µs | ±160 µs |
| Long (1) | 1100 µs| ±160 µs |
| Min bits | 35 | (variable) |
## Encoding
PWM; preamble: two short then alternating short/long.
## Frame Layout (variable)
- **51-bit format:** serial (28) | button (4) | counter (16) — “MAGIC CODE” / Dynamic; parsed for serial/btn/cnt.
- Other lengths (35, 57, 63, 64, 81, 82) decoded as raw bit count but not field-parsed.
## Decoder Steps
1. **Reset** — Wait for preamble (2 short + alternating).
2. **CheckPreamble** — Confirm preamble pattern.
3. **SaveDuration** — Store pulse duration.
4. **CheckDuration** — Shortshort = 0, longlong = 1 (or equivalent); add bit; on end marker, if bit_count in {35,51,57,63,64,81,82} return decode (51-bit parsed for fields).
## Encoder
Not implemented (no encoder in reference).
## Frequencies
433.92 MHz.
+45
View File
@@ -0,0 +1,45 @@
# Star Line Protocol
**Rust module:** `src/protocols/star_line.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/star_line.c`
## Overview
Star Line uses PWM: 250 µs = 0, 500 µs = 1. 64 bits: key_fix (32) + key_hop (32), sent MSB-first (reversed on air). Header: 6 pairs of 1000 µs HIGH + 1000 µs LOW. KeeLoq: fix = serial(24) + button(8); hop encrypted with manufacturer key or normal-learning derived key.
## Timing
| Parameter | Value | Notes |
|-----------|---------|---------|
| Short (0) | 250 µs | ±120 µs |
| Long (1) | 500 µs | ±120 µs |
| Header | 1000 µs × 2 (6 pairs) | |
| Min bits | 64 | |
## Encoding
PWM; 64 bits MSB-first (reversed on air). KeeLoq encrypt for hop; fix half plain.
## Frame Layout (64 bits)
- **key_fix (32 bits):** serial (24) + button (8).
- **key_hop (32 bits):** KeeLoq-encrypted rolling code (MF key or normal-learning key).
## Decoder Steps
1. **Reset** — Wait for header (6 × 1000 µs HIGH, 1000 µs LOW).
2. **CheckPreamble** — Confirm 6 header pairs.
3. **SaveDuration** — Store duration.
4. **CheckDuration** — Shortshort = 0, longlong = 1; at 64 bits KeeLoq-decrypt hop (or normal-learning), extract serial/button/counter, return.
## Encoder
Supported; header, 64-bit fix+hop (KeeLoq encrypt hop with MF or derived key).
## Frequencies
433.92 MHz.
## Keystore
Star Line manufacturer key (keystore type 20, `star_line_mf_key`). Used for KeeLoq hop decryption and normal-learning derivation.
+43
View File
@@ -0,0 +1,43 @@
# Subaru Protocol
**Rust module:** `src/protocols/subaru.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/subaru.c`
## Overview
Subaru uses PWM: 800 µs HIGH = 1, 1600 µs HIGH = 0; LOW is 800 µs after each bit. 64 bits total (8 bytes MSB first: button(4) + serial(24) + counter-related). Preamble: 79 full 1600 µs pairs + 80th HIGH only; then gap 2800 µs, sync 2800 µs HIGH + 1600 µs LOW. Complex counter decoding from bytes 47.
## Timing
| Parameter | Value | Notes |
|-----------|---------|---------|
| Short (1) | 800 µs | ±200 µs |
| Long (0) | 1600 µs | ±200 µs |
| Gap | 2800 µs | |
| Sync | 2800 µs HIGH + 1600 µs LOW | |
| Min bits | 64 | |
## Encoding
PWM: duration of HIGH = bit value (800 = 1, 1600 = 0); LOW 800 µs after each bit.
## Frame Layout (64 bits = 8 bytes)
- 4 bits button, 24 bits serial, counter-related in bytes 47 (decode_counter in code).
## Decoder Steps
1. **Reset** — Wait for long HIGH (preamble).
2. **CheckPreamble** — Count 79 long pairs + 80th HIGH; then expect gap 2800 µs.
3. **FoundGap** — Gap seen → look for sync (2800 HIGH, 1600 LOW).
4. **FoundSync** — Sync seen → SaveDuration.
5. **SaveDuration** — On HIGH: store duration, → CheckDuration. On end marker → return decode if 64 bits.
6. **CheckDuration** — On LOW: pair (te_last, duration) → shortshort = 1, longlong = 0; add bit, → SaveDuration.
## Encoder
Supported; builds preamble, gap, sync, then 64 PWM bits.
## Frequencies
433.92 MHz (and/or 315 MHz as in reference).
+42
View File
@@ -0,0 +1,42 @@
# Suzuki Protocol
**Rust module:** `src/protocols/suzuki.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/suzuki.c`
## Overview
Suzuki uses PWM: 250 µs HIGH = 0, 500 µs HIGH = 1; LOW 250 µs after each bit. 64 bits total. Preamble: 350 short HIGH / short LOW pairs; 2000 µs gap at end. Field layout: serial = (data_high&0xFFF)<<16 | data_low>>16; btn = (data_low>>12)&0xF; cnt = (data_high<<4)>>16.
## Timing
| Parameter | Value | Notes |
|------------|---------|---------|
| Short (0) | 250 µs | ±99 µs |
| Long (1) | 500 µs | ±99 µs |
| Preamble | 350 pairs | |
| Gap | 2000 µs | ±399 µs |
| Min bits | 64 | |
## Encoding
PWM: 250 µs HIGH = 0, 500 µs HIGH = 1; LOW 250 µs after each bit.
## Frame Layout (64 bits)
- serial: (data_high & 0xFFF) << 16 | data_low >> 16
- button: (data_low >> 12) & 0xF
- counter: (data_high << 4) >> 16
## Decoder Steps
1. **Reset** — Wait for short pulse (preamble).
2. **CountPreamble** — Count 350 short pairs; on 2000 µs gap → DecodeData.
3. **DecodeData** — Short = 0, long = 1; at 64 bits parse fields and return.
## Encoder
Supported; 350 preamble pairs, gap, 64 PWM bits.
## Frequencies
433.92 MHz.
+43
View File
@@ -0,0 +1,43 @@
# VAG (VW/Audi/Seat/Skoda) Protocol
**Rust module:** `src/protocols/vag.rs`
**Reference:** `REFERENCES/ProtoPirate/protocols/vag.c`
## Overview
VAG supports multiple types (1, 2, 3, 4) with different timing and encryption. 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. Type 1/2 use AUT64 or TEA decryption; type 3/4 use AUT64. Button names: Unlock, Lock, Boot. Keys loaded from keystore (VAG raw 64 bytes = 4×16-byte AUT64 keys; lookup by index 1, 2, 3). **Decode and encode** are both supported; encode uses capture data plus stored vag_type/key_idx.
## Timing
- **Type 1/2:** 300 µs short, 600 µs long, ±79/80; Preamble1→Data1 gap 600 µs ±79; end-of-data gap < 4000 µs.
- **Type 3/4:** 500 µs short, 1000 µs long, ±80; Preamble2 count 500±80; Sync2A 500/1000 µs ±79; Sync2B/Sync2C 750 µs ±79; Data2 short 500±120, long 1000±120.
## Encoding
Manchester; type-dependent short/long and sync sequences. Encoder builds the waveform from **decoded capture data** (serial, button, counter, key1) plus **protocol extra** (vag_type, key_idx) so retransmit works after decoder reset.
## Frame Layout (80 bits)
- **key1 (64 bits)** + **key2 (16 bits)**. Dispatch byte in key2; key index for AUT64 (type 1/2). Type 3/4: AUT64 decrypt.
## Decoder Steps
1. **Reset** — 300 µs or 500 µs (type-dependent) → Preamble1 or Preamble2.
2. **Preamble1** — Count; gap 600 µs → Data1. **Data1** — Manchester; 80 bits; parse type 1/2 (AUT64 or TEA).
3. **Preamble2** — Count 500 µs pulses; Sync2A (500/1000) → Sync2B (750) → Sync2C (750) → Data2. **Data2** — Manchester 80 bits; AUT64 decrypt (type 3/4).
Parse (vag_parse_data): dispatch 0x2A/0x1C/0x46 and 0x2B/0x1D/0x47; try AUT64 with key index 0,1,2; or TEA for type 2.
## Encoder (encode from capture)
- **Supports encoding:** protocol reports `true`; TX Lock/Unlock/Trunk available when the capture has encoder data.
- **Stored state:** On successful decrypt, the decoder sets `DecodedSignal.extra = Some(vag_type | (key_idx << 8))`. The app copies this to `Capture.data_extra`. Without `data_extra` (e.g. old import or undecrypted capture), encode returns `None`.
- **Encode path:** `encode_signal(decoded)` uses `decoded.serial`, `decoded.button`, `decoded.counter`, `decoded.data` (key1 / type_byte), and `decoded.extra` (vag_type, key_idx) to build type 1, 2, or 3/4 waveform. No decoder instance state is used so retransmit works after reset.
## Frequencies
433.92 MHz, 434.42 MHz.
## Keystore
VAG AUT64 keys: 4×16-byte packed keys from embedded blob (“VAG ” + 64 bytes) or file. Lookup by `get_vag_key((key_index+1) as u8)` (index 1, 2, 3).