capsules_extra/ieee802154/xmac.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! X-MAC protocol layer for low power 802.15.4 reception, intended primarily
6//! to manage an Atmel RF233 radio.
7//!
8//! Original X-MAC paper, on which this implementation is heavily based:
9//! <http://www.cs.cmu.edu/~andersoe/papers/xmac-sensys.pdf>
10//!
11//! Nodes using this layer place their radios to sleep for the vast majority of
12//! the time, thereby reducing power consumption. Transmitters wake and send a
13//! stream of small, strobed `preamble` packets to the desired recipient. If a
14//! receiver wakes and ACKS a relevant preamble, the receiver waits for a data
15//! packet before returning to sleep. See comments below for implementation
16//! details.
17//!
18//! Additional notes:
19//!
20//! * Since much of a node's time is spent sleeping, transmission latency is
21//! much higher than using a radio that is always powered on.
22//! * Err(ErrorCode::NOACK)s may be generated when transmitting, if the
23//! destination node cannot acknowledge within the maximum retry interval.
24//! * Since X-MAC relies on proper sleep/wake behavior for all nodes, any
25//! node with this implementation will not be able to communicate correctly
26//! with non-XMAC-wrapped radios.
27//!
28//! Usage
29//! -----
30//! This capsule implements the `capsules::ieee802154::mac::Mac` interface while
31//! wrapping an actual `kernel::hil::radio::Radio' with a similar interface, and
32//! can be used as the backend for a `capsules::ieee802154::device::MacDevice`,
33//! which should fully encode frames before passing it to this layer.
34//!
35//! In general, given a radio driver `RF233Device`,
36//! a `kernel::hil::time::Alarm`, and a `kernel::hil::rng::Rng` device, the
37//! necessary modifications to the board configuration are shown below for `imix`s:
38//!
39//! ```rust,ignore
40//! # use kernel::static_init;
41//!
42//! // main.rs
43//!
44//! use capsules::ieee802154::mac::Mac;
45//! use capsules::ieee802154::xmac;
46//! type XMacDevice = capsules::ieee802154::xmac::XMac<'static, RF233Device, Alarm>;
47//!
48//! // ...
49//! // XMac needs one buffer in addition to those provided to the RF233 driver.
50//! // 1. stores actual packet contents to free the SPI buffers used by the
51//! // radio for transmitting preamble packets
52//! static mut MAC_BUF: [u8; radio::MAX_BUF_SIZE] = [0x00; radio::MAX_BUF_SIZE];
53//! // ...
54//! let xmac: &XMacDevice = static_init!(XMacDevice, xmac::XMac::new(rf233, alarm, rng, &mut MAC_BUF));
55//! rng.set_client(xmac);
56//! alarm.set_client(xmac);
57//!
58//! // Hook up the radio to the XMAC implementation.
59//! rf233.set_transmit_client(xmac);
60//! rf233.set_receive_client(xmac, &mut RF233_RX_BUF);
61//! rf233.set_power_client(xmac);
62//!
63//! xmac.initialize();
64//!
65//! // We can now use the XMac driver to instantiate a MacDevice like a Framer
66//! let mac_device = static_init!(
67//! capsules::ieee802154::framer::Framer<'static, XMacDevice>,
68//! capsules::ieee802154::framer::Framer::new(xmac));
69//! xmac.set_transmit_client(mac_device);
70//! xmac.set_receive_client(mac_device);
71//! xmac.set_config_client(mac_device);
72//! ```
73
74//
75// TODO: Test no-preamble transmission with randomized backoff, requires 3
76// devices.
77// TODO: Modifying sleep time with traffic load to optimize energy usage.
78// TODO: Remove expectation that radios cancel pending sleeps when receiving a
79// new packet (see line 652).
80//
81// Author: Jean-Luc Watson
82// Date: Nov 21 2017
83//
84
85use crate::ieee802154::mac::Mac;
86use crate::net::ieee802154::{FrameType, FrameVersion, Header, MacAddress, PanID};
87use core::cell::Cell;
88use kernel::hil::radio;
89use kernel::hil::rng::{self, Rng};
90use kernel::hil::time::{self, Alarm, ConvertTicks, Ticks};
91use kernel::utilities::cells::{OptionalCell, TakeCell};
92use kernel::ErrorCode;
93
94// Time the radio will remain awake listening for packets before sleeping.
95// Observing the RF233, receive callbacks for preambles are generated only after
96// having been awake for more than 4-6 ms; 10 ms is a safe amount of time where
97// we are very likely to pick up any incoming preambles, and is half as much
98// as the 20 ms lower bound in Buettner et al.
99const WAKE_TIME_MS: u32 = 10;
100// Time the radio will sleep between wakes. Configurable to any desired value
101// less than or equal to the max time the transmitter sends preambles before
102// abandoning the transmission.
103const SLEEP_TIME_MS: u32 = 250;
104// Time the radio will continue to send preamble packets before aborting the
105// transmission and returning NOACK. Should be at least as large as the maximum
106// sleep time for any node in the network.
107const PREAMBLE_TX_MS: u32 = 251;
108
109// Maximum backoff for a transmitter attempting to send a data packet, when the
110// node has detected a data packet sent to the same destination from another
111// transmitter. This is an optimization that eliminates the need for any
112// preambles when the receiving node is shown to already be awake.
113const MAX_TX_BACKOFF_MS: u32 = 10;
114// After receiving a data packet, maximum time a node will stay awake to receive
115// any additional incoming packets before going to sleep.
116const MAX_RX_SLEEP_DELAY_MS: u32 = MAX_TX_BACKOFF_MS;
117
118#[allow(non_camel_case_types)]
119#[derive(Copy, Clone, PartialEq)]
120enum XMacState {
121 // The primary purpose of these states is to manage the timer that runs the
122 // protocol and determines the state of the radio (e.g. if in SLEEP, an
123 // alarm indicates we should transition to AWAKE).
124 AWAKE, // Awake and listening for incoming preambles
125 DELAY_SLEEP, // Receiving done; waiting for any other incoming data packets
126 SLEEP, // Asleep and not receiving or transmitting
127 STARTUP, // Radio waking up, PowerClient::on() transitions to next state
128 TX_PREAMBLE, // Transmitting preambles and waiting for an ACK
129 TX, // Transmitting data packet to the destination node
130 TX_DELAY, // Backing off to send data directly without preamble
131}
132
133// Information extracted for each packet from the data buffer provided to
134// transmit(), used to generate preamble packets and detect when a delayed
135// direct transmission (described above) is appropriate.
136#[derive(Copy, Clone, Eq, PartialEq)]
137pub struct XMacHeaderInfo {
138 pub dst_pan: Option<PanID>,
139 pub dst_addr: Option<MacAddress>,
140 pub src_pan: Option<PanID>,
141 pub src_addr: Option<MacAddress>,
142}
143
144// The X-MAC `driver` consists primarily of a backend radio driver, an alarm for
145// transitioning between different portions of the protocol, and a source of
146// randomness for transmit backoffs. In addition, we maintain two packet buffers
147// (one for transmit, one for receive) that cycle without copying between XMAC,
148// the tx/rx client, and the underlying radio driver. The transmit buffer can
149// also hold the actual data packet contents while preambles are being
150// transmitted.
151pub struct XMac<'a, R: radio::Radio<'a>, A: Alarm<'a>> {
152 radio: &'a R,
153 alarm: &'a A,
154 rng: &'a dyn Rng<'a>,
155 tx_client: OptionalCell<&'a dyn radio::TxClient>,
156 rx_client: OptionalCell<&'a dyn radio::RxClient>,
157 state: Cell<XMacState>,
158 delay_sleep: Cell<bool>,
159
160 tx_header: Cell<Option<XMacHeaderInfo>>,
161 tx_payload: TakeCell<'static, [u8]>,
162 tx_len: Cell<usize>,
163
164 tx_preamble_pending: Cell<bool>,
165 tx_preamble_seq_num: Cell<u8>,
166 tx_preamble_buf: TakeCell<'static, [u8]>,
167
168 rx_pending: Cell<bool>,
169}
170
171impl<'a, R: radio::Radio<'a>, A: Alarm<'a>> XMac<'a, R, A> {
172 pub fn new(
173 radio: &'a R,
174 alarm: &'a A,
175 rng: &'a dyn Rng<'a>,
176 mac_buf: &'static mut [u8],
177 ) -> XMac<'a, R, A> {
178 XMac {
179 radio,
180 alarm,
181 rng,
182 tx_client: OptionalCell::empty(),
183 rx_client: OptionalCell::empty(),
184 state: Cell::new(XMacState::STARTUP),
185 delay_sleep: Cell::new(false),
186 tx_header: Cell::new(None),
187 tx_payload: TakeCell::empty(),
188 tx_len: Cell::new(0),
189 tx_preamble_pending: Cell::new(false),
190 tx_preamble_seq_num: Cell::new(0),
191 tx_preamble_buf: TakeCell::new(mac_buf),
192 rx_pending: Cell::new(false),
193 }
194 }
195
196 fn sleep_time(&self) -> u32 {
197 // TODO (ongoing) modify based on traffic load to efficiently schedule
198 // sleep. Currently sleeps for a constant amount of time.
199 SLEEP_TIME_MS
200 }
201
202 fn sleep(&self) {
203 // If transmitting/delaying sleep, we don't want to try to sleep (again)
204 if self.state.get() == XMacState::AWAKE {
205 // If we should delay sleep (completed RX), set timer accordingly
206 if self.delay_sleep.get() {
207 self.state.set(XMacState::DELAY_SLEEP);
208 self.set_timer_ms(MAX_RX_SLEEP_DELAY_MS);
209
210 // Otherwise, don't sleep if expecting a data packet or transmitting
211 } else if !self.rx_pending.get() {
212 let _ = self.radio.stop();
213 self.state.set(XMacState::SLEEP);
214 self.set_timer_ms(self.sleep_time());
215 }
216 }
217 }
218
219 // Sets the timer to fire a set number of milliseconds in the future based
220 // on the current tick value.
221 fn set_timer_ms(&self, ms: u32) {
222 let interval = self.alarm.ticks_from_ms(ms);
223 self.set_timer(interval);
224 }
225
226 fn set_timer(&self, ticks: A::Ticks) {
227 self.alarm.set_alarm(self.alarm.now(), ticks);
228 }
229
230 fn transmit_preamble(&self) {
231 let mut result: Result<(), (ErrorCode, &'static mut [u8])> = Ok(());
232 let buf = self.tx_preamble_buf.take().unwrap();
233 let tx_header = self.tx_header.get().unwrap();
234
235 // If we're not currently sending preambles, skip transmission
236 if let XMacState::TX_PREAMBLE = self.state.get() {
237 // Generate preamble frame. We use a reserved frame type (0b101) to
238 // distinguish from regular data frames, increment a sequence
239 // number for each consecutive packet sent, and send with no
240 // security.
241 let header = Header {
242 frame_type: FrameType::Multipurpose,
243 frame_pending: false,
244 ack_requested: true,
245 version: FrameVersion::V2006,
246 seq: Some(self.tx_preamble_seq_num.get()),
247 dst_pan: tx_header.dst_pan,
248 dst_addr: tx_header.dst_addr,
249 src_pan: tx_header.src_pan,
250 src_addr: tx_header.src_addr,
251 security: None,
252 header_ies: Default::default(),
253 header_ies_len: 0,
254 payload_ies: Default::default(),
255 payload_ies_len: 0,
256 };
257
258 self.tx_preamble_seq_num
259 .set(self.tx_preamble_seq_num.get() + 1);
260
261 match header.encode(&mut buf[radio::PSDU_OFFSET..], true).done() {
262 // If we can successfully encode the preamble, transmit.
263 Some((data_offset, _)) => {
264 result = self.radio.transmit(buf, data_offset + radio::PSDU_OFFSET);
265 }
266 None => {
267 self.tx_preamble_buf.replace(buf);
268 self.call_tx_client(
269 self.tx_payload.take().unwrap(),
270 false,
271 Err(ErrorCode::FAIL),
272 );
273 return;
274 }
275 }
276 }
277
278 // If the transmission fails, callback directly back into the client
279 let _ = result.map_err(|(ecode, buf)| {
280 self.call_tx_client(buf, false, Err(ecode));
281 });
282 }
283
284 fn transmit_packet(&self) {
285 // If we have actual data to transmit, send it and report errors to
286 // client.
287 if self.tx_payload.is_some() {
288 let tx_buf = self.tx_payload.take().unwrap();
289
290 let _ = self
291 .radio
292 .transmit(tx_buf, self.tx_len.get())
293 .map_err(|(ecode, buf)| {
294 self.call_tx_client(buf, false, Err(ecode));
295 });
296 }
297 }
298
299 // Reports back to client that transmission is complete, radio can turn off
300 // if not kept awake by other portions of the protocol.
301 fn call_tx_client(&self, buf: &'static mut [u8], acked: bool, result: Result<(), ErrorCode>) {
302 self.state.set(XMacState::AWAKE);
303 self.sleep();
304 self.tx_client.map(move |c| {
305 c.send_done(buf, acked, result);
306 });
307 }
308
309 // Reports any received packet back to the client and starts going to sleep.
310 // Does not propagate preamble packets up to the RxClient.
311 fn call_rx_client(
312 &self,
313 buf: &'static mut [u8],
314 len: usize,
315 lqi: u8,
316 crc_valid: bool,
317 result: Result<(), ErrorCode>,
318 ) {
319 self.delay_sleep.set(true);
320 self.sleep();
321
322 self.rx_client.map(move |c| {
323 c.receive(buf, len, lqi, crc_valid, result);
324 });
325 }
326}
327
328impl<'a, R: radio::Radio<'a>, A: Alarm<'a>> rng::Client for XMac<'a, R, A> {
329 fn randomness_available(
330 &self,
331 randomness: &mut dyn Iterator<Item = u32>,
332 _error: Result<(), ErrorCode>,
333 ) -> rng::Continue {
334 match randomness.next() {
335 Some(random) => {
336 if self.state.get() == XMacState::TX_DELAY {
337 // When another data packet to our desired destination is
338 // detected, we backoff a random amount before sending our
339 // own data with no preamble. This assumes that the reciever
340 // will remain awake long enough to receive our transmission,
341 // as it should with this implementation. Since Rng is
342 // asynchronous, we account for the time spent waiting for
343 // the callback and randomly determine the remaining time
344 // spent backing off.
345 let ticks_remaining = self.alarm.get_alarm().wrapping_sub(self.alarm.now());
346 let backoff = A::Ticks::from(ticks_remaining.into_u32() % random);
347 self.set_timer(backoff);
348 }
349 rng::Continue::Done
350 }
351 None => rng::Continue::More,
352 }
353 }
354}
355
356// The vast majority of these calls pass through to the underlying radio driver.
357impl<'a, R: radio::Radio<'a>, A: Alarm<'a>> Mac<'a> for XMac<'a, R, A> {
358 fn initialize(&self) -> Result<(), ErrorCode> {
359 self.state.set(XMacState::STARTUP);
360 Ok(())
361 }
362
363 // Always lie and say the radio is on when sleeping, as XMAC will wake up
364 // itself to send preambles if necessary.
365 fn is_on(&self) -> bool {
366 if self.state.get() == XMacState::SLEEP {
367 return true;
368 }
369 self.radio.is_on()
370 }
371
372 fn start(&self) -> Result<(), ErrorCode> {
373 self.state.set(XMacState::STARTUP);
374 self.radio.start()
375 }
376
377 fn set_config_client(&self, client: &'a dyn radio::ConfigClient) {
378 self.radio.set_config_client(client)
379 }
380
381 fn set_address(&self, addr: u16) {
382 self.radio.set_address(addr)
383 }
384
385 fn set_address_long(&self, addr: [u8; 8]) {
386 self.radio.set_address_long(addr)
387 }
388
389 fn set_pan(&self, id: u16) {
390 self.radio.set_pan(id)
391 }
392
393 fn get_address(&self) -> u16 {
394 self.radio.get_address()
395 }
396
397 fn get_address_long(&self) -> [u8; 8] {
398 self.radio.get_address_long()
399 }
400
401 fn get_pan(&self) -> u16 {
402 self.radio.get_pan()
403 }
404
405 fn config_commit(&self) {
406 self.radio.config_commit()
407 }
408
409 fn set_transmit_client(&self, client: &'a dyn radio::TxClient) {
410 self.tx_client.set(client);
411 }
412
413 fn set_receive_client(&self, client: &'a dyn radio::RxClient) {
414 self.rx_client.set(client);
415 }
416
417 fn set_receive_buffer(&self, buffer: &'static mut [u8]) {
418 self.radio.set_receive_buffer(buffer);
419 }
420
421 fn transmit(
422 &self,
423 full_mac_frame: &'static mut [u8],
424 frame_len: usize,
425 ) -> Result<(), (ErrorCode, &'static mut [u8])> {
426 // If the radio is busy, we already have data to transmit, or the buffer
427 // size is wrong, fail before attempting to send any preamble packets
428 // (and waking up the radio).
429 let frame_len = frame_len + radio::MFR_SIZE;
430 if self.radio.busy() || self.tx_payload.is_some() {
431 return Err((ErrorCode::BUSY, full_mac_frame));
432 } else if radio::PSDU_OFFSET + frame_len >= full_mac_frame.len() {
433 return Err((ErrorCode::SIZE, full_mac_frame));
434 }
435
436 match Header::decode(&full_mac_frame[radio::PSDU_OFFSET..], false).done() {
437 Some((_, (header, _))) => {
438 self.tx_len.set(frame_len - radio::PSDU_OFFSET);
439 self.tx_header.set(Some(XMacHeaderInfo {
440 dst_addr: header.dst_addr,
441 dst_pan: header.dst_pan,
442 src_addr: header.src_addr,
443 src_pan: header.src_pan,
444 }));
445 }
446 None => {
447 self.tx_header.set(None);
448 }
449 }
450
451 match self.tx_header.get() {
452 Some(_) => {
453 self.tx_payload.replace(full_mac_frame);
454 }
455 None => {
456 return Err((ErrorCode::FAIL, full_mac_frame));
457 }
458 }
459
460 self.tx_preamble_seq_num.set(0);
461
462 // If the radio is on, start the preamble timer and start transmitting
463 if self.radio.is_on() {
464 self.state.set(XMacState::TX_PREAMBLE);
465 self.set_timer_ms(PREAMBLE_TX_MS);
466 self.transmit_preamble();
467
468 // If the radio is currently sleeping, wake it and indicate that when
469 // ready, it should begin transmitting preambles
470 } else {
471 self.state.set(XMacState::STARTUP);
472 self.tx_preamble_pending.set(true);
473 let _ = self.radio.start();
474 }
475
476 Ok(())
477 }
478}
479
480// Core of the XMAC protocol - when the timer fires, the protocol state
481// indicates the next state/action to take.
482impl<'a, R: radio::Radio<'a>, A: Alarm<'a>> time::AlarmClient for XMac<'a, R, A> {
483 fn alarm(&self) {
484 match self.state.get() {
485 XMacState::SLEEP => {
486 // If asleep, start the radio and wait for the PowerClient to
487 // indicate that the radio is ready
488 if !self.radio.is_on() {
489 self.state.set(XMacState::STARTUP);
490 let _ = self.radio.start();
491 } else {
492 self.set_timer_ms(WAKE_TIME_MS);
493 self.state.set(XMacState::AWAKE);
494 }
495 }
496 // If we've been delaying sleep or haven't heard any incoming
497 // preambles, turn the radio off.
498 XMacState::AWAKE => {
499 self.sleep();
500 }
501 XMacState::DELAY_SLEEP => {
502 self.delay_sleep.set(false);
503 self.state.set(XMacState::AWAKE);
504 self.sleep();
505 }
506 // If we've sent preambles for longer than the maximum sleep time of
507 // any node in the network, then our destination is non-responsive;
508 // return NOACK to the client.
509 XMacState::TX_PREAMBLE => {
510 self.call_tx_client(
511 self.tx_payload.take().unwrap(),
512 false,
513 Err(ErrorCode::NOACK),
514 );
515 }
516 // After a randomized backoff period, transmit the data directly.
517 XMacState::TX_DELAY => {
518 self.state.set(XMacState::TX);
519 self.transmit_packet();
520 }
521 _ => {}
522 }
523 }
524}
525
526impl<'a, R: radio::Radio<'a>, A: Alarm<'a>> radio::PowerClient for XMac<'a, R, A> {
527 fn changed(&self, on: bool) {
528 // If the radio turns on and we're in STARTUP, then either transition to
529 // listening for incoming preambles or start transmitting preambles if
530 // the radio was turned on for a transmission.
531 if on {
532 if let XMacState::STARTUP = self.state.get() {
533 if self.tx_preamble_pending.get() {
534 self.tx_preamble_pending.set(false);
535 self.state.set(XMacState::TX_PREAMBLE);
536 self.set_timer_ms(PREAMBLE_TX_MS);
537 self.transmit_preamble();
538 } else {
539 self.state.set(XMacState::AWAKE);
540 self.set_timer_ms(WAKE_TIME_MS);
541 }
542 }
543 }
544 }
545}
546
547impl<'a, R: radio::Radio<'a>, A: Alarm<'a>> radio::TxClient for XMac<'a, R, A> {
548 fn send_done(&self, buf: &'static mut [u8], acked: bool, result: Result<(), ErrorCode>) {
549 match self.state.get() {
550 // Completed a data transmission to the destination node
551 XMacState::TX => {
552 self.call_tx_client(buf, acked, result);
553 }
554 // Completed a preamble transmission
555 XMacState::TX_PREAMBLE => {
556 self.tx_preamble_buf.replace(buf);
557 if acked {
558 // Destination signals ready to receive data
559 self.state.set(XMacState::TX);
560 self.transmit_packet();
561 } else {
562 // Continue resending preambles
563 self.transmit_preamble();
564 }
565 }
566 XMacState::TX_DELAY | XMacState::SLEEP => {
567 // If, while sending preambles, we switch to TX_DELAY mode, the
568 // last preamble sent will complete afterwards. If no ACK, the
569 // radio may have fallen sleep before the callback is processed.
570 self.tx_preamble_buf.replace(buf);
571 }
572 _ => {}
573 }
574 }
575}
576
577// The receive callback is complicated by the fact that, to determine when a
578// destination node is receiving packets/awake while we are attempting a
579// transmission, we put the radio in promiscuous mode. Not a huge issue, but
580// we need to be wary of incoming packets not actually addressed to our node.
581impl<'a, R: radio::Radio<'a>, A: Alarm<'a>> radio::RxClient for XMac<'a, R, A> {
582 fn receive(
583 &self,
584 buf: &'static mut [u8],
585 frame_len: usize,
586 lqi: u8,
587 crc_valid: bool,
588 result: Result<(), ErrorCode>,
589 ) {
590 let mut data_received: bool = false;
591 let mut continue_sleep: bool = true;
592
593 // First, check to make sure we can decode the MAC header (especially
594 // the destination address) to see if we can backoff/send pending
595 // transmission.
596 if let Some((_, (header, _))) = Header::decode(&buf[radio::PSDU_OFFSET..], false).done() {
597 if let Some(dst_addr) = header.dst_addr {
598 let addr_match = match dst_addr {
599 MacAddress::Short(addr) => addr == self.radio.get_address(),
600 MacAddress::Long(long_addr) => long_addr == self.radio.get_address_long(),
601 };
602 // The destination doesn't match our address, check to see if we
603 // can backoff a pending transmission if it exists rather than
604 // continue sending preambles.
605 if !addr_match {
606 if self.state.get() == XMacState::TX_PREAMBLE {
607 if let Some(tx_dst_addr) = self.tx_header.get().and_then(|hdr| hdr.dst_addr)
608 {
609 if tx_dst_addr == dst_addr {
610 // Randomize backoff - since the callback is asynchronous, set the
611 // timer for the max and adjust later. As a result, we can't
612 // backoff for more than the Rng generation time.
613 self.state.set(XMacState::TX_DELAY);
614 let _ = self.rng.get();
615 self.set_timer_ms(MAX_TX_BACKOFF_MS);
616 continue_sleep = false;
617 }
618 }
619 }
620 } else {
621 // We've received either a preamble or data packet
622 match header.frame_type {
623 FrameType::Multipurpose => {
624 continue_sleep = false;
625 self.rx_pending.set(true);
626 }
627 FrameType::Data => {
628 continue_sleep = false;
629 data_received = true;
630 }
631 _ => {}
632 }
633 }
634 }
635 }
636
637 // TODO: this currently assumes that upon receiving a packet, the radio
638 // will cancel a pending sleep, and an additional call to Radio::stop()
639 // is required to shut down the radio. This works specifically for the
640 // RF233 with the added line at rf233.rs:744. In progress: it might be
641 // possible to remove this requirement.
642 if self.state.get() == XMacState::SLEEP {
643 self.state.set(XMacState::AWAKE);
644 }
645
646 if data_received {
647 self.rx_pending.set(false);
648 self.call_rx_client(buf, frame_len, lqi, crc_valid, result);
649 } else {
650 self.radio.set_receive_buffer(buf);
651 }
652
653 // If we should go to sleep (i.e. not waiting up for any additional data
654 // packets), shut the radio down. If a prior sleep was pending, it was
655 // cancelled as the result of the RX (see above).
656 if continue_sleep {
657 self.sleep();
658 }
659 }
660}