-
Notifications
You must be signed in to change notification settings - Fork 10
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
New module for integrating Matter into RIOT OS #92
Draft
maikerlab
wants to merge
9
commits into
RIOT-OS:main
Choose a base branch
from
maikerlab:with_matter
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
093983d
matter: Add new feature 'with_matter' to support the rs-matter library
maikerlab faaed06
matter: Rename wrapper for UnconnectedUdpSocket to MatterCompatUdpSocket
maikerlab a67c93e
pub use Ipv6Addr from core::net or from no-std-net, if embedded-nal i…
maikerlab 6b517bc
matter: remove logger implementation and log dependency
maikerlab 1190442
matter: add fn sys_rand and VfsDataFetcher with the intent to get com…
maikerlab fe1aa07
matter: add PersistenceManager (not implemented yet)
maikerlab 1ffbcf0
fix: byte arrays read from VFS layer must be decoded with little-endian
maikerlab 2d946f2
matter: implement sys_epoch function using periph_rtc and ztimer_sec
maikerlab 5e62302
matter: renamed VfsDataFetcher to FirmwareDataFetcher; refactoring
maikerlab File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,10 @@ | ||
//! Components for interacting with IPv6 messages on GNRC | ||
|
||
use core::mem::MaybeUninit; | ||
#[cfg(any(feature = "with_embedded_nal", feature = "with_embedded_nal_async"))] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @chrysn how about that? embedded-nal also uses the types from no-std-net. I don't know if an Ipv6Addr must be used if none of the embedded-nal features are activated, but as a "fallback" we can use the one from core::net |
||
pub use no_std_net::{Ipv6Addr, SocketAddr}; | ||
#[cfg(not(any(feature = "with_embedded_nal", feature = "with_embedded_nal_async")))] | ||
pub use core::net::{Ipv6Addr, SocketAddr}; | ||
|
||
use riot_sys::{ipv6_addr_from_str, ipv6_addr_t, kernel_pid_t}; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
use core::time::Duration; | ||
use crate::mutex::Mutex; | ||
use crate::socket_embedded_nal_async_udp::UnconnectedUdpSocket; | ||
use crate::{vfs, ztimer}; | ||
use crate::random::Random; | ||
use crate::error::NumericError; | ||
use riot_sys::{ZTIMER_MSEC, inline::{ztimer_now, ztimer_clock}}; | ||
use embedded_nal_async::{UnconnectedUdp, SocketAddr}; | ||
use embassy_futures::select::{Either, select}; | ||
use embedded_hal_async::delay::DelayNs as _; | ||
use embassy_sync::{ | ||
signal::Signal, | ||
blocking_mutex::raw::NoopRawMutex, | ||
}; | ||
use rand_core_06::RngCore as _; | ||
use rs_matter::error::{Error, ErrorCode}; | ||
use rs_matter::data_model::sdm::dev_att::{DataType, DevAttDataFetcher}; | ||
use rs_matter::Matter; | ||
use rs_matter::transport::network::{UdpReceive, UdpSend}; | ||
|
||
// RIOT_EPOCH(2020) in seconds since UNIX Epoch | ||
const RIOT_EPOCH_SECS: u64 = 1577833200; | ||
|
||
pub struct MatterCompatUdpSocket { | ||
local_addr: SocketAddr, | ||
socket: Mutex<UnconnectedUdpSocket>, | ||
release_socket_notification: Notification, | ||
socket_released_notification: Notification, | ||
} | ||
|
||
pub type Notification = Signal<NoopRawMutex, ()>; | ||
|
||
impl MatterCompatUdpSocket { | ||
pub fn new(local_addr: SocketAddr, socket: UnconnectedUdpSocket) -> Self { | ||
Self { | ||
local_addr, | ||
socket: Mutex::new(socket), | ||
release_socket_notification: Notification::new(), | ||
socket_released_notification: Notification::new(), | ||
} | ||
} | ||
} | ||
|
||
impl UdpSend for &MatterCompatUdpSocket { | ||
async fn send_to(&mut self, data: &[u8], addr: SocketAddr) -> Result<(), Error> { | ||
if addr.is_ipv4() { | ||
// IPv4 not supported! | ||
return Ok(()); | ||
} | ||
// Tell recv_from to release mutex | ||
self.release_socket_notification.signal(()); | ||
ztimer::Delay.delay_ms(10).await; | ||
let mut sock = self.socket.try_lock().expect("receiver should have ensured that this mutex is free"); | ||
sock.send(self.local_addr, addr, data) | ||
.await | ||
.map_err(|_| Error::new(ErrorCode::StdIoError))?; | ||
// Release socket and notify recv_from -> sending is finished | ||
drop(sock); | ||
self.socket_released_notification.signal(()); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl UdpReceive for &MatterCompatUdpSocket { | ||
async fn recv_from(&mut self, buffer: &mut [u8]) -> Result<(usize, SocketAddr), Error> { | ||
loop { | ||
let mut sock = self.socket.try_lock().expect("sender should have ensured that this mutex is free"); | ||
match select( | ||
self.release_socket_notification.wait(), | ||
sock.receive_into(buffer), | ||
).await { | ||
Either::First(_) => { | ||
// Release Mutex for send_to | ||
drop(sock); | ||
// ... and wait until available again | ||
self.socket_released_notification.wait().await; | ||
continue; | ||
} | ||
Either::Second(res) => { | ||
let (bytes_recvd, remote_addr) = res.map(|(bytes_recvd, _, remote_addr)| | ||
(bytes_recvd, remote_addr) | ||
).map_err(|_| Error::new(ErrorCode::StdIoError))?; | ||
return Ok((bytes_recvd, remote_addr)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Generate random bytes using the RIOT RNG | ||
#[cfg(riot_module_random)] | ||
pub fn sys_rand(buf: &mut [u8]) { | ||
Random::new().fill_bytes(buf); | ||
} | ||
|
||
/// Returns Duration since UNIX Epoch (01.01.1970 00:00:00) | ||
pub fn sys_epoch() -> Duration { | ||
let epoch_sec = RIOT_EPOCH_SECS + get_riot_sec() as u64; | ||
let mut epoch_ms: u32 = unsafe { | ||
ztimer_now(ZTIMER_MSEC as *mut ztimer_clock) % 1000 | ||
}; | ||
Duration::from_millis((epoch_sec*1000) + epoch_ms as u64) | ||
} | ||
|
||
/// Returns elapsed seconds since `RIOT_EPOCH` using `periph_rtc` | ||
#[cfg(riot_module_periph_rtc)] | ||
fn get_riot_sec() -> u32 { | ||
use riot_sys::{rtc_get_time, rtc_tm_normalize, rtc_mktime}; | ||
unsafe { | ||
let mut now = riot_sys::tm::default(); | ||
rtc_get_time(&mut now); | ||
rtc_tm_normalize(&mut now); | ||
rtc_mktime(&mut now) | ||
} | ||
} | ||
|
||
/// Returns elapsed seconds since `RIOT_EPOCH` using `ztimer_sec` | ||
#[cfg(all(not(riot_module_periph_rtc), riot_module_ztimer_sec))] | ||
fn get_riot_sec() -> u32 { | ||
use riot_sys::ZTIMER_SEC; | ||
unsafe { | ||
ztimer_now(ZTIMER_SEC as *mut ztimer_clock) | ||
} | ||
} | ||
|
||
pub trait CommissioningDataFetcher { | ||
/// Reads Discriminator and Passcode) from device firmware | ||
fn read_commissioning_data(&self) -> Result<(u16, u32), NumericError>; | ||
} | ||
|
||
/// Provides methods for reading Matter data from VFS (Virtual File System Layer) | ||
/// such as commissioning and device attestation data. | ||
/// For now, only reading from constfs (mountpoint `/const`) is supported, but could be extended to support various filesystems and proper encryption. | ||
/// | ||
/// It is expected that the following files exist in the VFS layer of the target device, otherwise it will panic: | ||
/// - `/const/cd`: Certificate Declaration | ||
/// - `/const/pai`: Product Attestation Intermediary Certificate | ||
/// - `/const/dac`: Device Attestation Certificate | ||
/// - `/const/dac_pubkey`: DAC Public Key | ||
/// - `/const/dac_privkey`: DAC Private Key | ||
/// - `/const/passcode`: Passcode required for successful commissioning | ||
/// - `/const/discriminator`: Required for Node Discovery via mDNS | ||
pub struct FirmwareDataFetcher; | ||
|
||
impl FirmwareDataFetcher { | ||
pub fn new() -> Self{ | ||
Self {} | ||
} | ||
} | ||
|
||
impl CommissioningDataFetcher for FirmwareDataFetcher { | ||
fn read_commissioning_data(&self) -> Result<(u16, u32), NumericError> { | ||
// TODO: Read Commissioning Data from VFS | ||
todo!("not implemented - see https://github.com/RIOT-OS/rust-riot-wrappers/issues/93"); | ||
|
||
let mut passcode_data: [u8; 4] = [0; 4]; | ||
let mut passcode_file = vfs::File::open("/const/passcode")?; | ||
passcode_file.read(&mut passcode_data)?; | ||
let passcode = u32::from_le_bytes(passcode_data); | ||
|
||
let mut discriminator_data: [u8; 2]= [0; 2]; | ||
let mut discriminator_file = vfs::File::open("/const/discriminator")?; | ||
discriminator_file.read(&mut discriminator_data)?; | ||
let discriminator = u16::from_le_bytes(discriminator_data); | ||
|
||
Ok((discriminator, passcode)) | ||
} | ||
} | ||
|
||
impl DevAttDataFetcher for FirmwareDataFetcher { | ||
fn get_devatt_data(&self, data_type: DataType, data: &mut [u8]) -> Result<usize, Error> { | ||
// TODO: Read Device Attestation Data from VFS | ||
todo!("not implemented - see https://github.com/RIOT-OS/rust-riot-wrappers/issues/93"); | ||
let src_path = match data_type { | ||
DataType::CertDeclaration => "/const/cd", | ||
DataType::PAI => "/const/pai", | ||
DataType::DAC => "/const/dac", | ||
DataType::DACPubKey => "/const/dac_pubkey", | ||
DataType::DACPrivKey => "/const/dac_privkey" | ||
}; | ||
let mut src = vfs::File::open(src_path).map_err(|_| Error::new(ErrorCode::StdIoError))?; | ||
let len = src.read(data) | ||
.map_err(|_| Error::new(ErrorCode::StdIoError))?; | ||
if len <= data.len() { | ||
let data = &mut data[0..len]; | ||
Ok(len) | ||
} else { | ||
Err(ErrorCode::NoSpace.into()) | ||
} | ||
} | ||
} | ||
|
||
/// Used for storing and loading ACL and Fabric data in a key-value store | ||
pub struct PersistenceManager<'a> { | ||
matter: &'a Matter<'a>, | ||
buf: [u8; 4096], | ||
dir: &'a str, | ||
} | ||
|
||
impl<'a> PersistenceManager<'a> { | ||
#[inline(always)] | ||
pub fn new(matter: &'a Matter<'a>) -> Result<Self, Error> { | ||
let mut buf = [0; 4096]; | ||
Ok(Self { matter, buf, dir: "data" }) | ||
} | ||
|
||
/// Waits for data changes by the Matter service and saves ACL and/or fabric data | ||
pub async fn run(&mut self) -> Result<(), Error> { | ||
todo!("A key-value store must be implemented for PersistenceManager"); | ||
loop { | ||
self.matter.wait_changed().await; | ||
if self.matter.is_changed() { | ||
if let Some(data) = self.matter.store_acls(&mut self.buf)? { | ||
todo!("not implemented yet") | ||
//Self::store("acls", data)?; | ||
} | ||
|
||
if let Some(data) = self.matter.store_fabrics(&mut self.buf)? { | ||
todo!("not implemented yet") | ||
//Self::store("fabrics", data)?; | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Loads data from the key-value store and writes it to the buffer | ||
fn load<'b>(key: &str, buf: &'b mut [u8]) -> Result<Option<&'b [u8]>, Error> { | ||
todo!("not implemented yet") | ||
} | ||
|
||
/// Stores data to the key-value store | ||
fn store(key: &str, data: &[u8]) -> Result<(), Error> { | ||
todo!("not implemented yet") | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Is it foreseeable that the adjustments there can be upstreamed? Are there open PRs?
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.
No, not yet. I will discuss this with rs-matter contributors, bc it's also not ideal if all the possible specific adaptations for different OS etc. are in this repo
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.
I checked again and I guess we could get rid of all the changes I made in rs-matter.
The only "big" task which needs to be done is implementing embassy-time-driver and embassy-time-queue-driver using ztimer.