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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#![no_std]
//! # MiniMQ
//! Provides a minimal MQTTv5 client and message parsing for the MQTT version 5 protocol.
//!
//! This crate provides a minimalistic MQTT 5 client that can be used to publish topics to an MQTT
//! broker and subscribe to receive messages on specific topics.
//!
//! # Limitations
//! This library does not currently support the following elements:
//! * Quality-of-service `ExactlyOnce`
//! * Session timeouts
//! * Server keep alive timeouts (ping)
//! * Bulk subscriptions
//! * Server Authentication
//! * Encryption
//! * Topic aliases
//!
//! # Requirements
//! This library requires that the user provide it an object that implements a basic TcpStack that
//! can be used as the transport layer for MQTT communications.
//!
//! The maximum message size is configured through generic parameters. This allows the maximum
//! message size to be configured by the user. Note that buffers will be allocated on the stack, so it
//! is important to select a size such that the stack does not overflow.
//!
//! # Example
//! Below is a sample snippet showing how this library is used. An example application is provided
//! in `examples/minimq-stm32h7`, which targets the Nucleo-H743 development board with an external
//! temperature sensor installed.
//!
//! ```no_run
//! use minimq::{Minimq, QoS};
//!
//! // Construct an MQTT client with a maximum packet size of 256 bytes.
//! // Connect to a broker at localhost - Use a client ID of "test".
//! let mut mqtt: Minimq<_, _, 256, 16> = Minimq::new(
//!         "127.0.0.1".parse().unwrap(),
//!         "test",
//!         std_embedded_nal::Stack::default(),
//!         std_embedded_time::StandardClock::default()).unwrap();
//!
//! let mut subscribed = false;
//!
//! loop {
//!     if mqtt.client.is_connected() && !subscribed {
//!         mqtt.client.subscribe("topic", &[]).unwrap();
//!         subscribed = true;
//!     }
//!
//!     mqtt.poll(|client, topic, message, properties| {
//!         match topic {
//!             "topic" => {
//!                println!("{:?}", message);
//!                client.publish("echo", message, QoS::AtMostOnce, &[]).unwrap();
//!             },
//!             topic => println!("Unknown topic: {}", topic),
//!         };
//!     }).unwrap();
//! }
//! ```

pub(crate) mod de;
pub(crate) mod ser;

mod message_types;
mod mqtt_client;
mod network_manager;
mod properties;
mod session_state;

use message_types::MessageType;
pub use properties::Property;

pub use embedded_nal;
pub use embedded_time;
pub use mqtt_client::{Minimq, QoS};

#[cfg(feature = "logging")]
pub(crate) use log::{debug, error, info, warn};

/// Errors that are specific to the MQTT protocol implementation.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum ProtocolError {
    Bounds,
    DataSize,
    Invalid,
    Failed,
    PacketSize,
    MalformedPacket,
    MalformedInteger,
    UnknownProperty,
    UnsupportedPacket,
    BufferSize,
    InvalidProperty,
}

/// Possible errors encountered during an MQTT connection.
#[derive(Debug, PartialEq)]
pub enum Error<E> {
    Network(E),
    WriteFail,
    NotReady,
    Unsupported,
    ProvidedClientIdTooLong,
    Failed(u8),
    Protocol(ProtocolError),
    SessionReset,
    Clock(embedded_time::clock::Error),
}

impl<E> From<embedded_time::clock::Error> for Error<E> {
    fn from(clock: embedded_time::clock::Error) -> Self {
        Error::Clock(clock)
    }
}

impl<E> From<ProtocolError> for Error<E> {
    fn from(error: ProtocolError) -> Self {
        Error::Protocol(error)
    }
}

#[doc(hidden)]
#[cfg(not(feature = "logging"))]
mod mqtt_log {
    #[doc(hidden)]
    #[macro_export]
    macro_rules! debug {
        ($($arg:tt)+) => {
            ()
        };
    }

    #[doc(hidden)]
    #[macro_export]
    macro_rules! info {
        ($($arg:tt)+) => {
            ()
        };
    }

    #[doc(hidden)]
    #[macro_export]
    macro_rules! warn {
        ($($arg:tt)+) => {
            ()
        };
    }

    #[doc(hidden)]
    #[macro_export]
    macro_rules! error {
        ($($arg:tt)+) => {
            ()
        };
    }
}