Version 1.0.0
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user