Simplify API by combining Matter, Transport and TransportRunner; simplify Mdns and Psm runners
This commit is contained in:
parent
71b9a578d0
commit
916f2148f8
29 changed files with 520 additions and 629 deletions
6
.github/workflows/test-linux.yml
vendored
6
.github/workflows/test-linux.yml
vendored
|
@ -15,11 +15,11 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
crypto-backend: ['crypto_openssl', 'crypto_rustcrypto', 'crypto_mbedtls']
|
crypto-backend: ['rustcrypto', 'mbedtls', 'openssl']
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cd matter; cargo build --verbose --no-default-features --features ${{matrix.crypto-backend}}
|
run: cd matter; cargo build --no-default-features --features ${{matrix.crypto-backend}}
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cd matter; cargo test --verbose --no-default-features --features ${{matrix.crypto-backend}} -- --test-threads=1
|
run: cd matter; cargo test --no-default-features --features os,${{matrix.crypto-backend}} -- --test-threads=1
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
|
resolver = "2"
|
||||||
members = ["matter", "matter_macro_derive"]
|
members = ["matter", "matter_macro_derive"]
|
||||||
|
|
||||||
exclude = ["examples/*"]
|
exclude = ["examples/*", "tools/tlv_tool"]
|
||||||
|
|
||||||
# For compatibility with ESP IDF
|
# For compatibility with ESP IDF
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
|
|
13
README.md
13
README.md
|
@ -41,23 +41,24 @@ The `async` metaphor however comes with a bit higher memory usage, due to not en
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Building the library:
|
### Building the library
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cargo build
|
$ cargo build
|
||||||
```
|
```
|
||||||
|
|
||||||
Building and running the example (Linux, MacOS X):
|
### Building and running the example (Linux, MacOS X)
|
||||||
|
|
||||||
```
|
```
|
||||||
$ cargo run --example onoff_light
|
$ cargo run --example onoff_light
|
||||||
```
|
```
|
||||||
|
|
||||||
Building the example (Espressif's ESP-IDF):
|
### Building the example (Espressif's ESP-IDF)
|
||||||
|
|
||||||
* Install all build prerequisites described [here](https://github.com/esp-rs/esp-idf-template#prerequisites)
|
* Install all build prerequisites described [here](https://github.com/esp-rs/esp-idf-template#prerequisites)
|
||||||
* Build with the following command line:
|
* Build with the following command line:
|
||||||
```
|
```
|
||||||
export MCU=esp32; export CARGO_TARGET_XTENSA_ESP32_ESPIDF_LINKER=ldproxy; export RUSTFLAGS="-C default-linker-libraries"; export WIFI_SSID=ssid;export WIFI_PASS=pass; cargo build --example onoff_light --no-default-features --features std,crypto_rustcrypto --target xtensa-esp32-espidf -Zbuild-std=std,panic_abort
|
export MCU=esp32; export CARGO_TARGET_XTENSA_ESP32_ESPIDF_LINKER=ldproxy; export RUSTFLAGS="-C default-linker-libraries"; export WIFI_SSID=ssid;export WIFI_PASS=pass; cargo build --example onoff_light --no-default-features --features esp-idf --target xtensa-esp32-espidf -Zbuild-std=std,panic_abort
|
||||||
```
|
```
|
||||||
* If you are building for a different Espressif MCU, change the `MCU` variable, the `xtensa-esp32-espidf` target and the name of the `CARGO_TARGET_<esp-idf-target-uppercase>_LINKER` variable to match your MCU and its Rust target. Available Espressif MCUs and targets are:
|
* If you are building for a different Espressif MCU, change the `MCU` variable, the `xtensa-esp32-espidf` target and the name of the `CARGO_TARGET_<esp-idf-target-uppercase>_LINKER` variable to match your MCU and its Rust target. Available Espressif MCUs and targets are:
|
||||||
* esp32 / xtensa-esp32-espidf
|
* esp32 / xtensa-esp32-espidf
|
||||||
|
@ -69,6 +70,10 @@ export MCU=esp32; export CARGO_TARGET_XTENSA_ESP32_ESPIDF_LINKER=ldproxy; export
|
||||||
* Put in `WIFI_SSID` / `WIFI_PASS` the SSID & password for your wireless router
|
* Put in `WIFI_SSID` / `WIFI_PASS` the SSID & password for your wireless router
|
||||||
* Flash using the `espflash` utility described in the build prerequsites' link above
|
* Flash using the `espflash` utility described in the build prerequsites' link above
|
||||||
|
|
||||||
|
### Building the example (ESP32-XX baremetal or RP2040)
|
||||||
|
|
||||||
|
Coming soon!
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
||||||
With the `chip-tool` (the current tool for testing Matter) use the Ethernet commissioning mechanism:
|
With the `chip-tool` (the current tool for testing Matter) use the Ethernet commissioning mechanism:
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
use core::borrow::Borrow;
|
use core::borrow::Borrow;
|
||||||
use core::pin::pin;
|
use core::pin::pin;
|
||||||
|
|
||||||
|
use embassy_futures::select::select3;
|
||||||
use log::info;
|
use log::info;
|
||||||
use matter::core::{CommissioningData, Matter};
|
use matter::core::{CommissioningData, Matter};
|
||||||
use matter::data_model::cluster_basic_information::BasicInfoConfig;
|
use matter::data_model::cluster_basic_information::BasicInfoConfig;
|
||||||
|
@ -27,18 +28,18 @@ use matter::data_model::objects::*;
|
||||||
use matter::data_model::root_endpoint;
|
use matter::data_model::root_endpoint;
|
||||||
use matter::data_model::system_model::descriptor;
|
use matter::data_model::system_model::descriptor;
|
||||||
use matter::error::Error;
|
use matter::error::Error;
|
||||||
use matter::mdns::MdnsService;
|
use matter::mdns::{MdnsRunBuffers, MdnsService};
|
||||||
use matter::persist::FilePsm;
|
|
||||||
use matter::secure_channel::spake2p::VerifierData;
|
use matter::secure_channel::spake2p::VerifierData;
|
||||||
|
use matter::transport::core::RunBuffers;
|
||||||
use matter::transport::network::{Ipv4Addr, Ipv6Addr, NetworkStack};
|
use matter::transport::network::{Ipv4Addr, Ipv6Addr, NetworkStack};
|
||||||
use matter::transport::runner::{AllUdpBuffers, TransportRunner};
|
use matter::utils::select::EitherUnwrap;
|
||||||
|
|
||||||
mod dev_att;
|
mod dev_att;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
fn main() -> Result<(), Error> {
|
fn main() -> Result<(), Error> {
|
||||||
let thread = std::thread::Builder::new()
|
let thread = std::thread::Builder::new()
|
||||||
.stack_size(140 * 1024)
|
.stack_size(150 * 1024)
|
||||||
.spawn(run)
|
.spawn(run)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -56,11 +57,11 @@ fn run() -> Result<(), Error> {
|
||||||
initialize_logger();
|
initialize_logger();
|
||||||
|
|
||||||
info!(
|
info!(
|
||||||
"Matter memory: mDNS={}, Matter={}, TransportRunner={}, UdpBuffers={}",
|
"Matter memory: mDNS={}, Matter={}, MdnsBuffers={}, RunBuffers={}",
|
||||||
core::mem::size_of::<MdnsService>(),
|
core::mem::size_of::<MdnsService>(),
|
||||||
core::mem::size_of::<Matter>(),
|
core::mem::size_of::<Matter>(),
|
||||||
core::mem::size_of::<TransportRunner>(),
|
core::mem::size_of::<MdnsRunBuffers>(),
|
||||||
core::mem::size_of::<AllUdpBuffers>(),
|
core::mem::size_of::<RunBuffers>(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let dev_det = BasicInfoConfig {
|
let dev_det = BasicInfoConfig {
|
||||||
|
@ -73,12 +74,6 @@ fn run() -> Result<(), Error> {
|
||||||
device_name: "OnOff Light",
|
device_name: "OnOff Light",
|
||||||
};
|
};
|
||||||
|
|
||||||
let psm_path = std::env::temp_dir().join("matter-iot");
|
|
||||||
info!("Persisting from/to {}", psm_path.display());
|
|
||||||
|
|
||||||
#[cfg(all(feature = "std", not(target_os = "espidf")))]
|
|
||||||
let psm = matter::persist::FilePsm::new(psm_path)?;
|
|
||||||
|
|
||||||
let (ipv4_addr, ipv6_addr, interface) = initialize_network()?;
|
let (ipv4_addr, ipv6_addr, interface) = initialize_network()?;
|
||||||
|
|
||||||
let dev_att = dev_att::HardCodedDevAtt::new();
|
let dev_att = dev_att::HardCodedDevAtt::new();
|
||||||
|
@ -106,7 +101,7 @@ fn run() -> Result<(), Error> {
|
||||||
matter::MATTER_PORT,
|
matter::MATTER_PORT,
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("mDNS initialized: {:p}", &mdns);
|
info!("mDNS initialized");
|
||||||
|
|
||||||
let matter = Matter::new(
|
let matter = Matter::new(
|
||||||
// vid/pid should match those in the DAC
|
// vid/pid should match those in the DAC
|
||||||
|
@ -118,36 +113,28 @@ fn run() -> Result<(), Error> {
|
||||||
matter::MATTER_PORT,
|
matter::MATTER_PORT,
|
||||||
);
|
);
|
||||||
|
|
||||||
info!("Matter initialized: {:p}", &matter);
|
info!("Matter initialized");
|
||||||
|
|
||||||
#[cfg(all(feature = "std", not(target_os = "espidf")))]
|
#[cfg(all(feature = "std", not(target_os = "espidf")))]
|
||||||
{
|
let mut psm = matter::persist::Psm::new(&matter, std::env::temp_dir().join("matter-iot"))?;
|
||||||
let mut buf = [0; 4096];
|
|
||||||
let buf = &mut buf;
|
|
||||||
if let Some(data) = psm.load("acls", buf)? {
|
|
||||||
matter.load_acls(data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(data) = psm.load("fabrics", buf)? {
|
|
||||||
matter.load_fabrics(data)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut runner = TransportRunner::new(&matter);
|
|
||||||
|
|
||||||
info!("Transport runner initialized: {:p}", &runner);
|
|
||||||
|
|
||||||
let handler = HandlerCompat(handler(&matter));
|
let handler = HandlerCompat(handler(&matter));
|
||||||
|
|
||||||
// NOTE (no_std): If using the `embassy-net` UDP implementation, replace this dummy stack with the `embassy-net` one
|
// When using a custom UDP stack, remove the network stack initialization below
|
||||||
// When using a custom UDP stack, remove this
|
// and call `Matter::run_piped()` instead, by utilizing the TX & RX `Pipe` structs
|
||||||
|
// to push/pull your UDP packets from/to the Matter stack.
|
||||||
|
// Ditto for `MdnsService`.
|
||||||
|
//
|
||||||
|
// When using the `embassy-net` feature (as opposed to the Rust Standard Library network stack),
|
||||||
|
// this initialization would be more complex.
|
||||||
let stack = NetworkStack::new();
|
let stack = NetworkStack::new();
|
||||||
|
|
||||||
let mut buffers = AllUdpBuffers::new();
|
let mut mdns_buffers = MdnsRunBuffers::new();
|
||||||
|
let mut mdns_runner = pin!(mdns.run(&stack, &mut mdns_buffers));
|
||||||
|
|
||||||
let mut fut = pin!(runner.run_udp_all(
|
let mut buffers = RunBuffers::new();
|
||||||
|
let mut runner = matter.run(
|
||||||
&stack,
|
&stack,
|
||||||
&mdns,
|
|
||||||
&mut buffers,
|
&mut buffers,
|
||||||
CommissioningData {
|
CommissioningData {
|
||||||
// TODO: Hard-coded for now
|
// TODO: Hard-coded for now
|
||||||
|
@ -155,16 +142,30 @@ fn run() -> Result<(), Error> {
|
||||||
discriminator: 250,
|
discriminator: 250,
|
||||||
},
|
},
|
||||||
&handler,
|
&handler,
|
||||||
));
|
);
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Matter transport runner memory: {}",
|
||||||
|
core::mem::size_of_val(&runner)
|
||||||
|
);
|
||||||
|
|
||||||
|
let mut runner = pin!(runner);
|
||||||
|
|
||||||
|
#[cfg(all(feature = "std", not(target_os = "espidf")))]
|
||||||
|
let mut psm_runner = pin!(psm.run());
|
||||||
|
|
||||||
|
#[cfg(not(all(feature = "std", not(target_os = "espidf"))))]
|
||||||
|
let mut psm_runner = pin!(core::future::pending());
|
||||||
|
|
||||||
|
let mut runner = select3(&mut runner, &mut mdns_runner, &mut psm_runner);
|
||||||
|
|
||||||
// NOTE: For no_std, replace with your own no_std way of polling the future
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
async_io::block_on(&mut fut)?;
|
async_io::block_on(&mut runner).unwrap()?;
|
||||||
|
|
||||||
// NOTE (no_std): For no_std, replace with your own more efficient no_std executor,
|
// NOTE (no_std): For no_std, replace with your own more efficient no_std executor,
|
||||||
// because the executor used below is a simple busy-loop poller
|
// because the executor used below is a simple busy-loop poller
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
embassy_futures::block_on(&mut fut)?;
|
embassy_futures::block_on(&mut runner).unwrap()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -268,26 +269,6 @@ fn initialize_network() -> Result<(Ipv4Addr, Ipv6Addr, u32), Error> {
|
||||||
Ok((ip, ipv6, 0 as _))
|
Ok((ip, ipv6, 0 as _))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "std", not(target_os = "espidf")))]
|
|
||||||
#[inline(never)]
|
|
||||||
async fn save(matter: &Matter<'_>, psm: &FilePsm) -> Result<(), Error> {
|
|
||||||
let mut buf = [0; 4096];
|
|
||||||
let buf = &mut buf;
|
|
||||||
|
|
||||||
loop {
|
|
||||||
matter.wait_changed().await;
|
|
||||||
if matter.is_changed() {
|
|
||||||
if let Some(data) = matter.store_acls(buf)? {
|
|
||||||
psm.store("acls", data)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(data) = matter.store_fabrics(buf)? {
|
|
||||||
psm.store("fabrics", data)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "espidf")]
|
#[cfg(target_os = "espidf")]
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
fn initialize_logger() {
|
fn initialize_logger() {
|
||||||
|
|
|
@ -8,23 +8,23 @@ repository = "https://github.com/kedars/matter-rs"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
keywords = ["matter", "smart", "smart-home", "IoT", "ESP32"]
|
keywords = ["matter", "smart", "smart-home", "IoT", "ESP32"]
|
||||||
categories = ["embedded", "network-programming"]
|
categories = ["embedded", "network-programming"]
|
||||||
license = "MIT"
|
license = "Apache-2.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "matter"
|
name = "matter"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["os", "crypto_rustcrypto"]
|
default = ["os", "mbedtls"]
|
||||||
os = ["std", "backtrace", "env_logger", "nix", "critical-section/std", "embassy-sync/std", "embassy-time/std"]
|
os = ["std", "backtrace", "env_logger", "nix", "critical-section/std", "embassy-sync/std", "embassy-time/std"]
|
||||||
esp-idf = ["std", "crypto_rustcrypto", "esp-idf-sys", "esp-idf-hal", "esp-idf-svc"]
|
esp-idf = ["std", "rustcrypto", "esp-idf-sys"]
|
||||||
std = ["alloc", "rand", "qrcode", "async-io", "esp-idf-sys?/std", "embassy-time/generic-queue-16"]
|
std = ["alloc", "rand", "qrcode", "async-io", "esp-idf-sys?/std", "embassy-time/generic-queue-16"]
|
||||||
backtrace = []
|
backtrace = []
|
||||||
alloc = []
|
alloc = []
|
||||||
nightly = []
|
nightly = []
|
||||||
crypto_openssl = ["alloc", "openssl", "foreign-types", "hmac", "sha2"]
|
openssl = ["alloc", "dep:openssl", "foreign-types", "hmac", "sha2"]
|
||||||
crypto_mbedtls = ["alloc", "mbedtls"]
|
mbedtls = ["alloc", "dep:mbedtls"]
|
||||||
crypto_rustcrypto = ["alloc", "sha2", "hmac", "pbkdf2", "hkdf", "aes", "ccm", "p256", "elliptic-curve", "crypto-bigint", "x509-cert", "rand_core"]
|
rustcrypto = ["alloc", "sha2", "hmac", "pbkdf2", "hkdf", "aes", "ccm", "p256", "elliptic-curve", "crypto-bigint", "x509-cert", "rand_core"]
|
||||||
embassy-net = ["dep:embassy-net", "dep:embassy-net-driver", "smoltcp"]
|
embassy-net = ["dep:embassy-net", "dep:embassy-net-driver", "smoltcp"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -58,10 +58,10 @@ smoltcp = { version = "0.10", default-features = false, optional = true }
|
||||||
# STD-only dependencies
|
# STD-only dependencies
|
||||||
rand = { version = "0.8.5", optional = true }
|
rand = { version = "0.8.5", optional = true }
|
||||||
qrcode = { version = "0.12", default-features = false, optional = true } # Print QR code
|
qrcode = { version = "0.12", default-features = false, optional = true } # Print QR code
|
||||||
async-io = { version = "=1.12", optional = true } # =1.2 for compatibility with ESP IDF
|
async-io = { version = "=1.12", optional = true } # =1.12 for compatibility with ESP IDF
|
||||||
|
|
||||||
# crypto
|
# crypto
|
||||||
openssl = { git = "https://github.com/sfackler/rust-openssl", optional = true }
|
openssl = { version = "0.10.55", optional = true }
|
||||||
foreign-types = { version = "0.3.2", optional = true }
|
foreign-types = { version = "0.3.2", optional = true }
|
||||||
|
|
||||||
# rust-crypto
|
# rust-crypto
|
||||||
|
@ -81,18 +81,22 @@ x509-cert = { version = "0.2.0", default-features = false, features = ["pem"], o
|
||||||
astro-dnssd = { version = "0.3" }
|
astro-dnssd = { version = "0.3" }
|
||||||
|
|
||||||
[target.'cfg(not(target_os = "espidf"))'.dependencies]
|
[target.'cfg(not(target_os = "espidf"))'.dependencies]
|
||||||
mbedtls = { git = "https://github.com/fortanix/rust-mbedtls", optional = true }
|
mbedtls = { version = "0.9", optional = true }
|
||||||
env_logger = { version = "0.10.0", optional = true }
|
env_logger = { version = "0.10.0", optional = true }
|
||||||
nix = { version = "0.26", features = ["net"], optional = true }
|
nix = { version = "0.26", features = ["net"], optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_os = "espidf")'.dependencies]
|
[target.'cfg(target_os = "espidf")'.dependencies]
|
||||||
esp-idf-sys = { version = "0.33", optional = true, default-features = false, features = ["native", "binstart"] }
|
esp-idf-sys = { version = "0.33", optional = true, default-features = false, features = ["native"] }
|
||||||
esp-idf-hal = { version = "0.41", optional = true, features = ["embassy-sync", "critical-section"] } # TODO: Only necessary for the examples
|
|
||||||
esp-idf-svc = { version = "0.46", optional = true, features = ["embassy-time-driver"] } # TODO: Only necessary for the examples
|
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
embuild = "0.31.2"
|
embuild = "0.31.2"
|
||||||
|
|
||||||
|
[target.'cfg(target_os = "espidf")'.dev-dependencies]
|
||||||
|
esp-idf-sys = { version = "0.33", default-features = false, features = ["binstart"] }
|
||||||
|
esp-idf-hal = { version = "0.41", features = ["embassy-sync", "critical-section"] }
|
||||||
|
esp-idf-svc = { version = "0.46", features = ["embassy-time-driver"] }
|
||||||
|
embedded-svc = { version = "0.25" }
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "onoff_light"
|
name = "onoff_light"
|
||||||
path = "../examples/onoff_light/src/main.rs"
|
path = "../examples/onoff_light/src/main.rs"
|
||||||
|
|
|
@ -28,8 +28,11 @@ use crate::{
|
||||||
mdns::Mdns,
|
mdns::Mdns,
|
||||||
pairing::{print_pairing_code_and_qr, DiscoveryCapabilities},
|
pairing::{print_pairing_code_and_qr, DiscoveryCapabilities},
|
||||||
secure_channel::{pake::PaseMgr, spake2p::VerifierData},
|
secure_channel::{pake::PaseMgr, spake2p::VerifierData},
|
||||||
transport::exchange::Notification,
|
transport::{
|
||||||
utils::{epoch::Epoch, rand::Rand},
|
exchange::{ExchangeCtx, MAX_EXCHANGES},
|
||||||
|
session::SessionMgr,
|
||||||
|
},
|
||||||
|
utils::{epoch::Epoch, rand::Rand, select::Notification},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The Matter Port */
|
/* The Matter Port */
|
||||||
|
@ -45,17 +48,20 @@ pub struct CommissioningData {
|
||||||
|
|
||||||
/// The primary Matter Object
|
/// The primary Matter Object
|
||||||
pub struct Matter<'a> {
|
pub struct Matter<'a> {
|
||||||
pub fabric_mgr: RefCell<FabricMgr>,
|
fabric_mgr: RefCell<FabricMgr>,
|
||||||
pub acl_mgr: RefCell<AclMgr>,
|
pub acl_mgr: RefCell<AclMgr>, // Public for tests
|
||||||
pub pase_mgr: RefCell<PaseMgr>,
|
pase_mgr: RefCell<PaseMgr>,
|
||||||
pub failsafe: RefCell<FailSafe>,
|
failsafe: RefCell<FailSafe>,
|
||||||
pub persist_notification: Notification,
|
persist_notification: Notification,
|
||||||
pub mdns: &'a dyn Mdns,
|
pub(crate) send_notification: Notification,
|
||||||
pub epoch: Epoch,
|
mdns: &'a dyn Mdns,
|
||||||
pub rand: Rand,
|
pub(crate) epoch: Epoch,
|
||||||
pub dev_det: &'a BasicInfoConfig<'a>,
|
pub(crate) rand: Rand,
|
||||||
pub dev_att: &'a dyn DevAttDataFetcher,
|
dev_det: &'a BasicInfoConfig<'a>,
|
||||||
pub port: u16,
|
dev_att: &'a dyn DevAttDataFetcher,
|
||||||
|
pub(crate) port: u16,
|
||||||
|
pub(crate) exchanges: RefCell<heapless::Vec<ExchangeCtx, MAX_EXCHANGES>>,
|
||||||
|
pub session_mgr: RefCell<SessionMgr>, // Public for tests
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Matter<'a> {
|
impl<'a> Matter<'a> {
|
||||||
|
@ -94,12 +100,15 @@ impl<'a> Matter<'a> {
|
||||||
pase_mgr: RefCell::new(PaseMgr::new(epoch, rand)),
|
pase_mgr: RefCell::new(PaseMgr::new(epoch, rand)),
|
||||||
failsafe: RefCell::new(FailSafe::new()),
|
failsafe: RefCell::new(FailSafe::new()),
|
||||||
persist_notification: Notification::new(),
|
persist_notification: Notification::new(),
|
||||||
|
send_notification: Notification::new(),
|
||||||
mdns,
|
mdns,
|
||||||
epoch,
|
epoch,
|
||||||
rand,
|
rand,
|
||||||
dev_det,
|
dev_det,
|
||||||
dev_att,
|
dev_att,
|
||||||
port,
|
port,
|
||||||
|
exchanges: RefCell::new(heapless::Vec::new()),
|
||||||
|
session_mgr: RefCell::new(SessionMgr::new(epoch, rand)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +169,7 @@ impl<'a> Matter<'a> {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn notify_changed(&self) {
|
pub fn notify_changed(&self) {
|
||||||
if self.is_changed() {
|
if self.is_changed() {
|
||||||
self.persist_notification.signal(());
|
self.persist_notification.signal(());
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
|
use core::fmt::{self, Debug};
|
||||||
|
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
|
@ -355,3 +357,9 @@ impl Sha256 {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Sha256 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "Sha256")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use core::fmt::{self, Debug};
|
||||||
|
|
||||||
use crate::error::{Error, ErrorCode};
|
use crate::error::{Error, ErrorCode};
|
||||||
use crate::utils::rand::Rand;
|
use crate::utils::rand::Rand;
|
||||||
|
|
||||||
|
@ -391,3 +393,9 @@ impl Sha256 {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Debug for Sha256 {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||||
|
write!(f, "Sha256")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -37,37 +37,29 @@ pub const ECDH_SHARED_SECRET_LEN_BYTES: usize = 32;
|
||||||
|
|
||||||
pub const EC_SIGNATURE_LEN_BYTES: usize = 64;
|
pub const EC_SIGNATURE_LEN_BYTES: usize = 64;
|
||||||
|
|
||||||
#[cfg(all(feature = "crypto_mbedtls", target_os = "espidf"))]
|
#[cfg(all(feature = "mbedtls", target_os = "espidf"))]
|
||||||
mod crypto_esp_mbedtls;
|
mod crypto_esp_mbedtls;
|
||||||
#[cfg(all(feature = "crypto_mbedtls", target_os = "espidf"))]
|
#[cfg(all(feature = "mbedtls", target_os = "espidf"))]
|
||||||
pub use self::crypto_esp_mbedtls::*;
|
pub use self::crypto_esp_mbedtls::*;
|
||||||
|
|
||||||
#[cfg(all(feature = "crypto_mbedtls", not(target_os = "espidf")))]
|
#[cfg(all(feature = "mbedtls", not(target_os = "espidf")))]
|
||||||
mod crypto_mbedtls;
|
mod crypto_mbedtls;
|
||||||
#[cfg(all(feature = "crypto_mbedtls", not(target_os = "espidf")))]
|
#[cfg(all(feature = "mbedtls", not(target_os = "espidf")))]
|
||||||
pub use self::crypto_mbedtls::*;
|
pub use self::crypto_mbedtls::*;
|
||||||
|
|
||||||
#[cfg(feature = "crypto_openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
mod crypto_openssl;
|
mod crypto_openssl;
|
||||||
#[cfg(feature = "crypto_openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
pub use self::crypto_openssl::*;
|
pub use self::crypto_openssl::*;
|
||||||
|
|
||||||
#[cfg(feature = "crypto_rustcrypto")]
|
#[cfg(feature = "rustcrypto")]
|
||||||
mod crypto_rustcrypto;
|
mod crypto_rustcrypto;
|
||||||
#[cfg(feature = "crypto_rustcrypto")]
|
#[cfg(feature = "rustcrypto")]
|
||||||
pub use self::crypto_rustcrypto::*;
|
pub use self::crypto_rustcrypto::*;
|
||||||
|
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(feature = "openssl", feature = "mbedtls", feature = "rustcrypto")))]
|
||||||
feature = "crypto_openssl",
|
|
||||||
feature = "crypto_mbedtls",
|
|
||||||
feature = "crypto_rustcrypto"
|
|
||||||
)))]
|
|
||||||
pub mod crypto_dummy;
|
pub mod crypto_dummy;
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(feature = "openssl", feature = "mbedtls", feature = "rustcrypto")))]
|
||||||
feature = "crypto_openssl",
|
|
||||||
feature = "crypto_mbedtls",
|
|
||||||
feature = "crypto_rustcrypto"
|
|
||||||
)))]
|
|
||||||
pub use self::crypto_dummy::*;
|
pub use self::crypto_dummy::*;
|
||||||
|
|
||||||
impl<'a> FromTLV<'a> for KeyPair {
|
impl<'a> FromTLV<'a> for KeyPair {
|
||||||
|
|
|
@ -1,3 +1,20 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020-2022 Project CHIP Authors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
use crate::data_model::objects::Node;
|
use crate::data_model::objects::Node;
|
||||||
|
|
||||||
#[cfg(feature = "nightly")]
|
#[cfg(feature = "nightly")]
|
||||||
|
|
|
@ -149,7 +149,7 @@ impl<T> From<std::sync::PoisonError<T>> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "crypto_openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
impl From<openssl::error::ErrorStack> for Error {
|
impl From<openssl::error::ErrorStack> for Error {
|
||||||
fn from(e: openssl::error::ErrorStack) -> Self {
|
fn from(e: openssl::error::ErrorStack) -> Self {
|
||||||
::log::error!("Error in TLS: {}", e);
|
::log::error!("Error in TLS: {}", e);
|
||||||
|
@ -157,7 +157,7 @@ impl From<openssl::error::ErrorStack> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "crypto_mbedtls", not(target_os = "espidf")))]
|
#[cfg(all(feature = "mbedtls", not(target_os = "espidf")))]
|
||||||
impl From<mbedtls::Error> for Error {
|
impl From<mbedtls::Error> for Error {
|
||||||
fn from(e: mbedtls::Error) -> Self {
|
fn from(e: mbedtls::Error) -> Self {
|
||||||
::log::error!("Error in TLS: {}", e);
|
::log::error!("Error in TLS: {}", e);
|
||||||
|
@ -173,7 +173,7 @@ impl From<esp_idf_sys::EspError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "crypto_rustcrypto")]
|
#[cfg(feature = "rustcrypto")]
|
||||||
impl From<ccm::aead::Error> for Error {
|
impl From<ccm::aead::Error> for Error {
|
||||||
fn from(_e: ccm::aead::Error) -> Self {
|
fn from(_e: ccm::aead::Error) -> Self {
|
||||||
Self::new(ErrorCode::Crypto)
|
Self::new(ErrorCode::Crypto)
|
||||||
|
|
|
@ -609,7 +609,7 @@ impl<'a, 'r, 'p> Interaction<'a, 'r, 'p> {
|
||||||
rx: &mut Packet<'_>,
|
rx: &mut Packet<'_>,
|
||||||
tx: &mut Packet<'_>,
|
tx: &mut Packet<'_>,
|
||||||
) -> Result<Option<Duration>, Error> {
|
) -> Result<Option<Duration>, Error> {
|
||||||
let epoch = exchange.transport().matter().epoch;
|
let epoch = exchange.matter.epoch;
|
||||||
|
|
||||||
let mut opcode: OpCode = rx.get_proto_opcode()?;
|
let mut opcode: OpCode = rx.get_proto_opcode()?;
|
||||||
|
|
||||||
|
@ -641,7 +641,7 @@ impl<'a, 'r, 'p> Interaction<'a, 'r, 'p> {
|
||||||
where
|
where
|
||||||
S: FnOnce() -> u32,
|
S: FnOnce() -> u32,
|
||||||
{
|
{
|
||||||
let epoch = exchange.transport().matter().epoch;
|
let epoch = exchange.matter.epoch;
|
||||||
|
|
||||||
let opcode = rx.get_proto_opcode()?;
|
let opcode = rx.get_proto_opcode()?;
|
||||||
let rx_data = rx.as_slice();
|
let rx_data = rx.as_slice();
|
||||||
|
|
|
@ -55,19 +55,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(feature = "std", target_os = "macos"))]
|
|
||||||
pub use astro::MdnsRunner;
|
|
||||||
#[cfg(all(feature = "std", target_os = "macos"))]
|
#[cfg(all(feature = "std", target_os = "macos"))]
|
||||||
pub use astro::MdnsService;
|
pub use astro::MdnsService;
|
||||||
#[cfg(all(feature = "std", target_os = "macos"))]
|
#[cfg(all(feature = "std", target_os = "macos"))]
|
||||||
pub use astro::MdnsUdpBuffers;
|
pub use astro::MdnsUdpBuffers;
|
||||||
|
|
||||||
#[cfg(not(all(feature = "std", target_os = "macos")))]
|
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
||||||
pub use builtin::MdnsRunner;
|
pub use builtin::MdnsRunBuffers;
|
||||||
#[cfg(not(all(feature = "std", target_os = "macos")))]
|
#[cfg(not(all(feature = "std", target_os = "macos")))]
|
||||||
pub use builtin::MdnsService;
|
pub use builtin::MdnsService;
|
||||||
#[cfg(not(all(feature = "std", target_os = "macos")))]
|
|
||||||
pub use builtin::MdnsUdpBuffers;
|
|
||||||
|
|
||||||
pub struct DummyMdns;
|
pub struct DummyMdns;
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,17 @@ use log::info;
|
||||||
|
|
||||||
use super::ServiceMode;
|
use super::ServiceMode;
|
||||||
|
|
||||||
|
/// Only for API-compatibility with builtin::MdnsRunner
|
||||||
|
pub struct MdnsUdpBuffers(());
|
||||||
|
|
||||||
|
/// Only for API-compatibility with builtin::MdnsRunner
|
||||||
|
impl MdnsUdpBuffers {
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MdnsService<'a> {
|
pub struct MdnsService<'a> {
|
||||||
dev_det: &'a BasicInfoConfig<'a>,
|
dev_det: &'a BasicInfoConfig<'a>,
|
||||||
matter_port: u16,
|
matter_port: u16,
|
||||||
|
@ -78,16 +89,15 @@ impl<'a> MdnsService<'a> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Only for API-compatibility with builtin::MdnsRunner
|
/// Only for API-compatibility with builtin::MdnsRunner
|
||||||
pub struct MdnsUdpBuffers(());
|
pub async fn run_udp(&mut self, buffers: &mut MdnsUdpBuffers) -> Result<(), Error> {
|
||||||
|
core::future::pending::<Result<(), Error>>().await
|
||||||
|
}
|
||||||
|
|
||||||
/// Only for API-compatibility with builtin::MdnsRunner
|
/// Only for API-compatibility with builtin::MdnsRunner
|
||||||
impl MdnsUdpBuffers {
|
pub async fn run(&self, _tx_pipe: &Pipe<'_>, _rx_pipe: &Pipe<'_>) -> Result<(), Error> {
|
||||||
#[inline(always)]
|
core::future::pending::<Result<(), Error>>().await
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,21 +110,3 @@ impl<'a> super::Mdns for MdnsService<'a> {
|
||||||
MdnsService::remove(self, service)
|
MdnsService::remove(self, service)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only for API-compatibility with builtin::MdnsRunner
|
|
||||||
pub struct MdnsRunner<'a>(&'a MdnsService<'a>);
|
|
||||||
|
|
||||||
/// Only for API-compatibility with builtin::MdnsRunner
|
|
||||||
impl<'a> MdnsRunner<'a> {
|
|
||||||
pub const fn new(mdns: &'a MdnsService<'a>) -> Self {
|
|
||||||
Self(mdns)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run_udp(&mut self, buffers: &mut MdnsUdpBuffers) -> Result<(), Error> {
|
|
||||||
core::future::pending::<Result<(), Error>>().await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run(&self, _tx_pipe: &Pipe<'_>, _rx_pipe: &Pipe<'_>) -> Result<(), Error> {
|
|
||||||
core::future::pending::<Result<(), Error>>().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -22,6 +22,25 @@ const IPV6_BROADCAST_ADDR: Ipv6Addr = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0, 0x
|
||||||
|
|
||||||
const PORT: u16 = 5353;
|
const PORT: u16 = 5353;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
||||||
|
pub struct MdnsRunBuffers {
|
||||||
|
udp: crate::transport::udp::UdpBuffers,
|
||||||
|
tx_buf: core::mem::MaybeUninit<[u8; crate::transport::packet::MAX_TX_BUF_SIZE]>,
|
||||||
|
rx_buf: core::mem::MaybeUninit<[u8; crate::transport::packet::MAX_RX_BUF_SIZE]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
||||||
|
impl MdnsRunBuffers {
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
udp: crate::transport::udp::UdpBuffers::new(),
|
||||||
|
tx_buf: core::mem::MaybeUninit::uninit(),
|
||||||
|
rx_buf: core::mem::MaybeUninit::uninit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct MdnsService<'a> {
|
pub struct MdnsService<'a> {
|
||||||
host: Host<'a>,
|
host: Host<'a>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
|
@ -100,39 +119,12 @@ impl<'a> MdnsService<'a> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
pub struct MdnsUdpBuffers {
|
|
||||||
udp: crate::transport::udp::UdpBuffers,
|
|
||||||
tx_buf: core::mem::MaybeUninit<[u8; crate::transport::packet::MAX_TX_BUF_SIZE]>,
|
|
||||||
rx_buf: core::mem::MaybeUninit<[u8; crate::transport::packet::MAX_RX_BUF_SIZE]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
impl MdnsUdpBuffers {
|
|
||||||
#[inline(always)]
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
udp: crate::transport::udp::UdpBuffers::new(),
|
|
||||||
tx_buf: core::mem::MaybeUninit::uninit(),
|
|
||||||
rx_buf: core::mem::MaybeUninit::uninit(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct MdnsRunner<'a>(&'a MdnsService<'a>);
|
|
||||||
|
|
||||||
impl<'a> MdnsRunner<'a> {
|
|
||||||
pub const fn new(mdns: &'a MdnsService<'a>) -> Self {
|
|
||||||
Self(mdns)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
||||||
pub async fn run_udp<D>(
|
pub async fn run<D>(
|
||||||
&mut self,
|
&self,
|
||||||
stack: &crate::transport::network::NetworkStack<D>,
|
stack: &crate::transport::network::NetworkStack<D>,
|
||||||
buffers: &mut MdnsUdpBuffers,
|
buffers: &mut MdnsRunBuffers,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
D: crate::transport::network::NetworkStackDriver,
|
D: crate::transport::network::NetworkStackDriver,
|
||||||
|
@ -146,14 +138,14 @@ impl<'a> MdnsRunner<'a> {
|
||||||
|
|
||||||
// V6 multicast does not work with smoltcp yet (see https://github.com/smoltcp-rs/smoltcp/pull/602)
|
// V6 multicast does not work with smoltcp yet (see https://github.com/smoltcp-rs/smoltcp/pull/602)
|
||||||
#[cfg(not(feature = "embassy-net"))]
|
#[cfg(not(feature = "embassy-net"))]
|
||||||
if let Some(interface) = self.0.interface {
|
if let Some(interface) = self.interface {
|
||||||
udp.join_multicast_v6(IPV6_BROADCAST_ADDR, interface)
|
udp.join_multicast_v6(IPV6_BROADCAST_ADDR, interface)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
udp.join_multicast_v4(
|
udp.join_multicast_v4(
|
||||||
IP_BROADCAST_ADDR,
|
IP_BROADCAST_ADDR,
|
||||||
crate::transport::network::Ipv4Addr::from(self.0.host.ip),
|
crate::transport::network::Ipv4Addr::from(self.host.ip),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -202,14 +194,14 @@ impl<'a> MdnsRunner<'a> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut run = pin!(async move { self.run(tx_pipe, rx_pipe).await });
|
let mut run = pin!(async move { self.run_piped(tx_pipe, rx_pipe).await });
|
||||||
|
|
||||||
embassy_futures::select::select3(&mut tx, &mut rx, &mut run)
|
embassy_futures::select::select3(&mut tx, &mut rx, &mut run)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&self, tx_pipe: &Pipe<'_>, rx_pipe: &Pipe<'_>) -> Result<(), Error> {
|
pub async fn run_piped(&self, tx_pipe: &Pipe<'_>, rx_pipe: &Pipe<'_>) -> Result<(), Error> {
|
||||||
let mut broadcast = pin!(self.broadcast(tx_pipe));
|
let mut broadcast = pin!(self.broadcast(tx_pipe));
|
||||||
let mut respond = pin!(self.respond(rx_pipe, tx_pipe));
|
let mut respond = pin!(self.respond(rx_pipe, tx_pipe));
|
||||||
|
|
||||||
|
@ -220,7 +212,7 @@ impl<'a> MdnsRunner<'a> {
|
||||||
async fn broadcast(&self, tx_pipe: &Pipe<'_>) -> Result<(), Error> {
|
async fn broadcast(&self, tx_pipe: &Pipe<'_>) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
select(
|
select(
|
||||||
self.0.notification.wait(),
|
self.notification.wait(),
|
||||||
Timer::after(Duration::from_secs(30)),
|
Timer::after(Duration::from_secs(30)),
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
@ -229,13 +221,13 @@ impl<'a> MdnsRunner<'a> {
|
||||||
IpAddr::V4(IP_BROADCAST_ADDR),
|
IpAddr::V4(IP_BROADCAST_ADDR),
|
||||||
IpAddr::V6(IPV6_BROADCAST_ADDR),
|
IpAddr::V6(IPV6_BROADCAST_ADDR),
|
||||||
] {
|
] {
|
||||||
if self.0.interface.is_some() || addr == IpAddr::V4(IP_BROADCAST_ADDR) {
|
if self.interface.is_some() || addr == IpAddr::V4(IP_BROADCAST_ADDR) {
|
||||||
loop {
|
loop {
|
||||||
let sent = {
|
let sent = {
|
||||||
let mut data = tx_pipe.data.lock().await;
|
let mut data = tx_pipe.data.lock().await;
|
||||||
|
|
||||||
if data.chunk.is_none() {
|
if data.chunk.is_none() {
|
||||||
let len = self.0.host.broadcast(&self.0, data.buf, 60)?;
|
let len = self.host.broadcast(self, data.buf, 60)?;
|
||||||
|
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
info!("Broadasting mDNS entry to {}:{}", addr, PORT);
|
info!("Broadasting mDNS entry to {}:{}", addr, PORT);
|
||||||
|
@ -280,7 +272,7 @@ impl<'a> MdnsRunner<'a> {
|
||||||
let mut tx_data = tx_pipe.data.lock().await;
|
let mut tx_data = tx_pipe.data.lock().await;
|
||||||
|
|
||||||
if tx_data.chunk.is_none() {
|
if tx_data.chunk.is_none() {
|
||||||
let len = self.0.host.respond(&self.0, data, tx_data.buf, 60)?;
|
let len = self.host.respond(self, data, tx_data.buf, 60)?;
|
||||||
|
|
||||||
if len > 0 {
|
if len > 0 {
|
||||||
info!("Replying to mDNS query from {}", rx_chunk.addr);
|
info!("Replying to mDNS query from {}", rx_chunk.addr);
|
||||||
|
|
|
@ -96,7 +96,7 @@ pub fn print_pairing_code_and_qr(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(self) fn passwd_from_comm_data(comm_data: &CommissioningData) -> u32 {
|
fn passwd_from_comm_data(comm_data: &CommissioningData) -> u32 {
|
||||||
// todo: should this be part of the comm_data implementation?
|
// todo: should this be part of the comm_data implementation?
|
||||||
match comm_data.verifier.data {
|
match comm_data.verifier.data {
|
||||||
VerifierOption::Password(pwd) => pwd,
|
VerifierOption::Password(pwd) => pwd,
|
||||||
|
|
|
@ -15,31 +15,63 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use file_psm::*;
|
pub use fileio::*;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
mod file_psm {
|
pub mod fileio {
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
use crate::error::{Error, ErrorCode};
|
use crate::error::{Error, ErrorCode};
|
||||||
|
use crate::Matter;
|
||||||
|
|
||||||
pub struct FilePsm {
|
pub struct Psm<'a> {
|
||||||
|
matter: &'a Matter<'a>,
|
||||||
dir: PathBuf,
|
dir: PathBuf,
|
||||||
|
buf: [u8; 4096],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FilePsm {
|
impl<'a> Psm<'a> {
|
||||||
pub fn new(dir: PathBuf) -> Result<Self, Error> {
|
#[inline(always)]
|
||||||
|
pub fn new(matter: &'a Matter<'a>, dir: PathBuf) -> Result<Self, Error> {
|
||||||
fs::create_dir_all(&dir)?;
|
fs::create_dir_all(&dir)?;
|
||||||
|
|
||||||
Ok(Self { dir })
|
info!("Persisting from/to {}", dir.display());
|
||||||
|
|
||||||
|
let mut buf = [0; 4096];
|
||||||
|
|
||||||
|
if let Some(data) = Self::load(&dir, "acls", &mut buf)? {
|
||||||
|
matter.load_acls(data)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(data) = Self::load(&dir, "fabrics", &mut buf)? {
|
||||||
|
matter.load_fabrics(data)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Self { matter, dir, buf })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load<'a>(&self, key: &str, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
|
pub async fn run(&mut self) -> Result<(), Error> {
|
||||||
let path = self.dir.join(key);
|
loop {
|
||||||
|
self.matter.wait_changed().await;
|
||||||
|
|
||||||
|
if self.matter.is_changed() {
|
||||||
|
if let Some(data) = self.matter.store_acls(&mut self.buf)? {
|
||||||
|
Self::store(&self.dir, "acls", data)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(data) = self.matter.store_fabrics(&mut self.buf)? {
|
||||||
|
Self::store(&self.dir, "fabrics", data)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load<'b>(dir: &Path, key: &str, buf: &'b mut [u8]) -> Result<Option<&'b [u8]>, Error> {
|
||||||
|
let path = dir.join(key);
|
||||||
|
|
||||||
match fs::File::open(path) {
|
match fs::File::open(path) {
|
||||||
Ok(mut file) => {
|
Ok(mut file) => {
|
||||||
|
@ -69,8 +101,8 @@ mod file_psm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store(&self, key: &str, data: &[u8]) -> Result<(), Error> {
|
fn store(dir: &Path, key: &str, data: &[u8]) -> Result<(), Error> {
|
||||||
let path = self.dir.join(key);
|
let path = dir.join(key);
|
||||||
|
|
||||||
let mut file = fs::File::create(path)?;
|
let mut file = fs::File::create(path)?;
|
||||||
|
|
||||||
|
|
|
@ -15,17 +15,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(feature = "openssl", feature = "mbedtls", feature = "rustcrypto")))]
|
||||||
feature = "crypto_openssl",
|
|
||||||
feature = "crypto_mbedtls",
|
|
||||||
feature = "crypto_rustcrypto"
|
|
||||||
)))]
|
|
||||||
pub use super::crypto_dummy::CryptoSpake2;
|
pub use super::crypto_dummy::CryptoSpake2;
|
||||||
#[cfg(all(feature = "crypto_mbedtls", target_os = "espidf"))]
|
#[cfg(all(feature = "mbedtls", target_os = "espidf"))]
|
||||||
pub use super::crypto_esp_mbedtls::CryptoSpake2;
|
pub use super::crypto_esp_mbedtls::CryptoSpake2;
|
||||||
#[cfg(all(feature = "crypto_mbedtls", not(target_os = "espidf")))]
|
#[cfg(all(feature = "mbedtls", not(target_os = "espidf")))]
|
||||||
pub use super::crypto_mbedtls::CryptoSpake2;
|
pub use super::crypto_mbedtls::CryptoSpake2;
|
||||||
#[cfg(feature = "crypto_openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
pub use super::crypto_openssl::CryptoSpake2;
|
pub use super::crypto_openssl::CryptoSpake2;
|
||||||
#[cfg(feature = "crypto_rustcrypto")]
|
#[cfg(feature = "rustcrypto")]
|
||||||
pub use super::crypto_rustcrypto::CryptoSpake2;
|
pub use super::crypto_rustcrypto::CryptoSpake2;
|
||||||
|
|
|
@ -17,19 +17,15 @@
|
||||||
|
|
||||||
pub mod case;
|
pub mod case;
|
||||||
pub mod common;
|
pub mod common;
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(feature = "openssl", feature = "mbedtls", feature = "rustcrypto")))]
|
||||||
feature = "crypto_openssl",
|
|
||||||
feature = "crypto_mbedtls",
|
|
||||||
feature = "crypto_rustcrypto"
|
|
||||||
)))]
|
|
||||||
mod crypto_dummy;
|
mod crypto_dummy;
|
||||||
#[cfg(all(feature = "crypto_mbedtls", target_os = "espidf"))]
|
#[cfg(all(feature = "mbedtls", target_os = "espidf"))]
|
||||||
mod crypto_esp_mbedtls;
|
mod crypto_esp_mbedtls;
|
||||||
#[cfg(all(feature = "crypto_mbedtls", not(target_os = "espidf")))]
|
#[cfg(all(feature = "mbedtls", not(target_os = "espidf")))]
|
||||||
mod crypto_mbedtls;
|
mod crypto_mbedtls;
|
||||||
#[cfg(feature = "crypto_openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
pub mod crypto_openssl;
|
pub mod crypto_openssl;
|
||||||
#[cfg(feature = "crypto_rustcrypto")]
|
#[cfg(feature = "rustcrypto")]
|
||||||
pub mod crypto_rustcrypto;
|
pub mod crypto_rustcrypto;
|
||||||
|
|
||||||
pub mod core;
|
pub mod core;
|
||||||
|
|
|
@ -15,14 +15,18 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use core::{borrow::Borrow, cell::RefCell};
|
use core::borrow::Borrow;
|
||||||
|
use core::mem::MaybeUninit;
|
||||||
|
use core::pin::pin;
|
||||||
|
|
||||||
use embassy_futures::select::select;
|
use embassy_futures::select::{select, select_slice, Either};
|
||||||
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Channel};
|
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Channel};
|
||||||
use embassy_time::{Duration, Timer};
|
use embassy_time::{Duration, Timer};
|
||||||
|
|
||||||
use log::{error, info, warn};
|
use log::{error, info, warn};
|
||||||
|
|
||||||
|
use crate::utils::select::Notification;
|
||||||
|
use crate::CommissioningData;
|
||||||
use crate::{
|
use crate::{
|
||||||
alloc,
|
alloc,
|
||||||
data_model::{core::DataModel, objects::DataModelHandler},
|
data_model::{core::DataModel, objects::DataModelHandler},
|
||||||
|
@ -33,18 +37,17 @@ use crate::{
|
||||||
core::SecureChannel,
|
core::SecureChannel,
|
||||||
},
|
},
|
||||||
transport::packet::Packet,
|
transport::packet::Packet,
|
||||||
|
utils::select::EitherUnwrap,
|
||||||
Matter,
|
Matter,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
exchange::{
|
exchange::{
|
||||||
Exchange, ExchangeCtr, ExchangeCtx, ExchangeId, ExchangeState, Notification, Role,
|
Exchange, ExchangeCtr, ExchangeCtx, ExchangeId, ExchangeState, Role, MAX_EXCHANGES,
|
||||||
MAX_EXCHANGES,
|
|
||||||
},
|
},
|
||||||
mrp::ReliableMessage,
|
mrp::ReliableMessage,
|
||||||
packet::{MAX_RX_BUF_SIZE, MAX_RX_STATUS_BUF_SIZE, MAX_TX_BUF_SIZE},
|
packet::{MAX_RX_BUF_SIZE, MAX_RX_STATUS_BUF_SIZE, MAX_TX_BUF_SIZE},
|
||||||
pipe::{Chunk, Pipe},
|
pipe::{Chunk, Pipe},
|
||||||
session::SessionMgr,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -66,33 +69,216 @@ impl From<u8> for OpCodeDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Transport<'a> {
|
type TxBuf = MaybeUninit<[u8; MAX_TX_BUF_SIZE]>;
|
||||||
matter: &'a Matter<'a>,
|
type RxBuf = MaybeUninit<[u8; MAX_RX_BUF_SIZE]>;
|
||||||
pub(crate) exchanges: RefCell<heapless::Vec<ExchangeCtx, MAX_EXCHANGES>>,
|
type SxBuf = MaybeUninit<[u8; MAX_RX_STATUS_BUF_SIZE]>;
|
||||||
pub(crate) send_notification: Notification,
|
|
||||||
pub session_mgr: RefCell<SessionMgr>,
|
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
||||||
|
pub struct RunBuffers {
|
||||||
|
udp_bufs: crate::transport::udp::UdpBuffers,
|
||||||
|
run_bufs: PacketBuffers,
|
||||||
|
tx_buf: TxBuf,
|
||||||
|
rx_buf: RxBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Transport<'a> {
|
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
||||||
|
impl RunBuffers {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn new(matter: &'a Matter<'a>) -> Self {
|
pub const fn new() -> Self {
|
||||||
let epoch = matter.epoch;
|
|
||||||
let rand = matter.rand;
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
matter,
|
udp_bufs: crate::transport::udp::UdpBuffers::new(),
|
||||||
exchanges: RefCell::new(heapless::Vec::new()),
|
run_bufs: PacketBuffers::new(),
|
||||||
send_notification: Notification::new(),
|
tx_buf: core::mem::MaybeUninit::uninit(),
|
||||||
session_mgr: RefCell::new(SessionMgr::new(epoch, rand)),
|
rx_buf: core::mem::MaybeUninit::uninit(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn matter(&self) -> &'a Matter<'a> {
|
pub struct PacketBuffers {
|
||||||
self.matter
|
tx: [TxBuf; MAX_EXCHANGES],
|
||||||
|
rx: [RxBuf; MAX_EXCHANGES],
|
||||||
|
sx: [SxBuf; MAX_EXCHANGES],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PacketBuffers {
|
||||||
|
const TX_ELEM: TxBuf = MaybeUninit::uninit();
|
||||||
|
const RX_ELEM: RxBuf = MaybeUninit::uninit();
|
||||||
|
const SX_ELEM: SxBuf = MaybeUninit::uninit();
|
||||||
|
|
||||||
|
const TX_INIT: [TxBuf; MAX_EXCHANGES] = [Self::TX_ELEM; MAX_EXCHANGES];
|
||||||
|
const RX_INIT: [RxBuf; MAX_EXCHANGES] = [Self::RX_ELEM; MAX_EXCHANGES];
|
||||||
|
const SX_INIT: [SxBuf; MAX_EXCHANGES] = [Self::SX_ELEM; MAX_EXCHANGES];
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
tx: Self::TX_INIT,
|
||||||
|
rx: Self::RX_INIT,
|
||||||
|
sx: Self::SX_INIT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Matter<'a> {
|
||||||
|
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
||||||
|
pub async fn run<D, H>(
|
||||||
|
&self,
|
||||||
|
stack: &crate::transport::network::NetworkStack<D>,
|
||||||
|
buffers: &mut RunBuffers,
|
||||||
|
dev_comm: CommissioningData,
|
||||||
|
handler: &H,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
D: crate::transport::network::NetworkStackDriver,
|
||||||
|
H: DataModelHandler,
|
||||||
|
{
|
||||||
|
let udp = crate::transport::udp::UdpListener::new(
|
||||||
|
stack,
|
||||||
|
crate::transport::network::SocketAddr::new(
|
||||||
|
crate::transport::network::IpAddr::V6(
|
||||||
|
crate::transport::network::Ipv6Addr::UNSPECIFIED,
|
||||||
|
),
|
||||||
|
self.port,
|
||||||
|
),
|
||||||
|
&mut buffers.udp_bufs,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let tx_pipe = Pipe::new(unsafe { buffers.tx_buf.assume_init_mut() });
|
||||||
|
let rx_pipe = Pipe::new(unsafe { buffers.rx_buf.assume_init_mut() });
|
||||||
|
|
||||||
|
let tx_pipe = &tx_pipe;
|
||||||
|
let rx_pipe = &rx_pipe;
|
||||||
|
let udp = &udp;
|
||||||
|
let run_bufs = &mut buffers.run_bufs;
|
||||||
|
|
||||||
|
let mut tx = pin!(async move {
|
||||||
|
loop {
|
||||||
|
{
|
||||||
|
let mut data = tx_pipe.data.lock().await;
|
||||||
|
|
||||||
|
if let Some(chunk) = data.chunk {
|
||||||
|
udp.send(chunk.addr.unwrap_udp(), &data.buf[chunk.start..chunk.end])
|
||||||
|
.await?;
|
||||||
|
data.chunk = None;
|
||||||
|
tx_pipe.data_consumed_notification.signal(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tx_pipe.data_supplied_notification.wait().await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut rx = pin!(async move {
|
||||||
|
loop {
|
||||||
|
{
|
||||||
|
let mut data = rx_pipe.data.lock().await;
|
||||||
|
|
||||||
|
if data.chunk.is_none() {
|
||||||
|
let (len, addr) = udp.recv(data.buf).await?;
|
||||||
|
|
||||||
|
data.chunk = Some(Chunk {
|
||||||
|
start: 0,
|
||||||
|
end: len,
|
||||||
|
addr: crate::transport::network::Address::Udp(addr),
|
||||||
|
});
|
||||||
|
rx_pipe.data_supplied_notification.signal(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_pipe.data_consumed_notification.wait().await;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut run = pin!(async move {
|
||||||
|
self.run_piped(run_bufs, tx_pipe, rx_pipe, dev_comm, handler)
|
||||||
|
.await
|
||||||
|
});
|
||||||
|
|
||||||
|
embassy_futures::select::select3(&mut tx, &mut rx, &mut run)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn initiate(&self, _fabric_id: u64, _node_id: u64) -> Result<Exchange<'a>, Error> {
|
pub async fn run_piped<H>(
|
||||||
unimplemented!()
|
&self,
|
||||||
|
buffers: &mut PacketBuffers,
|
||||||
|
tx_pipe: &Pipe<'_>,
|
||||||
|
rx_pipe: &Pipe<'_>,
|
||||||
|
dev_comm: CommissioningData,
|
||||||
|
handler: &H,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
H: DataModelHandler,
|
||||||
|
{
|
||||||
|
info!("Running Matter transport");
|
||||||
|
|
||||||
|
let buf = unsafe { buffers.rx[0].assume_init_mut() };
|
||||||
|
|
||||||
|
if self.start_comissioning(dev_comm, buf)? {
|
||||||
|
info!("Comissioning started");
|
||||||
|
}
|
||||||
|
|
||||||
|
let construction_notification = Notification::new();
|
||||||
|
|
||||||
|
let mut rx = pin!(self.handle_rx(buffers, rx_pipe, &construction_notification, handler));
|
||||||
|
let mut tx = pin!(self.handle_tx(tx_pipe));
|
||||||
|
|
||||||
|
select(&mut rx, &mut tx).await.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
async fn handle_rx<H>(
|
||||||
|
&self,
|
||||||
|
buffers: &mut PacketBuffers,
|
||||||
|
rx_pipe: &Pipe<'_>,
|
||||||
|
construction_notification: &Notification,
|
||||||
|
handler: &H,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
H: DataModelHandler,
|
||||||
|
{
|
||||||
|
info!("Creating queue for {} exchanges", 1);
|
||||||
|
|
||||||
|
let channel = Channel::<NoopRawMutex, _, 1>::new();
|
||||||
|
|
||||||
|
info!("Creating {} handlers", MAX_EXCHANGES);
|
||||||
|
let mut handlers = heapless::Vec::<_, MAX_EXCHANGES>::new();
|
||||||
|
|
||||||
|
info!("Handlers size: {}", core::mem::size_of_val(&handlers));
|
||||||
|
|
||||||
|
// Unsafely allow mutable aliasing in the packet pools by different indices
|
||||||
|
let pools: *mut PacketBuffers = buffers;
|
||||||
|
|
||||||
|
for index in 0..MAX_EXCHANGES {
|
||||||
|
let channel = &channel;
|
||||||
|
let handler_id = index;
|
||||||
|
|
||||||
|
let pools = unsafe { pools.as_mut() }.unwrap();
|
||||||
|
|
||||||
|
let tx_buf = unsafe { pools.tx[handler_id].assume_init_mut() };
|
||||||
|
let rx_buf = unsafe { pools.rx[handler_id].assume_init_mut() };
|
||||||
|
let sx_buf = unsafe { pools.sx[handler_id].assume_init_mut() };
|
||||||
|
|
||||||
|
handlers
|
||||||
|
.push(self.exchange_handler(tx_buf, rx_buf, sx_buf, handler_id, channel, handler))
|
||||||
|
.map_err(|_| ())
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut rx = pin!(self.handle_rx_multiplex(rx_pipe, construction_notification, &channel));
|
||||||
|
|
||||||
|
let result = select(&mut rx, select_slice(&mut handlers)).await;
|
||||||
|
|
||||||
|
if let Either::First(result) = result {
|
||||||
|
if let Err(e) = &result {
|
||||||
|
error!("Exitting RX loop due to an error: {:?}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
result?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -230,11 +416,11 @@ impl<'a> Transport<'a> {
|
||||||
|
|
||||||
match rx.get_proto_id() {
|
match rx.get_proto_id() {
|
||||||
PROTO_ID_SECURE_CHANNEL => {
|
PROTO_ID_SECURE_CHANNEL => {
|
||||||
let sc = SecureChannel::new(self.matter());
|
let sc = SecureChannel::new(self);
|
||||||
|
|
||||||
sc.handle(&mut exchange, &mut rx, &mut tx).await?;
|
sc.handle(&mut exchange, &mut rx, &mut tx).await?;
|
||||||
|
|
||||||
self.matter().notify_changed();
|
self.notify_changed();
|
||||||
}
|
}
|
||||||
PROTO_ID_INTERACTION_MODEL => {
|
PROTO_ID_INTERACTION_MODEL => {
|
||||||
let dm = DataModel::new(handler);
|
let dm = DataModel::new(handler);
|
||||||
|
@ -244,7 +430,7 @@ impl<'a> Transport<'a> {
|
||||||
dm.handle(&mut exchange, &mut rx, &mut tx, &mut rx_status)
|
dm.handle(&mut exchange, &mut rx, &mut tx, &mut rx_status)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.matter().notify_changed();
|
self.notify_changed();
|
||||||
}
|
}
|
||||||
other => {
|
other => {
|
||||||
error!("Unknown Proto-ID: {}", other);
|
error!("Unknown Proto-ID: {}", other);
|
||||||
|
@ -254,6 +440,11 @@ impl<'a> Transport<'a> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_transport(&self) {
|
||||||
|
self.exchanges.borrow_mut().clear();
|
||||||
|
self.session_mgr.borrow_mut().reset();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn process_rx<'r>(
|
pub fn process_rx<'r>(
|
||||||
&'r self,
|
&'r self,
|
||||||
construction_notification: &'r Notification,
|
construction_notification: &'r Notification,
|
||||||
|
@ -297,7 +488,7 @@ impl<'a> Transport<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.matter().notify_changed();
|
self.notify_changed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,13 +496,13 @@ impl<'a> Transport<'a> {
|
||||||
let constructor = ExchangeCtr {
|
let constructor = ExchangeCtr {
|
||||||
exchange: Exchange {
|
exchange: Exchange {
|
||||||
id: ctx.id.clone(),
|
id: ctx.id.clone(),
|
||||||
transport: self,
|
matter: self,
|
||||||
notification: Notification::new(),
|
notification: Notification::new(),
|
||||||
},
|
},
|
||||||
construction_notification,
|
construction_notification,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.matter().notify_changed();
|
self.notify_changed();
|
||||||
|
|
||||||
Ok(Some(constructor))
|
Ok(Some(constructor))
|
||||||
} else if src_rx.proto.proto_id == PROTO_ID_SECURE_CHANNEL
|
} else if src_rx.proto.proto_id == PROTO_ID_SECURE_CHANNEL
|
||||||
|
@ -338,7 +529,7 @@ impl<'a> Transport<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.matter().notify_changed();
|
self.notify_changed();
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -354,7 +545,7 @@ impl<'a> Transport<'a> {
|
||||||
|
|
||||||
let mut exchanges = self.exchanges.borrow_mut();
|
let mut exchanges = self.exchanges.borrow_mut();
|
||||||
|
|
||||||
let ctx = Self::get(&mut exchanges, exchange_id).unwrap();
|
let ctx = ExchangeCtx::get(&mut exchanges, exchange_id).unwrap();
|
||||||
|
|
||||||
let state = &mut ctx.state;
|
let state = &mut ctx.state;
|
||||||
|
|
||||||
|
@ -397,11 +588,11 @@ impl<'a> Transport<'a> {
|
||||||
// ..
|
// ..
|
||||||
// }
|
// }
|
||||||
| ExchangeState::Complete { .. } // | ExchangeState::CompleteAcknowledge { .. }
|
| ExchangeState::Complete { .. } // | ExchangeState::CompleteAcknowledge { .. }
|
||||||
) || ctx.mrp.is_ack_ready(*self.matter.borrow())
|
) || ctx.mrp.is_ack_ready(*self.borrow())
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(ctx) = ctx {
|
if let Some(ctx) = ctx {
|
||||||
self.matter().notify_changed();
|
self.notify_changed();
|
||||||
|
|
||||||
let state = &mut ctx.state;
|
let state = &mut ctx.state;
|
||||||
|
|
||||||
|
@ -460,7 +651,7 @@ impl<'a> Transport<'a> {
|
||||||
dest_tx.log("Sending packet");
|
dest_tx.log("Sending packet");
|
||||||
|
|
||||||
self.pre_send(ctx, dest_tx)?;
|
self.pre_send(ctx, dest_tx)?;
|
||||||
self.matter().notify_changed();
|
self.notify_changed();
|
||||||
|
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
@ -500,7 +691,7 @@ impl<'a> Transport<'a> {
|
||||||
let session = session_mgr.mut_by_index(sess_index).unwrap();
|
let session = session_mgr.mut_by_index(sess_index).unwrap();
|
||||||
|
|
||||||
// Decrypt the message
|
// Decrypt the message
|
||||||
session.recv(self.matter.epoch, rx)?;
|
session.recv(self.epoch, rx)?;
|
||||||
|
|
||||||
// Get the exchange
|
// Get the exchange
|
||||||
// TODO: Handle out of space
|
// TODO: Handle out of space
|
||||||
|
@ -513,7 +704,7 @@ impl<'a> Transport<'a> {
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Message Reliability Protocol
|
// Message Reliability Protocol
|
||||||
exch.mrp.recv(rx, self.matter.epoch)?;
|
exch.mrp.recv(rx, self.epoch)?;
|
||||||
|
|
||||||
Ok((exch, new))
|
Ok((exch, new))
|
||||||
}
|
}
|
||||||
|
@ -576,11 +767,4 @@ impl<'a> Transport<'a> {
|
||||||
Err(ErrorCode::NoExchange.into())
|
Err(ErrorCode::NoExchange.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get<'r>(
|
|
||||||
exchanges: &'r mut heapless::Vec<ExchangeCtx, MAX_EXCHANGES>,
|
|
||||||
id: &ExchangeId,
|
|
||||||
) -> Option<&'r mut ExchangeCtx> {
|
|
||||||
exchanges.iter_mut().find(|exchange| exchange.id == *id)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
acl::Accessor,
|
acl::Accessor,
|
||||||
error::{Error, ErrorCode},
|
error::{Error, ErrorCode},
|
||||||
|
utils::select::Notification,
|
||||||
Matter,
|
Matter,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
core::Transport,
|
|
||||||
mrp::ReliableMessage,
|
mrp::ReliableMessage,
|
||||||
network::Address,
|
network::Address,
|
||||||
packet::Packet,
|
packet::Packet,
|
||||||
|
@ -16,8 +14,6 @@ use super::{
|
||||||
|
|
||||||
pub const MAX_EXCHANGES: usize = 8;
|
pub const MAX_EXCHANGES: usize = 8;
|
||||||
|
|
||||||
pub type Notification = embassy_sync::signal::Signal<NoopRawMutex, ()>;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone, Default)]
|
||||||
pub(crate) enum Role {
|
pub(crate) enum Role {
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -43,6 +39,15 @@ pub(crate) struct ExchangeCtx {
|
||||||
pub(crate) state: ExchangeState,
|
pub(crate) state: ExchangeState,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ExchangeCtx {
|
||||||
|
pub(crate) fn get<'r>(
|
||||||
|
exchanges: &'r mut heapless::Vec<ExchangeCtx, MAX_EXCHANGES>,
|
||||||
|
id: &ExchangeId,
|
||||||
|
) -> Option<&'r mut ExchangeCtx> {
|
||||||
|
exchanges.iter_mut().find(|exchange| exchange.id == *id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) enum ExchangeState {
|
pub(crate) enum ExchangeState {
|
||||||
Construction {
|
Construction {
|
||||||
|
@ -144,7 +149,7 @@ impl SessionId {
|
||||||
}
|
}
|
||||||
pub struct Exchange<'a> {
|
pub struct Exchange<'a> {
|
||||||
pub(crate) id: ExchangeId,
|
pub(crate) id: ExchangeId,
|
||||||
pub(crate) transport: &'a Transport<'a>,
|
pub(crate) matter: &'a Matter<'a>,
|
||||||
pub(crate) notification: Notification,
|
pub(crate) notification: Notification,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,21 +158,8 @@ impl<'a> Exchange<'a> {
|
||||||
&self.id
|
&self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matter(&self) -> &Matter<'a> {
|
|
||||||
self.transport.matter()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transport(&self) -> &Transport<'a> {
|
|
||||||
self.transport
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn accessor(&self) -> Result<Accessor<'a>, Error> {
|
pub fn accessor(&self) -> Result<Accessor<'a>, Error> {
|
||||||
self.with_session(|sess| {
|
self.with_session(|sess| Ok(Accessor::for_session(sess, &self.matter.acl_mgr)))
|
||||||
Ok(Accessor::for_session(
|
|
||||||
sess,
|
|
||||||
&self.transport.matter().acl_mgr,
|
|
||||||
))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_session_mut<F, T>(&self, f: F) -> Result<T, Error>
|
pub fn with_session_mut<F, T>(&self, f: F) -> Result<T, Error>
|
||||||
|
@ -175,7 +167,7 @@ impl<'a> Exchange<'a> {
|
||||||
F: FnOnce(&mut Session) -> Result<T, Error>,
|
F: FnOnce(&mut Session) -> Result<T, Error>,
|
||||||
{
|
{
|
||||||
self.with_ctx(|_self, ctx| {
|
self.with_ctx(|_self, ctx| {
|
||||||
let mut session_mgr = _self.transport.session_mgr.borrow_mut();
|
let mut session_mgr = _self.matter.session_mgr.borrow_mut();
|
||||||
|
|
||||||
let sess_index = session_mgr
|
let sess_index = session_mgr
|
||||||
.get(
|
.get(
|
||||||
|
@ -201,15 +193,11 @@ impl<'a> Exchange<'a> {
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut SessionMgr) -> Result<T, Error>,
|
F: FnOnce(&mut SessionMgr) -> Result<T, Error>,
|
||||||
{
|
{
|
||||||
let mut session_mgr = self.transport.session_mgr.borrow_mut();
|
let mut session_mgr = self.matter.session_mgr.borrow_mut();
|
||||||
|
|
||||||
f(&mut session_mgr)
|
f(&mut session_mgr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn initiate(&mut self, fabric_id: u64, node_id: u64) -> Result<Exchange<'a>, Error> {
|
|
||||||
self.transport.initiate(fabric_id, node_id).await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn acknowledge(&mut self) -> Result<(), Error> {
|
pub async fn acknowledge(&mut self) -> Result<(), Error> {
|
||||||
let wait = self.with_ctx_mut(|_self, ctx| {
|
let wait = self.with_ctx_mut(|_self, ctx| {
|
||||||
if !matches!(ctx.state, ExchangeState::Active) {
|
if !matches!(ctx.state, ExchangeState::Active) {
|
||||||
|
@ -222,7 +210,7 @@ impl<'a> Exchange<'a> {
|
||||||
ctx.state = ExchangeState::Acknowledge {
|
ctx.state = ExchangeState::Acknowledge {
|
||||||
notification: &_self.notification as *const _,
|
notification: &_self.notification as *const _,
|
||||||
};
|
};
|
||||||
_self.transport.send_notification.signal(());
|
_self.matter.send_notification.signal(());
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
@ -249,7 +237,7 @@ impl<'a> Exchange<'a> {
|
||||||
rx: rx as *mut _,
|
rx: rx as *mut _,
|
||||||
notification: &_self.notification as *const _,
|
notification: &_self.notification as *const _,
|
||||||
};
|
};
|
||||||
_self.transport.send_notification.signal(());
|
_self.matter.send_notification.signal(());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
@ -275,7 +263,7 @@ impl<'a> Exchange<'a> {
|
||||||
tx: tx as *const _,
|
tx: tx as *const _,
|
||||||
notification: &_self.notification as *const _,
|
notification: &_self.notification as *const _,
|
||||||
};
|
};
|
||||||
_self.transport.send_notification.signal(());
|
_self.matter.send_notification.signal(());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
|
@ -289,9 +277,9 @@ impl<'a> Exchange<'a> {
|
||||||
where
|
where
|
||||||
F: FnOnce(&Self, &ExchangeCtx) -> Result<T, Error>,
|
F: FnOnce(&Self, &ExchangeCtx) -> Result<T, Error>,
|
||||||
{
|
{
|
||||||
let mut exchanges = self.transport.exchanges.borrow_mut();
|
let mut exchanges = self.matter.exchanges.borrow_mut();
|
||||||
|
|
||||||
let exchange = Transport::get(&mut exchanges, &self.id).ok_or(ErrorCode::NoExchange)?; // TODO
|
let exchange = ExchangeCtx::get(&mut exchanges, &self.id).ok_or(ErrorCode::NoExchange)?; // TODO
|
||||||
|
|
||||||
f(self, exchange)
|
f(self, exchange)
|
||||||
}
|
}
|
||||||
|
@ -300,9 +288,9 @@ impl<'a> Exchange<'a> {
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Self, &mut ExchangeCtx) -> Result<T, Error>,
|
F: FnOnce(&mut Self, &mut ExchangeCtx) -> Result<T, Error>,
|
||||||
{
|
{
|
||||||
let mut exchanges = self.transport.exchanges.borrow_mut();
|
let mut exchanges = self.matter.exchanges.borrow_mut();
|
||||||
|
|
||||||
let exchange = Transport::get(&mut exchanges, &self.id).ok_or(ErrorCode::NoExchange)?; // TODO
|
let exchange = ExchangeCtx::get(&mut exchanges, &self.id).ok_or(ErrorCode::NoExchange)?; // TODO
|
||||||
|
|
||||||
f(self, exchange)
|
f(self, exchange)
|
||||||
}
|
}
|
||||||
|
@ -312,7 +300,7 @@ impl<'a> Drop for Exchange<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.with_ctx_mut(|_self, ctx| {
|
let _ = self.with_ctx_mut(|_self, ctx| {
|
||||||
ctx.state = ExchangeState::Closed;
|
ctx.state = ExchangeState::Closed;
|
||||||
_self.transport.send_notification.signal(());
|
_self.matter.send_notification.signal(());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
});
|
});
|
||||||
|
|
|
@ -24,6 +24,5 @@ pub mod packet;
|
||||||
pub mod pipe;
|
pub mod pipe;
|
||||||
pub mod plain_hdr;
|
pub mod plain_hdr;
|
||||||
pub mod proto_hdr;
|
pub mod proto_hdr;
|
||||||
pub mod runner;
|
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod udp;
|
pub mod udp;
|
||||||
|
|
|
@ -1,319 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020-2022 Project CHIP Authors
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use core::{mem::MaybeUninit, pin::pin};
|
|
||||||
|
|
||||||
use embassy_futures::select::{select, select_slice, Either};
|
|
||||||
use embassy_sync::{blocking_mutex::raw::NoopRawMutex, channel::Channel};
|
|
||||||
|
|
||||||
use log::{error, info};
|
|
||||||
|
|
||||||
use crate::{data_model::objects::DataModelHandler, CommissioningData, Matter};
|
|
||||||
use crate::{error::Error, transport::packet::MAX_RX_BUF_SIZE, utils::select::EitherUnwrap};
|
|
||||||
|
|
||||||
use super::{
|
|
||||||
core::Transport,
|
|
||||||
exchange::{Notification, MAX_EXCHANGES},
|
|
||||||
packet::{MAX_RX_STATUS_BUF_SIZE, MAX_TX_BUF_SIZE},
|
|
||||||
pipe::{Chunk, Pipe},
|
|
||||||
};
|
|
||||||
|
|
||||||
type TxBuf = MaybeUninit<[u8; MAX_TX_BUF_SIZE]>;
|
|
||||||
type RxBuf = MaybeUninit<[u8; MAX_RX_BUF_SIZE]>;
|
|
||||||
type SxBuf = MaybeUninit<[u8; MAX_RX_STATUS_BUF_SIZE]>;
|
|
||||||
|
|
||||||
struct PacketPools {
|
|
||||||
tx: [TxBuf; MAX_EXCHANGES],
|
|
||||||
rx: [RxBuf; MAX_EXCHANGES],
|
|
||||||
sx: [SxBuf; MAX_EXCHANGES],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PacketPools {
|
|
||||||
const TX_ELEM: TxBuf = MaybeUninit::uninit();
|
|
||||||
const RX_ELEM: RxBuf = MaybeUninit::uninit();
|
|
||||||
const SX_ELEM: SxBuf = MaybeUninit::uninit();
|
|
||||||
|
|
||||||
const TX_INIT: [TxBuf; MAX_EXCHANGES] = [Self::TX_ELEM; MAX_EXCHANGES];
|
|
||||||
const RX_INIT: [RxBuf; MAX_EXCHANGES] = [Self::RX_ELEM; MAX_EXCHANGES];
|
|
||||||
const SX_INIT: [SxBuf; MAX_EXCHANGES] = [Self::SX_ELEM; MAX_EXCHANGES];
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
tx: Self::TX_INIT,
|
|
||||||
rx: Self::RX_INIT,
|
|
||||||
sx: Self::SX_INIT,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
pub struct AllUdpBuffers {
|
|
||||||
transport: TransportUdpBuffers,
|
|
||||||
mdns: crate::mdns::MdnsUdpBuffers,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
impl AllUdpBuffers {
|
|
||||||
#[inline(always)]
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
transport: TransportUdpBuffers::new(),
|
|
||||||
mdns: crate::mdns::MdnsUdpBuffers::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
pub struct TransportUdpBuffers {
|
|
||||||
udp: crate::transport::udp::UdpBuffers,
|
|
||||||
tx_buf: TxBuf,
|
|
||||||
rx_buf: RxBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
impl TransportUdpBuffers {
|
|
||||||
#[inline(always)]
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
udp: crate::transport::udp::UdpBuffers::new(),
|
|
||||||
tx_buf: core::mem::MaybeUninit::uninit(),
|
|
||||||
rx_buf: core::mem::MaybeUninit::uninit(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This struct implements an executor-agnostic option to run the Matter transport stack end-to-end.
|
|
||||||
///
|
|
||||||
/// Since it is not possible to use executor tasks spawning in an executor-agnostic way (yet),
|
|
||||||
/// the async loops are arranged as one giant future. Therefore, the cost is a slightly slower execution
|
|
||||||
/// due to the generated future being relatively big and deeply nested.
|
|
||||||
///
|
|
||||||
/// Users are free to implement their own async execution loop, by utilizing the `Transport`
|
|
||||||
/// struct directly with their async executor of choice.
|
|
||||||
pub struct TransportRunner<'a> {
|
|
||||||
transport: Transport<'a>,
|
|
||||||
pools: PacketPools,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TransportRunner<'a> {
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn new(matter: &'a Matter<'a>) -> Self {
|
|
||||||
Self::wrap(Transport::new(matter))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub const fn wrap(transport: Transport<'a>) -> Self {
|
|
||||||
Self {
|
|
||||||
transport,
|
|
||||||
pools: PacketPools::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transport(&self) -> &Transport {
|
|
||||||
&self.transport
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
pub async fn run_udp_all<D, H>(
|
|
||||||
&mut self,
|
|
||||||
stack: &crate::transport::network::NetworkStack<D>,
|
|
||||||
mdns: &crate::mdns::MdnsService<'_>,
|
|
||||||
buffers: &mut AllUdpBuffers,
|
|
||||||
dev_comm: CommissioningData,
|
|
||||||
handler: &H,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
D: crate::transport::network::NetworkStackDriver,
|
|
||||||
H: DataModelHandler,
|
|
||||||
{
|
|
||||||
let mut mdns_runner = crate::mdns::MdnsRunner::new(mdns);
|
|
||||||
|
|
||||||
let mut mdns = pin!(mdns_runner.run_udp(stack, &mut buffers.mdns));
|
|
||||||
let mut transport = pin!(self.run_udp(stack, &mut buffers.transport, dev_comm, handler));
|
|
||||||
|
|
||||||
embassy_futures::select::select(&mut mdns, &mut transport)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(any(feature = "std", feature = "embassy-net"))]
|
|
||||||
pub async fn run_udp<D, H>(
|
|
||||||
&mut self,
|
|
||||||
stack: &crate::transport::network::NetworkStack<D>,
|
|
||||||
buffers: &mut TransportUdpBuffers,
|
|
||||||
dev_comm: CommissioningData,
|
|
||||||
handler: &H,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
D: crate::transport::network::NetworkStackDriver,
|
|
||||||
H: DataModelHandler,
|
|
||||||
{
|
|
||||||
let udp = crate::transport::udp::UdpListener::new(
|
|
||||||
stack,
|
|
||||||
crate::transport::network::SocketAddr::new(
|
|
||||||
crate::transport::network::IpAddr::V6(
|
|
||||||
crate::transport::network::Ipv6Addr::UNSPECIFIED,
|
|
||||||
),
|
|
||||||
self.transport.matter().port,
|
|
||||||
),
|
|
||||||
&mut buffers.udp,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let tx_pipe = Pipe::new(unsafe { buffers.tx_buf.assume_init_mut() });
|
|
||||||
let rx_pipe = Pipe::new(unsafe { buffers.rx_buf.assume_init_mut() });
|
|
||||||
|
|
||||||
let tx_pipe = &tx_pipe;
|
|
||||||
let rx_pipe = &rx_pipe;
|
|
||||||
let udp = &udp;
|
|
||||||
|
|
||||||
let mut tx = pin!(async move {
|
|
||||||
loop {
|
|
||||||
{
|
|
||||||
let mut data = tx_pipe.data.lock().await;
|
|
||||||
|
|
||||||
if let Some(chunk) = data.chunk {
|
|
||||||
udp.send(chunk.addr.unwrap_udp(), &data.buf[chunk.start..chunk.end])
|
|
||||||
.await?;
|
|
||||||
data.chunk = None;
|
|
||||||
tx_pipe.data_consumed_notification.signal(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tx_pipe.data_supplied_notification.wait().await;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut rx = pin!(async move {
|
|
||||||
loop {
|
|
||||||
{
|
|
||||||
let mut data = rx_pipe.data.lock().await;
|
|
||||||
|
|
||||||
if data.chunk.is_none() {
|
|
||||||
let (len, addr) = udp.recv(data.buf).await?;
|
|
||||||
|
|
||||||
data.chunk = Some(Chunk {
|
|
||||||
start: 0,
|
|
||||||
end: len,
|
|
||||||
addr: crate::transport::network::Address::Udp(addr),
|
|
||||||
});
|
|
||||||
rx_pipe.data_supplied_notification.signal(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rx_pipe.data_consumed_notification.wait().await;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut run = pin!(async move { self.run(tx_pipe, rx_pipe, dev_comm, handler).await });
|
|
||||||
|
|
||||||
embassy_futures::select::select3(&mut tx, &mut rx, &mut run)
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn run<H>(
|
|
||||||
&mut self,
|
|
||||||
tx_pipe: &Pipe<'_>,
|
|
||||||
rx_pipe: &Pipe<'_>,
|
|
||||||
dev_comm: CommissioningData,
|
|
||||||
handler: &H,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
H: DataModelHandler,
|
|
||||||
{
|
|
||||||
info!("Running Matter transport");
|
|
||||||
|
|
||||||
let buf = unsafe { self.pools.rx[0].assume_init_mut() };
|
|
||||||
|
|
||||||
if self.transport.matter().start_comissioning(dev_comm, buf)? {
|
|
||||||
info!("Comissioning started");
|
|
||||||
}
|
|
||||||
|
|
||||||
let construction_notification = Notification::new();
|
|
||||||
|
|
||||||
let mut rx = pin!(Self::handle_rx(
|
|
||||||
&self.transport,
|
|
||||||
&mut self.pools,
|
|
||||||
rx_pipe,
|
|
||||||
&construction_notification,
|
|
||||||
handler
|
|
||||||
));
|
|
||||||
let mut tx = pin!(self.transport.handle_tx(tx_pipe));
|
|
||||||
|
|
||||||
select(&mut rx, &mut tx).await.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
async fn handle_rx<H>(
|
|
||||||
transport: &Transport<'_>,
|
|
||||||
pools: &mut PacketPools,
|
|
||||||
rx_pipe: &Pipe<'_>,
|
|
||||||
construction_notification: &Notification,
|
|
||||||
handler: &H,
|
|
||||||
) -> Result<(), Error>
|
|
||||||
where
|
|
||||||
H: DataModelHandler,
|
|
||||||
{
|
|
||||||
info!("Creating queue for {} exchanges", 1);
|
|
||||||
|
|
||||||
let channel = Channel::<NoopRawMutex, _, 1>::new();
|
|
||||||
|
|
||||||
info!("Creating {} handlers", MAX_EXCHANGES);
|
|
||||||
let mut handlers = heapless::Vec::<_, MAX_EXCHANGES>::new();
|
|
||||||
|
|
||||||
info!("Handlers size: {}", core::mem::size_of_val(&handlers));
|
|
||||||
|
|
||||||
// Unsafely allow mutable aliasing in the packet pools by different indices
|
|
||||||
let pools: *mut PacketPools = pools;
|
|
||||||
|
|
||||||
for index in 0..MAX_EXCHANGES {
|
|
||||||
let channel = &channel;
|
|
||||||
let handler_id = index;
|
|
||||||
|
|
||||||
let pools = unsafe { pools.as_mut() }.unwrap();
|
|
||||||
|
|
||||||
let tx_buf = unsafe { pools.tx[handler_id].assume_init_mut() };
|
|
||||||
let rx_buf = unsafe { pools.rx[handler_id].assume_init_mut() };
|
|
||||||
let sx_buf = unsafe { pools.sx[handler_id].assume_init_mut() };
|
|
||||||
|
|
||||||
handlers
|
|
||||||
.push(
|
|
||||||
transport
|
|
||||||
.exchange_handler(tx_buf, rx_buf, sx_buf, handler_id, channel, handler),
|
|
||||||
)
|
|
||||||
.map_err(|_| ())
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rx =
|
|
||||||
pin!(transport.handle_rx_multiplex(rx_pipe, &construction_notification, &channel));
|
|
||||||
|
|
||||||
let result = select(&mut rx, select_slice(&mut handlers)).await;
|
|
||||||
|
|
||||||
if let Either::First(result) = result {
|
|
||||||
if let Err(e) = &result {
|
|
||||||
error!("Exitting RX loop due to an error: {:?}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
result?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -306,6 +306,11 @@ impl SessionMgr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset(&mut self) {
|
||||||
|
self.sessions.clear();
|
||||||
|
self.next_sess_id = 1;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mut_by_index(&mut self, index: usize) -> Option<&mut Session> {
|
pub fn mut_by_index(&mut self, index: usize) -> Option<&mut Session> {
|
||||||
self.sessions.get_mut(index).and_then(Option::as_mut)
|
self.sessions.get_mut(index).and_then(Option::as_mut)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[cfg(all(feature = "std", not(feature = "embassy-net")))]
|
#[cfg(all(feature = "std", not(feature = "embassy-net")))]
|
||||||
pub use async_io::*;
|
pub use self::async_io::*;
|
||||||
|
|
||||||
#[cfg(feature = "embassy-net")]
|
#[cfg(feature = "embassy-net")]
|
||||||
pub use embassy_net::*;
|
pub use self::embassy_net::*;
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub mod async_io {
|
pub mod async_io {
|
||||||
|
@ -88,7 +88,7 @@ pub mod async_io {
|
||||||
#[cfg(target_os = "espidf")]
|
#[cfg(target_os = "espidf")]
|
||||||
{
|
{
|
||||||
fn esp_setsockopt<T>(
|
fn esp_setsockopt<T>(
|
||||||
socket: &mut UdpSocket,
|
socket: &UdpSocket,
|
||||||
proto: u32,
|
proto: u32,
|
||||||
option: u32,
|
option: u32,
|
||||||
value: T,
|
value: T,
|
||||||
|
@ -119,7 +119,7 @@ pub mod async_io {
|
||||||
};
|
};
|
||||||
|
|
||||||
esp_setsockopt(
|
esp_setsockopt(
|
||||||
&mut self.0,
|
&mut self.0.get_ref(),
|
||||||
esp_idf_sys::IPPROTO_IP,
|
esp_idf_sys::IPPROTO_IP,
|
||||||
esp_idf_sys::IP_ADD_MEMBERSHIP,
|
esp_idf_sys::IP_ADD_MEMBERSHIP,
|
||||||
mreq,
|
mreq,
|
||||||
|
|
|
@ -48,16 +48,15 @@ use matter::{
|
||||||
secure_channel::{self, common::PROTO_ID_SECURE_CHANNEL, spake2p::VerifierData},
|
secure_channel::{self, common::PROTO_ID_SECURE_CHANNEL, spake2p::VerifierData},
|
||||||
tlv::{TLVWriter, TagType, ToTLV},
|
tlv::{TLVWriter, TagType, ToTLV},
|
||||||
transport::{
|
transport::{
|
||||||
exchange::Notification,
|
core::PacketBuffers,
|
||||||
packet::{Packet, MAX_RX_BUF_SIZE, MAX_TX_BUF_SIZE},
|
packet::{Packet, MAX_RX_BUF_SIZE, MAX_TX_BUF_SIZE},
|
||||||
pipe::Pipe,
|
pipe::Pipe,
|
||||||
runner::TransportRunner,
|
|
||||||
},
|
},
|
||||||
transport::{
|
transport::{
|
||||||
network::Address,
|
network::Address,
|
||||||
session::{CaseDetails, CloneData, NocCatIds, SessionMode},
|
session::{CaseDetails, CloneData, NocCatIds, SessionMode},
|
||||||
},
|
},
|
||||||
utils::select::EitherUnwrap,
|
utils::select::{EitherUnwrap, Notification},
|
||||||
CommissioningData, Matter, MATTER_PORT,
|
CommissioningData, Matter, MATTER_PORT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -248,7 +247,7 @@ impl<'a> ImEngine<'a> {
|
||||||
input: &[&ImInput],
|
input: &[&ImInput],
|
||||||
out: &mut heapless::Vec<ImOutput, N>,
|
out: &mut heapless::Vec<ImOutput, N>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let mut runner = TransportRunner::new(&self.matter);
|
self.matter.reset_transport();
|
||||||
|
|
||||||
let clone_data = CloneData::new(
|
let clone_data = CloneData::new(
|
||||||
IM_ENGINE_REMOTE_PEER_ID,
|
IM_ENGINE_REMOTE_PEER_ID,
|
||||||
|
@ -259,8 +258,8 @@ impl<'a> ImEngine<'a> {
|
||||||
SessionMode::Case(CaseDetails::new(1, &self.cat_ids)),
|
SessionMode::Case(CaseDetails::new(1, &self.cat_ids)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let sess_idx = runner
|
let sess_idx = self
|
||||||
.transport()
|
.matter
|
||||||
.session_mgr
|
.session_mgr
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.clone_session(&clone_data)
|
.clone_session(&clone_data)
|
||||||
|
@ -281,10 +280,9 @@ impl<'a> ImEngine<'a> {
|
||||||
let rx_pipe_buf = &mut rx_pipe_buf;
|
let rx_pipe_buf = &mut rx_pipe_buf;
|
||||||
|
|
||||||
let handler = &handler;
|
let handler = &handler;
|
||||||
let runner = &mut runner;
|
|
||||||
|
|
||||||
let mut msg_ctr = runner
|
let mut msg_ctr = self
|
||||||
.transport()
|
.matter
|
||||||
.session_mgr
|
.session_mgr
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.mut_by_index(sess_idx)
|
.mut_by_index(sess_idx)
|
||||||
|
@ -294,9 +292,13 @@ impl<'a> ImEngine<'a> {
|
||||||
let resp_notif = Notification::new();
|
let resp_notif = Notification::new();
|
||||||
let resp_notif = &resp_notif;
|
let resp_notif = &resp_notif;
|
||||||
|
|
||||||
|
let mut buffers = PacketBuffers::new();
|
||||||
|
let buffers = &mut buffers;
|
||||||
|
|
||||||
embassy_futures::block_on(async move {
|
embassy_futures::block_on(async move {
|
||||||
select3(
|
select3(
|
||||||
runner.run(
|
self.matter.run_piped(
|
||||||
|
buffers,
|
||||||
tx_pipe,
|
tx_pipe,
|
||||||
rx_pipe,
|
rx_pipe,
|
||||||
CommissioningData {
|
CommissioningData {
|
||||||
|
|
|
@ -100,7 +100,7 @@ fn test_timed_cmd_success() {
|
||||||
ImEngine::timed_commands(
|
ImEngine::timed_commands(
|
||||||
input,
|
input,
|
||||||
&TimedInvResponse::TransactionSuccess(expected),
|
&TimedInvResponse::TransactionSuccess(expected),
|
||||||
400,
|
2000,
|
||||||
0,
|
0,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
|
@ -130,7 +130,7 @@ fn test_timed_cmd_timedout_mismatch() {
|
||||||
ImEngine::timed_commands(
|
ImEngine::timed_commands(
|
||||||
input,
|
input,
|
||||||
&TimedInvResponse::TransactionError(IMStatusCode::TimedRequestMisMatch),
|
&TimedInvResponse::TransactionError(IMStatusCode::TimedRequestMisMatch),
|
||||||
400,
|
2000,
|
||||||
0,
|
0,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
name = "matter_macro_derive"
|
name = "matter_macro_derive"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[lib]
|
[lib]
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
[package]
|
[package]
|
||||||
name = "tlv_tool"
|
name = "tlv_tool"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2018"
|
edition = "2021"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue