Version 1.0.0

This commit is contained in:
leviathan
2026-02-07 17:35:27 -05:00
parent c8bff9afd7
commit 4339895b41
43 changed files with 12218 additions and 3 deletions
+201
View File
@@ -0,0 +1,201 @@
//! Scher-Khan protocol decoder
//!
//! Ported from protopirate's scher_khan.c
//!
//! Protocol characteristics:
//! - PWM encoding: 750/1100µs timing
//! - Variable bit count (35, 51, 57, 63, 64, 81, 82)
//! - Decode-only (no encoder)
//!
//! References:
//! - https://phreakerclub.com/72
use super::{DecodedSignal, ProtocolDecoder, ProtocolTiming};
use crate::duration_diff;
use crate::radio::demodulator::LevelDuration;
const TE_SHORT: u32 = 750;
const TE_LONG: u32 = 1100;
const TE_DELTA: u32 = 160;
const MIN_COUNT_BIT: usize = 35;
/// Decoder states
#[derive(Debug, Clone, Copy, PartialEq)]
enum DecoderStep {
Reset,
CheckPreamble,
SaveDuration,
CheckDuration,
}
/// Scher-Khan protocol decoder
pub struct ScherKhanDecoder {
step: DecoderStep,
te_last: u32,
header_count: u16,
decode_data: u64,
decode_count_bit: usize,
}
impl ScherKhanDecoder {
pub fn new() -> Self {
Self {
step: DecoderStep::Reset,
te_last: 0,
header_count: 0,
decode_data: 0,
decode_count_bit: 0,
}
}
fn parse_data(data: u64, bit_count: usize) -> DecodedSignal {
let (serial, btn, cnt) = match bit_count {
51 => {
// MAGIC CODE, Dynamic
let serial =
((data >> 24) & 0xFFFFFF0) as u32 | ((data >> 20) & 0x0F) as u32;
let btn = ((data >> 24) & 0x0F) as u8;
let cnt = (data & 0xFFFF) as u16;
(Some(serial), Some(btn), Some(cnt))
}
_ => (None, None, None),
};
DecodedSignal {
serial,
button: btn,
counter: cnt,
crc_valid: true,
data,
data_count_bit: bit_count,
encoder_capable: false,
}
}
}
impl ProtocolDecoder for ScherKhanDecoder {
fn name(&self) -> &'static str {
"Scher-Khan"
}
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]
}
fn reset(&mut self) {
self.step = DecoderStep::Reset;
self.te_last = 0;
self.header_count = 0;
self.decode_data = 0;
self.decode_count_bit = 0;
}
fn feed(&mut self, level: bool, duration: u32) -> Option<DecodedSignal> {
match self.step {
DecoderStep::Reset => {
if level && duration_diff!(duration, TE_SHORT * 2) < TE_DELTA {
self.step = DecoderStep::CheckPreamble;
self.te_last = duration;
self.header_count = 0;
}
}
DecoderStep::CheckPreamble => {
if level {
if duration_diff!(duration, TE_SHORT * 2) < TE_DELTA
|| duration_diff!(duration, TE_SHORT) < TE_DELTA
{
self.te_last = duration;
} else {
self.step = DecoderStep::Reset;
}
} else if duration_diff!(duration, TE_SHORT * 2) < TE_DELTA
|| duration_diff!(duration, TE_SHORT) < TE_DELTA
{
if duration_diff!(self.te_last, TE_SHORT * 2) < TE_DELTA {
self.header_count += 1;
} else if duration_diff!(self.te_last, TE_SHORT) < TE_DELTA {
// Found start bit
if self.header_count >= 2 {
self.step = DecoderStep::SaveDuration;
self.decode_data = 0;
self.decode_count_bit = 1;
} else {
self.step = DecoderStep::Reset;
}
} else {
self.step = DecoderStep::Reset;
}
} else {
self.step = DecoderStep::Reset;
}
}
DecoderStep::SaveDuration => {
if level {
if duration >= (TE_DELTA * 2 + TE_LONG) {
// Found stop bit
self.step = DecoderStep::Reset;
if self.decode_count_bit >= MIN_COUNT_BIT {
let result =
Self::parse_data(self.decode_data, self.decode_count_bit);
self.decode_data = 0;
self.decode_count_bit = 0;
return Some(result);
}
self.decode_data = 0;
self.decode_count_bit = 0;
} else {
self.te_last = duration;
self.step = DecoderStep::CheckDuration;
}
} else {
self.step = DecoderStep::Reset;
}
}
DecoderStep::CheckDuration => {
if !level {
if duration_diff!(self.te_last, TE_SHORT) < TE_DELTA
&& duration_diff!(duration, TE_SHORT) < TE_DELTA
{
// Bit 0
self.decode_data = (self.decode_data << 1) | 0;
self.decode_count_bit += 1;
self.step = DecoderStep::SaveDuration;
} else if duration_diff!(self.te_last, TE_LONG) < TE_DELTA
&& duration_diff!(duration, TE_LONG) < TE_DELTA
{
// Bit 1
self.decode_data = (self.decode_data << 1) | 1;
self.decode_count_bit += 1;
self.step = DecoderStep::SaveDuration;
} else {
self.step = DecoderStep::Reset;
}
} else {
self.step = DecoderStep::Reset;
}
}
}
None
}
fn supports_encoding(&self) -> bool {
false
}
fn encode(&self, _decoded: &DecodedSignal, _button: u8) -> Option<Vec<LevelDuration>> {
None
}
}