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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#![cfg_attr(not(test), no_std)]

#[cfg(feature = "std")]
extern crate std;

// This mod MUST go first, so that the others see its macros.
pub(crate) mod fmt;

mod client;
mod eventloop;
mod options;
mod packet;
mod state;

pub use bbqueue;

pub use client::Client;
use core::convert::TryFrom;
pub use eventloop::EventLoop;
use heapless::{String, Vec};
pub use mqttrust::encoding::v4::{Pid, Publish, QoS, QosPid, Suback};
pub use mqttrust::*;
pub use options::{Broker, MqttOptions};
use state::StateError;

#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt-impl", derive(defmt::Format))]
pub struct PublishNotification {
    pub dup: bool,
    pub qospid: QoS,
    pub retain: bool,
    pub topic_name: String<256>,
    pub payload: Vec<u8, 4096>,
}

/// Includes incoming packets from the network and other interesting events
/// happening in the eventloop
#[derive(Debug, PartialEq)]
// #[cfg_attr(feature = "defmt-impl", derive(defmt::Format))]
pub enum Notification {
    /// Incoming connection acknowledge
    ConnAck,
    /// Incoming publish from the broker
    #[cfg(not(feature = "std"))]
    Publish(heapless::pool::singleton::Box<state::BoxedPublish, heapless::pool::Init>),
    #[cfg(feature = "std")]
    Publish(std::boxed::Box<PublishNotification>),
    /// Incoming puback from the broker
    Puback(Pid),
    /// Incoming pubrec from the broker
    Pubrec(Pid),
    /// Incoming pubcomp from the broker
    Pubcomp(Pid),
    // TODO:
    // Suback(Suback),
    /// Incoming suback from the broker
    Suback(Pid),
    /// Incoming unsuback from the broker
    Unsuback(Pid),
    // Eventloop error
    Abort(EventError),
}

impl<'a> TryFrom<Publish<'a>> for PublishNotification {
    type Error = StateError;

    fn try_from(p: Publish<'a>) -> Result<Self, Self::Error> {
        Ok(PublishNotification {
            dup: p.dup,
            qospid: p.qos,
            retain: p.retain,
            topic_name: String::from(p.topic_name),
            payload: Vec::from_slice(p.payload).map_err(|_| {
                error!("Failed to convert payload to notification!");
                StateError::PayloadEncoding
            })?,
        })
    }
}

/// Critical errors during eventloop polling
#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt-impl", derive(defmt::Format))]
pub enum EventError {
    MqttState(StateError),
    Timeout,
    Encoding(mqttrust::encoding::v4::Error),
    Network(NetworkError),
    BufferSize,
    Clock,
}

#[derive(Debug, PartialEq)]
#[cfg_attr(feature = "defmt-impl", derive(defmt::Format))]
pub enum NetworkError {
    Read,
    Write,
    NoSocket,
    SocketOpen,
    SocketConnect,
    SocketClosed,
    DnsLookupFailed,
}

impl From<mqttrust::encoding::v4::Error> for EventError {
    fn from(e: mqttrust::encoding::v4::Error) -> Self {
        EventError::Encoding(e)
    }
}

impl From<StateError> for EventError {
    fn from(e: StateError) -> Self {
        EventError::MqttState(e)
    }
}