#![allow(unexpected_cfgs)]
#![recursion_limit = "256"]
fn main() -> Result<(), anyhow::Error> {
#[cfg(any(esp32c6, esp32h2))]
{
example::main()
}
#[cfg(not(any(esp32c6, esp32h2)))]
panic!("This example is only supported on ESP32-C6 and ESP32-H2 chips. Please select a different example or target.");
}
#[cfg(any(esp32c6, esp32h2))]
mod example {
use core::pin::pin;
use alloc::sync::Arc;
use esp_idf_matter::init_async_io;
use esp_idf_matter::matter::crypto::{default_crypto, Crypto};
use esp_idf_matter::matter::dm::clusters::app::on_off::test::TestOnOffDeviceLogic;
use esp_idf_matter::matter::dm::clusters::app::on_off::{self, OnOffHandler, OnOffHooks};
use esp_idf_matter::matter::dm::clusters::desc::{self, ClusterHandler as _, DescHandler};
use esp_idf_matter::matter::dm::devices::test::{
DAC_PRIVKEY, TEST_DEV_ATT, TEST_DEV_COMM, TEST_DEV_DET,
};
use esp_idf_matter::matter::dm::devices::DEV_TYPE_ON_OFF_LIGHT;
use esp_idf_matter::matter::dm::endpoints::ROOT_ENDPOINT_ID;
use esp_idf_matter::matter::dm::{Async, Dataver, EmptyHandler, Endpoint, Node};
use esp_idf_matter::matter::persist::DummyKvBlobStore;
use esp_idf_matter::matter::utils::init::InitMaybeUninit;
use esp_idf_matter::matter::{clusters, devices};
use esp_idf_matter::wireless::{EspMatterThread, EspThreadMatterStack};
#[cfg(esp_idf_bt_bluedroid_enabled)]
use esp_idf_svc::bt::reduce_bt_memory;
use esp_idf_svc::eventloop::EspSystemEventLoop;
use esp_idf_svc::hal::peripherals::Peripherals;
use esp_idf_svc::hal::task::block_on;
use esp_idf_svc::hal::task::thread::ThreadSpawnConfiguration;
use esp_idf_svc::io::vfs::MountedEventfs;
use esp_idf_svc::nvs::EspDefaultNvsPartition;
use log::{error, info};
use rand::Rng;
use static_cell::StaticCell;
extern crate alloc;
const STACK_SIZE: usize = 10 * 1024;
const BUMP_SIZE: usize = 14000;
pub fn main() -> Result<(), anyhow::Error> {
esp_idf_svc::log::init_from_env();
info!("Starting...");
ThreadSpawnConfiguration::set(&ThreadSpawnConfiguration {
name: Some(c"matter"),
..Default::default()
})?;
let thread = std::thread::Builder::new()
.stack_size(STACK_SIZE)
.spawn(run)
.unwrap();
thread.join().unwrap()
}
#[inline(never)]
#[cold]
fn run() -> Result<(), anyhow::Error> {
let result = block_on(pin!(matter()));
if let Err(e) = &result {
error!("Matter aborted execution with error: {e:?}");
}
{
info!("Matter finished execution successfully");
}
result
}
async fn matter() -> Result<(), anyhow::Error> {
let stack = MATTER_STACK.uninit().init_with(EspThreadMatterStack::init(
&TEST_DEV_DET,
TEST_DEV_COMM,
&TEST_DEV_ATT,
));
info!("Matter initialized");
let sysloop = EspSystemEventLoop::take()?;
let nvs = EspDefaultNvsPartition::take()?;
#[cfg_attr(not(esp_idf_bt_bluedroid_enabled), allow(unused_mut))]
let mut peripherals = Peripherals::take()?;
let mounted_event_fs = Arc::new(MountedEventfs::mount(6)?);
init_async_io(mounted_event_fs.clone())?;
ThreadSpawnConfiguration::set(&ThreadSpawnConfiguration {
name: Some(c"heap-monitor"),
..Default::default()
})?;
std::thread::Builder::new()
.stack_size(3092)
.spawn(|| loop {
use esp_idf_svc::sys::{
heap_caps_get_info, multi_heap_info_t, MALLOC_CAP_INTERNAL,
};
let mut info: multi_heap_info_t = unsafe { core::mem::zeroed() };
unsafe { heap_caps_get_info(&mut info, MALLOC_CAP_INTERNAL) };
info!(
"HEAP internal: free={} largest={} min_ever={} allocated={} (bytes)",
info.total_free_bytes,
info.largest_free_block,
info.minimum_free_bytes,
info.total_allocated_bytes,
);
std::thread::sleep(core::time::Duration::from_secs(5));
})
.unwrap();
#[cfg(esp_idf_bt_bluedroid_enabled)]
reduce_bt_memory(unsafe { peripherals.modem.reborrow() })?;
let crypto = default_crypto(rand::rng(), DAC_PRIVKEY);
let mut weak_rand = crypto.weak_rand()?;
let on_off = OnOffHandler::new_standalone(
Dataver::new_rand(&mut weak_rand),
LIGHT_ENDPOINT_ID,
TestOnOffDeviceLogic::new(true),
);
let handler = EmptyHandler
.chain(
|e, _| e == ROOT_ENDPOINT_ID,
Async(EspThreadMatterStack::<0, ()>::root_handler(
&(),
&mut weak_rand,
)),
)
.chain(
|e, c| e == LIGHT_ENDPOINT_ID && c == TestOnOffDeviceLogic::CLUSTER.id,
on_off::HandlerAsyncAdaptor(&on_off),
)
.chain(
|e, c| e == LIGHT_ENDPOINT_ID && c == DescHandler::CLUSTER.id,
Async(desc::DescHandler::new(Dataver::new_rand(&mut weak_rand)).adapt()),
);
let mut store = DummyKvBlobStore;
stack.startup(&crypto, &mut store).await?;
let kv = stack.kv(store);
let mut srp_host_eui64 = [0; 8];
weak_rand.fill_bytes(&mut srp_host_eui64);
let matter = pin!(stack.run_coex(
EspMatterThread::new(peripherals.modem, sysloop, nvs, mounted_event_fs, stack)
.with_srp_host_eui64(srp_host_eui64),
&crypto,
(NODE, handler),
&kv,
(),
));
info!("Async Matter task runner initialized");
info!("About to run Matter");
matter.await?;
Ok(())
}
static MATTER_STACK: StaticCell<EspThreadMatterStack<BUMP_SIZE, ()>> = StaticCell::new();
const LIGHT_ENDPOINT_ID: u16 = 1;
const NODE: Node = Node {
endpoints: &[
EspThreadMatterStack::<0, ()>::root_endpoint(),
Endpoint::new(
LIGHT_ENDPOINT_ID,
devices!(DEV_TYPE_ON_OFF_LIGHT),
clusters!(DescHandler::CLUSTER, TestOnOffDeviceLogic::CLUSTER),
),
],
};
}