Skip to content

Commit 6c53af6

Browse files
authored
Rework the notion of Epoch (#449)
(This PR started with the introduction of the Software Diagnostics cluster handler, which currently I cannot remove, as it is intermingled with the rest, but that's a small code change anyway.) === The important change here is the retirement of the `Epoch` type-alias from the `rs-matter` codebase. The `Epoch (= fn() -> core::time::Duration)` did have the semantics of a piece of code returning the current time since the Unix epoch. However, and in 99% of the cases, we needed a **much weaker** semantics - i.e. to measure some duration between a previous event, and a current event, where both events did happen during the **current** MCU boot cycle. This is perfectly doable by just utilizing `embassy_time::Instant::now()` whose semantics is anyway "monotonic time since boot", so most of the call-sites using `Epoch` were just switched to `embassy_time::Instant::now()`. The few call-sites that did need a wall-clock (not even a monotonic btw) - these are primarily certificate validation call-sites - are now switched to a wholly-new infrastructure that revolves around the `TimeSync` cluster, which is now implemented. Out of the box, `rs-matter` (and its `TimeSync` cluster handler) now does support: - Reporting on and setting a UTC timestamp with Matter epoch semantics, including persistence of this timestamp - Optional registration of a Trusted Time Source, as well as refreshing the UTC timestamp from this trusted time source NB: To reduce the flash-code-size price of the new time-sync infrastructure, the `endpoints::with_XXX_sys` root-endpoint handler-builders had to be rewritten to work upside-down: * Rather than taking the user-handler and wrapping it inside its own handler-chain * ... these now return the root-endpoint handler that **the user has to wrap with its own handler-chain** This allowed to combine multiple non-async handlers together before wrapping them with `Async(...)` which reduces the code-bloat generated by the compiler async state machinery.
1 parent da2d79e commit 6c53af6

58 files changed

Lines changed: 3847 additions & 1474 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bloat-check/src/bin/bloat-check.rs

Lines changed: 27 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,12 @@ use esp_rtos::embassy::Executor;
5757

5858
use rs_matter::crypto::backend::rustcrypto::RustCrypto;
5959
use rs_matter::crypto::{Crypto, RngCore, WeakTestOnlyRand};
60+
use rs_matter::dm::clusters::app::on_off::NoLevelControl;
61+
use rs_matter::dm::clusters::app::on_off::{self, test::TestOnOffDeviceLogic, OnOffHooks};
6062
use rs_matter::dm::clusters::desc::{self, ClusterHandler as _, DescHandler};
6163
use rs_matter::dm::clusters::net_comm::{
62-
NetCtl, NetCtlError, NetCtlStatus, NetworkScanInfo, NetworkType, SharedNetworks, WirelessCreds,
64+
NetCtl, NetCtlError, NetworkScanInfo, NetworkType, SharedNetworks, WirelessCreds,
6365
};
64-
use rs_matter::dm::clusters::app::on_off::NoLevelControl;
65-
use rs_matter::dm::clusters::app::on_off::{self, test::TestOnOffDeviceLogic, OnOffHooks};
6666
use rs_matter::dm::clusters::wifi_diag::{
6767
SecurityTypeEnum, WiFiVersionEnum, WifiDiag, WirelessDiag,
6868
};
@@ -76,7 +76,7 @@ use rs_matter::dm::networks::wireless::{
7676
use rs_matter::dm::networks::NetChangeNotif;
7777
use rs_matter::dm::subscriptions::{Subscriptions, DEFAULT_MAX_SUBSCRIPTIONS};
7878
use rs_matter::dm::{endpoints, IMBuffer};
79-
use rs_matter::dm::{Async, DataModel, Dataver, EmptyHandler, Endpoint, EpClMatcher, Node};
79+
use rs_matter::dm::{Async, DataModel, Dataver, Endpoint, EpClMatcher, Node};
8080
use rs_matter::error::Error;
8181
use rs_matter::pairing::qr::QrTextType;
8282
use rs_matter::pairing::DiscoveryCapabilities;
@@ -89,7 +89,6 @@ use rs_matter::transport::network::mdns::builtin::{BuiltinMdnsResponder, Host};
8989
use rs_matter::transport::network::{
9090
Address, ChainedNetwork, Ipv4Addr, Ipv6Addr, NetworkReceive, NetworkSend, NoNetwork,
9191
};
92-
use rs_matter::utils::epoch::dummy_epoch;
9392
use rs_matter::utils::init::{init, Init, InitMaybeUninit};
9493
use rs_matter::utils::storage::pooled::PooledBuffers;
9594
use rs_matter::utils::sync::DynBase;
@@ -174,12 +173,11 @@ impl<'a> MatterStack<'a> {
174173
&TEST_DEV_DET,
175174
TEST_DEV_COMM,
176175
&TEST_DEV_ATT,
177-
dummy_epoch,
178176
MATTER_PORT,
179177
),
180178
buffers <- PooledBuffers::init(0),
181179
subscriptions <- Subscriptions::init(),
182-
events <- Events::init(dummy_epoch),
180+
events <- Events::init(),
183181
networks <- SharedNetworks::init(WifiNetworks::init()),
184182
net_ctl_state <- NetCtlState::init_with_mutex(),
185183
btp <- Btp::init(),
@@ -196,13 +194,12 @@ type AppNetworks = SharedNetworks<WifiNetworks<3>>;
196194
type AppNetCtl<'a> = NetCtlWithStatusImpl<'a, FakeWifi>;
197195
type AppWirelessMgr<'a> = WirelessMgr<'a, &'a AppNetworks, &'a AppNetCtl<'a>>;
198196
type AppTransport<'a> = ChainedNetwork<FakeUdp, &'a Btp, fn(&Address) -> bool>;
199-
type AppHandler<'a> = handler_chain_type!(
197+
type AppDmHandler<'a> = handler_chain_type!(
200198
EpClMatcher => on_off::HandlerAsyncAdaptor<on_off::OnOffHandler<'a, TestOnOffDeviceLogic, NoLevelControl>>,
201199
EpClMatcher => Async<desc::HandlerAdaptor<DescHandler<'a>>>
202-
| EmptyHandler
200+
| WifiSysHandler<'a, &'a AppNetCtl<'a>>
203201
);
204202
type AppCrypto = RustCrypto<'static, WeakTestOnlyRand>;
205-
type AppDmHandler<'a> = WifiSysHandler<'a, &'a AppNetCtl<'a>, AppHandler<'a>>;
206203
type AppDataModel<'a> = DataModel<
207204
'a,
208205
DEFAULT_MAX_SUBSCRIPTIONS,
@@ -465,11 +462,9 @@ fn main() -> ! {
465462
.matter
466463
.print_standard_qr_code(QrTextType::Unicode, DiscoveryCapabilities::IP));
467464

468-
unwrap!(stack.matter.open_basic_comm_window(
469-
MAX_COMM_WINDOW_TIMEOUT_SECS,
470-
crypto,
471-
&(),
472-
));
465+
unwrap!(stack
466+
.matter
467+
.open_basic_comm_window(MAX_COMM_WINDOW_TIMEOUT_SECS, crypto, &()));
473468
}
474469

475470
executor.run(|spawner| {
@@ -553,7 +548,11 @@ fn mdns_task_fut<'a, C: Crypto + 'a>(
553548
}
554549

555550
#[embassy_executor::task]
556-
async fn mdns_task(mdns: &'static mut BuiltinMdnsResponder, matter: &'static Matter<'static>, crypto: &'static AppCrypto) {
551+
async fn mdns_task(
552+
mdns: &'static mut BuiltinMdnsResponder,
553+
matter: &'static Matter<'static>,
554+
crypto: &'static AppCrypto,
555+
) {
557556
info!("Starting mDNS task...");
558557
unwrap!(mdns_task_fut(mdns, matter, crypto).await);
559558
}
@@ -646,32 +645,21 @@ const NODE: Node<'static> = Node {
646645

647646
/// The Data Model handler for our Matter device.
648647
/// The handler is the root endpoint 0 handler plus the on-off handler and its descriptor.
649-
fn dm_handler<'a, T>(
648+
fn dm_handler<'a>(
650649
mut rand: impl RngCore + Copy,
651650
on_off: on_off::OnOffHandler<'a, TestOnOffDeviceLogic, NoLevelControl>,
652651
wifi_diag: &'a dyn WifiDiag,
653-
net_ctl: T,
654-
) -> WifiSysHandler<'a, T, AppHandler<'a>>
655-
where
656-
T: NetCtl + NetCtlStatus + WifiDiag,
657-
{
658-
endpoints::with_wifi_sys(
659-
&true,
660-
&(),
661-
&(),
662-
wifi_diag,
663-
net_ctl,
664-
rand,
665-
EmptyHandler
666-
.chain(
667-
EpClMatcher::new(Some(1), Some(desc::DescHandler::CLUSTER.id)),
668-
Async(desc::DescHandler::new(Dataver::new_rand(&mut rand)).adapt()),
669-
)
670-
.chain(
671-
EpClMatcher::new(Some(1), Some(TestOnOffDeviceLogic::CLUSTER.id)),
672-
on_off::HandlerAsyncAdaptor(on_off),
673-
),
674-
)
652+
net_ctl: &'a AppNetCtl,
653+
) -> AppDmHandler<'a> {
654+
endpoints::WifiSysHandlerBuilder::new(net_ctl, wifi_diag).build(rand)
655+
.chain(
656+
EpClMatcher::new(Some(1), Some(desc::DescHandler::CLUSTER.id)),
657+
Async(desc::DescHandler::new(Dataver::new_rand(&mut rand)).adapt()),
658+
)
659+
.chain(
660+
EpClMatcher::new(Some(1), Some(TestOnOffDeviceLogic::CLUSTER.id)),
661+
on_off::HandlerAsyncAdaptor(on_off),
662+
)
675663
}
676664

677665
/// A fake UDP implementation

examples/src/bin/bridge.rs

Lines changed: 62 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ use rs_matter::dm::networks::eth::EthNetwork;
4141
use rs_matter::dm::networks::SysNetifs;
4242
use rs_matter::dm::subscriptions::Subscriptions;
4343
use rs_matter::dm::{
44-
Async, Cluster, DataModel, DataModelHandler, Dataver, EmptyHandler, Endpoint, EpClMatcher,
45-
InvokeContext, Node, ReadContext,
44+
Async, Cluster, DataModel, DataModelHandler, Dataver, Endpoint, EpClMatcher, InvokeContext,
45+
Node, ReadContext,
4646
};
4747
use rs_matter::error::Error;
4848
use rs_matter::pairing::qr::QrTextType;
@@ -69,10 +69,10 @@ fn main() -> Result<(), Error> {
6969
);
7070

7171
// Create the Matter object
72-
let mut matter = Matter::new_default(&TEST_DEV_DET, TEST_DEV_COMM, &TEST_DEV_ATT, MATTER_PORT);
72+
let mut matter = Matter::new(&TEST_DEV_DET, TEST_DEV_COMM, &TEST_DEV_ATT, MATTER_PORT);
7373

7474
// Create the events
75-
let mut events: Events = Events::new_default();
75+
let mut events: Events = Events::new();
7676

7777
// Persistence
7878
let mut kv_buf = [0; 4096];
@@ -208,68 +208,64 @@ fn dm_handler<'a, OH: OnOffHooks, LH: LevelControlHooks>(
208208
) -> impl DataModelHandler + 'a {
209209
(
210210
NODE,
211-
endpoints::with_eth_sys(
212-
&false,
213-
&(),
214-
&SysNetifs,
215-
rand,
216-
EmptyHandler
217-
// The next chain is the handler for the "aggregator" endpoint 1.
218-
//
219-
// Note how the descriptor cluster is a bit different compared to the normal ones.
220-
// The `Aggregator` descriptor cluster takes care of declaring all bridged endpoints
221-
// as such.
222-
//
223-
// Implementing the "Actions" cluster (and declaring it in the ep1 meta-data)
224-
// would allow one to designate locations/areas to the bridged devices. However, this is
225-
// not yet supported by Google home and Apple, as per
226-
// https://www.1home.io/docs/en/server/configure-devices#manage-rooms
227-
.chain(
228-
EpClMatcher::new(Some(1), Some(desc::DescHandler::CLUSTER.id)),
229-
Async(desc::DescHandler::new_aggregator(Dataver::new_rand(&mut rand)).adapt()),
230-
)
231-
// The following chains are the handlers for the bridged devices corresponding to ep 2 and ep3.
232-
//
233-
// In addition to the usual clusters, every bridged endpoint needs to implement the
234-
// "Bridged" cluster as well.
235-
//
236-
// Note also that we are re-using here the ready-made `OnOffHandler` from `rs-matter` for demoing purposes.
237-
// In production setups, user is expected to define their own handler for their bridge device cluster(s)
238-
// which is likely to do remote calls over a proprietary protocol so as to e.g. retrieve the state of
239-
// the lamp, or to switch it on/off.
240-
.chain(
241-
EpClMatcher::new(Some(2), Some(desc::DescHandler::CLUSTER.id)),
242-
Async(desc::DescHandler::new(Dataver::new_rand(&mut rand)).adapt()),
243-
)
244-
.chain(
245-
EpClMatcher::new(Some(2), Some(groups::GroupsHandler::CLUSTER.id)),
246-
Async(groups::GroupsHandler::new(Dataver::new_rand(&mut rand)).adapt()),
247-
)
248-
.chain(
249-
EpClMatcher::new(Some(2), Some(TestOnOffDeviceLogic::CLUSTER.id)),
250-
on_off::HandlerAsyncAdaptor(on_off_ep2),
251-
)
252-
.chain(
253-
EpClMatcher::new(Some(2), Some(BridgedHandler::CLUSTER.id)),
254-
Async(BridgedHandler::new(Dataver::new_rand(&mut rand)).adapt()),
255-
)
256-
.chain(
257-
EpClMatcher::new(Some(3), Some(desc::DescHandler::CLUSTER.id)),
258-
Async(desc::DescHandler::new(Dataver::new_rand(&mut rand)).adapt()),
259-
)
260-
.chain(
261-
EpClMatcher::new(Some(3), Some(groups::GroupsHandler::CLUSTER.id)),
262-
Async(groups::GroupsHandler::new(Dataver::new_rand(&mut rand)).adapt()),
263-
)
264-
.chain(
265-
EpClMatcher::new(Some(3), Some(TestOnOffDeviceLogic::CLUSTER.id)),
266-
on_off::HandlerAsyncAdaptor(on_off_ep3),
267-
)
268-
.chain(
269-
EpClMatcher::new(Some(3), Some(BridgedHandler::CLUSTER.id)),
270-
Async(BridgedHandler::new(Dataver::new_rand(&mut rand)).adapt()),
271-
),
272-
),
211+
endpoints::EthSysHandlerBuilder::new()
212+
.netif_diag(&SysNetifs)
213+
.build(rand)
214+
// The next chain is the handler for the "aggregator" endpoint 1.
215+
//
216+
// Note how the descriptor cluster is a bit different compared to the normal ones.
217+
// The `Aggregator` descriptor cluster takes care of declaring all bridged endpoints
218+
// as such.
219+
//
220+
// Implementing the "Actions" cluster (and declaring it in the ep1 meta-data)
221+
// would allow one to designate locations/areas to the bridged devices. However, this is
222+
// not yet supported by Google home and Apple, as per
223+
// https://www.1home.io/docs/en/server/configure-devices#manage-rooms
224+
.chain(
225+
EpClMatcher::new(Some(1), Some(desc::DescHandler::CLUSTER.id)),
226+
Async(desc::DescHandler::new_aggregator(Dataver::new_rand(&mut rand)).adapt()),
227+
)
228+
// The following chains are the handlers for the bridged devices corresponding to ep 2 and ep3.
229+
//
230+
// In addition to the usual clusters, every bridged endpoint needs to implement the
231+
// "Bridged" cluster as well.
232+
//
233+
// Note also that we are re-using here the ready-made `OnOffHandler` from `rs-matter` for demoing purposes.
234+
// In production setups, user is expected to define their own handler for their bridge device cluster(s)
235+
// which is likely to do remote calls over a proprietary protocol so as to e.g. retrieve the state of
236+
// the lamp, or to switch it on/off.
237+
.chain(
238+
EpClMatcher::new(Some(2), Some(desc::DescHandler::CLUSTER.id)),
239+
Async(desc::DescHandler::new(Dataver::new_rand(&mut rand)).adapt()),
240+
)
241+
.chain(
242+
EpClMatcher::new(Some(2), Some(groups::GroupsHandler::CLUSTER.id)),
243+
Async(groups::GroupsHandler::new(Dataver::new_rand(&mut rand)).adapt()),
244+
)
245+
.chain(
246+
EpClMatcher::new(Some(2), Some(TestOnOffDeviceLogic::CLUSTER.id)),
247+
on_off::HandlerAsyncAdaptor(on_off_ep2),
248+
)
249+
.chain(
250+
EpClMatcher::new(Some(2), Some(BridgedHandler::CLUSTER.id)),
251+
Async(BridgedHandler::new(Dataver::new_rand(&mut rand)).adapt()),
252+
)
253+
.chain(
254+
EpClMatcher::new(Some(3), Some(desc::DescHandler::CLUSTER.id)),
255+
Async(desc::DescHandler::new(Dataver::new_rand(&mut rand)).adapt()),
256+
)
257+
.chain(
258+
EpClMatcher::new(Some(3), Some(groups::GroupsHandler::CLUSTER.id)),
259+
Async(groups::GroupsHandler::new(Dataver::new_rand(&mut rand)).adapt()),
260+
)
261+
.chain(
262+
EpClMatcher::new(Some(3), Some(TestOnOffDeviceLogic::CLUSTER.id)),
263+
on_off::HandlerAsyncAdaptor(on_off_ep3),
264+
)
265+
.chain(
266+
EpClMatcher::new(Some(3), Some(BridgedHandler::CLUSTER.id)),
267+
Async(BridgedHandler::new(Dataver::new_rand(&mut rand)).adapt()),
268+
),
273269
)
274270
}
275271

0 commit comments

Comments
 (0)