1#![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#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
28pub enum NfcId {
29 SingleSize([u8; 4]),
31 DoubleSize([u8; 7]),
33 TripleSize([u8; 10]),
35}
36
37#[derive(Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
39pub enum SelResProtocol {
40 #[default]
42 Type2 = 0,
43 Type4A = 1,
45 NfcDep = 2,
47 NfcDepAndType4A = 3,
49}
50
51#[derive(Clone)]
53pub struct Config {
54 pub nfcid1: NfcId,
56 pub sdd_pat: SddPat,
58 pub plat_conf: u8,
60 pub protocol: SelResProtocol,
62}
63
64pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82#[non_exhaustive]
83pub enum Error {
84 RxError,
86 RxOverrun,
88 Deactivated,
90 Collision,
92 BufferNotInRAM,
94}
95
96pub 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 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 #[cfg(feature = "nrf52832")]
164 unsafe {
165 (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 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 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 #[cfg(not(feature = "nrf52832"))]
211 r.autocolresconfig().write(|w| w.0 = 0b10);
212
213 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; 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 #[cfg(not(feature = "nrf52832"))]
266 r.autocolresconfig().write(|w| w.0 = 0b11u32);
267
268 #[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 pub async fn transmit(&mut self, buf: &[u8]) -> Result<(), Error> {
294 let r = pac::NFCT;
295
296 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 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 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 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 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 r.events_rxframeend().write_value(0);
376 r.events_rxerror().write_value(0);
377
378 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
422pub fn wake_on_nfc_sense() {
424 NFCT.tasks_sense().write_value(0x01);
425}