infrared/protocol/denon/
mod.rs1use crate::{
2 protocol::Protocol,
3 receiver::{
4 time::{InfraMonotonic, PulseSpans},
5 DecoderFactory, ProtocolDecoder, State,
6 },
7};
8
9#[cfg(test)]
10mod test;
11
12const HEADER_HIGH: u32 = 3400;
13const HEADER_LOW: u32 = 1600;
14const DATA_HIGH: u32 = 480;
15const ZERO_LOW: u32 = 360;
16const ONE_LOW: u32 = 1200;
17const PULSE: [u32; 8] = [
18 (HEADER_HIGH + HEADER_LOW),
19 (DATA_HIGH + ZERO_LOW),
20 (DATA_HIGH + ONE_LOW),
21 0,
22 0,
23 0,
24 0,
25 0,
26];
27
28const TOL: [u32; 8] = [8, 10, 10, 0, 0, 0, 0, 0];
29
30pub struct Denon;
32
33impl Protocol for Denon {
34 type Cmd = DenonCommand;
35}
36
37impl<Mono: InfraMonotonic> DecoderFactory<Mono> for Denon {
38 type Decoder = DenonDecoder<Mono>;
39
40 fn decoder(freq: u32) -> Self::Decoder {
41 DenonDecoder {
42 state: DenonState::Idle,
43 buf: 0,
44 dt_save: Mono::ZERO_DURATION,
45 spans: PulseSpans::new(freq, &PULSE, &TOL),
46 }
47 }
48}
49
50pub struct DenonDecoder<Mono: InfraMonotonic> {
51 state: DenonState,
52 buf: u64,
53 dt_save: Mono::Duration,
54 spans: PulseSpans<Mono>,
55}
56
57#[derive(Debug)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub struct DenonCommand {
60 pub bits: u64,
61}
62
63impl<Mono: InfraMonotonic> ProtocolDecoder<Mono, DenonCommand> for DenonDecoder<Mono> {
64 #[rustfmt::skip]
65 fn event(&mut self, rising: bool, dt: Mono::Duration) -> State {
66
67 if rising {
68 let pulsewidth = self.spans.get::<PulseWidth>( self.dt_save + dt)
69 .unwrap_or(PulseWidth::Fail);
70
71 self.state = match (self.state, pulsewidth) {
72 (DenonState::Idle, PulseWidth::Sync) => DenonState::Data(0),
73 (DenonState::Idle, _) => DenonState::Idle,
74 (DenonState::Data(47), PulseWidth::Zero) => DenonState::Done,
75 (DenonState::Data(47), PulseWidth::One) => DenonState::Done,
76 (DenonState::Data(idx), PulseWidth::Zero) => DenonState::Data(idx + 1),
77 (DenonState::Data(idx), PulseWidth::One) => { self.buf |= 1 << idx; DenonState::Data(idx + 1) }
78 (DenonState::Data(_ix), _) => DenonState::Idle,
79 (DenonState::Done, _) => DenonState::Done,
80 };
81
82 self.dt_save = Mono::ZERO_DURATION;
83 } else {
84 self.dt_save = dt;
85 }
86
87 self.state.into()
88 }
89
90 fn command(&self) -> Option<DenonCommand> {
91 if self.state == DenonState::Done {
92 Some(DenonCommand { bits: self.buf })
93 } else {
94 None
95 }
96 }
97 fn reset(&mut self) {
98 self.state = DenonState::Idle;
99 self.buf = 0;
100 self.dt_save = Mono::ZERO_DURATION;
101 }
102
103 fn spans(&self) -> &PulseSpans<Mono> {
104 &self.spans
105 }
106}
107
108#[derive(Copy, Clone, Debug, PartialEq, Eq)]
109#[cfg_attr(feature = "defmt", derive(defmt::Format))]
110pub enum DenonState {
111 Idle,
112 Data(u8),
113 Done,
114}
115
116impl From<DenonState> for State {
117 fn from(status: DenonState) -> Self {
118 match status {
119 DenonState::Idle => State::Idle,
120 DenonState::Data(_) => State::Receiving,
121 DenonState::Done => State::Done,
122 }
123 }
124}
125
126#[derive(Debug)]
127#[cfg_attr(feature = "defmt", derive(defmt::Format))]
128enum PulseWidth {
129 Sync,
130 Zero,
131 One,
132 Fail,
133}
134
135impl From<usize> for PulseWidth {
136 fn from(value: usize) -> Self {
137 match value {
138 0 => PulseWidth::Sync,
139 1 => PulseWidth::Zero,
140 2 => PulseWidth::One,
141 _ => PulseWidth::Fail,
142 }
143 }
144}