Files
lora-card-reader/pn532/src/driver.rs
T
2026-08-30 16:27:44 +08:00

213 lines
6.4 KiB
Rust

//! High-level PN532 command driver.
use crate::commands::*;
use crate::error::Error;
use crate::interface::Interface;
use crate::StatusCode;
use core::time::Duration;
/// A card UID read by [`Pn532::read_passive_target_id`].
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Uid {
pub bytes: heapless::Vec<u8, 7>,
}
impl core::fmt::Display for Uid {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
#[cfg(feature = "alloc")]
{
write!(f, "{}", hex::encode(&self.bytes))
}
#[cfg(not(feature = "alloc"))]
{
write!(f, "{:?}", self)
}
}
}
/// Outcome of [`Pn532::tg_init_as_target`] / [`Pn532::tg_init_as_target_default`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TargetInitStatus {
/// The PN532 entered target mode.
Success,
/// No initiator appeared within the timeout.
Timeout,
/// The operation failed.
Failed,
}
/// Driver for the NXP PN532 NFC controller.
pub struct Pn532<B: Interface, const N: usize = 64> {
pub(crate) interface: B,
pub(crate) in_listed_tag: u8,
pub(crate) buffer: [u8; N],
}
impl<B: Interface, const N: usize> Pn532<B, N> {
/// Create a driver over the given transport interface.
pub fn new(interface: B) -> Self {
Self {
interface,
in_listed_tag: 0,
buffer: [0; N],
}
}
/// Initialise the PN532: pulse the reset pin (if provided) and wait for it
/// to become ready.
pub fn begin(&mut self) -> Result<(), Error<B::TransportError>> {
self.interface.begin()
}
// -- internal helpers ---------------------------------------------------
pub(crate) fn send(&mut self, header_len: usize) -> Result<(), Error<B::TransportError>> {
self.interface.write_command(&self.buffer[..header_len], &[])
}
pub(crate) fn send_with_body(
&mut self,
header_len: usize,
body: &[u8],
) -> Result<(), Error<B::TransportError>> {
self.interface
.write_command(&self.buffer[..header_len], body)
}
pub(crate) fn read(&mut self) -> Result<usize, Error<B::TransportError>> {
self.interface.read_response(&mut self.buffer, 1000)
}
pub(crate) fn read_timeout(&mut self, timeout: Duration) -> Result<usize, Error<B::TransportError>> {
self.interface.read_response(&mut self.buffer, timeout.as_millis() as u16)
}
// -- generic PN532 functions -------------------------------------------
/// Read the PN532 firmware version and ID.
pub fn get_firmware_version(&mut self) -> Result<u32, Error<B::TransportError>> {
self.buffer[0] = pn532::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<u8, Error<B::TransportError>> {
self.buffer[0] = pn532::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<B::TransportError>> {
self.buffer[0] = pn532::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<B::TransportError>> {
let pinstate = pinstate | (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
self.buffer[0] = pn532::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<u8, Error<B::TransportError>> {
self.buffer[0] = pn532::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<B::TransportError>> {
self.buffer[0] = pn532::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<B::TransportError>> {
self.buffer[0] = pn532::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<B::TransportError>> {
self.buffer[0] = pn532::RFCONFIGURATION;
self.buffer[1] = 1;
self.buffer[2] = 0x00 | auto_rfca | rf_on_off;
self.send(3)?;
self.read()?;
Ok(())
}
/// return error if current buffer contains an error code
pub(crate) fn validate_buffer(&self, len: usize) -> Result<(), Error<B::TransportError>> {
if len == 0 || (self.buffer[0] & 0x3F) != 0 {
Err(Error::Status(StatusCode::from_bits(self.buffer[0] & 0x3F)))
} else {
Ok(())
}
}
/// Release the card.
pub fn release(&mut self) -> Result<(), Error<B::TransportError>> {
self.buffer[0] = pn532::INRELEASE;
self.buffer[1] = 0x00;
self.send(2)?;
let len = self.read_timeout(Duration::from_secs(1))?;
self.validate_buffer(len)?;
Ok(())
}
}