ezsp/apis_saltans/conversion/
event.rs1use apis_saltans_hw::aps::apsde::{
11 ConfirmStatus, DataConfirm, Destination, IndividualEndpoint, NetworkAddress,
12};
13use apis_saltans_hw::core::Endpoint;
14use apis_saltans_hw::{ApsdeEvent, DeviceEvent, Event, NetworkEvent};
15
16use crate::ember::Status;
17use crate::ember::aps::Options;
18use crate::ember::device::Update;
19use crate::ember::message::Outgoing;
20use crate::parameters::messaging::handler::MessageSent;
21use crate::parameters::networking::handler::ChildJoin;
22use crate::parameters::trust_center::handler::TrustCenterJoin;
23
24impl TryFrom<MessageSent> for Event {
25 type Error = MessageSent;
26
27 fn try_from(message_sent: MessageSent) -> Result<Self, Self::Error> {
28 if !message_sent.aps_frame().options().contains(Options::RETRY) {
29 return Err(message_sent);
30 }
31 let source_endpoint =
32 IndividualEndpoint::new(Endpoint::from(message_sent.aps_frame().source_endpoint()))
33 .ok_or_else(|| message_sent.clone())?;
34 let destination_endpoint = Endpoint::from(message_sent.aps_frame().destination_endpoint());
35 let destination = match message_sent.typ().map_err(|_| message_sent.clone())? {
36 Outgoing::Direct => Destination::Network {
37 address: NetworkAddress::new(message_sent.index_or_destination())
38 .ok_or_else(|| message_sent.clone())?,
39 endpoint: destination_endpoint,
40 },
41 Outgoing::ViaAddressTable
42 | Outgoing::ViaBinding
43 | Outgoing::Multicast
44 | Outgoing::Broadcast => return Err(message_sent),
45 };
46 let status = match message_sent.status() {
47 Ok(Status::Success) => ConfirmStatus::success(),
48 Ok(status) => ConfirmStatus::Network(status.into()),
49 Err(status) => ConfirmStatus::Network(status),
50 };
51 let confirmation = DataConfirm::new(destination, source_endpoint, status, ());
52
53 Ok(Self::Apsde(ApsdeEvent::DataConfirm {
54 counter: message_sent.message_tag(),
55 confirmation,
56 }))
57 }
58}
59
60impl TryFrom<ChildJoin> for Event {
61 type Error = ChildJoin;
62
63 fn try_from(child_join: ChildJoin) -> Result<Self, Self::Error> {
64 let event = if child_join.joining() {
65 DeviceEvent::Joined(child_join.try_into()?)
66 } else {
67 DeviceEvent::Left(child_join.try_into()?)
68 };
69
70 Ok(Self::Device(event))
71 }
72}
73
74impl TryFrom<Status> for Event {
75 type Error = Status;
76
77 fn try_from(status: Status) -> Result<Self, Self::Error> {
78 let event = match status {
79 Status::NetworkUp => NetworkEvent::Up,
80 Status::NetworkDown => NetworkEvent::Down,
81 Status::NetworkOpened => NetworkEvent::Opened,
82 Status::NetworkClosed => NetworkEvent::Closed,
83 other => return Err(other),
84 };
85
86 Ok(Self::Network(event))
87 }
88}
89
90impl TryFrom<TrustCenterJoin> for Event {
91 type Error = TrustCenterJoin;
92
93 fn try_from(trust_center_join: TrustCenterJoin) -> Result<Self, Self::Error> {
94 let Ok(status) = trust_center_join.status() else {
95 return Err(trust_center_join);
96 };
97
98 let event = match status {
99 Update::StandardSecurityUnsecuredJoin => {
100 DeviceEvent::Joined(trust_center_join.try_into()?)
101 }
102 Update::StandardSecurityUnsecuredRejoin => DeviceEvent::Rejoined {
103 address: trust_center_join.try_into()?,
104 secured: false,
105 },
106 Update::StandardSecuritySecuredRejoin => DeviceEvent::Rejoined {
107 address: trust_center_join.try_into()?,
108 secured: true,
109 },
110 Update::DeviceLeft => DeviceEvent::Left(trust_center_join.try_into()?),
111 };
112
113 Ok(Self::Device(event))
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use apis_saltans_hw::aps::apsde::{ConfirmStatus, Destination};
120 use apis_saltans_hw::{ApsdeEvent, Event};
121 use le_stream::FromLeStream;
122
123 use crate::parameters::messaging::handler::MessageSent;
124
125 const MESSAGE_TAG: u8 = 0x34;
126 const APS_SEQUENCE: u8 = 0x56;
127 const OPTIONS_INDEX: usize = 9;
128 const STATUS_INDEX: usize = 15;
129 const STATUS_SUCCESS: u8 = 0x00;
130 const STATUS_DELIVERY_FAILED: u8 = 0x66;
131 const MESSAGE_SENT_BYTES: [u8; 17] = [
132 0x00,
133 0x78,
134 0x56,
135 0x04,
136 0x01,
137 0x06,
138 0x03,
139 0x01,
140 0x02,
141 0x40,
142 0x00,
143 0x00,
144 0x00,
145 APS_SEQUENCE,
146 MESSAGE_TAG,
147 STATUS_SUCCESS,
148 0x00,
149 ];
150
151 fn message_sent(status: u8) -> MessageSent {
152 let mut bytes = MESSAGE_SENT_BYTES;
153 bytes[STATUS_INDEX] = status;
154 MessageSent::from_le_stream(bytes.into_iter())
155 .expect("messageSent test callback is complete")
156 }
157
158 #[test]
159 fn converts_successful_message_sent_to_data_confirmation() {
160 let event = Event::try_from(message_sent(STATUS_SUCCESS))
161 .expect("direct messageSent callback is representable");
162 let Event::Apsde(ApsdeEvent::DataConfirm {
163 counter,
164 confirmation,
165 }) = event
166 else {
167 panic!("messageSent must become a data confirmation");
168 };
169
170 assert_eq!(counter, MESSAGE_TAG);
171 assert_eq!(confirmation.status(), ConfirmStatus::success());
172 assert!(matches!(
173 confirmation.destination(),
174 Destination::Network { .. }
175 ));
176 }
177
178 #[test]
179 fn preserves_failed_message_sent_status() {
180 let event = Event::try_from(message_sent(STATUS_DELIVERY_FAILED))
181 .expect("direct messageSent callback is representable");
182 let Event::Apsde(ApsdeEvent::DataConfirm { confirmation, .. }) = event else {
183 panic!("messageSent must become a data confirmation");
184 };
185
186 assert_eq!(
187 confirmation.status(),
188 ConfirmStatus::Network(STATUS_DELIVERY_FAILED)
189 );
190 }
191
192 #[test]
193 fn rejects_unacknowledged_message_sent() {
194 let mut message = MESSAGE_SENT_BYTES;
195 message[OPTIONS_INDEX] = 0;
196 let message = MessageSent::from_le_stream(message.into_iter())
197 .expect("messageSent test callback is complete");
198
199 assert!(Event::try_from(message).is_err());
200 }
201}