From 7b4fd4615cdec5aedec89cb7c9b60f8486eeff66 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Thu, 9 Jul 2026 22:37:23 -0400 Subject: [PATCH] Pass through `sleepy_destination` for extended APS ACKs --- crates/ziggurat-driver/src/zigbee_stack/aps.rs | 11 ++++++----- crates/ziggurat-protocol/src/bridge.rs | 1 + crates/ziggurat-protocol/src/wire.rs | 5 ++++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/crates/ziggurat-driver/src/zigbee_stack/aps.rs b/crates/ziggurat-driver/src/zigbee_stack/aps.rs index 2cf2d08..0db77e9 100644 --- a/crates/ziggurat-driver/src/zigbee_stack/aps.rs +++ b/crates/ziggurat-driver/src/zigbee_stack/aps.rs @@ -293,10 +293,10 @@ impl ZigbeeStack { Ok((nwk_frame, ack_data)) } - /// How long to wait for a device's APS ack: longer for a sleepy child, which only - /// sees (and acks) the frame after polling. - fn aps_ack_timeout(&self, destination: Nwk) -> Duration { - if self.sleepy_child_eui64(destination).is_some() { + /// How long to wait for a device's APS ack: longer for a sleepy destination, which + /// only sees (and acks) the frame after polling. + fn aps_ack_timeout(&self, destination: Nwk, sleepy_destination: bool) -> Duration { + if sleepy_destination || self.sleepy_child_eui64(destination).is_some() { self.tunables.aps_ack_timeout_indirect() } else { self.tunables.aps_ack_timeout() @@ -321,6 +321,7 @@ impl ZigbeeStack { aps_seq: u8, data: Vec, aps_security: Option, + sleepy_destination: bool, priority: TxPriority, request_id: RequestId, ) -> Result<(), ZigbeeStackError> { @@ -341,7 +342,7 @@ impl ZigbeeStack { // An APS-ack send is confirmed by the end-to-end ack: register it (with the // deadline the timeout reactor uses) before enqueueing so a fast reply is caught. if let Some(ack_data) = &ack_data { - let deadline = self.core_now() + self.aps_ack_timeout(destination); + let deadline = self.core_now() + self.aps_ack_timeout(destination, sleepy_destination); self.state.pending_aps_acks.lock().insert( ack_data.clone(), PendingApsAck { diff --git a/crates/ziggurat-protocol/src/bridge.rs b/crates/ziggurat-protocol/src/bridge.rs index 381074b..8e8bc86 100644 --- a/crates/ziggurat-protocol/src/bridge.rs +++ b/crates/ziggurat-protocol/src/bridge.rs @@ -266,6 +266,7 @@ pub fn send_aps( payload.aps_seq, payload.asdu, aps_security, + payload.flags.sleepy_destination, TxPriority::from_host(payload.priority as i8), StackRequestId::from(request_id), ) diff --git a/crates/ziggurat-protocol/src/wire.rs b/crates/ziggurat-protocol/src/wire.rs index 217f76f..cce8410 100644 --- a/crates/ziggurat-protocol/src/wire.rs +++ b/crates/ziggurat-protocol/src/wire.rs @@ -322,7 +322,10 @@ pub struct SendApsFlags { pub aps_ack: bool, pub aps_encryption: bool, pub delivery_mode: ApsDeliveryMode, - pub reserved: u3, + /// The destination is a sleepy device. It only sees frames by polling its parent, + /// so the APS ack wait must cover a poll cycle. + pub sleepy_destination: bool, + pub reserved: u2, } #[abstract_bits]