diff --git a/pn532/src/driver.rs b/pn532/src/driver.rs index ea322dd..163c891 100644 --- a/pn532/src/driver.rs +++ b/pn532/src/driver.rs @@ -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 { +pub struct Pn532 +where + RST: OutputPin, + IRQ: InputPin, + DELAY: DelayNs, + B: Interface +{ pub(crate) interface: B, pub(crate) in_listed_tag: u8, pub(crate) buffer: [u8; N], + _rst: PhantomData, + _irq: PhantomData, + _delay: PhantomData, } -impl Pn532 { +impl Pn532 +where + RST: OutputPin, + IRQ: InputPin, + DELAY: DelayNs, + B: Interface +{ /// 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, } } diff --git a/pn532/src/interface/i2c.rs b/pn532/src/interface/i2c.rs index a563f02..b53b3b8 100644 --- a/pn532/src/interface/i2c.rs +++ b/pn532/src/interface/i2c.rs @@ -77,7 +77,7 @@ impl I2cInterface { } } -impl Interface for I2cInterface +impl Interface for I2cInterface where I2C: I2c, D: DelayNs, @@ -86,17 +86,16 @@ where { type TransportError = I2C::Error; - fn begin(&mut self) -> Result<(), Error> { - // 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( diff --git a/pn532/src/interface/mod.rs b/pn532/src/interface/mod.rs index 7dd7614..eef5d16 100644 --- a/pn532/src/interface/mod.rs +++ b/pn532/src/interface/mod.rs @@ -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 { /// 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>; + fn begin(&mut self) -> Result<(), Error> { + // 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( diff --git a/pn532/src/protocol/felica/felica_lite_s/auth.rs b/pn532/src/protocol/felica/felica_lite_s/auth.rs index edd3f83..48f981d 100644 --- a/pn532/src/protocol/felica/felica_lite_s/auth.rs +++ b/pn532/src/protocol/felica/felica_lite_s/auth.rs @@ -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 Pn532 { +impl Pn532 +where + RST: OutputPin, + IRQ: InputPin, + DELAY: DelayNs, + B: Interface +{ pub(crate) fn set_random_challenge(&mut self, card: &CardSession, rng: &mut impl Rng) -> Result> { diff --git a/pn532/src/protocol/felica/felica_lite_s/issuance.rs b/pn532/src/protocol/felica/felica_lite_s/issuance.rs index 2b43207..6a57731 100644 --- a/pn532/src/protocol/felica/felica_lite_s/issuance.rs +++ b/pn532/src/protocol/felica/felica_lite_s/issuance.rs @@ -1,6 +1,14 @@ +use embedded_hal::delay::DelayNs; +use embedded_hal::digital::{InputPin, OutputPin}; use crate::{Interface, Pn532}; -impl Pn532 { +impl Pn532 +where + RST: OutputPin, + IRQ: InputPin, + DELAY: DelayNs, + B: Interface +{ pub fn setup_first_issuance(&mut self) { todo!() } diff --git a/pn532/src/protocol/felica/felica_lite_s/mod.rs b/pn532/src/protocol/felica/felica_lite_s/mod.rs index d09ec3c..3309ecf 100644 --- a/pn532/src/protocol/felica/felica_lite_s/mod.rs +++ b/pn532/src/protocol/felica/felica_lite_s/mod.rs @@ -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 Pn532 { +impl Pn532 +where + RST: OutputPin, + IRQ: InputPin, + DELAY: DelayNs, + B: Interface +{ pub fn try_authenticate(&mut self, rng: &mut impl Rng, card: &CardSession, key: &CardKey) -> Result, crate::Error> { diff --git a/pn532/src/protocol/felica/mod.rs b/pn532/src/protocol/felica/mod.rs index e52a744..1e4e0a9 100644 --- a/pn532/src/protocol/felica/mod.rs +++ b/pn532/src/protocol/felica/mod.rs @@ -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 Pn532 { +impl Pn532 +where + RST: OutputPin, + IRQ: InputPin, + DELAY: DelayNs, + B: Interface +{ /// Poll for a FeliCa card. pub fn felica_polling( &mut self, diff --git a/pn532/src/tg.rs b/pn532/src/tg.rs index 7015ee0..010e1bc 100644 --- a/pn532/src/tg.rs +++ b/pn532/src/tg.rs @@ -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 Pn532 { +impl Pn532 +where + RST: OutputPin, + IRQ: InputPin, + DELAY: DelayNs, + B: Interface +{ /// Initialize the PN532 as a target using a raw command frame. pub fn tg_init_as_target( &mut self, diff --git a/src/components/card_reader.rs b/src/components/card_reader.rs index cd7c9a6..4dd940a 100644 --- a/src/components/card_reader.rs +++ b/src/components/card_reader.rs @@ -21,7 +21,7 @@ fn get_card_key() -> &'static CardKey { } pub struct CardReader<'a> { - driver: Pn532, Delay, gpio::Output<'a>, gpio::Input<'a>>> + driver: Pn532, gpio::Input<'a>, Delay, pn532::I2cInterface, Delay, gpio::Output<'a>, gpio::Input<'a>>> } impl<'a> CardReader<'a> {