NFC recv frame

This commit is contained in:
ferris 2023-10-25 12:32:45 +02:00
parent f956d19e6e
commit 6d8d50f328
3 changed files with 206 additions and 0 deletions

View File

@ -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",

144
embassy-nrf/src/nfc.rs Normal file
View File

@ -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<interrupt::typelevel::NFCT> 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<P = NFCT> + 'd,
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::NFCT, InterruptHandler> + '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<const N: usize>(&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(())
}
}

View File

@ -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<const MAX_BLOCKS: usize> {
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<const N: usize>() -> Result<NfcType2Tag<N> {
}