1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use core::fmt::Debug;

use crate::{
    receiver::{
        time::{InfraMonotonic, PulseSpans},
        DecodingError,
    },
    Protocol,
};

/// Used to create a Decoder for a protocol
///
/// Handles the creation of the pulse spans for the protocol
pub trait DecoderFactory<Mono: InfraMonotonic>: Protocol {
    /// Type of the decoder
    type Decoder: ProtocolDecoder<Mono, Self::Cmd>;

    /// Create the decoder
    fn decoder(freq: u32) -> Self::Decoder;
}

/// Protocol decode state machine
pub trait ProtocolDecoder<Mono: InfraMonotonic, Cmd> {
    /// Notify the state machine of a new event
    /// * `edge`: true = positive edge, false = negative edge
    /// * `dt` : Duration since last event
    fn event(&mut self, edge: bool, dt: Mono::Duration) -> State;

    /// Get the command
    /// Returns the data if State == Done, otherwise None
    fn command(&self) -> Option<Cmd>;

    /// Reset the decoder
    fn reset(&mut self);

    /// Get the time spans
    fn spans(&self) -> &PulseSpans<Mono>;

    /// I don't care about the details, just give me a command (or an error)!
    fn event_total(
        &mut self,
        edge: bool,
        dt: Mono::Duration,
    ) -> Result<Option<Cmd>, DecodingError> {
        match self.event(edge, dt) {
            State::Idle | State::Receiving => Ok(None),
            State::Done => {
                let cmd = self.command();
                self.reset();
                Ok(cmd)
            }
            State::Error(err) => {
                self.reset();
                Err(err)
            }
        }
    }
}

#[derive(PartialEq, Eq, Copy, Clone, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Protocol decoder status
pub enum State {
    /// Idle
    Idle,
    /// Receiving data
    Receiving,
    /// Command successfully decoded
    Done,
    /// Error while decoding
    Error(DecodingError),
}