esb_ng/
peripherals.rs

1// #[cfg(feature = "51")]
2// use nrf51_pac as pac;
3
4// #[cfg(feature = "52810")]
5// use nrf52810_pac as pac;
6
7// #[cfg(feature = "52832")]
8// use nrf52832_pac as pac;
9
10// #[cfg(feature = "52833")]
11// use nrf52833_pac as pac;
12
13// #[cfg(feature = "52840")]
14// use nrf52840_pac as pac;
15
16use nrf_pac::{
17    self as pac,
18    radio::{
19        regs::{Int as RadioInt, Prefix0, Prefix1, Rxaddresses},
20        vals::{Crcstatus, Endian, Len, Mode},
21    },
22    timer::{regs::Int as TimerInt, vals::Bitmode},
23    TIMER0, TIMER1, TIMER2,
24};
25
26use core::sync::atomic::{compiler_fence, Ordering};
27
28use crate::{
29    app::{Addresses, FramedConsumer},
30    payload::{PayloadR, PayloadW},
31    Error,
32};
33pub(crate) use pac::{radio::vals::Txpower, radio::Radio, Interrupt};
34// TODO
35pub use pac::RADIO;
36
37const CRC_INIT: u32 = 0x0000_FFFF;
38const CRC_POLY: u32 = 0x0001_1021;
39const NUM_PIPES: usize = 8;
40
41#[inline]
42fn bytewise_bit_swap(value: u32) -> u32 {
43    value.reverse_bits().swap_bytes()
44}
45
46#[inline]
47fn address_conversion(value: u32) -> u32 {
48    value.reverse_bits()
49}
50
51#[derive(Copy, Clone, PartialEq, Debug)]
52pub(crate) enum RxPayloadState {
53    Ack,
54    NoAck,
55    RepeatedAck,
56    RepeatedNoAck,
57    BadCRC,
58}
59
60pub struct EsbRadio<const OUT: usize, const IN: usize>
61{
62    radio: Radio,
63    tx_grant: Option<PayloadR<OUT>>,
64    rx_grant: Option<PayloadW<IN>>,
65    last_crc: [u16; NUM_PIPES],
66    last_pid: [u8; NUM_PIPES],
67    cached_pipe: u8,
68}
69
70impl<const OUT: usize, const IN: usize> EsbRadio<OUT, IN>
71{
72    pub(crate) fn new(radio: Radio) -> Self {
73        EsbRadio {
74            radio,
75            tx_grant: None,
76            rx_grant: None,
77            last_crc: [0; NUM_PIPES],
78            last_pid: [0; NUM_PIPES],
79            cached_pipe: 0,
80        }
81    }
82
83    pub(crate) fn init(&mut self, max_payload: u8, tx_power: Txpower, addresses: &Addresses) {
84        // Disables all interrupts, Nordic's code writes to all bits, seems to be okay
85        self.radio.intenclr().write_value(RadioInt(0xFFFF_FFFF));
86        self.radio.mode().write(|w| w.set_mode(Mode::NRF_2MBIT));
87        let len_bits = if max_payload <= 32 { 6 } else { 8 };
88        // Convert addresses to remain compatible with nRF24L devices
89        let base0 = address_conversion(u32::from_le_bytes(addresses.base0));
90        let base1 = address_conversion(u32::from_le_bytes(addresses.base1));
91        let prefix0 = bytewise_bit_swap(u32::from_le_bytes(addresses.prefixes0));
92        let prefix1 = bytewise_bit_swap(u32::from_le_bytes(addresses.prefixes1));
93
94        self.radio.shorts().write(|w| {
95            w.set_ready_start(true);
96            w.set_end_disable(true);
97            w.set_address_rssistart(true);
98            w.set_disabled_rssistop(true);
99        });
100
101        // Enable fast ramp-up
102        #[cfg(feature = "fast-ru")]
103        self.radio.modecnf0.modify(|w| w.ru().fast());
104
105        self.radio.txpower().write(|w| w.set_txpower(tx_power));
106
107        self.radio.pcnf0().write(|w| {
108            w.set_lflen(len_bits);
109            w.set_s1len(3);
110        });
111
112        self.radio.pcnf1().write(|w| {
113            w.set_maxlen(max_payload);
114            // 4-Byte Base Address + 1-Byte Address Prefix
115            w.set_balen(4);
116            // Nordic's code doesn't use whitening, maybe enable in the future ?
117            // w.set_whiteen(true);
118            w.set_statlen(0);
119            w.set_endian(Endian::BIG);
120        });
121
122        self.radio
123            .crcinit()
124            .write(|w| w.set_crcinit(CRC_INIT & 0x00FF_FFFF));
125
126        self.radio
127            .crcpoly()
128            .write(|w| w.set_crcpoly(CRC_POLY & 0x00FF_FFFF));
129
130        self.radio.crccnf().write(|w| w.set_len(Len::TWO));
131
132        self.radio.base0().write_value(base0);
133        self.radio.base1().write_value(base1);
134
135        self.radio.prefix0().write_value(Prefix0(prefix0));
136        self.radio.prefix1().write_value(Prefix1(prefix1));
137
138        // NOTE(unsafe) `rf_channel` was checked to be between 0 and 100 during the creation of
139        // the `Adresses` object
140        self.radio
141            .frequency()
142            .write(|w| w.set_frequency(addresses.rf_channel));
143    }
144
145    // Clears the Disabled event to not retrigger the interrupt
146    #[inline]
147    pub(crate) fn clear_disabled_event(&mut self) {
148        self.radio.events_disabled().write_value(0);
149    }
150
151    // Checks the Disabled event
152    #[inline]
153    pub(crate) fn check_disabled_event(&mut self) -> bool {
154        self.radio.events_disabled().read() == 1
155    }
156
157    // Clears the End event to not retrigger the interrupt
158    #[inline]
159    pub(crate) fn clear_end_event(&mut self) {
160        self.radio.events_end().write_value(0);
161    }
162
163    // Checks the Ready event
164    #[inline]
165    pub(crate) fn check_ready_event(&self) -> bool {
166        self.radio.events_ready().read() == 1
167    }
168
169    // Clears the Ready event to not retrigger the interrupt
170    #[inline]
171    pub(crate) fn clear_ready_event(&mut self) {
172        self.radio.events_ready().write_value(0);
173    }
174
175    // Disables Disabled interrupt
176    #[inline]
177    pub(crate) fn disable_disabled_interrupt(&mut self) {
178        self.radio.intenclr().write(|w| w.set_disabled(true));
179    }
180
181    // Disables the radio and the `radio disabled` interrupt
182    pub(crate) fn stop(&mut self, drop_grants: bool) {
183        self.radio.shorts().modify(|w| {
184            w.set_disabled_rxen(false);
185            w.set_disabled_txen(false);
186        });
187        self.disable_disabled_interrupt();
188        self.radio.tasks_disable().write_value(1);
189
190        // Wait for the disable event to kick in, to make sure that the `task_disable` write won't
191        // trigger an interrupt
192        while self.radio.events_disabled().read() == 0 {}
193        self.clear_disabled_event();
194
195        // "Subsequent reads and writes cannot be moved ahead of preceding reads."
196        compiler_fence(Ordering::Acquire);
197
198        if drop_grants {
199            // Drop grants we might have
200            self.tx_grant.take();
201            self.rx_grant.take();
202        }
203    }
204
205    // --------------- PTX methods --------------- //
206
207    // Transmit a packet and setup interrupts.
208    pub(crate) fn transmit(&mut self, payload: PayloadR<OUT>, ack: bool) {
209        if ack {
210            // Go to RX mode after the transmission
211            self.radio.shorts().modify(|w| w.set_disabled_rxen(true));
212        }
213        self.radio.intenset().write(|w| w.set_disabled(true));
214        // NOTE(unsafe) Pipe fits in 3 bits
215        self.radio
216            .txaddress()
217            .write(|w| w.set_txaddress(payload.pipe()));
218        // NOTE(unsafe) Pipe only goes from 0 through 7
219        self.radio
220            .rxaddresses()
221            .write_value(Rxaddresses(1 << payload.pipe()));
222
223        self.radio
224            .packetptr()
225            .write_value(payload.dma_pointer() as u32);
226        self.radio.events_address().write_value(0);
227        self.clear_disabled_event();
228        self.clear_ready_event();
229        self.clear_end_event();
230        self.radio.events_payload().write_value(0); // do we need this ? Probably not
231
232        // "Preceding reads and writes cannot be moved past subsequent writes."
233        compiler_fence(Ordering::Release);
234
235        self.radio.tasks_txen().write_value(1);
236        self.tx_grant = Some(payload);
237    }
238
239    // Must be called after the end of TX if the user did not request an ack
240    pub(crate) fn finish_tx_no_ack(&mut self) {
241        // We could use `Acquire` ordering if could prove that a read occurred
242        // "No re-ordering of reads and writes across this point is allowed."
243        compiler_fence(Ordering::SeqCst);
244
245        // Transmission completed, release packet. If we are here we should always have the tx_grant
246        if let Some(grant) = self.tx_grant.take() {
247            grant.release();
248        }
249
250        // It will be enabled again in a call to `transmit`.
251        self.disable_disabled_interrupt();
252    }
253
254    // Must be called after the end of TX if the user requested for an ack.
255    // Timers must be set accordingly by the upper stack
256    pub(crate) fn prepare_for_ack(&mut self, mut rx_buf: PayloadW<IN>) {
257        self.clear_ready_event();
258        // We need a compiler fence here because the DMA will automatically start listening for
259        // packets after the ramp-up is completed
260        // "Preceding reads and writes cannot be moved past subsequent writes."
261        compiler_fence(Ordering::Release);
262        self.radio
263            .packetptr()
264            .write_value(rx_buf.dma_pointer() as u32);
265
266        // Check if the radio turn around was faster than us
267        debug_assert!(!self.check_ready_event(), "Missed window (PTX)");
268
269        self.rx_grant = Some(rx_buf);
270        // this already fired
271        self.radio.shorts().modify(|w| w.set_disabled_rxen(false));
272
273        // We don't release the packet here because we may need to retransmit
274    }
275
276    // Returns true if the ack was received successfully
277    // The upper stack is responsible for checking and disabling the timeouts
278    #[inline]
279    pub(crate) fn check_ack(&mut self) -> Result<bool, Error> {
280        let ret = self.radio.crcstatus().read().crcstatus() == Crcstatus::CRCOK;
281        // "Subsequent reads and writes cannot be moved ahead of preceding reads."
282        compiler_fence(Ordering::Acquire);
283
284        if ret {
285            let (tx_grant, mut rx_grant) = (
286                self.tx_grant.take().ok_or(Error::InternalError)?,
287                self.rx_grant.take().ok_or(Error::InternalError)?,
288            );
289
290            let pipe = tx_grant.pipe();
291            tx_grant.release();
292
293            let rssi = self.radio.rssisample().read().rssisample();
294            rx_grant.set_pipe(pipe);
295            rx_grant.set_rssi(rssi);
296            rx_grant.commit_all();
297        } else {
298            // Drop `tx_grant` and `rx_grant` so the upper stack can pass them again in the next
299            // `transmit` and `prepare_for_ack`
300            self.tx_grant.take();
301            self.rx_grant.take();
302        }
303        Ok(ret)
304    }
305
306    // --------------- PRX methods --------------- //
307
308    // Start listening for packets and setup necessary shorts and interrupts
309    pub(crate) fn start_receiving(&mut self, mut rx_buf: PayloadW<IN>, enabled_pipes: u8) {
310        // Start TX after receiving a packet as it might need an ack
311        self.radio.shorts().modify(|w| w.set_disabled_txen(true));
312
313        self.radio.intenset().write(|w| w.set_disabled(true));
314        self.radio
315            .rxaddresses()
316            .write_value(Rxaddresses(enabled_pipes as u32));
317
318        self.radio
319            .packetptr()
320            .write_value(rx_buf.dma_pointer() as u32);
321        self.radio.events_address().write_value(0);
322        self.clear_disabled_event();
323        self.clear_ready_event();
324        self.clear_end_event();
325        self.radio.events_payload().write_value(0); // TODO: do we need this ? Probably not
326
327        // "Preceding reads and writes cannot be moved past subsequent writes."
328        compiler_fence(Ordering::Release);
329
330        self.radio.tasks_rxen().write_value(1);
331
332        self.rx_grant = Some(rx_buf);
333    }
334
335    // Check the received packet.
336    #[inline]
337    pub(crate) fn check_packet(
338        &mut self,
339        consumer: &mut FramedConsumer<OUT>,
340    ) -> Result<RxPayloadState, Error> {
341        // If the user didn't provide a packet to send, we will fall back to this empty ack packet
342        static FALLBACK_ACK: [u8; 2] = [0, 0];
343
344        if self.radio.crcstatus().read().crcstatus() == Crcstatus::CRCERROR {
345            // Bad CRC, clear events and restart RX.
346            self.stop(false);
347            self.radio.shorts().modify(|w| w.set_disabled_txen(true));
348            self.radio.intenset().write(|w| w.set_disabled(true));
349            // "Preceding reads and writes cannot be moved past subsequent writes."
350            compiler_fence(Ordering::Release);
351
352            // NOTE(unsafe) 1 is a valid value to write to this register
353            self.radio.tasks_rxen().write_value(1);
354            return Ok(RxPayloadState::BadCRC);
355        }
356        // "Subsequent reads and writes cannot be moved ahead of preceding reads."
357        compiler_fence(Ordering::Acquire);
358        self.clear_ready_event();
359
360        let pipe = self.radio.rxmatch().read().rxmatch() as usize;
361        let crc = self.radio.rxcrc().read().rxcrc() as u16;
362        let rx_grant = self.rx_grant.as_ref().ok_or(Error::InternalError)?;
363        let (pid, ack) = (rx_grant.pid(), !rx_grant.no_ack());
364        let repeated = (self.last_crc[pipe] == crc) && (self.last_pid[pipe] == pid);
365
366        if ack {
367            // This is a bit risky, the radio is turning around since before the beginning of the
368            // method, we should have enough time if the Radio interrupt is top priority, otherwise
369            // we might have a problem, should we disable the `disabled_txen` shorcut ? We might
370            // have problems to acknowledge consistently if we do so.
371
372            // NOTE(unsafe) Any byte value is valid for this register.
373            self.radio.txaddress().write(|w| {
374                w.set_txaddress(pipe as u8);
375            });
376
377            let mut dma_pointer = FALLBACK_ACK.as_ptr() as u32;
378
379            if repeated {
380                if pipe == self.cached_pipe as usize {
381                    if let Some(grant) = &self.tx_grant {
382                        dma_pointer = grant.dma_pointer() as u32;
383                    }
384                }
385            } else {
386                // Our last ack packet was received, release it and ask for a new one
387                if let Some(grant) = self.tx_grant.take() {
388                    grant.release();
389                }
390
391                // "No re-ordering of reads and writes across this point is allowed."
392                compiler_fence(Ordering::SeqCst);
393
394                if let Ok(payload) = consumer.read().map(PayloadR::new) {
395                    dma_pointer = payload.dma_pointer() as u32;
396                    self.tx_grant = Some(payload);
397                }
398            }
399
400            // "Preceding reads and writes cannot be moved past subsequent writes."
401            compiler_fence(Ordering::Release);
402
403            // NOTE(unsafe) Any u32 is valid to write to this register.
404            self.radio.packetptr().write_value(dma_pointer);
405
406            // Check if the ramp-up was faster than us :/
407            debug_assert!(!self.check_ready_event(), "Missed window (PRX)");
408
409            // Disables the shortcut for `txen`, we already hit that.
410            // Enables the shortcut for `rxen` to turn around to rx after the end of the ack
411            // transmission.
412            self.radio.shorts().modify(|w| {
413                w.set_disabled_txen(false);
414                w.set_disabled_rxen(true);
415            });
416        } else {
417            // Stops the radio before transmission begins
418            self.stop(false);
419        }
420
421        if repeated {
422            if ack {
423                return Ok(RxPayloadState::RepeatedAck);
424            } else {
425                return Ok(RxPayloadState::RepeatedNoAck);
426            }
427        }
428        self.last_crc[pipe] = crc;
429        self.last_pid[pipe] = pid;
430        self.cached_pipe = pipe as u8;
431
432        let mut grant = self.rx_grant.take().ok_or(Error::InternalError)?;
433        let rssi = self.radio.rssisample().read().rssisample();
434        grant.set_rssi(rssi);
435        grant.set_pipe(pipe as u8);
436        grant.commit_all();
437        if ack {
438            Ok(RxPayloadState::Ack)
439        } else {
440            Ok(RxPayloadState::NoAck)
441        }
442    }
443
444    // Must be called after the end of the ack transmission.
445    // `rx_buf` must only be `None` if a previous call to `check_packet` returned `RepeatedAck`
446    pub(crate) fn complete_rx_ack(
447        &mut self,
448        mut rx_buf: Option<PayloadW<IN>>,
449    ) -> Result<(), Error> {
450        let dma_pointer = if let Some(mut grant) = rx_buf.take() {
451            let pointer = grant.dma_pointer() as u32;
452            self.rx_grant = Some(grant);
453            pointer
454        } else {
455            self.rx_grant
456                .as_mut()
457                .ok_or(Error::InternalError)?
458                .dma_pointer() as u32
459        };
460
461        // "No re-ordering of reads and writes across this point is allowed."
462        compiler_fence(Ordering::SeqCst);
463
464        self.radio.packetptr().write_value(dma_pointer);
465
466        // We don't release the `tx_grant` here, because we don't know if it was really received.
467
468        // Disables the shortcut for `rxen`, we already hit that.
469        // Enables the shortcut for `txen` to turn around to tx after receiving a packet
470        // transmission.
471        self.radio.shorts().modify(|w| {
472            w.set_disabled_rxen(false);
473            w.set_disabled_txen(true);
474        });
475        Ok(())
476    }
477
478    // Must be called after `check_packet` returns `RxPayloadState::NoAck`.
479    // `rx_buf` must only be `None` if a previous call to `check_packet` returned `RepeatedNoAck`
480    pub(crate) fn complete_rx_no_ack(&mut self, mut rx_buf: Option<PayloadW<IN>>) {
481        // Since we're in the no-ack branch, the previous value of `packetptr` still is the last
482        // `rx_grant` that we still hold if `check_packet` returned `RepeatedNoAck`. Therefore, we
483        // only need to update if `rx_buf` is `Some`.
484        if let Some(mut grant) = rx_buf.take() {
485            self.radio
486                .packetptr()
487                .write_value(grant.dma_pointer() as u32);
488            self.rx_grant = Some(grant);
489        }
490
491        self.radio.shorts().modify(|w| w.set_disabled_txen(true));
492        self.radio.intenset().write(|w| w.set_disabled(true));
493        // "Preceding reads and writes cannot be moved past subsequent writes."
494        compiler_fence(Ordering::Release);
495
496        self.radio.tasks_rxen().write_value(1);
497    }
498}
499
500mod sealed {
501    pub trait Sealed {}
502}
503
504/// Trait implemented for the nRF timer peripherals.
505pub trait EsbTimer: sealed::Sealed {
506    /// Initialize the timer with a 1MHz rate.
507    fn init(&mut self);
508
509    /// Configures the timer's interrupt used for the retransmit, to fire after a given time in
510    /// micro seconds.
511    fn set_interrupt_retransmit(&mut self, micros: u16);
512
513    /// Acknowledges the retransmit interrupt.
514    fn clear_interrupt_retransmit();
515
516    /// Returns whether the retransmit interrupt is currently pending, atomically.
517    fn is_retransmit_pending() -> bool;
518
519    /// Configures the timer's interrupt used for the acknowledge timeout, to fire after a given
520    /// time in micro seconds.
521    fn set_interrupt_ack(&mut self, micros: u16);
522
523    /// Acknowledges the ack timeout interrupt.
524    fn clear_interrupt_ack();
525
526    /// Returns whether the ack timeout interrupt is currently pending.
527    fn is_ack_pending() -> bool;
528
529    /// Stops the timer, atomically.
530    fn stop();
531}
532
533use pac::timer::Timer;
534
535pub trait PtrTimer {
536    const ME: Timer;
537    fn timer(&mut self) -> &mut Timer;
538    /// # Safety
539    ///
540    /// You only take once
541    unsafe fn take() -> Self;
542}
543
544pub struct Timer0 {
545    timer: Timer,
546}
547pub struct Timer1 {
548    timer: Timer,
549}
550pub struct Timer2 {
551    timer: Timer,
552}
553
554impl PtrTimer for Timer0 {
555    const ME: Timer = TIMER0;
556
557    fn timer(&mut self) -> &mut Timer {
558        &mut self.timer
559    }
560
561    unsafe fn take() -> Self {
562        Self { timer: Self::ME }
563    }
564}
565
566impl PtrTimer for Timer1 {
567    const ME: Timer = TIMER1;
568
569    fn timer(&mut self) -> &mut Timer {
570        &mut self.timer
571    }
572
573    unsafe fn take() -> Self {
574        Self { timer: Self::ME }
575    }
576}
577
578impl PtrTimer for Timer2 {
579    const ME: Timer = TIMER2;
580
581    fn timer(&mut self) -> &mut Timer {
582        &mut self.timer
583    }
584
585    unsafe fn take() -> Self {
586        Self { timer: Self::ME }
587    }
588}
589
590impl<T: PtrTimer + sealed::Sealed> EsbTimer for T {
591    #[inline]
592    fn init(&mut self) {
593        // Disables all interrupts, Nordic's code writes to all bits, seems to be okay
594        self.timer().intenclr().write_value(TimerInt(0xFFFF_FFFF));
595        Self::stop();
596        self.timer()
597            .bitmode()
598            .write(|w| w.set_bitmode(Bitmode::_32BIT));
599        // 2^4 = 16
600        // 16 MHz / 16 = 1 MHz = µs resolution
601        self.timer().prescaler().write(|w| w.set_prescaler(4));
602    }
603
604    // CC[0] will be used for the retransmit timeout and CC[1] will be used for the ack
605    // timeout
606
607    #[inline]
608    fn set_interrupt_retransmit(&mut self, micros: u16) {
609        self.timer().cc(0).write_value(micros as u32);
610        self.timer().events_compare(0).write_value(0);
611        self.timer().intenset().write(|w| w.set_compare(0, true));
612
613        // Clears and starts the counter
614        self.timer().tasks_clear().write_value(1);
615        self.timer().tasks_start().write_value(1);
616    }
617
618    #[inline]
619    fn clear_interrupt_retransmit() {
620        // NOTE(unsafe) This will be used for atomic operations, only
621        let timer = Self::ME;
622
623        timer.intenclr().write(|w| w.set_compare(0, false));
624        timer.events_compare(0).write_value(0);
625
626        Self::stop();
627    }
628
629    #[inline]
630    fn is_retransmit_pending() -> bool {
631        // NOTE(unsafe) This will be used for atomic operations, only
632        let timer = Self::ME;
633
634        timer.events_compare(0).read() == 1u32
635    }
636
637    fn set_interrupt_ack(&mut self, micros: u16) {
638        // get current counter
639        self.timer().tasks_capture(1).write_value(1);
640        let current_counter = self.timer().cc(1).read();
641
642        self.timer()
643            .cc(1)
644            .write_value(current_counter + micros as u32);
645        self.timer().events_compare(1).write_value(0);
646        self.timer().intenset().write(|w| w.set_compare(1, true));
647    }
648
649    #[inline]
650    fn clear_interrupt_ack() {
651        // NOTE(unsafe) This will be used for atomic operations, only
652        let timer = Self::ME;
653
654        timer.intenclr().write(|w| w.set_compare(1, false));
655        timer.events_compare(1).write_value(0);
656    }
657
658    #[inline]
659    fn is_ack_pending() -> bool {
660        // NOTE(unsafe) This will be used for atomic operations, only
661        let timer = Self::ME;
662
663        timer.events_compare(1).read() == 1u32
664    }
665
666    #[inline]
667    fn stop() {
668        // NOTE(unsafe) This will be used for atomic operations, only
669        let timer = Self::ME;
670
671        timer.tasks_stop().write_value(1);
672    }
673}
674
675impl sealed::Sealed for Timer0 {}
676impl sealed::Sealed for Timer1 {}
677impl sealed::Sealed for Timer2 {}
678
679// #[cfg(not(feature = "51"))]
680// impl_timer!(pac::TIMER0, pac::TIMER1, pac::TIMER2);
681
682// #[cfg(feature = "51")]
683// impl_timer!(pac::TIMER0);