//! High-level PN532 command driver. use crate::commands::*; use crate::error::{Error}; use crate::interface::Interface; pub(crate) const PACKET_BUFFER_SIZE: usize = 64; /// A card UID read by [`Pn532::read_passive_target_id`]. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Uid { pub bytes: heapless::Vec, } impl core::fmt::Display for Uid { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { #[cfg(feature = "alloc")] return write!(f, "{}", hex::encode(&self.bytes)); #[cfg(not(feature = "alloc"))] { let mut buf: heapless::Vec = heapless::Vec::new(); hex::encode_to_slice(&self.bytes, &mut buf) .map_err(|_| core::fmt::Error)?; let s = heapless::String::from_utf8(buf) .map_err(|_| core::fmt::Error)?; write!(f, "{}", s) } } } #[cfg(feature = "defmt")] impl defmt::Format for Uid { fn format(&self, fmt: defmt::Formatter) { defmt::write!(fmt, "{}", defmt::Display2Format(self)); } } /// Outcome of [`Pn532::tg_init_as_target`] / [`Pn532::tg_init_as_target_default`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum TargetInitStatus { /// The PN532 entered target mode. Success, /// No initiator appeared within the timeout. Timeout, /// The operation failed. Failed, } /// Result of a successful FeliCa polling request. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct FelicaPollingResponse { /// The card's IDm (NFCID2). pub idm: [u8; 8], /// The card's PMm (PAD). pub pmm: [u8; 8], /// The card's system code, when returned. pub system_code_response: Option, } /// Driver for the NXP PN532 NFC controller. pub struct Pn532 { pub(crate) interface: B, pub(crate) in_listed_tag: u8, pub(crate) felica_idm: [u8; 8], pub(crate) felica_pmm: [u8; 8], pub(crate) buffer: [u8; PACKET_BUFFER_SIZE], } impl Pn532 { /// Create a driver over the given transport interface. pub fn new(interface: B) -> Self { Self { interface, in_listed_tag: 0, felica_idm: [0; 8], felica_pmm: [0; 8], buffer: [0; PACKET_BUFFER_SIZE], } } /// Initialise the PN532: pulse the reset pin (if provided) and wait for it /// to become ready. pub fn begin(&mut self) -> Result<(), Error> { self.interface.begin() } // -- internal helpers --------------------------------------------------- pub(crate) fn send(&mut self, header_len: usize) -> Result<(), Error> { self.interface.write_command(&self.buffer[..header_len], &[]) } pub(crate) fn send_with_body( &mut self, header_len: usize, body: &[u8], ) -> Result<(), Error> { self.interface .write_command(&self.buffer[..header_len], body) } pub(crate) fn read(&mut self) -> Result> { self.interface.read_response(&mut self.buffer, 1000) } pub(crate) fn read_timeout(&mut self, timeout_ms: u16) -> Result> { self.interface.read_response(&mut self.buffer, timeout_ms) } // -- generic PN532 functions ------------------------------------------- /// Read the PN532 firmware version and ID. pub fn get_firmware_version(&mut self) -> Result> { self.buffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; self.send(1)?; let len = self.read()?; if len < 4 { return Err(Error::InvalidFrame); } Ok(u32::from_be_bytes([ self.buffer[0], self.buffer[1], self.buffer[2], self.buffer[3], ])) } /// Read a 16-bit PN532 register. pub fn read_register(&mut self, reg: u16) -> Result> { self.buffer[0] = PN532_COMMAND_READREGISTER; self.buffer[1] = (reg >> 8) as u8; self.buffer[2] = reg as u8; self.send(3)?; let len = self.read()?; if len < 1 { return Err(Error::InvalidFrame); } Ok(self.buffer[0]) } /// Write to a 16-bit PN532 register. pub fn write_register(&mut self, reg: u16, val: u8) -> Result<(), Error> { self.buffer[0] = PN532_COMMAND_WRITEREGISTER; self.buffer[1] = (reg >> 8) as u8; self.buffer[2] = reg as u8; self.buffer[3] = val; self.send(4)?; self.read()?; Ok(()) } /// Set the PN532's GPIO pins (see the PN532 user manual for valid pins). pub fn write_gpio(&mut self, pinstate: u8) -> Result<(), Error> { let pinstate = pinstate | (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34); self.buffer[0] = PN532_COMMAND_WRITEGPIO; self.buffer[1] = PN532_GPIO_VALIDATIONBIT | pinstate; self.buffer[2] = 0x00; self.send(3)?; let len = self.read()?; if len == 0 { return Err(Error::InvalidFrame); } Ok(()) } /// Read the state of the PN532's GPIO pins. pub fn read_gpio(&mut self) -> Result> { self.buffer[0] = PN532_COMMAND_READGPIO; self.send(1)?; self.read()?; Ok(self.buffer[0]) } /// Configure the SAM (Secure Access Module) in normal mode. pub fn sam_config(&mut self) -> Result<(), Error> { self.buffer[0] = PN532_COMMAND_SAMCONFIGURATION; self.buffer[1] = 0x01; // normal mode self.buffer[2] = 0x14; // timeout 50 ms * 20 = 1 second self.buffer[3] = 0x01; // use IRQ pin self.send(4)?; self.read()?; Ok(()) } /// Set the `MxRtyPassiveActivation` RF configuration item. pub fn set_passive_activation_retries( &mut self, max_retries: u8, ) -> Result<(), Error> { self.buffer[0] = PN532_COMMAND_RFCONFIGURATION; self.buffer[1] = 5; self.buffer[2] = 0xFF; self.buffer[3] = 0x01; self.buffer[4] = max_retries; self.send(5)?; self.read()?; Ok(()) } /// Switch the RF field on/off. pub fn set_rf_field( &mut self, auto_rfca: u8, rf_on_off: u8, ) -> Result<(), Error> { self.buffer[0] = PN532_COMMAND_RFCONFIGURATION; self.buffer[1] = 1; self.buffer[2] = 0x00 | auto_rfca | rf_on_off; self.send(3)?; self.read()?; Ok(()) } }