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. //! High-level PN532 command driver.
use core::marker::PhantomData;
use crate::commands::*; use crate::commands::*;
use crate::error::Error; use crate::error::Error;
use crate::interface::Interface; use crate::interface::Interface;
use crate::StatusCode; use crate::{NoIrq, NoReset, StatusCode};
use core::time::Duration; 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}; use crate::types::constants::{PN532_GPIO_P32, PN532_GPIO_P34, PN532_GPIO_VALIDATION_BIT};
/// Driver for the NXP PN532 NFC controller. /// 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) interface: B,
pub(crate) in_listed_tag: u8, pub(crate) in_listed_tag: u8,
pub(crate) buffer: [u8; N], 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. /// Create a driver over the given transport interface.
pub fn new(interface: B) -> Self { pub fn new(interface: B) -> Self {
Self { Self {
interface, interface,
in_listed_tag: 0, in_listed_tag: 0,
buffer: [0; N], 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 where
I2C: I2c, I2C: I2c,
D: DelayNs, D: DelayNs,
@@ -86,17 +86,16 @@ where
{ {
type TransportError = I2C::Error; type TransportError = I2C::Error;
fn begin(&mut self) -> Result<(), Error<Self::TransportError>> { fn rst(&mut self) -> &mut RST {
// Pulse RSTPD_N: high -> low -> wait -> high -> wait. This mirrors the &mut self.reset
// Adafruit library's begin() reset sequence. }
self.reset.set_high().map_err(|_| Error::UnusedPin)?;
self.reset.set_low().map_err(|_| Error::UnusedPin)?; fn irq(&mut self) -> &mut IRQ {
self.delay.delay_ms(400); &mut self.irq
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. fn delay(&mut self) -> &mut D {
self.delay.delay_ms(500); &mut self.delay
Ok(())
} }
fn write_command( fn write_command(
+20 -3
View File
@@ -6,6 +6,8 @@
//! acknowledgement/response handshake. //! acknowledgement/response handshake.
mod i2c; mod i2c;
use embedded_hal::delay::DelayNs;
pub use i2c::I2cInterface; pub use i2c::I2cInterface;
use embedded_hal::digital::{ErrorKind, ErrorType, InputPin, OutputPin}; 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 /// Implementations are responsible for the frame/ack handshake described in
/// the PN532 user manual (UM0701-02). /// 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. /// The error type produced by the underlying physical transport.
type TransportError; 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. /// 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. /// Write a command frame (`header` + optional `body`) and wait for the ACK.
fn write_command( fn write_command(
@@ -1,11 +1,19 @@
use des::cipher::{Block, BlockCipherEncrypt, Key, KeyInit}; use des::cipher::{Block, BlockCipherEncrypt, Key, KeyInit};
use des::TdesEde2; use des::TdesEde2;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use rand_core::Rng; use rand_core::Rng;
use crate::{Interface, Pn532}; use crate::{Interface, Pn532};
use crate::types::felica::{CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode}; use crate::types::felica::{CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode};
use crate::types::felica::felica_lite_s::auth::{AuthSession, CardKey, MacInput, RandomChallenge, SessionKeys}; 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) pub(crate) fn set_random_challenge(&mut self, card: &CardSession, rng: &mut impl Rng)
-> Result<RandomChallenge, crate::Error<B::TransportError>> -> 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}; 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) { pub fn setup_first_issuance(&mut self) {
todo!() todo!()
} }
@@ -1,13 +1,21 @@
pub mod issuance; pub mod issuance;
pub mod auth; pub mod auth;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use rand_core::Rng; use rand_core::Rng;
use crate::{Interface, Pn532}; use crate::{Interface, Pn532};
use crate::protocol::felica::error::Error; use crate::protocol::felica::error::Error;
use crate::types::felica::{AsBlock, CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode}; use crate::types::felica::{AsBlock, CardSession, FelicaLiteSBlock, FelicaLiteSServiceCode};
use crate::types::felica::felica_lite_s::auth::{AuthSession, CardKey, MacInput}; 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) pub fn try_authenticate(&mut self, rng: &mut impl Rng, card: &CardSession, key: &CardKey)
-> Result<Option<AuthSession>, crate::Error<B::TransportError>> -> 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::error::Error;
use crate::interface::Interface; use crate::interface::Interface;
use core::time::Duration; use core::time::Duration;
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
use crate::types::felica::*; use crate::types::felica::*;
use crate::types::BaudRate; 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}; 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. /// Poll for a FeliCa card.
pub fn felica_polling( pub fn felica_polling(
&mut self, &mut self,
+9 -2
View File
@@ -2,7 +2,8 @@ use crate::commands::*;
use crate::error::StatusCode; use crate::error::StatusCode;
use crate::{Error, Interface, Pn532}; use crate::{Error, Interface, Pn532};
use core::time::Duration; 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`]. /// Outcome of [`Pn532::tg_init_as_target`] / [`Pn532::tg_init_as_target_default`].
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -16,7 +17,13 @@ pub enum TargetInitStatus {
Failed, 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. /// Initialize the PN532 as a target using a raw command frame.
pub fn tg_init_as_target( pub fn tg_init_as_target(
&mut self, &mut self,
+1 -1
View File
@@ -21,7 +21,7 @@ fn get_card_key() -> &'static CardKey {
} }
pub struct CardReader<'a> { pub struct CardReader<'a> {
driver: Pn532<pn532::I2cInterface<SharedI2c<'a>, Delay, gpio::Output<'a>, gpio::Input<'a>>> driver: Pn532<gpio::Output<'a>, gpio::Input<'a>, Delay, pn532::I2cInterface<SharedI2c<'a>, Delay, gpio::Output<'a>, gpio::Input<'a>>>
} }
impl<'a> CardReader<'a> { impl<'a> CardReader<'a> {