infrared/protocol/denon/
mod.rs

1use 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
30/// Denon protocol
31pub 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}