diff --git a/examples/onoff_light/src/main.rs b/examples/onoff_light/src/main.rs index 604ffce..3b94305 100644 --- a/examples/onoff_light/src/main.rs +++ b/examples/onoff_light/src/main.rs @@ -54,8 +54,8 @@ fn main() -> Result<(), impl Error> { device_name: "OnOff Light", }; - let mut mdns = matter::mdns::astro::AstroMdns::new()?; - //let mut mdns = matter::mdns::libmdns::LibMdns::new()?; + //let mut mdns = matter::mdns::astro::AstroMdns::new()?; + let mut mdns = matter::mdns::libmdns::LibMdns::new()?; //let mut mdns = matter::mdns::DummyMdns {}; let matter = Matter::new_default(&dev_info, &mut mdns, matter::transport::udp::MATTER_PORT); @@ -77,7 +77,7 @@ fn main() -> Result<(), impl Error> { matter.load_fabrics(data)?; } - matter.start::<4096>( + matter.start( CommissioningData { // TODO: Hard-coded for now verifier: VerifierData::new_with_pw(123456, *matter.borrow()), diff --git a/matter/src/core.rs b/matter/src/core.rs index e2e6b59..17452e3 100644 --- a/matter/src/core.rs +++ b/matter/src/core.rs @@ -116,19 +116,15 @@ impl<'a> Matter<'a> { self.acl_mgr.borrow_mut().store(buf) } - pub fn start( - &self, - dev_comm: CommissioningData, - buf: &mut [u8], - ) -> Result<(), Error> { + pub fn start(&self, dev_comm: CommissioningData, buf: &mut [u8]) -> Result<(), Error> { let open_comm_window = self.fabric_mgr.borrow().is_empty(); if open_comm_window { - print_pairing_code_and_qr::( + print_pairing_code_and_qr( self.dev_det, &dev_comm, DiscoveryCapabilities::default(), buf, - ); + )?; self.pase_mgr.borrow_mut().enable_pase_session( dev_comm.verifier, diff --git a/matter/src/pairing/code.rs b/matter/src/pairing/code.rs index 16e4fea..9106116 100644 --- a/matter/src/pairing/code.rs +++ b/matter/src/pairing/code.rs @@ -19,7 +19,7 @@ use core::fmt::Write; use super::*; -pub(super) fn compute_pairing_code(comm_data: &CommissioningData) -> heapless::String<32> { +pub fn compute_pairing_code(comm_data: &CommissioningData) -> heapless::String<32> { // 0: no Vendor ID and Product ID present in Manual Pairing Code const VID_PID_PRESENT: u8 = 0; diff --git a/matter/src/pairing/mod.rs b/matter/src/pairing/mod.rs index 96f3105..2dddce5 100644 --- a/matter/src/pairing/mod.rs +++ b/matter/src/pairing/mod.rs @@ -31,7 +31,7 @@ use crate::{ use self::{ code::{compute_pairing_code, pretty_print_pairing_code}, - qr::{payload_base38_representation, print_qr_code, QrSetupPayload}, + qr::{compute_qr_code, print_qr_code}, }; pub struct DiscoveryCapabilities { @@ -81,19 +81,19 @@ impl DiscoveryCapabilities { } /// Prepares and prints the pairing code and the QR code for easy pairing. -pub fn print_pairing_code_and_qr( +pub fn print_pairing_code_and_qr( dev_det: &BasicInfoConfig, comm_data: &CommissioningData, discovery_capabilities: DiscoveryCapabilities, buf: &mut [u8], -) { +) -> Result<(), Error> { let pairing_code = compute_pairing_code(comm_data); - let qr_code_data = QrSetupPayload::new(dev_det, comm_data, discovery_capabilities); - let data_str = - payload_base38_representation::(&qr_code_data, buf).expect("Failed to encode"); + let qr_code = compute_qr_code(dev_det, comm_data, discovery_capabilities, buf)?; pretty_print_pairing_code(&pairing_code); - print_qr_code(&data_str); + print_qr_code(&qr_code); + + Ok(()) } pub(self) fn passwd_from_comm_data(comm_data: &CommissioningData) -> u32 { diff --git a/matter/src/pairing/qr.rs b/matter/src/pairing/qr.rs index aa26481..3550dfb 100644 --- a/matter/src/pairing/qr.rs +++ b/matter/src/pairing/qr.rs @@ -253,20 +253,24 @@ pub enum CommissionningFlowType { Custom = 2, } -pub(super) fn payload_base38_representation( +pub(super) fn payload_base38_representation<'a>( payload: &QrSetupPayload, - buf: &mut [u8], -) -> Result, Error> { + buf: &'a mut [u8], +) -> Result<&'a str, Error> { if payload.is_valid() { - let (bits_buf, tlv_buf) = if payload.has_tlv() { - let (bits_buf, tlv_buf) = buf.split_at_mut(buf.len() / 2); + let (str_buf, bits_buf, tlv_buf) = if payload.has_tlv() { + let (str_buf, buf) = buf.split_at_mut(buf.len() / 3 * 2); - (bits_buf, Some(tlv_buf)) + let (bits_buf, tlv_buf) = buf.split_at_mut(buf.len() / 3); + + (str_buf, bits_buf, Some(tlv_buf)) } else { - (buf, None) + let (str_buf, buf) = buf.split_at_mut(buf.len() / 3 * 2); + + (str_buf, buf, None) }; - payload_base38_representation_with_tlv(payload, bits_buf, tlv_buf) + payload_base38_representation_with_tlv(payload, str_buf, bits_buf, tlv_buf) } else { Err(ErrorCode::InvalidArgument.into()) } @@ -315,16 +319,16 @@ fn estimate_struct_overhead(first_field_size: usize) -> usize { first_field_size + 4 + 2 } -pub(super) fn print_qr_code(qr_data: &str) { - info!("QR Code: {}", qr_data); +pub(super) fn print_qr_code(qr_code: &str) { + info!("QR Code: {}", qr_code); #[cfg(feature = "std")] { use qrcode::{render::unicode, QrCode, Version}; - let needed_version = compute_qr_version(qr_data); + let needed_version = compute_qr_version(qr_code); let code = - QrCode::with_version(qr_data, Version::Normal(needed_version), qrcode::EcLevel::M) + QrCode::with_version(qr_code, Version::Normal(needed_version), qrcode::EcLevel::M) .unwrap(); let image = code .render::() @@ -336,6 +340,16 @@ pub(super) fn print_qr_code(qr_data: &str) { } } +pub fn compute_qr_code<'a>( + dev_det: &BasicInfoConfig, + comm_data: &CommissioningData, + discovery_capabilities: DiscoveryCapabilities, + buf: &'a mut [u8], +) -> Result<&'a str, Error> { + let qr_code_data = QrSetupPayload::new(dev_det, comm_data, discovery_capabilities); + payload_base38_representation(&qr_code_data, buf) +} + fn compute_qr_version(qr_data: &str) -> i16 { match qr_data.len() { 0..=38 => 2, @@ -375,11 +389,12 @@ fn populate_bits( Ok(()) } -fn payload_base38_representation_with_tlv( +fn payload_base38_representation_with_tlv<'a>( payload: &QrSetupPayload, + str_buf: &'a mut [u8], bits_buf: &mut [u8], tlv_buf: Option<&mut [u8]>, -) -> Result, Error> { +) -> Result<&'a str, Error> { let tlv_data = if let Some(tlv_buf) = tlv_buf { Some(generate_tlv_from_optional_data(payload, tlv_buf)?) } else { @@ -388,13 +403,30 @@ fn payload_base38_representation_with_tlv( let bits = generate_bit_set(payload, bits_buf, tlv_data)?; - let mut base38_encoded: heapless::String = "MT:".into(); + let prefix = "MT:"; - for c in base38::encode(bits) { - base38_encoded.push(c).map_err(|_| ErrorCode::NoSpace)?; + if str_buf.len() < prefix.as_bytes().len() { + Err(ErrorCode::NoSpace)?; } - Ok(base38_encoded) + str_buf[..prefix.as_bytes().len()].copy_from_slice(prefix.as_bytes()); + + let mut offset = prefix.len(); + + for c in base38::encode(bits) { + let mut char_buf = [0; 4]; + let str = c.encode_utf8(&mut char_buf); + + if str_buf.len() - offset < str.as_bytes().len() { + Err(ErrorCode::NoSpace)?; + } + + str_buf[offset..offset + str.as_bytes().len()].copy_from_slice(str.as_bytes()); + + offset += str.as_bytes().len(); + } + + Ok(core::str::from_utf8(&str_buf[..offset])?) } fn generate_tlv_from_optional_data<'a>( @@ -557,8 +589,8 @@ mod tests { let disc_cap = DiscoveryCapabilities::new(false, true, false); let qr_code_data = QrSetupPayload::new(&dev_det, &comm_data, disc_cap); let mut buf = [0; 1024]; - let data_str = payload_base38_representation::<128>(&qr_code_data, &mut buf) - .expect("Failed to encode"); + let data_str = + payload_base38_representation(&qr_code_data, &mut buf).expect("Failed to encode"); assert_eq!(data_str, QR_CODE) } @@ -580,8 +612,8 @@ mod tests { let disc_cap = DiscoveryCapabilities::new(true, false, false); let qr_code_data = QrSetupPayload::new(&dev_det, &comm_data, disc_cap); let mut buf = [0; 1024]; - let data_str = payload_base38_representation::<128>(&qr_code_data, &mut buf) - .expect("Failed to encode"); + let data_str = + payload_base38_representation(&qr_code_data, &mut buf).expect("Failed to encode"); assert_eq!(data_str, QR_CODE) } @@ -626,8 +658,8 @@ mod tests { .expect("Failed to add optional data"); let mut buf = [0; 1024]; - let data_str = payload_base38_representation::<{ QR_CODE.len() }>(&qr_code_data, &mut buf) - .expect("Failed to encode"); + let data_str = + payload_base38_representation(&qr_code_data, &mut buf).expect("Failed to encode"); assert_eq!(data_str, QR_CODE) } }