dw3000_ng/hl/
receiving.rs

1#![allow(unused_imports)]
2
3use core::convert::TryInto;
4
5use byte::BytesExt as _;
6use fixed::traits::LossyInto;
7#[cfg(feature = "rssi")]
8use num_traits::Float;
9
10#[cfg(feature = "defmt")]
11use defmt::Format;
12
13use super::{AutoDoubleBufferReceiving, ReceiveTime, Receiving};
14use crate::{
15    configs::{BitRate, PulseRepetitionFrequency, SfdSequence},
16    maybe_async_attr, spi_type,
17    time::Instant,
18    Config, Error, FastCommand, Ready, DW3000,
19};
20
21use smoltcp::wire::Ieee802154Frame;
22
23/// An incoming message
24#[derive(Debug)]
25#[cfg_attr(feature = "defmt", derive(Format))]
26pub struct Message<'l> {
27    /// The time the message was received
28    ///
29    /// This time is based on the local system time, as defined in the SYS_TIME
30    /// register.
31    pub rx_time: Instant,
32
33    /// quality of the message received
34    pub rx_quality: RxQuality,
35
36    /// The MAC frame
37    pub frame: Ieee802154Frame<&'l [u8]>,
38}
39
40/// A struct representing the quality of the received message.
41#[cfg_attr(feature = "defmt", derive(Format))]
42#[derive(Debug, serde::Serialize, serde::Deserialize)]
43pub struct RxQuality {
44    /// The confidence that there was Line Of Sight between the sender and the
45    /// receiver.
46    ///
47    /// - 0 means it's very unlikely there was LOS.
48    /// - 1 means it's very likely there was LOS.
49    ///
50    /// The number doesn't give a guarantee, but an indication.
51    /// It is based on the
52    /// APS006_Part-3-DW3000-Diagnostics-for-NLOS-Channels-v1.1 document.
53    pub los_confidence_level: f32,
54    /// The radio signal strength indicator in dBm.
55    ///
56    /// The value is an estimation that is quite accurate up to -85 dBm.
57    /// Above -85 dBm, the estimation underestimates the actual value.
58    pub rssi: f32,
59}
60
61impl<SPI, RECEIVING> DW3000<SPI, RECEIVING>
62where
63    SPI: spi_type::spi::SpiDevice<u8>,
64    RECEIVING: Receiving,
65{
66    /// Returns the RX state of the DW3000
67    #[maybe_async_attr]
68    pub async fn rx_state(&mut self) -> Result<u8, Error<SPI>> {
69        Ok(self.ll.sys_state().read().await?.rx_state())
70    }
71
72    #[maybe_async_attr]
73    pub(super) async fn start_receiving(
74        &mut self,
75        recv_time: ReceiveTime,
76        config: Config,
77    ) -> Result<(), Error<SPI>> {
78        if config.frame_filtering {
79            self.ll
80                .sys_cfg()
81                .modify(
82                    |_, w| w.ffen(0b1), // enable frame filtering
83                )
84                .await?;
85            self.ll
86                .ff_cfg()
87                .modify(
88                    |_, w| {
89                        w.ffab(0b1) // receive beacon frames
90                            .ffad(0b1) // receive data frames
91                            .ffaa(0b1) // receive acknowledgement frames
92                            .ffam(0b1)
93                    }, // receive MAC command frames
94                )
95                .await?;
96        } else {
97            self.ll.sys_cfg().modify(|_, w| w.ffen(0b0)).await?; // disable frame filtering
98        }
99
100        match recv_time {
101            ReceiveTime::Delayed(time) => {
102                // Panic if the time is not rounded to top 31 bits
103                //
104                // NOTE: DW3000's DX_TIME register is 32 bits wide, but only the top 31 bits are used.
105                // The last bit is ignored per the user manual!!!
106                if time.value() % (1 << 9) != 0 {
107                    panic!("Time must be rounded to top 31 bits!");
108                }
109
110                // Put the time into the delay register
111                // By setting this register, the chip knows to delay before transmitting
112                self.ll
113                    .dx_time()
114                    .modify(|_, w| // 32-bits value of the most significant bits
115                    w.value( (time.value() >> 8) as u32 ))
116                    .await?;
117                self.fast_cmd(FastCommand::CMD_DRX).await?;
118            }
119            ReceiveTime::Now => self.fast_cmd(FastCommand::CMD_RX).await?,
120        }
121
122        Ok(())
123    }
124
125    /// Wait for receive operation to finish
126    ///
127    /// This method returns an `nb::Result` to indicate whether the transmission
128    /// has finished, or whether it is still ongoing. You can use this to busily
129    /// wait for the transmission to finish, for example using `nb`'s `block!`
130    /// macro, or you can use it in tandem with [`DW3000::enable_rx_interrupts`]
131    /// and the DW3000 IRQ output to wait in a more energy-efficient manner.
132    ///
133    /// Handling the DW3000's IRQ output line is out of the scope of this
134    /// driver, but please note that if you're using the DWM1001 module or
135    /// DWM1001-Dev board, that the `dwm1001` crate has explicit support for
136    /// this.
137    #[maybe_async_attr]
138    pub async fn r_wait<'b>(
139        &mut self,
140        buffer: &'b mut [u8],
141    ) -> nb::Result<Message<'b>, Error<SPI>> {
142        // ATTENTION:
143        // If you're changing anything about which SYS_STATUS flags are being
144        // checked in this method, also make sure to update `enable_interrupts`.
145        let sys_status = self
146            .ll()
147            .sys_status()
148            .read()
149            .await
150            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
151
152        // Is a frame ready?
153        if sys_status.rxfcg() == 0b0 {
154            // No frame ready. Check for errors.
155            if sys_status.rxfce() == 0b1 {
156                return Err(nb::Error::Other(Error::Fcs));
157            }
158            if sys_status.rxphe() == 0b1 {
159                return Err(nb::Error::Other(Error::Phy));
160            }
161            if sys_status.rxfsl() == 0b1 {
162                return Err(nb::Error::Other(Error::ReedSolomon));
163            }
164            if sys_status.rxsto() == 0b1 {
165                return Err(nb::Error::Other(Error::SfdTimeout));
166            }
167            if sys_status.arfe() == 0b1 {
168                return Err(nb::Error::Other(Error::FrameFilteringRejection));
169            }
170            if sys_status.rxfto() == 0b1 {
171                return Err(nb::Error::Other(Error::FrameWaitTimeout));
172            }
173            if sys_status.rxovrr() == 0b1 {
174                return Err(nb::Error::Other(Error::Overrun));
175            }
176            if sys_status.rxpto() == 0b1 {
177                return Err(nb::Error::Other(Error::PreambleDetectionTimeout));
178            }
179
180            // Some error flags that sound like valid errors aren't checked here,
181            // because experience has shown that they seem to occur spuriously
182            // without preventing a good frame from being received. Those are:
183            // - LDEERR: Leading Edge Detection Processing Error
184            // - RXPREJ: Receiver Preamble Rejection
185
186            // No errors detected. That must mean the frame is just not ready yet.
187            return Err(nb::Error::WouldBlock);
188        }
189
190        // Frame is ready. Continue.
191
192        // Wait until LDE processing is done. Before this is finished, the RX
193        // time stamp is not available.
194        let rx_time = self
195            .ll()
196            .rx_time()
197            .read()
198            .await
199            .map_err(|error| nb::Error::Other(Error::Spi(error)))?
200            .rx_stamp();
201
202        // `rx_time` comes directly from the register, which should always
203        // contain a 40-bit timestamp. Unless the hardware or its documentation
204        // are buggy, the following should never panic.
205        let rx_time = Instant::new(rx_time).unwrap();
206
207        let rssi = self.get_first_path_signal_power().await?;
208        let rx_quality = RxQuality {
209            los_confidence_level: 1.0, // TODO
210            rssi,
211        };
212
213        // Reset status bits. This is not strictly necessary, but it helps, if
214        // you have to inspect SYS_STATUS manually during debugging.
215        // NOTE: The `SYS_STATUS` register is write-to-clear
216        self.ll()
217            .sys_status()
218            .write(|w| {
219                w.rxprd(0b1) // Receiver Preamble Detected
220                    .rxsfdd(0b1) // Receiver SFD Detected
221                    .ciadone(0b1) // LDE Processing Done
222                    .rxphd(0b1) // Receiver PHY Header Detected
223                    .rxphe(0b1) // Receiver PHY Header Error
224                    .rxfr(0b1) // Receiver Data Frame Ready
225                    .rxfcg(0b1) // Receiver FCS Good
226                    .rxfce(0b1) // Receiver FCS Error
227                    .rxfsl(0b1) // Receiver Reed Solomon Frame Sync Loss
228                    .rxfto(0b1) // Receiver Frame Wait Timeout
229                    .ciaerr(0b1) // Leading Edge Detection Processing Error
230                    .rxovrr(0b1) // Receiver Overrun
231                    .rxpto(0b1) // Preamble Detection Timeout
232                    .rxsto(0b1) // Receiver SFD Timeout
233                    .rxprej(0b1) // Receiver Preamble Rejection
234            })
235            .await
236            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
237
238        // Read received frame
239        let rx_finfo = self
240            .ll()
241            .rx_finfo()
242            .read()
243            .await
244            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
245        let rx_buffer = self
246            .ll()
247            .rx_buffer_0()
248            .read()
249            .await
250            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
251
252        let len = rx_finfo.rxflen() as usize;
253
254        if buffer.len() < len {
255            return Err(nb::Error::Other(Error::BufferTooSmall {
256                required_len: len,
257            }));
258        }
259
260        buffer[..len].copy_from_slice(&rx_buffer.data()[..len]);
261
262        let buffer = &buffer[..len];
263
264        self.state.mark_finished();
265
266        let frame = Ieee802154Frame::new_checked(buffer).map_err(|_| {
267            nb::Error::Other(Error::Frame(byte::Error::BadInput {
268                err: "Cannot decode 802.15.4 frame",
269            }))
270        })?;
271
272        Ok(Message {
273            rx_time,
274            rx_quality,
275            frame,
276        })
277    }
278
279    /// Wait for receive operation to finish
280    ///
281    /// This method returns an `nb::Result` to indicate whether the transmission
282    /// has finished, or whether it is still ongoing. You can use this to busily
283    /// wait for the transmission to finish, for example using `nb`'s `block!`
284    /// macro, or you can use it in tandem with [`DW3000::enable_rx_interrupts`]
285    /// and the DW3000 IRQ output to wait in a more energy-efficient manner.
286    ///
287    /// Handling the DW3000's IRQ output line is out of the scope of this
288    /// driver, but please note that if you're using the DWM1001 module or
289    /// DWM1001-Dev board, that the `dwm1001` crate has explicit support for
290    /// this.
291    #[maybe_async_attr]
292    pub async fn r_wait_buf(
293        &mut self,
294        buffer: &mut [u8],
295    ) -> nb::Result<(usize, Instant, RxQuality), Error<SPI>> {
296        // ATTENTION:
297        // If you're changing anything about which SYS_STATUS flags are being
298        // checked in this method, also make sure to update `enable_interrupts`.
299        let sys_status = self
300            .ll()
301            .sys_status()
302            .read()
303            .await
304            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
305
306        // Is a frame ready?
307        if sys_status.rxfcg() == 0b0 {
308            // No frame ready. Check for errors.
309            if sys_status.rxfce() == 0b1 {
310                return Err(nb::Error::Other(Error::Fcs));
311            }
312            if sys_status.rxphe() == 0b1 {
313                return Err(nb::Error::Other(Error::Phy));
314            }
315            if sys_status.rxfsl() == 0b1 {
316                return Err(nb::Error::Other(Error::ReedSolomon));
317            }
318            if sys_status.rxsto() == 0b1 {
319                return Err(nb::Error::Other(Error::SfdTimeout));
320            }
321            if sys_status.arfe() == 0b1 {
322                return Err(nb::Error::Other(Error::FrameFilteringRejection));
323            }
324            if sys_status.rxfto() == 0b1 {
325                return Err(nb::Error::Other(Error::FrameWaitTimeout));
326            }
327            if sys_status.rxovrr() == 0b1 {
328                return Err(nb::Error::Other(Error::Overrun));
329            }
330            if sys_status.rxpto() == 0b1 {
331                return Err(nb::Error::Other(Error::PreambleDetectionTimeout));
332            }
333
334            // Some error flags that sound like valid errors aren't checked here,
335            // because experience has shown that they seem to occur spuriously
336            // without preventing a good frame from being received. Those are:
337            // - LDEERR: Leading Edge Detection Processing Error
338            // - RXPREJ: Receiver Preamble Rejection
339
340            // No errors detected. That must mean the frame is just not ready yet.
341            return Err(nb::Error::WouldBlock);
342        }
343
344        // Frame is ready. Continue.
345
346        // Wait until LDE processing is done. Before this is finished, the RX
347        // time stamp is not available.
348        let rx_time = self
349            .ll()
350            .rx_time()
351            .read()
352            .await
353            .map_err(|error| nb::Error::Other(Error::Spi(error)))?
354            .rx_stamp();
355
356        let rssi = self.get_first_path_signal_power().await?;
357        let rx_quality = RxQuality {
358            los_confidence_level: 1.0, // TODO
359            rssi,
360        };
361
362        // `rx_time` comes directly from the register, which should always
363        // contain a 40-bit timestamp. Unless the hardware or its documentation
364        // are buggy, the following should never panic.
365        let rx_time = Instant::new(rx_time).unwrap();
366
367        //  Reset status bits. This is not strictly necessary, but it helps, if
368        // you have to inspect SYS_STATUS manually during debugging.
369        self.ll()
370            .sys_status()
371            .write(|w| {
372                w.rxprd(0b1) // Receiver Preamble Detected
373                    .rxsfdd(0b1) // Receiver SFD Detected
374                    .ciadone(0b1) // LDE Processing Done
375                    .rxphd(0b1) // Receiver PHY Header Detected
376                    .rxphe(0b1) // Receiver PHY Header Error
377                    .rxfr(0b1) // Receiver Data Frame Ready
378                    .rxfcg(0b1) // Receiver FCS Good
379                    .rxfce(0b1) // Receiver FCS Error
380                    .rxfsl(0b1) // Receiver Reed Solomon Frame Sync Loss
381                    .rxfto(0b1) // Receiver Frame Wait Timeout
382                    .ciaerr(0b1) // Leading Edge Detection Processing Error
383                    .rxovrr(0b1) // Receiver Overrun
384                    .rxpto(0b1) // Preamble Detection Timeout
385                    .rxsto(0b1) // Receiver SFD Timeout
386                    .rxprej(0b1) // Receiver Preamble Rejection
387            })
388            .await
389            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
390
391        // Read received frame
392        let rx_finfo = self
393            .ll()
394            .rx_finfo()
395            .read()
396            .await
397            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
398        let rx_buffer = self
399            .ll()
400            .rx_buffer_0()
401            .read()
402            .await
403            .map_err(|error| nb::Error::Other(Error::Spi(error)))?;
404
405        let len = rx_finfo.rxflen() as usize;
406
407        if buffer.len() < len {
408            return Err(nb::Error::Other(Error::BufferTooSmall {
409                required_len: len,
410            }));
411        }
412
413        buffer[..len].copy_from_slice(&rx_buffer.data()[..len]);
414
415        self.state.mark_finished();
416
417        Ok((len, rx_time, rx_quality))
418    }
419
420    /// DW3000 User Manual 4.7.1
421    /// returns dBm
422    #[cfg(feature = "rssi")]
423    #[maybe_async_attr]
424    async fn get_first_path_signal_power(&mut self) -> Result<f32, Error<SPI>> {
425        let prf = self.state.get_rx_config().pulse_repetition_frequency;
426        let ll = self.ll();
427
428        #[derive(Copy, Clone)]
429        enum Method {
430            Ipatov,
431            Sts,
432        }
433
434        // prefer ipatov over sts
435        let method: Method = if ll.sys_cfg().read().await?.cia_ipatov() != 0 {
436            Method::Ipatov
437        } else if ll.sys_cfg().read().await?.cia_sts() != 0 {
438            Method::Sts
439        } else {
440            Err(Error::InvalidConfiguration)?
441        };
442
443        let a: f32 = match (prf, method) {
444            (PulseRepetitionFrequency::Mhz16, _) => 113.8,
445            (PulseRepetitionFrequency::Mhz64, Method::Ipatov) => 121.7,
446            (PulseRepetitionFrequency::Mhz64, Method::Sts) => 120.7,
447        };
448
449        let f1;
450        let f2;
451        let f3;
452        let n;
453
454        match method {
455            Method::Ipatov => {
456                f1 = ll.ip_diag_2().read().await?.ip_fp1m();
457                f2 = ll.ip_diag_3().read().await?.ip_fp2m();
458                f3 = ll.ip_diag_4().read().await?.ip_fp3m();
459                n = ll.ip_diag_12().read().await?.ip_nacc();
460            }
461            Method::Sts => {
462                f1 = ll.sts_diag_2().read().await?.cp0_fp1m();
463                f2 = ll.sts_diag_3().read().await?.cp0_fp2m();
464                f3 = ll.sts_diag_4().read().await?.cp0_fp3m();
465                n = ll.sts_diag_12().read().await?.cp0_nacc();
466            }
467        }
468
469        let d6: u32 = if ll.dgc_cfg().read().await?.rx_tune_en() != 0 {
470            let d: u32 = ll.dgc_dbg().read().await?.dgc_decision().into();
471            6u32 * d
472        } else {
473            0u32
474        };
475
476        Ok(10.0
477            * (((f1 * f1 + f2 * f2 + f3 * f3) as f32) / ((u32::from(n) * u32::from(n)) as f32))
478                .log10()
479            + (d6 as f32)
480            - a)
481    }
482
483    #[cfg(not(feature = "rssi"))]
484    #[maybe_async_attr]
485    async fn get_first_path_signal_power(&mut self) -> Result<f32, Error<SPI>> {
486        Ok(0.0)
487    }
488
489    #[allow(clippy::type_complexity)]
490    /// Finishes receiving and returns to the `Ready` state
491    ///
492    /// If the receive operation has finished, as indicated by `wait`, this is a
493    /// no-op. If the receive operation is still ongoing, it will be aborted.
494    #[maybe_async_attr]
495    pub async fn finish_receiving(mut self) -> Result<DW3000<SPI, Ready>, (Self, Error<SPI>)> {
496        // TO DO : if we are not in state 3 (IDLE), we need to have a reset of the module (with a new initialisation)
497        // BECAUSE : using force_idle (fast command 0) is not puting the pll back to stable !!!
498
499        if !self.state.is_finished() {
500            match self.force_idle().await {
501                Ok(()) => (),
502                Err(error) => return Err((self, error)),
503            }
504        }
505
506        Ok(DW3000 {
507            ll: self.ll,
508            seq: self.seq,
509            state: Ready,
510        })
511    }
512}