diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 2cc83d74..f80312c3 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -40,6 +40,7 @@ pub mod gpiote; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; pub mod nvmc; +pub mod nfc; #[cfg(any( feature = "nrf52810", feature = "nrf52811", diff --git a/embassy-nrf/src/nfc.rs b/embassy-nrf/src/nfc.rs new file mode 100644 index 00000000..02d4b2d2 --- /dev/null +++ b/embassy-nrf/src/nfc.rs @@ -0,0 +1,144 @@ +#![macro_use] +use core::future::poll_fn; +use core::marker::PhantomData; +use core::sync::atomic::{compiler_fence, Ordering}; +use core::task::Poll; + +use embassy_hal_internal::drop::OnDrop; +use embassy_hal_internal::{into_ref, PeripheralRef}; +use embassy_sync::waitqueue::AtomicWaker; +// use crate::chip::{EASY_DMA_SIZE, FORCE_COPY_BUFFER_SIZE}; +use pac::{nfct, NFCT}; + +use crate::util::slice_in_ram; +use crate::{interrupt, pac, peripherals, Peripheral}; + +/// Interrupt handler. +pub struct InterruptHandler { + _private: (), +} + +impl interrupt::typelevel::Handler for InterruptHandler { + unsafe fn on_interrupt() { + let r = unsafe { &*NFCT::ptr() }; + if r.events_rxframeend.read().bits() != 0 { + r.intenclr.write(|w| w.rxframeend().clear()); + WAKER.wake(); + } + if r.events_rxerror.read().bits() != 0 { + r.intenclr.write(|w| w.rxerror().clear()); + WAKER.wake(); + } + + // if r.events_calibratedone.read().bits() != 0 { + // r.intenclr.write(|w| w.calibratedone().clear()); + // WAKER.wake(); + // } + + // if r.events_end.read().bits() != 0 { + // r.intenclr.write(|w| w.end().clear()); + // WAKER.wake(); + // } + + // if r.events_started.read().bits() != 0 { + // r.intenclr.write(|w| w.started().clear()); + // WAKER.wake(); + // } + } +} + +static WAKER: AtomicWaker = AtomicWaker::new(); + +/// NFC error. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + /// Rx Error received while waiting for frame + RxError, + /// Rx buffer was overrun, increase your buffer size to resolve this + RxOverrun, +} + +/// Nfc Tag Read/Writer driver +pub struct NfcT<'d> { + _p: PeripheralRef<'d, NFCT>, +} + +impl<'d> NfcT<'d> { + /// Create an Nfc Tag driver + pub fn new( + _p: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding + 'd, + ) -> Self { + into_ref!(_p); + + let r = unsafe { &*NFCT::ptr() }; + r.tasks_activate.write(|w| w.tasks_activate().set_bit()); + + Self { _p } + } + + fn regs() -> &'static nfct::RegisterBlock { + unsafe { &*NFCT::ptr() } + } + + fn stop_recv_frame() { + let r = Self::regs(); + compiler_fence(Ordering::SeqCst); + + r.intenset.write(|w| w.rxframeend().clear_bit()); + r.intenset.write(|w| w.rxerror().clear_bit()); + r.events_rxframeend.reset(); + r.events_rxerror.reset(); + } + + /// Waits for a single frame to be loaded into `buf` + /// `buf`` is not pointing to the Data RAM region, an EasyDMA transfer may result in a hard fault or RAM corruption. + pub async fn recv_frame(&mut self, buf: &mut [u8; N]) -> Result<(), Error> { + // NOTE: Tx variant requires buf slice in ram validation + let r = Self::regs(); + + let on_drop = OnDrop::new(Self::stop_recv_frame); + + //Setup DMA + r.packetptr.write(|w| unsafe { w.bits(buf.as_mut_ptr() as u32) }); + r.maxlen.write(|w| unsafe { w.bits(N as _) }); + + // Reset and enable the end event + r.events_rxframeend.reset(); + r.events_rxerror.reset(); + r.intenset.write(|w| w.rxframeend().set()); + r.intenset.write(|w| w.rxerror().set()); + + // Enter RX state + r.tasks_enablerxdata.write(|w| w.tasks_enablerxdata().set_bit()); + + // Wait for 'rxframeend'/'rxerror' event. + poll_fn(|cx| { + let r = Self::regs(); + + WAKER.register(cx.waker()); + + if r.events_rxframeend.read().bits() != 0 { + r.events_rxframeend.reset(); + return Poll::Ready(Ok(())); + } + + if r.events_rxerror.read().bits() != 0 { + r.events_rxerror.reset(); + // If rx buffer is overrun, rxd.amount will indicate a longer message than maxlen & rxerror will be emitted + if r.rxd.amount.read().bits() > r.maxlen.read().bits() { + return Poll::Ready(Err(Error::RxOverrun)); + } + return Poll::Ready(Err(Error::RxError)); + } + + Poll::Pending + }) + .await?; + + drop(on_drop); + Ok(()) + } +} diff --git a/embassy-nrf/src/nfc_parse.rs b/embassy-nrf/src/nfc_parse.rs new file mode 100644 index 00000000..0332587a --- /dev/null +++ b/embassy-nrf/src/nfc_parse.rs @@ -0,0 +1,61 @@ + +/// Value indicating that the Type 2 Tag contains NFC Forum defined data. +const NFC_T2T_NFC_FORUM_DEFINED_DATA: u8 = 0xE1; + +/// Value used for calculating the first BCC byte of a Type 2 Tag serial number. +const NFC_T2T_UID_BCC_CASCADE_BYTE: u8 = 0x88; + +/// Supported major version of the Type 2 Tag specification. +const NFC_T2T_SUPPORTED_MAJOR_VERSION: u8 = 1; + +/// Supported minor version of the Type 2 Tag specification. +const NFC_T2T_SUPPORTED_MINOR_VERSION: u8 = 0; + +/// Type 2 Tag block size in bytes. +const NFC_T2T_BLOCK_SIZE: u8 = 4; + +/// Offset of the Capability Container area in the Type 2 Tag. +const NFC_T2T_CC_BLOCK_OFFSET: u8 = 12; + +/// Offset of the data area in the Type 2 Tag. +const NFC_T2T_FIRST_DATA_BLOCK_OFFSET: u8 = 16; + +#[derive(Default)] +pub struct NfcType2Capabilities { + major_ver: u8, + minor_ver: u8, + data_area_size: u8, + read_access: u8, + write_access: u8 +} + +#[derive(Default)] +pub struct NfcType2TagSerial { + manufacturer_id: u8, + serial_nr_l: u16, + serial_nr_h: u32, + check_byte_0: u8, + check_byte_1: u8, + internal: u8, +} + +#[derive(Default)] +pub struct NfcType2Tag { + sn: NfcType2TagSerial, + lock_bytes: u16, + capabilities: NfcType2Capabilities, + max_tlv: u16, + tlv_block_array: [u8; MAX_BLOCKS], + count_tlv: u16, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[non_exhaustive] +pub enum Error { + VersionNotSupported, +} + +pub fn parsee_type2() -> Result { + +} \ No newline at end of file