diff --git a/.cargo/config.toml b/.cargo/config.toml
index 0b9a9ef..a5c1398 100644
--- a/.cargo/config.toml
+++ b/.cargo/config.toml
@@ -3,7 +3,7 @@ runner = "espflash flash --monitor -B 921600 --chip esp32s3 --log-format defmt"
linker = "/home/fromost/.rustup/toolchains/esp/xtensa-esp-elf/esp-15.2.0_20250920/xtensa-esp-elf/bin/xtensa-esp32s3-elf-gcc"
[env]
-DEFMT_LOG = "info,lora=trace,eeprom24x=debug,pn532=trace"
+DEFMT_LOG = "info,lora=trace,eeprom24x=debug,pn532=debug"
[build]
rustflags = [
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..83f9a5e
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.pdf filter=lfs, diff=lfs merge=lfs -text
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..8adb403
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Cargo.toml b/Cargo.toml
index 2b99cc2..bbde586 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,21 +15,21 @@ test = false
debug = []
[dependencies]
-esp-hal = { version = "~1.1", features = ["defmt", "esp32s3", "unstable"] }
-esp-rtos = { version = "0.3.0", features = [
+esp-hal = { version = "~1.2", features = ["defmt", "esp32s3", "unstable"] }
+esp-rtos = { version = "0.4.0", features = [
"defmt",
"embassy",
"esp-alloc",
"esp32s3",
] }
-esp-alloc = { version = "0.10.0", features = ["defmt"] }
-esp-backtrace = { version = "0.19.0", features = [
+esp-alloc = { version = "0.11.0", features = ["defmt"] }
+esp-backtrace = { version = "0.20.0", features = [
"defmt",
"esp32s3",
"panic-handler",
] }
-esp-println = { version = "0.17.0", features = ["defmt-espflash", "esp32s3"] }
-esp-bootloader-esp-idf = { version = "0.5.0", features = ["defmt", "esp32s3"] }
+esp-println = { version = "0.18.0", features = ["defmt-espflash", "esp32s3"] }
+esp-bootloader-esp-idf = { version = "0.6.0", features = ["defmt", "esp32s3"] }
embassy-executor = { version = "0.10.0", features = ["defmt"] }
embassy-time = { version = "0.5.0", features = ["defmt", "generic-queue-8", "defmt-timestamp-uptime"] }
diff --git a/build.rs b/build.rs
index a7f6f8b..d4a692c 100644
--- a/build.rs
+++ b/build.rs
@@ -2,10 +2,10 @@ fn main() {
println!("cargo:rerun-if-changed=Cargo.toml");
patch_crate::run().expect("Failed while patching");
- let iter = dotenvy::from_path_iter(".env")
+ let environment = dotenvy::from_path_iter(".env")
.expect("failed to read .env");
- for item in iter {
+ for item in environment {
let (key, value) = item.expect("invalid .env entry");
println!("cargo::rustc-env={key}={value}");
diff --git a/pn532/datasheets/felica_lite_s.pdf b/pn532/datasheets/felica_lite_s.pdf
new file mode 100644
index 0000000..c03148c
Binary files /dev/null and b/pn532/datasheets/felica_lite_s.pdf differ
diff --git a/pn532/src/driver.rs b/pn532/src/driver.rs
index 163c891..68eb676 100644
--- a/pn532/src/driver.rs
+++ b/pn532/src/driver.rs
@@ -1,14 +1,14 @@
//! High-level PN532 command driver.
-use core::marker::PhantomData;
use crate::commands::*;
use crate::error::Error;
use crate::interface::Interface;
-use crate::{NoIrq, NoReset, StatusCode};
+use crate::types::constants::{PN532_GPIO_P32, PN532_GPIO_P34, PN532_GPIO_VALIDATION_BIT};
+use crate::{StatusCode};
+use core::marker::PhantomData;
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
@@ -16,7 +16,7 @@ where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
- B: Interface
+ B: Interface,
{
pub(crate) interface: B,
pub(crate) in_listed_tag: u8,
@@ -31,7 +31,7 @@ where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
- B: Interface
+ B: Interface,
{
/// Create a driver over the given transport interface.
pub fn new(interface: B) -> Self {
@@ -45,19 +45,24 @@ where
}
}
- /// Initialise the PN532: pulse the reset pin (if provided) and wait for it
+ /// Initialize the PN532: pulse the reset pin (if provided) and wait for it
/// to become ready.
pub fn begin(&mut self) -> Result<(), Error> {
- if let Err(Error::UnusedPin) = self.interface.begin() {
- crate::debug!("No reset pin")
+ match self.interface.begin() {
+ Ok(_) => Ok(()),
+ Err(Error::UnusedPin) => {
+ crate::debug!("Unused pin");
+ Ok(())
+ },
+ Err(e) => Err(e),
}
- Ok(())
}
// -- internal helpers ---------------------------------------------------
pub(crate) fn send(&mut self, header_len: usize) -> Result<(), Error> {
- self.interface.write_command(&self.buffer[..header_len], &[])
+ self.interface
+ .write_command(&self.buffer[..header_len], &[])
}
pub(crate) fn send_with_body(
@@ -73,8 +78,12 @@ where
self.interface.read_response(&mut self.buffer, 1000)
}
- pub(crate) fn read_timeout(&mut self, timeout: Duration) -> Result> {
- self.interface.read_response(&mut self.buffer, timeout.as_millis() as u16)
+ pub(crate) fn read_timeout(
+ &mut self,
+ timeout: Duration,
+ ) -> Result> {
+ self.interface
+ .read_response(&mut self.buffer, timeout.as_millis() as u16)
}
// -- generic PN532 functions -------------------------------------------
@@ -120,10 +129,10 @@ where
}
/// 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);
+ pub fn write_gpio(&mut self, pin_state: u8) -> Result<(), Error> {
+ let pin_state = pin_state | (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
self.buffer[0] = PN532Command::WriteGpio.into_bits();
- self.buffer[1] = PN532_GPIO_VALIDATION_BIT | pinstate;
+ self.buffer[1] = PN532_GPIO_VALIDATION_BIT | pin_state;
self.buffer[2] = 0x00;
self.send(3)?;
let len = self.read()?;
@@ -180,7 +189,7 @@ where
self.read()?;
Ok(())
}
-
+
/// return error if current buffer contains an error code
pub(crate) fn validate_buffer(&self, len: usize) -> Result<(), Error> {
if len == 0 || (self.buffer[0] & 0x3F) != 0 {
@@ -190,8 +199,6 @@ where
}
}
-
-
/// Release the card.
pub fn release(&mut self) -> Result<(), Error> {
self.buffer[0] = PN532Command::InRelease.into_bits();
diff --git a/pn532/src/interface/i2c.rs b/pn532/src/interface/i2c.rs
index b53b3b8..1bb3113 100644
--- a/pn532/src/interface/i2c.rs
+++ b/pn532/src/interface/i2c.rs
@@ -118,11 +118,7 @@ where
buf: &mut [u8],
timeout_ms: u16,
) -> Result> {
- // Wait for the PN532 to signal data is ready.
self.wait_ready(timeout_ms)?;
-
- // Read the full response frame in a single transaction, stripping the
- // RDY byte. Frame layout: PREAMBLE(3) + LEN + LCS + TFI + CMD + payload + DCS + POSTAMBLE.
let frame_len = buf.len() + 9;
if frame_len > MAX_DATA_LEN + 10 {
return Err(Error::NoSpace);
@@ -148,18 +144,11 @@ where
IRQ: InputPin,
{
/// Wait until the PN532 signals data is ready.
- ///
- /// With an IRQ pin this blocks until the pin goes low; without one it polls
- /// the I2C status byte. Either way the status byte is consumed, so the next
- /// read returns the frame itself.
fn wait_ready(&mut self, timeout_ms: u16) -> Result<(), Error> {
let mut elapsed = 0u16;
loop {
match self.irq.is_low() {
Ok(true) => {
- // IRQ asserted (active-low): data is ready. Poll the status
- // byte to confirm and consume it so the next read gets the
- // frame itself.
let mut status = [0u8; 1];
match self.i2c.read(PN532_I2C_ADDRESS, &mut status) {
Ok(()) if status[0] & 1 == 1 => return Ok(()),
@@ -173,8 +162,6 @@ where
}
}
Ok(false) | Err(_) => {
- // IRQ connected but not asserted yet (or a read error):
- // keep waiting.
self.delay.delay_ms(1);
elapsed += 1;
if timeout_ms != 0 && elapsed >= timeout_ms {
diff --git a/pn532/src/protocol/felica/felica_lite_s/auth.rs b/pn532/src/protocol/felica/felica_lite_s/auth.rs
index 48f981d..f07c8ff 100644
--- a/pn532/src/protocol/felica/felica_lite_s/auth.rs
+++ b/pn532/src/protocol/felica/felica_lite_s/auth.rs
@@ -40,66 +40,39 @@ where
let cipher = TdesEde2::new(&key);
Ok(SessionKeys::new(&cipher, &rc))
-
- // crate::trace!("RC: {:02X}", rc);
- // crate::trace!("CK DES key: {:02X}", des_key);
- // crate::trace!("RC DES input: {:02X}", des_rc);
- // crate::trace!("SK1 DES: {:02X}", sk1_des);
- // crate::trace!("SK1: {:02X}", sk1);
- // crate::trace!("SK2 DES: {:02X}", sk2_des);
- // crate::trace!("SK2: {:02X}", sk2);
}
- pub(crate) fn compute_mac(
+ /// 2-key Triple DES-CBC MAC over `block_list` followed by `block_data`.
+ pub(crate) fn compute_mac(
&mut self,
session: &AuthSession,
- input: &MacInput
+ key_bytes: [u8; 16],
+ block_list: &[u8; 8],
+ block_data: &[u8],
) -> [u8; 8] {
- // data layout from get_plain_text():
- //
- // [0..8] = block list
- // [8..24] = ID block
- // [24..40] = CKV block
- // [40..56] = MAC_A block (NOT used in MAC calculation)
-
- let block_list = &input.block_list();
- let block_data = &input.block_data();
-
- // FeliCa Lite-S uses the session keys with their byte order reversed
- // at the DES interface.
- let key_bytes = session.sk.as_des();
-
let key = Key::::try_from(key_bytes).unwrap();
let cipher = TdesEde2::new(&key);
- // RC1 is also byte-reversed at the DES interface.
let mut state_bytes = session.rc.rc1();
state_bytes.reverse();
-
- // The initial plaintext for MAC_A is the block-number list.
- // Byte order is reversed before the DES operation.
- let mut first = [0u8; 8];
- first.copy_from_slice(block_list);
- first.reverse();
+
+ let mut block_list = block_list.clone();
+ block_list.reverse();
for i in 0..8 {
- state_bytes[i] ^= first[i];
+ state_bytes[i] ^= block_list[i];
}
- let mut state = Block::::try_from(state_bytes).unwrap();
- cipher.encrypt_block(&mut state);
-
- // Process ID and CKV.
- //
- // Each 8-byte piece is byte-reversed before entering the
- // 2-key 3DES CBC operation.
+ let mut state_block = Block::::try_from(state_bytes).unwrap();
+ cipher.encrypt_block(&mut state_block);
+
for chunk in block_data.chunks_exact(8) {
let mut input = [0u8; 8];
input.copy_from_slice(chunk);
input.reverse();
for i in 0..8 {
- input[i] ^= state[i];
+ input[i] ^= state_block[i];
}
crate::trace!("MAC input: {:02X}", input);
@@ -107,16 +80,26 @@ where
let mut block = Block::::try_from(input).unwrap();
cipher.encrypt_block(&mut block);
- state = block;
+ state_block = block;
}
- // Reverse the final result back to FeliCa byte order.
- let mut mac: [u8; 8] = state.0;
+ let mut mac: [u8; 8] = state_block.0;
mac.reverse();
- crate::trace!("mac: {:02X}, maca: {:02X}", mac, input.maca());
+ crate::trace!("mac: {:02X}", mac);
mac
}
+ /// Compute the MAC_A value for a Write With MAC operation.
+ pub(crate) fn compute_write_mac(
+ &mut self,
+ session: &AuthSession,
+ plain: &[u8; 24],
+ ) -> [u8; 8] {
+ let mut header = [0u8; 8];
+ header.copy_from_slice(&plain[0..8]);
+ self.compute_mac(session, session.sk.as_des_write(), &header, &plain[8..24])
+ }
+
pub(crate) fn check_auth(
&mut self,
card: &CardSession,
@@ -133,7 +116,12 @@ where
let input = MacInput::new(
&data, block_list
);
- let mac = self.compute_mac(session, &input);
+ let mac = self.compute_mac(
+ session,
+ session.sk.as_des(),
+ &input.block_list(),
+ &input.block_data(),
+ );
Ok(mac == input.maca())
}
}
\ No newline at end of file
diff --git a/pn532/src/protocol/felica/felica_lite_s/issuance.rs b/pn532/src/protocol/felica/felica_lite_s/issuance.rs
index 6a57731..e94fab5 100644
--- a/pn532/src/protocol/felica/felica_lite_s/issuance.rs
+++ b/pn532/src/protocol/felica/felica_lite_s/issuance.rs
@@ -1,6 +1,9 @@
use embedded_hal::delay::DelayNs;
use embedded_hal::digital::{InputPin, OutputPin};
-use crate::{Interface, Pn532};
+use crate::{Error, Interface, Pn532};
+use crate::types::felica::{CardSession, FelicaLiteSBlock};
+use crate::types::felica::felica_lite_s::auth::{AuthSession, CardKey, CardKeyVersion};
+use crate::types::felica::felica_lite_s::config::MemoryConfig;
impl Pn532
where
@@ -9,7 +12,92 @@ where
DELAY: DelayNs,
B: Interface
{
- pub fn setup_first_issuance(&mut self) {
- todo!()
+ pub fn set_id(&mut self, card: &CardSession, arbitrary: [u8; 6], dfc: Option<[u8; 2]>) -> Result<(), Error> {
+ let dfc = dfc.unwrap_or_default();
+ let mut block = [0u8; 16];
+ block[8] = dfc[0];
+ block[9] = dfc[1];
+ block[10..16].copy_from_slice(&arbitrary);
+ self.write_block(
+ card,
+ &[FelicaLiteSBlock::ID],
+ &[block]
+ )
+ }
+
+ pub fn get_id(&mut self, card: &CardSession) -> Result<[u8; 16], Error> {
+ let mut block = [[0u8; 16]];
+ self.read_block(
+ card,
+ &[FelicaLiteSBlock::ID],
+ &mut block
+ )?;
+ crate::trace!("ID block: {:02X}", block);
+ Ok(block[0])
+ }
+
+ pub fn set_ck(&mut self, card: &CardSession, key: &CardKey) -> Result<(), Error> {
+ self.write_block(
+ card,
+ &[FelicaLiteSBlock::CK],
+ &[**key]
+ )
+ }
+
+ pub fn set_ck_with_mac(&mut self, card: &CardSession, session: &AuthSession, key: &CardKey) -> Result<(), Error> {
+ self.write_with_mac(
+ card,
+ session,
+ FelicaLiteSBlock::CK,
+ &**key
+ )
+ }
+
+ pub fn set_ckv(&mut self, card: &CardSession, version: &CardKeyVersion) -> Result<(), Error> {
+ self.write_block(
+ card,
+ &[FelicaLiteSBlock::CKV],
+ &[version.as_block()]
+ )
+ }
+
+ pub fn set_ckv_with_mac(&mut self, card: &CardSession, session: &AuthSession, version: &CardKeyVersion) -> Result<(), Error> {
+ self.write_with_mac(
+ card,
+ session,
+ FelicaLiteSBlock::CKV,
+ &version.as_block()
+ )
+ }
+
+ pub fn get_ckv(&mut self, card: &CardSession) -> Result> {
+ let mut block = [[0u8; 16]];
+ self.read_block(
+ card,
+ &[FelicaLiteSBlock::CKV],
+ &mut block
+ )?;
+ crate::trace!("CKV block: {:02X}", block);
+ Ok(CardKeyVersion::from(block[0]))
+ }
+
+ pub fn get_mc(&mut self, card: &CardSession) -> Result> {
+ let mut block = [[0u8; 16]];
+ self.read_block(
+ card,
+ &[FelicaLiteSBlock::MemoryConfig],
+ &mut block
+ )?;
+ crate::trace!("MC block: {:02X}", block[0]);
+ Ok(MemoryConfig::from(block[0]))
+ }
+
+ pub fn set_mc(&mut self, card: &CardSession, config: MemoryConfig) -> Result<(), Error> {
+ let block: [u8; 16] = config.into();
+ self.write_block(
+ card,
+ &[FelicaLiteSBlock::MemoryConfig],
+ &[block]
+ )
}
}
\ No newline at end of file
diff --git a/pn532/src/protocol/felica/felica_lite_s/mod.rs b/pn532/src/protocol/felica/felica_lite_s/mod.rs
index 3309ecf..2eaf293 100644
--- a/pn532/src/protocol/felica/felica_lite_s/mod.rs
+++ b/pn532/src/protocol/felica/felica_lite_s/mod.rs
@@ -23,11 +23,12 @@ where
let sk = self.get_session_keys(&rc, key)?;
let session = AuthSession::new(sk, rc);
let is_valid_auth = self.check_auth(card, &session)?;
- if is_valid_auth {
- Ok(Some(session))
- } else {
- Ok(None)
+
+ if !is_valid_auth {
+ return Ok(None);
}
+ self.try_external_authentication(card, &session)?;
+ Ok(Some(session))
}
pub fn read_with_mac(
@@ -40,7 +41,12 @@ where
let block_list = [block.as_block(), FelicaLiteSBlock::MACA as u16];
self.read_block(card, &block_list, &mut block_data)?;
let input = MacInput::new(&block_data, &block_list);
- let mac = self.compute_mac(session, &input);
+ let mac = self.compute_mac(
+ session,
+ session.sk.as_des(),
+ &input.block_list(),
+ &input.block_data(),
+ );
if mac != input.maca() {
return Err(crate::Error::FelicaError(Error::MACMismatch));
}
@@ -48,6 +54,47 @@ where
Ok(block_data[0])
}
+ /// Write one data block protected by a Write With MAC (manual §5.4.4).
+ pub fn write_with_mac(
+ &mut self,
+ card: &CardSession,
+ session: &AuthSession,
+ block: impl AsBlock,
+ data: &[u8; 16],
+ ) -> Result<(), crate::Error> {
+ let mut wcnt_block = [[0u8; 16]];
+ self.read_block(card, &[FelicaLiteSBlock::WCNT], &mut wcnt_block)?;
+ let mut wcnt = [0u8; 3];
+ wcnt.copy_from_slice(&wcnt_block[0][0..3]);
+
+ let mut plain = [0u8; 24];
+ plain[0..3].copy_from_slice(&wcnt);
+ plain[4] = block.as_block() as u8;
+ plain[6] = FelicaLiteSBlock::MACA.as_block() as u8;
+ plain[8..24].copy_from_slice(data);
+
+ let mac = self.compute_write_mac(session, &plain);
+
+ let mut mac_a = [0u8; 16];
+ mac_a[0..8].copy_from_slice(&mac);
+ mac_a[8..11].copy_from_slice(&wcnt);
+
+ let block_list = [block.as_block(), FelicaLiteSBlock::MACA as u16];
+ let block_data = [*data, mac_a];
+ self.write_block(card, &block_list, &block_data)
+ }
+
+ /// Complete External Authentication (manual §5.4.2, Figure 5-10).
+ pub(crate) fn try_external_authentication(
+ &mut self,
+ card: &CardSession,
+ session: &AuthSession,
+ ) -> Result<(), crate::Error> {
+ let mut state = [0u8; 16];
+ state[0] = 0x01; // EXT_AUTH: after authentication
+ self.write_with_mac(card, session, FelicaLiteSBlock::STATE, &state)
+ }
+
pub fn read_block(
&mut self,
card: &CardSession,
diff --git a/pn532/src/protocol/felica/mod.rs b/pn532/src/protocol/felica/mod.rs
index 1e4e0a9..fc44910 100644
--- a/pn532/src/protocol/felica/mod.rs
+++ b/pn532/src/protocol/felica/mod.rs
@@ -184,12 +184,13 @@ where
card.pmm.get_read_timeout(U, Some(Duration::from_millis(50)))
)?;
crate::trace!("Read Response: {:02X}", response);
+
+ if response_len >= 11 && (response[9] != 0 || response[10] != 0) {
+ return Err(Error::FelicaError(FelicaError::Status(response[9], response[10])));
+ }
if response_len != 12 + 16 * U {
return Err(Error::InvalidFrame);
}
- if response[9] != 0 || response[10] != 0 {
- return Err(Error::FelicaError(FelicaError::Status(response[9], response[10])));
- }
let mut k = 12;
for block in block_data.iter_mut().take(U) {
@@ -253,12 +254,13 @@ where
&mut response,
card.pmm.get_write_timeout(U, Some(Duration::from_millis(50)))
)?;
+
+ if response_len >= 11 && (response[9] != 0 || response[10] != 0) {
+ return Err(Error::FelicaError(FelicaError::Status(response[9], response[10])));
+ }
if response_len != RESPONSE_SIZE {
return Err(Error::InvalidFrame);
}
- if response[9] != 0 || response[10] != 0 {
- return Err(Error::FelicaError(FelicaError::Status(response[9], response[10])));
- }
Ok(())
}
}
diff --git a/pn532/src/types/felica/felica_lite_s/auth/card_key.rs b/pn532/src/types/felica/felica_lite_s/auth/card_key.rs
index 4394979..09d75d5 100644
--- a/pn532/src/types/felica/felica_lite_s/auth/card_key.rs
+++ b/pn532/src/types/felica/felica_lite_s/auth/card_key.rs
@@ -3,7 +3,7 @@ use core::ops::Deref;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
-pub struct CardKey(pub [u8; 16]);
+pub struct CardKey([u8; 16]);
impl CardKey {
/// FeliCa byte order:
@@ -50,4 +50,41 @@ impl Display for CardKey {
write!(f, "{:?}", self.0)
}
}
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct CardKeyVersion([u8; 2]);
+
+impl CardKeyVersion {
+ pub fn new(version: u16) -> Self {
+ let bytes = version.to_be_bytes();
+ CardKeyVersion(bytes)
+ }
+
+ pub fn as_block(&self) -> [u8; 16] {
+ let mut block = [0u8; 16];
+ block[0] = self.0[0];
+ block[1] = self.0[1];
+ block
+ }
+}
+
+impl From<[u8; 16]> for CardKeyVersion {
+ fn from(val: [u8; 16]) -> Self {
+ CardKeyVersion([val[0], val[1]])
+ }
+}
+
+impl Display for CardKeyVersion {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ #[cfg(feature = "alloc")]
+ {
+ write!(f, "{}", hex::encode_upper(self.0))
+ }
+ #[cfg(not(feature = "alloc"))]
+ {
+ write!(f, "{:?}", self.0)
+ }
+ }
}
\ No newline at end of file
diff --git a/pn532/src/types/felica/felica_lite_s/auth/sk.rs b/pn532/src/types/felica/felica_lite_s/auth/sk.rs
index 0a3e1cc..ef1d8cd 100644
--- a/pn532/src/types/felica/felica_lite_s/auth/sk.rs
+++ b/pn532/src/types/felica/felica_lite_s/auth/sk.rs
@@ -41,13 +41,23 @@ impl SessionKeys {
}
pub fn as_des(&self) -> [u8; 16] {
+ Self::key_des(&self.sk1, &self.sk2)
+ }
+
+ /// Session keys in DES byte order with the halves swapped (`SK2 || SK1`),
+ /// as required by the data-write MAC generation.
+ pub fn as_des_write(&self) -> [u8; 16] {
+ Self::key_des(&self.sk2, &self.sk1)
+ }
+
+ fn key_des(first: &[u8; 8], second: &[u8; 8]) -> [u8; 16] {
let mut key_bytes = [0u8; 16];
for i in 0..8 {
- key_bytes[i] = self.sk1[7 - i];
- key_bytes[8 + i] = self.sk2[7 - i];
+ key_bytes[i] = first[7 - i];
+ key_bytes[8 + i] = second[7 - i];
}
-
+
key_bytes
}
diff --git a/pn532/src/types/felica/felica_lite_s/config/access_level.rs b/pn532/src/types/felica/felica_lite_s/config/access_level.rs
new file mode 100644
index 0000000..b331e9b
--- /dev/null
+++ b/pn532/src/types/felica/felica_lite_s/config/access_level.rs
@@ -0,0 +1,10 @@
+use bitfields::bitflag;
+
+#[bitflag(u8)]
+#[derive(Debug, PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub enum AccessLevel {
+ ReadOnly = 0,
+ #[base]
+ ReadWrite = 1,
+}
\ No newline at end of file
diff --git a/pn532/src/types/felica/felica_lite_s/config/mod.rs b/pn532/src/types/felica/felica_lite_s/config/mod.rs
new file mode 100644
index 0000000..f962038
--- /dev/null
+++ b/pn532/src/types/felica/felica_lite_s/config/mod.rs
@@ -0,0 +1,185 @@
+mod access_level;
+use access_level::AccessLevel;
+
+use bitfields::bitfield;
+
+#[bitfield([u8; 4], from_endian = little, into_endian = little)]
+#[derive(PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Access {
+ #[bits(16)]
+ pub scratch_pad: ScratchPadAccessLevel,
+ /// 0xFF: ReadWrite
+ /// Other than 0xFF: Readonly
+ #[bits(8, default = 0)]
+ pub system_block: u8,
+ #[bits(1)]
+ pub is_ck_ckv_rewritable: bool,
+ #[bits(7)]
+ _reserved: u8,
+}
+
+#[bitfield([u8; 7], from_endian = little, into_endian = little)]
+#[derive(PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct Authentication {
+ #[bits(16)]
+ pub scratch_pad_read: ScratchPadAuth,
+ #[bits(16)]
+ pub scratch_pad_write: ScratchPadAuth,
+ #[bits(16)]
+ pub scratch_pad_mac_write: ScratchPadAuth,
+ #[bits(1, default = false)]
+ pub state_with_mac: bool,
+ #[bits(7, default = 0)]
+ _reserved_state: u8,
+}
+
+#[bitfield(u16)]
+#[derive(PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct ScratchPadAccessLevel {
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad0: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad1: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad2: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad3: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad4: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad5: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad6: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad7: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad8: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad9: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad10: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad11: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad12: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub pad13: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub reg: AccessLevel,
+ #[bits(1, default = AccessLevel::ReadWrite)]
+ pub mc: AccessLevel,
+}
+
+#[bitfield(u16)]
+#[derive(PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct ScratchPadAuth {
+ #[bits(1, default = false)]
+ pub pad0: bool,
+ #[bits(1, default = false)]
+ pub pad1: bool,
+ #[bits(1, default = false)]
+ pub pad2: bool,
+ #[bits(1, default = false)]
+ pub pad3: bool,
+ #[bits(1, default = false)]
+ pub pad4: bool,
+ #[bits(1, default = false)]
+ pub pad5: bool,
+ #[bits(1, default = false)]
+ pub pad6: bool,
+ #[bits(1, default = false)]
+ pub pad7: bool,
+ #[bits(1, default = false)]
+ pub pad8: bool,
+ #[bits(1, default = false)]
+ pub pad9: bool,
+ #[bits(1, default = false)]
+ pub pad10: bool,
+ #[bits(1, default = false)]
+ pub pad11: bool,
+ #[bits(1, default = false)]
+ pub pad12: bool,
+ #[bits(1, default = false)]
+ pub pad13: bool,
+ #[bits(1, default = false)]
+ pub reg: bool,
+ #[bits(1, default = false)]
+ _reserved: bool,
+}
+
+#[bitfield(u8)]
+#[derive(PartialEq, Eq)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct RFParameter {
+ #[bits(3, default = 0x07)]
+ pub parameter: u8,
+ #[bits(5, default = 0x1F)]
+ _reserved: u8,
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[cfg_attr(feature = "defmt", derive(defmt::Format))]
+pub struct MemoryConfig {
+ pub access: Access,
+ pub rf: RFParameter,
+ pub auth: Authentication,
+ /// 0x01: compatible
+ /// 0x00: incompatible
+ /// 0x02~0xFF: prohibited
+ pub ndef: u8,
+ _reserved: [u8; 3],
+}
+
+impl Default for MemoryConfig {
+ fn default() -> Self {
+ Self {
+ access: Access::from([0xFF, 0xFF, 0xFF, 0x00]),
+ rf: RFParameter::default(),
+ ndef: 0x00,
+ auth: Authentication::default(),
+ _reserved: [0u8; 3],
+ }
+ }
+}
+
+impl Into<[u8; 16]> for MemoryConfig {
+ fn into(self) -> [u8; 16] {
+ let mut block = [0u8; 16];
+
+ let access = self.access.into_bytes();
+
+ block[0] = access[0];
+ block[1] = access[1];
+ block[2] = access[2];
+ block[3] = self.ndef;
+ block[4] = self.rf.into_bits();
+ block[5] = access[3];
+
+ block[6..13].copy_from_slice(&self.auth.into_bytes());
+
+ block
+ }
+}
+
+impl From<[u8; 16]> for MemoryConfig {
+ fn from(value: [u8; 16]) -> Self {
+ let access = Access::from([value[0], value[1], value[2], value[5]]);
+
+ let rf = RFParameter::from(value[4]);
+
+ let auth: [u8; 7] = value[6..13].try_into().unwrap();
+ let auth = Authentication::from(auth);
+
+ Self {
+ access,
+ rf,
+ auth,
+ ndef: value[3],
+ _reserved: value[13..16].try_into().unwrap(),
+ }
+ }
+}
diff --git a/pn532/src/types/felica/felica_lite_s/mod.rs b/pn532/src/types/felica/felica_lite_s/mod.rs
index b07e0f5..d88de8c 100644
--- a/pn532/src/types/felica/felica_lite_s/mod.rs
+++ b/pn532/src/types/felica/felica_lite_s/mod.rs
@@ -2,9 +2,10 @@
///! User Manual: https://www.sony.net/Products/felica/business/tech-support/data/fls_usmnl_1.4e.pdf
pub mod auth;
+pub mod config;
use bitfields::bitflag;
-use super::{AsBlock, IDm, PMm};
+use super::AsBlock;
use super::AsServiceCode;
/// Service Code
@@ -68,7 +69,9 @@ pub enum Block {
/// Write counter block.
WCNT = 0x8090,
/// MAC_A block.
- MACA = 0x8091
+ MACA = 0x8091,
+ /// STATE block (EXT_AUTH / POLL_DIS).
+ STATE = 0x8092
}
impl AsBlock for Block {
diff --git a/pn532/src/types/felica/ic_type.rs b/pn532/src/types/felica/ic_type.rs
index ca01699..c0474d4 100644
--- a/pn532/src/types/felica/ic_type.rs
+++ b/pn532/src/types/felica/ic_type.rs
@@ -7,25 +7,8 @@ use bitfields::bitflag;
pub enum CardICType {
#[base]
Unknown = 0x00,
- S140 = 0x50,
- SA40_2P = 0x51,
- SA41_2C = 0x52,
- SA21_2 = 0x46,
- SA20_2 = 0x45,
- SA20_1 = 0x44,
- SA01_2 = 0x35,
- SA00_1 = 0x32,
- S962 = 0x20,
- S960 = 0x0D,
- S953 = 0x09,
- S952 = 0x08,
- S915 = 0x01,
- S982 = 0xF1,
- S978F = 0xF0,
- S967LiteS = 0xF2,
- S967Plug = 0xE1,
- S967NFC = 0xFF,
- S926 = 0xE0
+ S966 = 0xF1,
+ S965 = 0xF0,
}
/// https://www.sony.co.jp/en/Products/felica/business/tech-support/list.html
diff --git a/pn532/src/types/felica/idm.rs b/pn532/src/types/felica/idm.rs
index 52440db..970ab2f 100644
--- a/pn532/src/types/felica/idm.rs
+++ b/pn532/src/types/felica/idm.rs
@@ -1,7 +1,7 @@
use core::fmt::{Display, Formatter};
use bitfields::bitfield;
-#[bitfield([u8; 8], from_endian = big, into_endian = big)]
+#[bitfield([u8; 8], from_endian = little, into_endian = little)]
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct IDm {
diff --git a/pn532/src/types/felica/pmm.rs b/pn532/src/types/felica/pmm.rs
index 64ee2d9..a480df6 100644
--- a/pn532/src/types/felica/pmm.rs
+++ b/pn532/src/types/felica/pmm.rs
@@ -2,7 +2,7 @@ use core::fmt::{Display, Formatter};
use core::time::Duration;
use bitfields::bitfield;
-#[bitfield([u8; 8])]
+#[bitfield([u8; 8], from_endian = little, into_endian = little)]
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct PMm {
diff --git a/src/board.rs b/src/board.rs
index d16d327..76b4b60 100644
--- a/src/board.rs
+++ b/src/board.rs
@@ -13,7 +13,6 @@ use embassy_sync::pubsub::PubSubChannel;
use embassy_time::{Duration, Timer};
use esp_hal::gpio::{InputConfig, Level, Pull};
use esp_hal::i2c::master::I2c;
-use esp_hal::interrupt::software::SoftwareInterruptControl;
use esp_hal::peripherals::Peripherals;
use esp_hal::rng::{Trng, TrngSource};
use esp_hal::spi::master::{Config, Spi};
@@ -22,6 +21,7 @@ use esp_hal::{gpio, Async, Blocking};
use static_cell::StaticCell;
pub(crate) static LED_STATE: AtomicBool = AtomicBool::new(false);
+static TRNG_SOURCE: StaticCell = StaticCell::new();
pub struct Board {
spawner: Spawner,
@@ -29,16 +29,19 @@ pub struct Board {
clock: Clock<'static>,
storage: RomStorage<'static>,
card_reader: CardReader<'static>,
- trng: Trng
+ trng: Trng,
}
impl Board {
- pub async fn new(spawner: Spawner, peripherals: Peripherals) -> Result {
+ pub async fn new(
+ spawner: Spawner,
+ peripherals: Peripherals,
+ ) -> Result {
let timer_group = TimerGroup::new(peripherals.TIMG0);
- let sw_ctrl = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
- esp_rtos::start(timer_group.timer0, sw_ctrl.software_interrupt0);
+ esp_rtos::start(timer_group.timer0, peripherals.FROM_CPU_INTR0);
- static SPI_BUS: StaticCell>> = StaticCell::new();
+ static SPI_BUS: StaticCell>> =
+ StaticCell::new();
let spi = Spi::new(peripherals.SPI2, Config::default())?
.into_async()
.with_sck(peripherals.GPIO9)
@@ -46,21 +49,22 @@ impl Board {
.with_miso(peripherals.GPIO11);
let spi_bus = SPI_BUS.init(Mutex::new(spi));
- static I2C_BUS: StaticCell>>> = StaticCell::new();
- let async_i2c = I2c::new(
- peripherals.I2C0,
- esp_hal::i2c::master::Config::default()
- )?
+ static I2C_BUS: StaticCell>>> =
+ StaticCell::new();
+ let async_i2c = I2c::new(peripherals.I2C0, esp_hal::i2c::master::Config::default())?
.with_sda(peripherals.GPIO21)
.with_scl(peripherals.GPIO19);
let i2c_bus = I2C_BUS.init(BlockingMutex::new(RefCell::new(async_i2c)));
-
- let irq = gpio::Input::new(peripherals.GPIO6, InputConfig::default().with_pull(Pull::Up));
+
+ let irq = gpio::Input::new(
+ peripherals.GPIO6,
+ InputConfig::default().with_pull(Pull::Up),
+ );
let reset = gpio::Output::new(peripherals.GPIO5, Level::High, Default::default());
let card_reader = CardReader::new(SharedI2c::new(i2c_bus), irq, reset);
-
- let vext = gpio::Output::new(peripherals.GPIO36, Level::Low, Default::default());
+
let lora = {
+ let vext = gpio::Output::new(peripherals.GPIO36, Level::Low, Default::default());
let reset = gpio::Output::new(peripherals.GPIO12, Level::Low, Default::default());
let busy = gpio::Input::new(peripherals.GPIO13, InputConfig::default());
let dio1 = gpio::Input::new(peripherals.GPIO14, InputConfig::default());
@@ -70,62 +74,57 @@ impl Board {
Lora::new(spi_device, reset, busy, dio1, vext).await?
};
let clock = Clock::new(SharedI2c::new(i2c_bus), 0x68)?;
-
+
let led = gpio::Output::new(peripherals.GPIO35, Level::Low, Default::default());
spawner.spawn(led_task(led)?);
-
- let storage = RomStorage::new(
- SharedI2c::new(i2c_bus)
- );
-
+
+ let storage = RomStorage::new(SharedI2c::new(i2c_bus));
+
let trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1);
- core::mem::forget(trng_source);
+ TRNG_SOURCE.init(trng_source);
let trng = Trng::try_new()?;
-
- let instance = Self {
+
+ let instance = Self {
spawner,
lora,
clock,
storage,
card_reader,
- trng
+ trng,
};
Ok(instance)
}
pub async fn start(mut self) -> Result<(), crate::error::Error> {
+ static LORA_CHANNEL: StaticCell = StaticCell::new();
+ let lora_channel = LORA_CHANNEL.init(PubSubChannel::new());
+
self.card_reader.init()?;
self.lora.try_join().await?;
defmt::info!("Board started");
LED_STATE.store(true, Ordering::Relaxed);
-
+
let time = self.lora.get_time(self.clock.get_datetime()?).await?;
let datetime = self.clock.update_time(time)?;
let app_data = AppData {
- last_boot_time: datetime
+ last_boot_time: datetime,
};
defmt::debug!("stored app data: {}", self.storage.get_data::()?);
self.storage.write_data(&app_data).await?;
- static LORA_CHANNEL: StaticCell = StaticCell::new();
- let lora_channel = LORA_CHANNEL.init(PubSubChannel::new());
-
- self.spawner.spawn(
- components::card_reader::start_card_reader(
- self.card_reader,
- lora_channel.publisher()?,
- self.trng.clone()
- )?
- );
- self.spawner.spawn(
- components::lora::start_send_data_task(
- self.lora,
- lora_channel.subscriber()?
- )?
- );
- self.spawner.spawn(
- components::lora::start_heartbeat_task(lora_channel.publisher()?)?
- );
+ self.spawner
+ .spawn(components::card_reader::start_card_reader(
+ self.card_reader,
+ lora_channel.publisher()?,
+ self.trng.clone(),
+ )?);
+ self.spawner.spawn(components::lora::start_send_data_task(
+ self.lora,
+ lora_channel.subscriber()?,
+ )?);
+ self.spawner.spawn(components::lora::start_heartbeat_task(
+ lora_channel.publisher()?,
+ )?);
loop {
Timer::after_millis(100).await;
@@ -143,4 +142,4 @@ async fn led_task(mut led: gpio::Output<'static>) {
}
Timer::after(Duration::from_millis(50)).await;
}
-}
\ No newline at end of file
+}
diff --git a/src/components/card_reader.rs b/src/components/card_reader.rs
index 4dd940a..036eea8 100644
--- a/src/components/card_reader.rs
+++ b/src/components/card_reader.rs
@@ -4,10 +4,10 @@ use embassy_sync::once_lock::OnceLock;
use embassy_time::{Delay, Timer};
use esp_hal::gpio;
use esp_hal::rng::Trng;
-use pn532::types::felica::{CardSession, FelicaLiteSBlock, FelicaPollingRequestCode};
-use pn532::{Pn532};
-use pn532::types::felica::felica_lite_s::auth::CardKey;
-use pn532::types::BaudRate;
+use pn532::types::felica::felica_lite_s::auth::{CardKey, CardKeyVersion};
+use pn532::types::felica::felica_lite_s::config::{MemoryConfig, RFParameter};
+use pn532::types::felica::{CardSession, FelicaLiteSBlock};
+use pn532::Pn532;
static CARD_KEY: OnceLock = OnceLock::new();
const CARD_KEY_STR: &str = env!("CARD_KEY");
@@ -16,24 +16,30 @@ fn get_card_key() -> &'static CardKey {
CARD_KEY.get_or_init(|| {
let mut buffer = [0u8; 16];
hex::decode_to_slice(CARD_KEY_STR, &mut buffer).unwrap();
- CardKey(buffer)
+ CardKey::from(buffer)
})
}
pub struct CardReader<'a> {
- driver: Pn532, gpio::Input<'a>, Delay, pn532::I2cInterface, Delay, gpio::Output<'a>, gpio::Input<'a>>>
+ driver: Pn532<
+ gpio::Output<'a>,
+ gpio::Input<'a>,
+ Delay,
+ pn532::I2cInterface, Delay, gpio::Output<'a>, gpio::Input<'a>>,
+ >,
}
impl<'a> CardReader<'a> {
pub fn new(i2c: SharedI2c<'a>, irq: gpio::Input<'a>, reset: gpio::Output<'a>) -> Self {
Self {
- driver: Pn532::new(pn532::I2cInterface::with_reset_irq(i2c, Delay, reset, irq))
+ driver: Pn532::new(pn532::I2cInterface::with_reset_irq(i2c, Delay, reset, irq)),
}
}
-
+
pub fn init(&mut self) -> Result<(), crate::error::Error> {
self.driver.begin()?;
self.driver.sam_config()?;
+ self.driver.set_passive_activation_retries(5)?;
Ok(())
}
}
@@ -42,16 +48,29 @@ impl<'a> CardReader<'a> {
pub async fn start_card_reader(
mut card_reader: CardReader<'static>,
_publisher: LoraPublisher<'static>,
- mut trng: Trng
+ mut trng: Trng,
) -> () {
+ loop {
+ match _start_card_reader(&mut card_reader, &_publisher, &mut trng).await {
+ Ok(_) => {}
+ Err(e) => {
+ defmt::error!("Error while reading card: {}", e);
+ }
+ }
+ }
+}
+
+async fn _start_card_reader(
+ card_reader: &mut CardReader<'static>,
+ _publisher: &LoraPublisher<'static>,
+ trng: &mut Trng,
+) -> Result<(), crate::error::Error> {
let card_key = get_card_key();
defmt::trace!("card_key: {}", card_key);
-
+ let driver = &mut card_reader.driver;
loop {
- Timer::after_millis(50).await;
- let Some(response) = (match card_reader.driver.felica_polling(
- Default::default()
- ) {
+ Timer::after_millis(10).await;
+ let Some(response) = (match driver.felica_polling(Default::default()) {
Ok(v) => v,
Err(e) => {
defmt::error!("card_reader driver error: {}", e);
@@ -62,8 +81,9 @@ pub async fn start_card_reader(
continue;
};
defmt::info!("Polling card: {}", Debug2Format(&response));
+ defmt::debug!("IDm: {}", response.idm.into_bytes());
let card = CardSession::from(response);
-
+
// if let Err(e) = card_reader.driver.felica_write_without_encryption(
// &response.idm, &response.pmm,
// &[FelicaLiteSServiceCode::Write],
@@ -73,32 +93,64 @@ pub async fn start_card_reader(
// defmt::error!("card_reader write ck error: {}", e);
// continue;
// }
+ let id = driver.get_id(&card)?;
+ defmt::debug!("ID: {}", id);
+
+ if let Some(card_id) = option_env!("CARD_ID") {
+ let mut id = [0u8; 6];
+ hex::decode_to_slice(card_id,&mut id)?;
+ driver.set_id(&card, id, None)?;
+ }
+
+ let mut mc = driver.get_mc(&card)?;
+ defmt::info!("Config: {}", mc);
+ mc.access.set_system_block(0x00);
+ mc.ndef = 0x00;
+ mc.rf = RFParameter::from(0xFF);
+ mc.access.set_is_ck_ckv_rewritable(true);
+
+ let mut read_auth = mc.auth.scratch_pad_read();
+ read_auth.set_pad0(true);
+ mc.auth.set_scratch_pad_read(read_auth);
+
+ let mut write_auth = mc.auth.scratch_pad_write();
+ write_auth.set_pad0(true);
+ mc.auth.set_scratch_pad_write(write_auth);
+
+ let mut mac_auth = mc.auth.scratch_pad_mac_write();
+ mac_auth.set_pad0(true);
+ mc.auth.set_scratch_pad_mac_write(mac_auth);
- let auth_result = card_reader.driver.try_authenticate(
- &mut trng, &card, card_key
- );
- let session = match auth_result {
+ let block: [u8; 16] = mc.into();
+ defmt::debug!("1st insurance Config: {}", block);
+ driver.set_mc(&card, mc)?;
+
+ let session = match driver.try_authenticate(trng, &card, card_key) {
Ok(Some(sk)) => sk,
Ok(None) => {
defmt::warn!("card key is invalid");
continue;
- },
+ }
Err(e) => {
defmt::error!("card_reader auth error: {}", e);
continue;
}
};
- let read_result = card_reader.driver.read_with_mac(&card, &session, FelicaLiteSBlock::PAD0);
- let _read_data = match read_result {
+
+ driver.set_ck_with_mac(&card, &session, &card_key)?;
+ driver.set_ckv_with_mac(&card, &session, &CardKeyVersion::new(1))?;
+ driver.get_ckv(&card)?;
+
+ let _read_data = match driver.read_with_mac(&card, &session, FelicaLiteSBlock::PAD0) {
Ok(d) => d,
Err(e) => {
defmt::error!("card_reader read with mac error: {}", e);
continue;
}
};
-
- match card_reader.driver.release() {
- Ok(_) => {},
+
+ match driver.release() {
+ Ok(_) => {}
Err(e) => {
defmt::error!("card_reader release error: {}", e);
continue;
@@ -107,9 +159,9 @@ pub async fn start_card_reader(
// InRelease switches the RF field off when no target remains
// (UM0701-02 §7.3.11), so re-enable it before the next poll.
- if let Err(e) = card_reader.driver.set_rf_field(0x00, 0x01) {
+ if let Err(e) = driver.set_rf_field(0x00, 0x01) {
defmt::error!("card_reader RF field error: {}", e);
}
Timer::after_millis(200).await;
}
-}
\ No newline at end of file
+}
diff --git a/src/components/rom_storage.rs b/src/components/rom_storage.rs
index f1eb784..480e1c2 100644
--- a/src/components/rom_storage.rs
+++ b/src/components/rom_storage.rs
@@ -7,7 +7,7 @@ use embassy_time::{Duration, Timer};
use serde::de::DeserializeOwned;
use serde::Serialize;
-const ADDR_SIZE: usize = 256;
+const BLOCK_SIZE: usize = 256;
#[derive(thiserror::Error, Debug)]
pub(crate) enum StorageError {
@@ -44,7 +44,7 @@ impl<'d> RomStorage<'d> {
Ok(addr.clone())
} else {
let size = self.addr_table.len();
- let addr = size as u32 * ADDR_SIZE as u32;
+ let addr = size as u32 * BLOCK_SIZE as u32;
if addr >= u16::MAX as u32 {
return Err(StorageError::OutOfAddress)
}
@@ -58,7 +58,7 @@ impl<'d> RomStorage<'d> {
let addr = self.get_or_insert_addr::()?;
let bytes = postcard::to_allocvec(data)?;
let bytes_len = bytes.len();
- if bytes_len > ADDR_SIZE {
+ if bytes_len > BLOCK_SIZE {
return Err(StorageError::StorageOverSize(bytes_len).into());
}
for (i, chunk) in bytes.chunks(32).enumerate() {
@@ -74,7 +74,7 @@ impl<'d> RomStorage<'d> {
pub fn get_data(&mut self) -> Result {
let addr = self.get_or_insert_addr::()?;
- let mut bytes = [0u8; ADDR_SIZE];
+ let mut bytes = [0u8; BLOCK_SIZE];
self.driver.read_data(addr, &mut bytes)
.map_err(|e| StorageError::EEPROMError(e))?;
let data = postcard::from_bytes(&bytes)?;