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}