use alloc::vec::Vec; use core::convert::Infallible; use embedded_hal::i2c::I2c; use esp_hal::time::{Duration, Instant}; use log::{error, info}; use pn532::i2c::I2CInterface; use pn532::requests::SAMMode; use pn532::{nb, Pn532, Request}; /// Timer implementation required by `pn532::CountDown`. pub struct TimerWrapper { start: Instant, duration: Duration, counter: u32, } impl TimerWrapper { pub fn new() -> Self { Self { start: Instant::now(), duration: Duration::ZERO, counter: 0, } } } impl Default for TimerWrapper { fn default() -> Self { Self::new() } } impl pn532::CountDown for TimerWrapper { type Time = Duration; fn start(&mut self, timeout: T) where T: Into, { self.start = Instant::now(); self.duration = timeout.into(); self.counter = 0; } fn wait(&mut self) -> nb::Result<(), Infallible> { let elapsed = self.start.elapsed(); self.counter += 1; if elapsed >= self.duration { Ok(()) } else { Err(nb::Error::WouldBlock) } } } pub type Pn532Device = Pn532, (), 32>; /// PN532 NFC reader driver. pub struct NfcPn532Driver where I2C: I2c, { pn532: Pn532Device, } impl NfcPn532Driver where I2C: I2c, { pub fn new(i2c: I2C) -> Self { let pn532 = Pn532::new_async(I2CInterface { i2c }); Self { pn532 } } pub async fn configure_sam(&mut self) -> Result<(), ()> { if let Err(e) = self.pn532.process_async( &Request::sam_configuration(SAMMode::Normal, false), 0, ).await { error!("PN532 SAM configuration failed over I2C: {e:?}"); Err(()) } else { info!("PN532 SAM configuration successful on shared I2C bus"); Ok(()) } } pub async fn poll_target(&mut self) -> Result<(), ()> { match self.pn532.process_async(&Request::INLIST_ONE_ISO_A_TARGET, 23).await { Ok(uid) => { info!("PN532 detected NFC target UID: {uid:?}"); Ok(()) } Err(e) => { info!("No NFC card found on shared I2C bus: {e:?}"); Err(()) } } } pub fn parse_nfc_page(iteration: u8, bytes: &[u8]) -> Result<[u8; 4], ()> { let success = bytes.first().is_some_and(|x| *x == 0); if success { let mut arr = [0; 4]; arr.copy_from_slice(&bytes[1..5]); Ok(arr) } else { info!("err {iteration}: {:02x?}", bytes); Err(()) } } pub async fn read_card_data(&mut self) -> Result, ()> { if let Err(e) = self.poll_target().await { error!("PN532 I2C target poll failed before reading card data: {e:?}"); return Err(e); } let mut data: Vec = Vec::with_capacity(858); for i in 0x0B..=230 { let mut parse_result = Err(()); while parse_result.is_err() { let Ok(result) = self.pn532.process_async(&Request::ntag_read(i), 17).await else { continue; }; parse_result = Self::parse_nfc_page(i, result); } let bytes = parse_result.unwrap(); let bytes = if i == 0x0B { &bytes[1..] } else { &bytes }; data.extend(bytes); } info!("PN532 full card payload read over I2C: {:02x?}", data); Ok(data) } pub fn device_mut(&mut self) -> &mut Pn532Device { &mut self.pn532 } }