Interface refactor 2

This commit is contained in:
2026-08-31 09:39:08 +08:00
parent 2e25cda230
commit 89dfed231f
9 changed files with 101 additions and 25 deletions
+24 -3
View File
@@ -1,26 +1,47 @@
//! High-level PN532 command driver.
use core::marker::PhantomData;
use crate::commands::*;
use crate::error::Error;
use crate::interface::Interface;
use crate::StatusCode;
use crate::{NoIrq, NoReset, StatusCode};
use core::time::Duration;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use crate::types::constants::{PN532_GPIO_P32, PN532_GPIO_P34, PN532_GPIO_VALIDATION_BIT};
/// Driver for the NXP PN532 NFC controller.
pub struct Pn532<B: Interface, const N: usize = 64> {
pub struct Pn532<RST, IRQ, DELAY, B, const N: usize = 64>
where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
pub(crate) interface: B,
pub(crate) in_listed_tag: u8,
pub(crate) buffer: [u8; N],
_rst: PhantomData<RST>,
_irq: PhantomData<IRQ>,
_delay: PhantomData<DELAY>,
}
impl<B: Interface, const N: usize> Pn532<B, N> {
impl<RST, IRQ, DELAY, B, const N: usize> Pn532<RST, IRQ, DELAY, B, N>
where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
/// Create a driver over the given transport interface.
pub fn new(interface: B) -> Self {
Self {
interface,
in_listed_tag: 0,
buffer: [0; N],
_rst: PhantomData,
_irq: PhantomData,
_delay: PhantomData,
}
}
+11 -12
View File
@@ -77,7 +77,7 @@ impl<I2C, D, RST, IRQ> I2cInterface<I2C, D, RST, IRQ> {
}
}
impl<I2C, D, RST, IRQ> Interface for I2cInterface<I2C, D, RST, IRQ>
impl<I2C, D, RST, IRQ> Interface<RST, IRQ, D> for I2cInterface<I2C, D, RST, IRQ>
where
I2C: I2c,
D: DelayNs,
@@ -86,17 +86,16 @@ where
{
type TransportError = I2C::Error;
fn begin(&mut self) -> Result<(), Error<Self::TransportError>> {
// Pulse RSTPD_N: high -> low -> wait -> high -> wait. This mirrors the
// Adafruit library's begin() reset sequence.
self.reset.set_high().map_err(|_| Error::UnusedPin)?;
self.reset.set_low().map_err(|_| Error::UnusedPin)?;
self.delay.delay_ms(400);
self.reset.set_high().map_err(|_| Error::UnusedPin)?;
// Let the PN532 boot after the reset is released. The Adafruit library
// waits ~10 ms + a 500 ms wakeup here; give it a full 500 ms.
self.delay.delay_ms(500);
Ok(())
fn rst(&mut self) -> &mut RST {
&mut self.reset
}
fn irq(&mut self) -> &mut IRQ {
&mut self.irq
}
fn delay(&mut self) -> &mut D {
&mut self.delay
}
fn write_command(
+20 -3
View File
@@ -6,6 +6,8 @@
//! acknowledgement/response handshake.
mod i2c;
use embedded_hal::delay::DelayNs;
pub use i2c::I2cInterface;
use embedded_hal::digital::{ErrorKind, ErrorType, InputPin, OutputPin};
@@ -58,13 +60,28 @@ impl InputPin for NoIrq {
///
/// Implementations are responsible for the frame/ack handshake described in
/// the PN532 user manual (UM0701-02).
pub trait Interface {
pub trait Interface<RST: OutputPin, IRQ: InputPin, DELAY: DelayNs> {
/// The error type produced by the underlying physical transport.
type TransportError;
/// Initialise the hardware: pulse the reset pin (if provided) and wait for
/// Initialize the hardware: pulse the reset pin (if provided) and wait for
/// the PN532 to become ready.
fn begin(&mut self) -> Result<(), Error<Self::TransportError>>;
fn begin(&mut self) -> Result<(), Error<Self::TransportError>> {
// Pulse RSTPD_N: high -> low -> wait -> high -> wait. This mirrors the
// Adafruit library's begin() reset sequence.
self.rst().set_high().map_err(|_| Error::UnusedPin)?;
self.rst().set_low().map_err(|_| Error::UnusedPin)?;
self.delay().delay_ms(400);
self.rst().set_high().map_err(|_| Error::UnusedPin)?;
// Let the PN532 boot after the reset is released. The Adafruit library
// waits ~10 ms + a 500 ms wakeup here; give it a full 500 ms.
self.delay().delay_ms(500);
Ok(())
}
fn rst(&mut self) -> &mut RST;
fn irq(&mut self) -> &mut IRQ;
fn delay(&mut self) -> &mut DELAY;
/// Write a command frame (`header` + optional `body`) and wait for the ACK.
fn write_command(
@@ -1,11 +1,19 @@
use des::cipher::{Block, BlockCipherEncrypt, Key, KeyInit};
use des::TdesEde2;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use rand_core::Rng;
use crate::{Interface, Pn532};
use crate::types::felica::{CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode};
use crate::types::felica::felica_lite_s::auth::{AuthSession, CardKey, MacInput, RandomChallenge, SessionKeys};
impl<B: Interface, const N: usize> Pn532<B, N> {
impl<RST, IRQ, DELAY, B, const N: usize> Pn532<RST, IRQ, DELAY, B, N>
where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
pub(crate) fn set_random_challenge(&mut self, card: &CardSession, rng: &mut impl Rng)
-> Result<RandomChallenge, crate::Error<B::TransportError>>
{
@@ -1,6 +1,14 @@
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use crate::{Interface, Pn532};
impl<B: Interface, const N: usize> Pn532<B, N> {
impl<RST, IRQ, DELAY, B, const N: usize> Pn532<RST, IRQ, DELAY, B, N>
where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
pub fn setup_first_issuance(&mut self) {
todo!()
}
@@ -1,13 +1,21 @@
pub mod issuance;
pub mod auth;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use rand_core::Rng;
use crate::{Interface, Pn532};
use crate::protocol::felica::error::Error;
use crate::types::felica::{AsBlock, CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode};
use crate::types::felica::felica_lite_s::auth::{AuthSession, CardKey, MacInput};
impl<B: Interface, const N: usize> Pn532<B, N> {
impl<RST, IRQ, DELAY, B, const N: usize> Pn532<RST, IRQ, DELAY, B, N>
where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
pub fn try_authenticate(&mut self, rng: &mut impl Rng, card: &CardSession, key: &CardKey)
-> Result<Option<AuthSession>, crate::Error<B::TransportError>>
{
+9 -1
View File
@@ -8,11 +8,19 @@ use crate::driver::Pn532;
use crate::error::Error;
use crate::interface::Interface;
use core::time::Duration;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use crate::types::felica::*;
use crate::types::BaudRate;
use crate::types::felica::constants::{FELICA_READ_MAX_BLOCK_NUM, FELICA_READ_MAX_SERVICE_NUM, FELICA_WRITE_MAX_BLOCK_NUM, FELICA_WRITE_MAX_SERVICE_NUM};
impl<B: Interface, const N: usize> Pn532<B, N> {
impl<RST, IRQ, DELAY, B, const N: usize> Pn532<RST, IRQ, DELAY, B, N>
where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
/// Poll for a FeliCa card.
pub fn felica_polling(
&mut self,
+9 -2
View File
@@ -2,7 +2,8 @@ use crate::commands::*;
use crate::error::StatusCode;
use crate::{Error, Interface, Pn532};
use core::time::Duration;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
/// Outcome of [`Pn532::tg_init_as_target`] / [`Pn532::tg_init_as_target_default`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -16,7 +17,13 @@ pub enum TargetInitStatus {
Failed,
}
impl<B: Interface, const N: usize> Pn532<B, N> {
impl<RST, IRQ, DELAY, B, const N: usize> Pn532<RST, IRQ, DELAY, B, N>
where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
/// Initialize the PN532 as a target using a raw command frame.
pub fn tg_init_as_target(
&mut self,