Skip to content

Commit

Permalink
In place init (#3)
Browse files Browse the repository at this point in the history
* In-place init everything

* Build with Rust stable

* Use upstream pinned-init

* In-place init for MatterServices

* Update to the tip of my fork

* Leave a note for Alexa and ScanNetworks

* Compat with latest rs-matter that no longer has the ApplyInit interface

* More flexible Unix netif search

* Update to latest rs-matter tip; start testing with Matter C++ E2E

* fmt

* Clippy

* Remove the changes done for the ChipTool SDK e2e tests
  • Loading branch information
ivmarkov authored Sep 23, 2024
1 parent fe05211 commit 926062e
Show file tree
Hide file tree
Showing 13 changed files with 483 additions and 230 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ readme = "README.md"
rust-version = "1.77"

[patch.crates-io]
rs-matter = { git = "https://github.com/ivmarkov/rs-matter", branch = "wifi" }
rs-matter = { git = "https://github.com/ivmarkov/rs-matter", branch = "tip" }
#rs-matter = { path = "../rs-matter/rs-matter" }
#edge-nal = { git = "https://github.com/ivmarkov/edge-net" }
#edge-nal = { path = "../edge-net/edge-nal" }
Expand All @@ -25,7 +25,7 @@ rs-matter = { git = "https://github.com/ivmarkov/rs-matter", branch = "wifi" }
[features]
default = []
zeroconf = ["os", "rs-matter/zeroconf"]
os = ["backtrace", "rs-matter/os", "rs-matter/mbedtls", "embassy-time/std", "embassy-time/generic-queue"]
os = ["backtrace", "rs-matter/os", "rs-matter/rustcrypto", "embassy-time/std", "embassy-time/generic-queue"]
backtrace = ["std", "rs-matter/backtrace"]
std = ["alloc", "rs-matter/std", "edge-nal-std"]
alloc = ["embedded-svc/alloc"]
Expand All @@ -45,6 +45,7 @@ edge-nal-std = { version = "0.3", optional = true }
edge-mdns = { version = "0.3", optional = true }

[target.'cfg(all(unix, not(target_os = "espidf")))'.dependencies]
bitflags = "2"
nix = { version = "0.27", features = ["net"], optional = true }

[dev-dependencies]
Expand Down
44 changes: 23 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ Instantiate it and then call `MatterStack::<...>::run(...)`.

**Flexibility**.

Using `MatterStack<...>` hard-codes the following:
* _One large future_: The Matter stack is assembled as one large future which is not `Send`. Using an executor to poll that future together with others is still possible, but the executor should be a local one (i.e. Tokio's `LocalSet`, `async_executor::LocalExecutor` and so on).
* _Allocation strategy_: a number of large-ish buffers are const-allocated inside the `MatterStack` struct. This allows the whole stack to be statically-allocated with `ConstStaticCell` - yet - that would eat up 20 to 60K of your flash size, depending on the selected max number of subscriptions, exchange buffers and so on. A different allocation strategy might be provided in future.
The Matter stack is assembled as one large future which is not `Send`. Using an executor to poll that future together with others is still possible, but the executor should be a local one (i.e. Tokio's `LocalSet`, `async_executor::LocalExecutor` and so on).

## The examples are STD-only?

Expand Down Expand Up @@ -69,14 +67,15 @@ use rs_matter::data_model::objects::{Dataver, Endpoint, HandlerCompat, Node};
use rs_matter::data_model::system_model::descriptor;
use rs_matter::error::Error;
use rs_matter::secure_channel::spake2p::VerifierData;
use rs_matter::utils::init::InitMaybeUninit;
use rs_matter::utils::select::Coalesce;
use rs_matter::CommissioningData;

use rs_matter_stack::netif::UnixNetif;
use rs_matter_stack::persist::{DirKvBlobStore, KvBlobBuf, KvPersist};
use rs_matter_stack::EthMatterStack;

use static_cell::ConstStaticCell;
use static_cell::StaticCell;

#[path = "dev_att/dev_att.rs"]
mod dev_att;
Expand All @@ -88,9 +87,24 @@ fn main() -> Result<(), Error> {

info!("Starting...");

// Take the Matter stack (can be done only once),
// Initialize the Matter stack (can be done only once),
// as we'll run it in this thread
let stack = MATTER_STACK.take();
let stack = MATTER_STACK
.uninit()
.init_with(EthMatterStack::init_default(
&BasicInfoConfig {
vid: 0xFFF1,
pid: 0x8000,
hw_ver: 2,
sw_ver: 1,
sw_ver_str: "1",
serial_no: "aabbccdd",
device_name: "MyLight",
product_name: "ACME Light",
vendor_name: "ACME",
},
&DEV_ATT,
));

// Our "light" on-off cluster.
// Can be anything implementing `rs_matter::data_model::AsyncHandler`
Expand Down Expand Up @@ -162,21 +176,9 @@ fn main() -> Result<(), Error> {

/// The Matter stack is allocated statically to avoid
/// program stack blowups.
static MATTER_STACK: ConstStaticCell<EthMatterStack<KvBlobBuf<()>>> =
ConstStaticCell::new(EthMatterStack::new_default(
&BasicInfoConfig {
vid: 0xFFF1,
pid: 0x8000,
hw_ver: 2,
sw_ver: 1,
sw_ver_str: "1",
serial_no: "aabbccdd",
device_name: "MyLight",
product_name: "ACME Light",
vendor_name: "ACME",
},
&dev_att::HardCodedDevAtt::new(),
));
static MATTER_STACK: StaticCell<EthMatterStack<KvBlobBuf<()>>> = StaticCell::new();

const DEV_ATT: dev_att::HardCodedDevAtt = dev_att::HardCodedDevAtt::new();

/// Endpoint 0 (the root endpoint) always runs
/// the hidden Matter system clusters, so we pick ID=1
Expand Down
54 changes: 28 additions & 26 deletions examples/light.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ use rs_matter::data_model::device_types::DEV_TYPE_ON_OFF_LIGHT;
use rs_matter::data_model::objects::{Dataver, Endpoint, HandlerCompat, Node};
use rs_matter::data_model::system_model::descriptor;
use rs_matter::error::Error;
use rs_matter::secure_channel::spake2p::VerifierData;
use rs_matter::utils::init::InitMaybeUninit;
use rs_matter::utils::select::Coalesce;
use rs_matter::utils::std_mutex::StdRawMutex;
use rs_matter::CommissioningData;
use rs_matter::utils::sync::blocking::raw::StdRawMutex;
use rs_matter::BasicCommData;

use rs_matter_stack::modem::DummyLinuxModem;
use rs_matter_stack::persist::{DirKvBlobStore, KvBlobBuf, KvPersist};
use rs_matter_stack::WifiBleMatterStack;

use static_cell::ConstStaticCell;
use static_cell::StaticCell;

#[path = "dev_att/dev_att.rs"]
mod dev_att;
Expand All @@ -39,9 +39,28 @@ fn main() -> Result<(), Error> {

info!("Starting...");

// Take the Matter stack (can be done only once),
// Initialize the Matter stack (can be done only once),
// as we'll run it in this thread
let stack = MATTER_STACK.take();
let stack = MATTER_STACK
.uninit()
.init_with(WifiBleMatterStack::init_default(
&BasicInfoConfig {
vid: 0xFFF1,
pid: 0x8001,
hw_ver: 2,
sw_ver: 1,
sw_ver_str: "1",
serial_no: "aabbccdd",
device_name: "MyLight",
product_name: "ACME Light",
vendor_name: "ACME",
},
BasicCommData {
password: 20202021,
discriminator: 3840,
},
&DEV_ATT,
));

// Our "light" on-off cluster.
// Can be anything implementing `rs_matter::data_model::AsyncHandler`
Expand Down Expand Up @@ -75,11 +94,6 @@ fn main() -> Result<(), Error> {
KvPersist::new_wifi_ble(DirKvBlobStore::new_default(), stack),
// A Linux-specific modem using BlueZ
DummyLinuxModem::default(),
// Hard-coded for demo purposes
CommissioningData {
verifier: VerifierData::new_with_pw(123456, stack.matter().rand()),
discriminator: 250,
},
// Our `AsyncHandler` + `AsyncMetadata` impl
(NODE, handler),
// No user future to run
Expand Down Expand Up @@ -116,21 +130,9 @@ fn main() -> Result<(), Error> {
/// The Matter stack is allocated statically to avoid
/// program stack blowups.
/// It is also a mandatory requirement when the `WifiBle` stack variation is used.
static MATTER_STACK: ConstStaticCell<WifiBleMatterStack<StdRawMutex, KvBlobBuf<()>>> =
ConstStaticCell::new(WifiBleMatterStack::new_default(
&BasicInfoConfig {
vid: 0xFFF1,
pid: 0x8000,
hw_ver: 2,
sw_ver: 1,
sw_ver_str: "1",
serial_no: "aabbccdd",
device_name: "MyLight",
product_name: "ACME Light",
vendor_name: "ACME",
},
&dev_att::HardCodedDevAtt::new(),
));
static MATTER_STACK: StaticCell<WifiBleMatterStack<StdRawMutex, KvBlobBuf<()>>> = StaticCell::new();

const DEV_ATT: dev_att::HardCodedDevAtt = dev_att::HardCodedDevAtt::new();

/// Endpoint 0 (the root endpoint) always runs
/// the hidden Matter system clusters, so we pick ID=1
Expand Down
59 changes: 32 additions & 27 deletions examples/light_eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use core::pin::pin;
use embassy_futures::select::select;
use embassy_time::{Duration, Timer};

use env_logger::Target;
use log::info;

use rs_matter::data_model::cluster_basic_information::BasicInfoConfig;
Expand All @@ -22,29 +23,50 @@ use rs_matter::data_model::device_types::DEV_TYPE_ON_OFF_LIGHT;
use rs_matter::data_model::objects::{Dataver, Endpoint, HandlerCompat, Node};
use rs_matter::data_model::system_model::descriptor;
use rs_matter::error::Error;
use rs_matter::secure_channel::spake2p::VerifierData;
use rs_matter::utils::init::InitMaybeUninit;
use rs_matter::utils::select::Coalesce;
use rs_matter::CommissioningData;
use rs_matter::BasicCommData;

use rs_matter_stack::netif::UnixNetif;
use rs_matter_stack::persist::{DirKvBlobStore, KvBlobBuf, KvPersist};
use rs_matter_stack::EthMatterStack;

use static_cell::ConstStaticCell;
use static_cell::StaticCell;

#[path = "dev_att/dev_att.rs"]
mod dev_att;

fn main() -> Result<(), Error> {
env_logger::init_from_env(
env_logger::Builder::from_env(
env_logger::Env::default().filter_or(env_logger::DEFAULT_FILTER_ENV, "info"),
);
)
.target(Target::Stdout)
.init();

info!("Starting...");

// Take the Matter stack (can be done only once),
// Initialize the Matter stack (can be done only once),
// as we'll run it in this thread
let stack = MATTER_STACK.take();
let stack = MATTER_STACK
.uninit()
.init_with(EthMatterStack::init_default(
&BasicInfoConfig {
vid: 0xFFF1,
pid: 0x8001,
hw_ver: 2,
sw_ver: 1,
sw_ver_str: "1",
serial_no: "aabbccdd",
device_name: "MyLight",
product_name: "ACME Light",
vendor_name: "ACME",
},
BasicCommData {
password: 20202021,
discriminator: 3840,
},
&DEV_ATT,
));

// Our "light" on-off cluster.
// Can be anything implementing `rs_matter::data_model::AsyncHandler`
Expand Down Expand Up @@ -78,11 +100,6 @@ fn main() -> Result<(), Error> {
KvPersist::new_eth(DirKvBlobStore::new_default(), stack),
// Will try to find a default network interface
UnixNetif::default(),
// Hard-coded for demo purposes
CommissioningData {
verifier: VerifierData::new_with_pw(123456, stack.matter().rand()),
discriminator: 250,
},
// Our `AsyncHandler` + `AsyncMetadata` impl
(NODE, handler),
// No user future to run
Expand Down Expand Up @@ -116,21 +133,9 @@ fn main() -> Result<(), Error> {

/// The Matter stack is allocated statically to avoid
/// program stack blowups.
static MATTER_STACK: ConstStaticCell<EthMatterStack<KvBlobBuf<()>>> =
ConstStaticCell::new(EthMatterStack::new_default(
&BasicInfoConfig {
vid: 0xFFF1,
pid: 0x8000,
hw_ver: 2,
sw_ver: 1,
sw_ver_str: "1",
serial_no: "aabbccdd",
device_name: "MyLight",
product_name: "ACME Light",
vendor_name: "ACME",
},
&dev_att::HardCodedDevAtt::new(),
));
static MATTER_STACK: StaticCell<EthMatterStack<KvBlobBuf<()>>> = StaticCell::new();

const DEV_ATT: dev_att::HardCodedDevAtt = dev_att::HardCodedDevAtt::new();

/// Endpoint 0 (the root endpoint) always runs
/// the hidden Matter system clusters, so we pick ID=1
Expand Down
43 changes: 30 additions & 13 deletions src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rs_matter::data_model::sdm::nw_commissioning::EthNwCommCluster;
use rs_matter::data_model::sdm::{ethernet_nw_diagnostics, nw_commissioning};
use rs_matter::error::Error;
use rs_matter::pairing::DiscoveryCapabilities;
use rs_matter::CommissioningData;
use rs_matter::utils::init::{init, Init};

use crate::netif::Netif;
use crate::network::{Embedding, Network};
Expand All @@ -32,18 +32,26 @@ use crate::MatterStack;
///
/// The expectation is nevertheless that for production use-cases
/// the `Eth` network would really only be used for Ethernet.
pub struct Eth<E = ()>(E);
pub struct Eth<E = ()> {
embedding: E,
}

impl<E> Network for Eth<E>
where
E: Embedding + 'static,
{
const INIT: Self = Self(E::INIT);
const INIT: Self = Self { embedding: E::INIT };

type Embedding = E;

fn embedding(&self) -> &Self::Embedding {
&self.0
&self.embedding
}

fn init() -> impl Init<Self> {
init!(Self {
embedding <- E::init(),
})
}
}

Expand Down Expand Up @@ -85,6 +93,16 @@ where
Ok(())
}

/// Enable basic commissioning over IP (mDNS) by setting up a PASE session and printing the pairing code and QR code.
///
/// The method will return an error if there is not enough space in the buffer to print the pairing code and QR code
/// or if the PASE session could not be set up (due to another PASE session already being active, for example).
pub async fn enable_basic_commissioning(&self) -> Result<(), Error> {
self.matter()
.enable_basic_commissioning(DiscoveryCapabilities::IP, 0)
.await // TODO
}

/// Run the Matter stack for Ethernet network.
///
/// Parameters:
Expand All @@ -97,7 +115,6 @@ where
&self,
persist: P,
netif: I,
dev_comm: CommissioningData,
handler: H,
user: U,
) -> Result<(), Error>
Expand All @@ -111,14 +128,14 @@ where

let mut user = pin!(user);

self.run_with_netif(
persist,
netif,
Some((dev_comm, DiscoveryCapabilities::new(true, false, false))),
handler,
&mut user,
)
.await
// TODO persist.load().await?;

if !self.is_commissioned().await? {
self.enable_basic_commissioning().await?;
}

self.run_with_netif(persist, netif, handler, &mut user)
.await
}
}

Expand Down
Loading

0 comments on commit 926062e

Please sign in to comment.