NFC recv frame
This commit is contained in:
parent
f956d19e6e
commit
6d8d50f328
@ -40,6 +40,7 @@ pub mod gpiote;
|
|||||||
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
#[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))]
|
||||||
pub mod i2s;
|
pub mod i2s;
|
||||||
pub mod nvmc;
|
pub mod nvmc;
|
||||||
|
pub mod nfc;
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "nrf52810",
|
feature = "nrf52810",
|
||||||
feature = "nrf52811",
|
feature = "nrf52811",
|
||||||
|
144
embassy-nrf/src/nfc.rs
Normal file
144
embassy-nrf/src/nfc.rs
Normal 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(())
|
||||||
|
}
|
||||||
|
}
|
61
embassy-nrf/src/nfc_parse.rs
Normal file
61
embassy-nrf/src/nfc_parse.rs
Normal 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> {
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user