From f523b7d3942727939965d2d31c841d507adf0d91 Mon Sep 17 00:00:00 2001 From: fromost Date: Thu, 27 Aug 2026 10:52:52 +0800 Subject: [PATCH] use bitfield instead of strum --- pn532/Cargo.toml | 5 ++- pn532/src/driver.rs | 2 +- pn532/src/error.rs | 8 +++-- pn532/src/felica/mod.rs | 14 ++++----- pn532/src/felica/types/idm.rs | 30 +++--------------- pn532/src/felica/types/mod.rs | 52 ++++++++++++++++++++++++++----- pn532/src/felica/types/pmm.rs | 32 ++++++------------- pn532/src/felica/types/polling.rs | 16 +++++----- pn532/src/tg/mod.rs | 4 +-- 9 files changed, 83 insertions(+), 80 deletions(-) diff --git a/pn532/Cargo.toml b/pn532/Cargo.toml index 52852c1..b01c135 100644 --- a/pn532/Cargo.toml +++ b/pn532/Cargo.toml @@ -3,7 +3,6 @@ name = "pn532" version = "0.1.0" edition = "2024" description = "A no_std, embedded-hal driver for the NXP PN532 NFC controller (I2C interface)" -license = "BSD-3-Clause" keywords = ["nfc", "pn532", "embedded-hal", "no-std", "i2c"] categories = ["embedded", "no-std", "hardware-support"] @@ -20,9 +19,9 @@ defmt = { version = "~1.1", optional = true } hex = { version = "~0.4", default-features = false } des = { version = "~0.9", default-features = false } cbc = { version = "~0.2", default-features = false, features = ["block-padding"] } -strum = { version = "0.28.0", default-features = false, features = ["derive", "strum_macros"] } heapless = "~0.9" thiserror = { version = "~2", default-features = false } +bitfields = "3.1.0" [features] default = [] @@ -31,4 +30,4 @@ alloc = ["defmt/alloc", "hex/alloc", "heapless/alloc"] mifare-classic = [] iso14443a = [] felica = [] -felica-lite-s = ["felica"] \ No newline at end of file +felica-lite-s = ["felica"] diff --git a/pn532/src/driver.rs b/pn532/src/driver.rs index a2b9f0f..db035c6 100644 --- a/pn532/src/driver.rs +++ b/pn532/src/driver.rs @@ -199,7 +199,7 @@ impl Pn532 { /// 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 { - Err(Error::Status(StatusCode::from_repr(self.buffer[0] & 0x3F).unwrap())) + Err(Error::Status(StatusCode::from_bits(self.buffer[0] & 0x3F))) } else { Ok(()) } diff --git a/pn532/src/error.rs b/pn532/src/error.rs index a52ba0a..5753d66 100644 --- a/pn532/src/error.rs +++ b/pn532/src/error.rs @@ -1,6 +1,6 @@ use core::fmt::Debug; +use bitfields::bitflag; use defmt::Debug2Format; -use strum::FromRepr; /// Driver-level error type, generic over the transport (I2C) error. #[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)] @@ -40,9 +40,11 @@ impl defmt::Format for Error { } } -#[repr(u8)] -#[derive(FromRepr, Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, PartialEq, Eq)] +#[bitflag(u8)] pub enum StatusCode { + #[base] + Unknown = 0x00, TimeOut = 0x01, CRC = 0x02, Parity = 0x03, diff --git a/pn532/src/felica/mod.rs b/pn532/src/felica/mod.rs index 869ed4c..51ee979 100644 --- a/pn532/src/felica/mod.rs +++ b/pn532/src/felica/mod.rs @@ -124,7 +124,7 @@ impl Pn532 { let mut j = 0; cmd[j] = FELICA_CMD_REQUEST_SERVICE; j += 1; - cmd[j..j + 8].copy_from_slice(&card.to_bytes()); + cmd[j..j + 8].copy_from_slice(&card.into_be_bytes()); j += 8; cmd[j] = num_node as u8; j += 1; @@ -153,7 +153,7 @@ impl Pn532 { pub fn felica_request_response(&mut self, card: &PollingResponse) -> Result> { let mut cmd = [0u8; 9]; cmd[0] = FELICA_CMD_REQUEST_RESPONSE; - cmd[1..9].copy_from_slice(&card.idm.to_bytes()); + cmd[1..9].copy_from_slice(&card.idm.into_be_bytes()); let mut response = [0u8; 10]; let response_len = self.felica_send_command(&cmd, &mut response, Duration::from_millis(200))?; @@ -202,7 +202,7 @@ impl Pn532 { // command let mut cmd = heapless::Vec::::new(); cmd.push(FELICA_CMD_READ_WITHOUT_ENCRYPTION).unwrap(); - cmd.extend_from_slice(&card.to_bytes()).unwrap(); + cmd.extend_from_slice(&card.into_be_bytes()).unwrap(); cmd.push(num_service as u8).unwrap(); for sc in service_code_list { let sc: [u8; 2] = sc.as_service_code().to_le_bytes(); @@ -228,7 +228,7 @@ impl Pn532 { return Err(Error::InvalidFrame); } if response[9] != 0 || response[10] != 0 { - return Err(Error::Status(StatusCode::from_repr(response[9]).unwrap())); + return Err(Error::Status(StatusCode::from_bits(response[9]))); } let mut k = 12; @@ -275,7 +275,7 @@ impl Pn532 { // command let mut cmd = heapless::Vec::::new(); cmd.push(FELICA_CMD_WRITE_WITHOUT_ENCRYPTION).unwrap(); - cmd.extend_from_slice(&card.to_bytes()).unwrap(); + cmd.extend_from_slice(&card.into_be_bytes()).unwrap(); cmd.push(num_service as u8).unwrap(); for sc in service_code_list { let sc = sc.as_service_code().to_le_bytes(); @@ -301,7 +301,7 @@ impl Pn532 { return Err(Error::InvalidFrame); } if response[9] != 0 || response[10] != 0 { - return Err(Error::Status(StatusCode::from_repr(response[9]).unwrap())); + return Err(Error::Status(StatusCode::from_bits(response[9]))); } Ok(()) } @@ -316,7 +316,7 @@ impl Pn532 { ) -> Result> { let mut cmd = [0u8; 9]; cmd[0] = FELICA_CMD_REQUEST_SYSTEM_CODE; - cmd[1..9].copy_from_slice(&card.to_bytes()); + cmd[1..9].copy_from_slice(&card.into_be_bytes()); let mut response = [0u8; 10 + 2 * 16]; let response_len = self.felica_send_command(&cmd, &mut response, Duration::from_millis(200))?; diff --git a/pn532/src/felica/types/idm.rs b/pn532/src/felica/types/idm.rs index 5a62929..e17bfa3 100644 --- a/pn532/src/felica/types/idm.rs +++ b/pn532/src/felica/types/idm.rs @@ -1,30 +1,8 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +use bitfields::bitfield; + +#[bitfield([u8; 8])] +#[derive(PartialEq, Eq)] pub struct IDm { pub manufacturer: u8, pub card_id: [u8; 7] -} - -impl IDm { - /// The raw 8 bytes in wire order (manufacturer, ic_type, card_id). - pub fn to_bytes(&self) -> [u8; 8] { - let mut data = [0u8; 8]; - data[0] = self.manufacturer; - data[1..].copy_from_slice(&self.card_id); - data - } -} - -impl From<[u8; 8]> for IDm { - fn from(value: [u8; 8]) -> Self { - Self { - manufacturer: value[0], - card_id: value[1..].try_into().unwrap() - } - } -} - -impl Into<[u8; 8]> for IDm { - fn into(self) -> [u8; 8] { - self.to_bytes() - } } \ No newline at end of file diff --git a/pn532/src/felica/types/mod.rs b/pn532/src/felica/types/mod.rs index 2e59c40..2e08047 100644 --- a/pn532/src/felica/types/mod.rs +++ b/pn532/src/felica/types/mod.rs @@ -2,20 +2,21 @@ mod polling; mod pmm; mod idm; +use bitfields::bitflag; pub use idm::*; pub use pmm::*; pub use polling::*; -use strum::FromRepr; - pub trait AsServiceCode { fn as_service_code(&self) -> u16; fn from_service_code(val: u16) -> Self; } -#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u16)] +#[derive(Debug, PartialEq, Eq)] +#[bitflag(u16)] pub enum ServiceCode { + #[base] + Unknown = 0, /// FeliCa Lite read service code (read without key). Read = 0x000B, /// FeliCa Lite write service code (write without key). @@ -28,7 +29,7 @@ impl AsServiceCode for ServiceCode { } fn from_service_code(val: u16) -> Self { - Self::from_repr(val).unwrap() + Self::from_bits(val) } } @@ -47,9 +48,11 @@ pub trait AsBlock { } /// FeliCa Lite system block numbers. -#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u16)] +#[derive(Debug, PartialEq, Eq)] +#[bitflag(u16)] pub enum Block { + #[base] + Unknown = 0, /// Random challenge block. RC = 0x8080, /// MAC block. @@ -80,4 +83,39 @@ impl AsBlock for u16 { // 2-byte element (access mode 0 = standard area, service list order 0). *self | 0x8000 } +} + + +/// https://www.sony.co.jp/en/Products/felica/business/tech-support/list.html +#[derive(Debug, PartialEq, Eq)] +#[bitflag(u8)] +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 +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum MobileICType { + V3(u8), // 0x14~0x1F + V2(u8), // 0x10~0x13 + V1(u8) // 0x06~0x07 } \ No newline at end of file diff --git a/pn532/src/felica/types/pmm.rs b/pn532/src/felica/types/pmm.rs index 4ef2fd5..b675551 100644 --- a/pn532/src/felica/types/pmm.rs +++ b/pn532/src/felica/types/pmm.rs @@ -1,42 +1,28 @@ use core::time::Duration; +use bitfields::bitfield; -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[bitfield([u8; 8])] +#[derive(PartialEq, Eq)] pub struct PMm { pub rom_type: u8, pub ic_type: u8, + _f1: u8, + _f2: u8, + _f3: u8, pub read_timeout: u8, pub write_timeout: u8, -} - -impl From<[u8; 8]> for PMm { - fn from(value: [u8; 8]) -> Self { - Self { - rom_type: value[0], - ic_type: value[1], - read_timeout: value[5], - write_timeout: value[6], - } - } + _f4: u8, } impl PMm { - pub fn to_bytes(&self) -> [u8; 8] { - let mut data = [0u8; 8]; - data[0] = self.rom_type; - data[1] = self.ic_type; - data[5] = self.read_timeout; - data[6] = self.write_timeout; - data - } - /// Maximum response time for a Read command over `block_len` blocks: pub fn get_read_timeout(&self, block_len: usize, margin: Option) -> Duration { - Self::response_time(self.read_timeout, block_len) + margin.unwrap_or(Duration::default()) + Self::response_time(self.read_timeout(), block_len) + margin.unwrap_or(Duration::default()) } /// Maximum response time for a Write command over `block_len` blocks. pub fn get_write_timeout(&self, block_len: usize, margin: Option) -> Duration { - Self::response_time(self.write_timeout, block_len) + margin.unwrap_or(Duration::default()) + Self::response_time(self.write_timeout(), block_len) + margin.unwrap_or(Duration::default()) } /// `T x [(B+1)*n + (A+1)] x 4^E`, with `T = 256*16/fc ~= 302.06 us`. diff --git a/pn532/src/felica/types/polling.rs b/pn532/src/felica/types/polling.rs index 821cdee..deb91f7 100644 --- a/pn532/src/felica/types/polling.rs +++ b/pn532/src/felica/types/polling.rs @@ -1,17 +1,17 @@ +use bitfields::bitflag; use super::{IDm, PMm}; -use strum::FromRepr; -#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq, Default)] -#[repr(u8)] +#[derive(Debug, PartialEq, Eq, Default)] +#[bitflag(u8)] pub enum PollingRequestCode { - NoRequest, + NoRequest = 0x00, #[default] - SystemCode, - CommunicationPerformance + SystemCode = 0x01, + CommunicationPerformance = 0x02 } -#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq, Default)] -#[repr(u8)] +#[derive(Debug, PartialEq, Eq, Default)] +#[bitflag(u8)] pub enum PollingTimeSlot { #[default] _1 = 0x00, diff --git a/pn532/src/tg/mod.rs b/pn532/src/tg/mod.rs index d52e3d9..acf1e89 100644 --- a/pn532/src/tg/mod.rs +++ b/pn532/src/tg/mod.rs @@ -42,7 +42,7 @@ impl Pn532 { return Ok(0); } if self.buffer[0] != 0 { - return Err(Error::Status(StatusCode::from_repr(self.buffer[0]).unwrap())); + return Err(Error::Status(StatusCode::from_bits(self.buffer[0]))); } let data_len = len - 1; let copy_len = data_len.min(buf.len()); @@ -68,7 +68,7 @@ impl Pn532 { let len = self.read_timeout(Duration::from_millis(3000))?; if len == 0 || self.buffer[0] != 0 { - return Err(Error::Status(StatusCode::from_repr(self.buffer[0]).unwrap())); + return Err(Error::Status(StatusCode::from_bits(self.buffer[0]))); } Ok(()) }