-
Notifications
You must be signed in to change notification settings - Fork 227
Add mqtt v5 protocol implementation #590
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
27f79f5
3700783
f50dabf
72952ef
a9cda42
321aada
ea84735
c338eef
694f3ff
b29671f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -2,13 +2,24 @@ | |||
| use core::ffi::c_void; | ||||
| use core::fmt::Debug; | ||||
| use core::{slice, time}; | ||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| use std::vec::Vec; | ||||
|
|
||||
| extern crate alloc; | ||||
| use alloc::boxed::Box; | ||||
| use alloc::sync::Arc; | ||||
|
|
||||
| use embedded_svc::mqtt::client::{asynch, Client, Connection, Enqueue, ErrorType, Publish}; | ||||
|
|
||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| use embedded_svc::mqtt::client5::{MessageMetadata, SubscribePropertyConfig, UserPropertyItem}; | ||||
|
|
||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| use embedded_svc::mqtt::client5::UserPropertyList; | ||||
|
|
||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| use crate::mqtt::client5::EspUserPropertyList; | ||||
|
|
||||
| use crate::private::unblocker::Unblocker; | ||||
| use crate::sys::*; | ||||
|
|
||||
|
|
@@ -25,17 +36,31 @@ pub use embedded_svc::mqtt::client::{ | |||
| #[allow(unused_imports)] | ||||
| pub use super::*; | ||||
|
|
||||
| fn u8ptr_to_str<'a>(ptr: *const u8, len: usize) -> Option<&'a str> { | ||||
| if ptr.is_null() || len == 0 { | ||||
| return None; | ||||
| } | ||||
|
|
||||
| // SAFETY: The pointer is assumed to be valid and the length is non-zero. | ||||
| let slice: &'a [u8] = unsafe { core::slice::from_raw_parts(ptr, len) }; | ||||
| core::str::from_utf8(slice).ok() | ||||
| } | ||||
|
|
||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||||
| pub enum MqttProtocolVersion { | ||||
| V3_1, | ||||
| V3_1_1, | ||||
| #[cfg(esp_idf_mqtt_protocol_5)] | ||||
| V5, | ||||
| } | ||||
|
|
||||
| impl From<MqttProtocolVersion> for esp_mqtt_protocol_ver_t { | ||||
| fn from(pv: MqttProtocolVersion) -> Self { | ||||
| match pv { | ||||
| MqttProtocolVersion::V3_1 => esp_mqtt_protocol_ver_t_MQTT_PROTOCOL_V_3_1, | ||||
| MqttProtocolVersion::V3_1_1 => esp_mqtt_protocol_ver_t_MQTT_PROTOCOL_V_3_1_1, | ||||
| #[cfg(esp_idf_mqtt_protocol_5)] | ||||
| MqttProtocolVersion::V5 => esp_mqtt_protocol_ver_t_MQTT_PROTOCOL_V_5, | ||||
| } | ||||
| } | ||||
| } | ||||
|
|
@@ -337,22 +362,24 @@ impl<'a> TryFrom<&'a MqttClientConfiguration<'a>> | |||
| } | ||||
| } | ||||
|
|
||||
| struct UnsafeCallback<'a>(*mut Box<dyn FnMut(esp_mqtt_event_handle_t) + Send + 'a>); | ||||
| pub(crate) struct UnsafeCallback<'a>(*mut Box<dyn FnMut(esp_mqtt_event_handle_t) + Send + 'a>); | ||||
|
|
||||
| impl<'a> UnsafeCallback<'a> { | ||||
| fn from(boxed: &mut Box<Box<dyn FnMut(esp_mqtt_event_handle_t) + Send + 'a>>) -> Self { | ||||
| pub(crate) fn from( | ||||
| boxed: &mut Box<Box<dyn FnMut(esp_mqtt_event_handle_t) + Send + 'a>>, | ||||
| ) -> Self { | ||||
| Self(boxed.as_mut()) | ||||
| } | ||||
|
|
||||
| unsafe fn from_ptr(ptr: *mut c_void) -> Self { | ||||
| pub(crate) unsafe fn from_ptr(ptr: *mut c_void) -> Self { | ||||
| Self(ptr as *mut _) | ||||
| } | ||||
|
|
||||
| fn as_ptr(&self) -> *mut c_void { | ||||
| pub(crate) fn as_ptr(&self) -> *mut c_void { | ||||
| self.0 as *mut _ | ||||
| } | ||||
|
|
||||
| unsafe fn call(&self, data: esp_mqtt_event_handle_t) { | ||||
| pub(crate) unsafe fn call(&self, data: esp_mqtt_event_handle_t) { | ||||
| let reference = self.0.as_mut().unwrap(); | ||||
|
|
||||
| (reference)(data); | ||||
|
|
@@ -518,10 +545,29 @@ impl<'a> EspMqttClient<'a> { | |||
| self.subscribe_cstr(to_cstring_arg(topic)?.as_c_str(), qos) | ||||
| } | ||||
|
|
||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| pub fn subscribe_with_config<'ab>( | ||||
| &mut self, | ||||
| topic: &str, | ||||
| qos: QoS, | ||||
| config: SubscribePropertyConfig<'ab>, | ||||
| ) -> Result<MessageId, EspError> { | ||||
| self.subscribe_with_config_cstr(to_cstring_arg(topic)?.as_c_str(), qos, config) | ||||
| } | ||||
|
|
||||
| pub fn unsubscribe(&mut self, topic: &str) -> Result<MessageId, EspError> { | ||||
| self.unsubscribe_cstr(to_cstring_arg(topic)?.as_c_str()) | ||||
| } | ||||
|
|
||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| pub fn unsubscribe_with_config<'ab>( | ||||
| &mut self, | ||||
| topic: &str, | ||||
| config: SubscribePropertyConfig<'ab>, | ||||
| ) -> Result<MessageId, EspError> { | ||||
| self.unsubscribe_with_config_cstr(to_cstring_arg(topic)?.as_c_str(), config) | ||||
| } | ||||
|
|
||||
| pub fn publish( | ||||
| &mut self, | ||||
| topic: &str, | ||||
|
|
@@ -576,10 +622,61 @@ impl<'a> EspMqttClient<'a> { | |||
| res | ||||
| } | ||||
|
|
||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| pub fn subscribe_with_config_cstr( | ||||
| &mut self, | ||||
| topic: &core::ffi::CStr, | ||||
| qos: QoS, | ||||
| config: SubscribePropertyConfig<'_>, | ||||
| ) -> Result<MessageId, EspError> { | ||||
| let property = esp_mqtt5_subscribe_property_config_t { | ||||
| subscribe_id: config.subscribe_id, | ||||
| no_local_flag: config.no_local, | ||||
| retain_as_published_flag: config.retain_as_published, | ||||
| retain_handle: config.retain_handling, | ||||
|
||||
| is_share_subscribe: config.share_name.is_some(), | ||||
| share_name: config.share_name.map_or(core::ptr::null(), |s| s.as_ptr()), | ||||
|
||||
| user_property: if let Some(ref user_properties) = config.user_properties { | ||||
| EspUserPropertyList::from(user_properties).as_ptr() | ||||
| } else { | ||||
| mqtt5_user_property_handle_t::default() | ||||
| }, | ||||
|
Comment on lines
+639
to
+643
|
||||
| }; | ||||
|
|
||||
| Self::check(unsafe { | ||||
| esp_mqtt5_client_set_subscribe_property(self.raw_client, &property as *const _) | ||||
| })?; | ||||
|
|
||||
| self.subscribe_cstr(topic, qos) | ||||
| } | ||||
|
|
||||
| pub fn unsubscribe_cstr(&mut self, topic: &core::ffi::CStr) -> Result<MessageId, EspError> { | ||||
| Self::check(unsafe { esp_mqtt_client_unsubscribe(self.raw_client, topic.as_ptr()) }) | ||||
| } | ||||
|
|
||||
| #[cfg(all(esp_idf_mqtt_protocol_5, feature = "std"))] | ||||
| pub fn unsubscribe_with_config_cstr<'ab>( | ||||
| &mut self, | ||||
| topic: &core::ffi::CStr, | ||||
| config: SubscribePropertyConfig<'ab>, | ||||
|
Comment on lines
+657
to
+661
|
||||
| ) -> Result<MessageId, EspError> { | ||||
| let property = esp_mqtt5_unsubscribe_property_config_t { | ||||
| is_share_subscribe: config.share_name.is_some(), | ||||
| share_name: config.share_name.map_or(core::ptr::null(), |s| s.as_ptr()), | ||||
|
||||
| user_property: if let Some(ref user_properties) = config.user_properties { | ||||
| EspUserPropertyList::from(user_properties).as_ptr() | ||||
| } else { | ||||
| mqtt5_user_property_handle_t::default() | ||||
| }, | ||||
|
Comment on lines
+666
to
+670
|
||||
| }; | ||||
|
|
||||
| Self::check(unsafe { | ||||
| esp_mqtt5_client_set_unsubscribe_property(self.raw_client, &property as *const _) | ||||
| })?; | ||||
|
|
||||
| self.unsubscribe_cstr(topic) | ||||
| } | ||||
|
|
||||
| pub fn publish_cstr( | ||||
| &mut self, | ||||
| topic: &core::ffi::CStr, | ||||
|
|
@@ -674,7 +771,7 @@ impl ErrorType for EspMqttClient<'_> { | |||
| type Error = EspError; | ||||
| } | ||||
|
|
||||
| impl Client for EspMqttClient<'_> { | ||||
| impl<'a> Client for EspMqttClient<'a> { | ||||
| fn subscribe(&mut self, topic: &str, qos: QoS) -> Result<MessageId, Self::Error> { | ||||
| EspMqttClient::subscribe(self, topic, qos) | ||||
| } | ||||
|
|
@@ -711,8 +808,8 @@ impl Enqueue for EspMqttClient<'_> { | |||
| unsafe impl Send for EspMqttClient<'_> {} | ||||
|
|
||||
| pub struct EspMqttConnection { | ||||
| receiver: Receiver<EspMqttEvent<'static>>, | ||||
| given: bool, | ||||
| pub(crate) receiver: Receiver<EspMqttEvent<'static>>, | ||||
| pub(crate) given: bool, | ||||
| } | ||||
|
|
||||
| impl EspMqttConnection { | ||||
|
|
@@ -926,6 +1023,7 @@ impl EspAsyncMqttClient { | |||
| AsyncCommand::Subscribe { qos } => { | ||||
| let topic = | ||||
| unsafe { core::ffi::CStr::from_bytes_with_nul_unchecked(&work.topic) }; | ||||
|
|
||||
|
||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parameter type mismatch: The parameter 'config' should be of type 'UnsubscribePropertyConfig' not 'SubscribePropertyConfig'. This appears to be a copy-paste error from the subscribe_with_config method.