embassy_nrf/
nfct.rs

1//! NFC tag emulator driver.
2//!
3//! This driver implements support for emulating an ISO14443-3 card. Anticollision and selection
4//! are handled automatically in hardware, then the driver lets you receive and reply to
5//! raw ISO14443-3 frames in software.
6//!
7//! Higher layers such as ISO14443-4 aka ISO-DEP and ISO7816 must be handled on top
8//! in software.
9
10#![macro_use]
11
12use core::future::poll_fn;
13use core::sync::atomic::{compiler_fence, Ordering};
14use core::task::Poll;
15
16use embassy_sync::waitqueue::AtomicWaker;
17pub use vals::{Bitframesdd as SddPat, Discardmode as DiscardMode};
18
19use crate::interrupt::InterruptExt;
20use crate::pac::nfct::vals;
21use crate::pac::NFCT;
22use crate::peripherals::NFCT;
23use crate::util::slice_in_ram;
24use crate::{interrupt, pac, Peri};
25
26/// NFCID1 (aka UID) of different sizes.
27#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
28pub enum NfcId {
29    /// 4-byte UID.
30    SingleSize([u8; 4]),
31    /// 7-byte UID.
32    DoubleSize([u8; 7]),
33    /// 10-byte UID.
34    TripleSize([u8; 10]),
35}
36
37/// The protocol field to be sent in the `SEL_RES` response byte (b6-b7).
38#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
39pub enum SelResProtocol {
40    /// Configured for Type 2 Tag platform.
41    #[default]
42    Type2 = 0,
43    /// Configured for Type 4A Tag platform, compliant with ISO/IEC_14443.
44    Type4A = 1,
45    /// Configured for the NFC-DEP Protocol.
46    NfcDep = 2,
47    /// Configured for the NFC-DEP Protocol and Type 4A Tag platform.
48    NfcDepAndType4A = 3,
49}
50
51/// Config for the `NFCT` peripheral driver.
52#[derive(Clone)]
53pub struct Config {
54    /// NFCID1 to use during autocollision.
55    pub nfcid1: NfcId,
56    /// SDD pattern to be sent in `SENS_RES`.
57    pub sdd_pat: SddPat,
58    /// Platform config to be sent in `SEL_RES`.
59    pub plat_conf: u8,
60    /// Protocol to be sent in the `SEL_RES` response.
61    pub protocol: SelResProtocol,
62}
63
64/// Interrupt handler.
65pub struct InterruptHandler {
66    _private: (),
67}
68
69impl interrupt::typelevel::Handler<interrupt::typelevel::NFCT> for InterruptHandler {
70    unsafe fn on_interrupt() {
71        trace!("irq");
72        pac::NFCT.inten().write(|w| w.0 = 0);
73        WAKER.wake();
74    }
75}
76
77static WAKER: AtomicWaker = AtomicWaker::new();
78
79/// NFC error.
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82#[non_exhaustive]
83pub enum Error {
84    /// Rx Error received while waiting for frame
85    RxError,
86    /// Rx buffer was overrun, increase your buffer size to resolve this
87    RxOverrun,
88    /// Lost field.
89    Deactivated,
90    /// Collision
91    Collision,
92    /// The buffer is not in data RAM. It's most likely in flash, and nRF's DMA cannot access flash.
93    BufferNotInRAM,
94}
95
96/// NFC tag emulator driver.
97pub struct NfcT<'d> {
98    _p: Peri<'d, NFCT>,
99    rx_buf: [u8; 256],
100    tx_buf: [u8; 256],
101}
102
103impl<'d> NfcT<'d> {
104    /// Create an Nfc Tag driver
105    pub fn new(
106        _p: Peri<'d, NFCT>,
107        _irq: impl interrupt::typelevel::Binding<interrupt::typelevel::NFCT, InterruptHandler> + 'd,
108        config: &Config,
109    ) -> Self {
110        let r = pac::NFCT;
111
112        unsafe {
113            let reset = (r.as_ptr() as *mut u32).add(0xFFC / 4);
114            reset.write_volatile(0);
115            reset.read_volatile();
116            reset.write_volatile(1);
117        }
118
119        let nfcid_size = match &config.nfcid1 {
120            NfcId::SingleSize(bytes) => {
121                r.nfcid1_last().write(|w| w.0 = u32::from_be_bytes(*bytes));
122
123                vals::Nfcidsize::NFCID1SINGLE
124            }
125            NfcId::DoubleSize(bytes) => {
126                let (bytes, chunk) = bytes.split_last_chunk::<4>().unwrap();
127                r.nfcid1_last().write(|w| w.0 = u32::from_be_bytes(*chunk));
128
129                let mut chunk = [0u8; 4];
130                chunk[1..].copy_from_slice(bytes);
131                r.nfcid1_2nd_last().write(|w| w.0 = u32::from_be_bytes(chunk));
132
133                vals::Nfcidsize::NFCID1DOUBLE
134            }
135            NfcId::TripleSize(bytes) => {
136                let (bytes, chunk) = bytes.split_last_chunk::<4>().unwrap();
137                r.nfcid1_last().write(|w| w.0 = u32::from_be_bytes(*chunk));
138
139                let (bytes, chunk2) = bytes.split_last_chunk::<3>().unwrap();
140                let mut chunk = [0u8; 4];
141                chunk[1..].copy_from_slice(chunk2);
142                r.nfcid1_2nd_last().write(|w| w.0 = u32::from_be_bytes(chunk));
143
144                let mut chunk = [0u8; 4];
145                chunk[1..].copy_from_slice(bytes);
146                r.nfcid1_3rd_last().write(|w| w.0 = u32::from_be_bytes(chunk));
147
148                vals::Nfcidsize::NFCID1TRIPLE
149            }
150        };
151
152        r.sensres().write(|w| {
153            w.set_nfcidsize(nfcid_size);
154            w.set_bitframesdd(config.sdd_pat);
155            w.set_platfconfig(config.plat_conf & 0xF);
156        });
157
158        r.selres().write(|w| {
159            w.set_protocol(config.protocol as u8);
160        });
161
162        // errata
163        #[cfg(feature = "nrf52832")]
164        unsafe {
165            // Errata 57 nrf52832 only
166            //(0x40005610 as *mut u32).write_volatile(0x00000005);
167            //(0x40005688 as *mut u32).write_volatile(0x00000001);
168            //(0x40005618 as *mut u32).write_volatile(0x00000000);
169            //(0x40005614 as *mut u32).write_volatile(0x0000003F);
170
171            // Errata 98
172            (0x4000568C as *mut u32).write_volatile(0x00038148);
173        }
174
175        r.inten().write(|w| w.0 = 0);
176
177        interrupt::NFCT.unpend();
178        unsafe { interrupt::NFCT.enable() };
179
180        // clear all shorts
181        r.shorts().write(|_| {});
182
183        let res = Self {
184            _p,
185            tx_buf: [0u8; 256],
186            rx_buf: [0u8; 256],
187        };
188
189        assert!(slice_in_ram(&res.tx_buf), "TX Buf not in ram");
190        assert!(slice_in_ram(&res.rx_buf), "RX Buf not in ram");
191
192        res
193    }
194
195    /// Wait for field on and select.
196    ///
197    /// This waits for the field to become on, and then for a reader to select us. The ISO14443-3
198    /// sense, anticollision and select procedure is handled entirely in hardware.
199    ///
200    /// When this returns, we have successfully been selected as a card. You must then
201    /// loop calling [`receive`](Self::receive) and responding with [`transmit`](Self::transmit).
202    pub async fn activate(&mut self) {
203        let r = pac::NFCT;
204        loop {
205            r.events_fieldlost().write_value(0);
206            r.events_fielddetected().write_value(0);
207            r.tasks_sense().write_value(1);
208
209            // enable autocoll
210            #[cfg(not(feature = "nrf52832"))]
211            r.autocolresconfig().write(|w| w.0 = 0b10);
212
213            // framedelaymax=4096 is needed to make it work with phones from
214            // a certain company named after some fruit.
215            r.framedelaymin().write(|w| w.set_framedelaymin(1152));
216            r.framedelaymax().write(|w| w.set_framedelaymax(4096));
217            r.framedelaymode().write(|w| {
218                w.set_framedelaymode(vals::Framedelaymode::WINDOW_GRID);
219            });
220
221            info!("waiting for field");
222            poll_fn(|cx| {
223                WAKER.register(cx.waker());
224
225                if r.events_fielddetected().read() != 0 {
226                    r.events_fielddetected().write_value(0);
227                    return Poll::Ready(());
228                }
229
230                r.inten().write(|w| {
231                    w.set_fielddetected(true);
232                });
233                Poll::Pending
234            })
235            .await;
236
237            #[cfg(feature = "time")]
238            embassy_time::Timer::after_millis(1).await; // workaround errata 190
239
240            r.events_selected().write_value(0);
241            r.tasks_activate().write_value(1);
242
243            trace!("Waiting to be selected");
244            poll_fn(|cx| {
245                let r = pac::NFCT;
246
247                WAKER.register(cx.waker());
248
249                if r.events_selected().read() != 0 || r.events_fieldlost().read() != 0 {
250                    return Poll::Ready(());
251                }
252
253                r.inten().write(|w| {
254                    w.set_selected(true);
255                    w.set_fieldlost(true);
256                });
257                Poll::Pending
258            })
259            .await;
260            if r.events_fieldlost().read() != 0 {
261                continue;
262            }
263
264            // disable autocoll
265            #[cfg(not(feature = "nrf52832"))]
266            r.autocolresconfig().write(|w| w.0 = 0b11u32);
267
268            // once anticoll is done, set framedelaymax to the maximum possible.
269            // this gives the firmware as much time as possible to reply.
270            // higher layer still has to reply faster than the FWT it specifies in the iso14443-4 ATS,
271            // but that's not our concern.
272            //
273            // nrf52832 field is 16bit instead of 20bit. this seems to force a too short timeout, maybe it's a SVD bug?
274            #[cfg(not(feature = "nrf52832"))]
275            r.framedelaymax().write(|w| w.set_framedelaymax(0xF_FFFF));
276            #[cfg(feature = "nrf52832")]
277            r.framedelaymax().write(|w| w.set_framedelaymax(0xFFFF));
278
279            return;
280        }
281    }
282
283    /// Transmit an ISO14443-3 frame to the reader.
284    ///
285    /// You must call this only after receiving a frame with [`receive`](Self::receive),
286    /// and only once. Higher-layer protocols usually define timeouts, so calling this
287    /// too late can cause things to fail.
288    ///
289    /// This will fail with [`Error::Deactivated`] if we have been deselected due to either
290    /// the field being switched off or due to the ISO14443 state machine. When this happens,
291    /// you must stop calling [`receive`](Self::receive) and [`transmit`](Self::transmit), reset
292    /// all protocol state, and go back to calling [`activate`](Self::activate).
293    pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), Error> {
294        let r = pac::NFCT;
295
296        //Setup DMA
297        self.tx_buf[..buf.len()].copy_from_slice(buf);
298        r.packetptr().write_value(self.tx_buf.as_ptr() as u32);
299        r.maxlen().write(|w| w.0 = buf.len() as _);
300
301        // Set packet length
302        r.txd().amount().write(|w| {
303            w.set_txdatabits(0);
304            w.set_txdatabytes(buf.len() as _);
305        });
306
307        r.txd().frameconfig().write(|w| {
308            w.set_crcmodetx(true);
309            w.set_discardmode(DiscardMode::DISCARD_END);
310            w.set_parity(true);
311            w.set_sof(true);
312        });
313
314        r.events_error().write_value(0);
315        r.events_txframeend().write_value(0);
316        r.errorstatus().write(|w| w.0 = 0xffff_ffff);
317
318        // Start starttx task
319        compiler_fence(Ordering::SeqCst);
320        r.tasks_starttx().write_value(1);
321
322        poll_fn(move |cx| {
323            trace!("polling tx");
324            let r = pac::NFCT;
325            WAKER.register(cx.waker());
326
327            if r.events_fieldlost().read() != 0 {
328                return Poll::Ready(Err(Error::Deactivated));
329            }
330
331            if r.events_txframeend().read() != 0 {
332                trace!("Txframend hit, should be finished trasmitting");
333                return Poll::Ready(Ok(()));
334            }
335
336            if r.events_error().read() != 0 {
337                trace!("Got error?");
338                let errs = r.errorstatus().read();
339                r.errorstatus().write(|w| w.0 = 0xFFFF_FFFF);
340                trace!("errors: {:08x}", errs.0);
341                r.events_error().write_value(0);
342                return Poll::Ready(Err(Error::RxError));
343            }
344
345            r.inten().write(|w| {
346                w.set_txframeend(true);
347                w.set_error(true);
348                w.set_fieldlost(true);
349            });
350
351            Poll::Pending
352        })
353        .await
354    }
355
356    /// Receive an ISO14443-3 frame from the reader.
357    ///
358    /// After calling this, you must send back a response with [`transmit`](Self::transmit),
359    /// and only once. Higher-layer protocols usually define timeouts, so calling this
360    /// too late can cause things to fail.
361    pub async fn receive(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
362        let r = pac::NFCT;
363
364        r.rxd().frameconfig().write(|w| {
365            w.set_crcmoderx(true);
366            w.set_parity(true);
367            w.set_sof(true);
368        });
369
370        //Setup DMA
371        r.packetptr().write_value(self.rx_buf.as_mut_ptr() as u32);
372        r.maxlen().write(|w| w.0 = self.rx_buf.len() as _);
373
374        // Reset and enable the end event
375        r.events_rxframeend().write_value(0);
376        r.events_rxerror().write_value(0);
377
378        // Start enablerxdata only after configs are finished writing
379        compiler_fence(Ordering::SeqCst);
380        r.tasks_enablerxdata().write_value(1);
381
382        poll_fn(move |cx| {
383            trace!("polling rx");
384            let r = pac::NFCT;
385            WAKER.register(cx.waker());
386
387            if r.events_fieldlost().read() != 0 {
388                return Poll::Ready(Err(Error::Deactivated));
389            }
390
391            if r.events_rxerror().read() != 0 {
392                trace!("RXerror got in recv frame, should be back in idle state");
393                r.events_rxerror().write_value(0);
394                let errs = r.framestatus().rx().read();
395                r.framestatus().rx().write(|w| w.0 = 0xFFFF_FFFF);
396                trace!("errors: {:08x}", errs.0);
397                return Poll::Ready(Err(Error::RxError));
398            }
399
400            if r.events_rxframeend().read() != 0 {
401                trace!("RX Frameend got in recv frame, should have data");
402                r.events_rxframeend().write_value(0);
403                return Poll::Ready(Ok(()));
404            }
405
406            r.inten().write(|w| {
407                w.set_rxframeend(true);
408                w.set_rxerror(true);
409                w.set_fieldlost(true);
410            });
411
412            Poll::Pending
413        })
414        .await?;
415
416        let n = r.rxd().amount().read().rxdatabytes() as usize - 2;
417        buf[..n].copy_from_slice(&self.rx_buf[..n]);
418        Ok(n)
419    }
420}
421
422/// Wake the system if there if an NFC field close to the antenna
423pub fn wake_on_nfc_sense() {
424    NFCT.tasks_sense().write_value(0x01);
425}