use bitfield instead of strum
This commit is contained in:
+2
-3
@@ -3,7 +3,6 @@ name = "pn532"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
description = "A no_std, embedded-hal driver for the NXP PN532 NFC controller (I2C interface)"
|
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"]
|
keywords = ["nfc", "pn532", "embedded-hal", "no-std", "i2c"]
|
||||||
categories = ["embedded", "no-std", "hardware-support"]
|
categories = ["embedded", "no-std", "hardware-support"]
|
||||||
|
|
||||||
@@ -20,9 +19,9 @@ defmt = { version = "~1.1", optional = true }
|
|||||||
hex = { version = "~0.4", default-features = false }
|
hex = { version = "~0.4", default-features = false }
|
||||||
des = { version = "~0.9", default-features = false }
|
des = { version = "~0.9", default-features = false }
|
||||||
cbc = { version = "~0.2", default-features = false, features = ["block-padding"] }
|
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"
|
heapless = "~0.9"
|
||||||
thiserror = { version = "~2", default-features = false }
|
thiserror = { version = "~2", default-features = false }
|
||||||
|
bitfields = "3.1.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
@@ -31,4 +30,4 @@ alloc = ["defmt/alloc", "hex/alloc", "heapless/alloc"]
|
|||||||
mifare-classic = []
|
mifare-classic = []
|
||||||
iso14443a = []
|
iso14443a = []
|
||||||
felica = []
|
felica = []
|
||||||
felica-lite-s = ["felica"]
|
felica-lite-s = ["felica"]
|
||||||
|
|||||||
+1
-1
@@ -199,7 +199,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
/// return error if current buffer contains an error code
|
/// return error if current buffer contains an error code
|
||||||
pub(crate) fn validate_buffer(&self, len: usize) -> Result<(), Error<B::TransportError>> {
|
pub(crate) fn validate_buffer(&self, len: usize) -> Result<(), Error<B::TransportError>> {
|
||||||
if len == 0 || (self.buffer[0] & 0x3F) != 0 {
|
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 {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -1,6 +1,6 @@
|
|||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
use bitfields::bitflag;
|
||||||
use defmt::Debug2Format;
|
use defmt::Debug2Format;
|
||||||
use strum::FromRepr;
|
|
||||||
|
|
||||||
/// Driver-level error type, generic over the transport (I2C) error.
|
/// Driver-level error type, generic over the transport (I2C) error.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
|
||||||
@@ -40,9 +40,11 @@ impl<E: Debug> defmt::Format for Error<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[derive(FromRepr, Debug, Clone, Copy, PartialEq, Eq)]
|
#[bitflag(u8)]
|
||||||
pub enum StatusCode {
|
pub enum StatusCode {
|
||||||
|
#[base]
|
||||||
|
Unknown = 0x00,
|
||||||
TimeOut = 0x01,
|
TimeOut = 0x01,
|
||||||
CRC = 0x02,
|
CRC = 0x02,
|
||||||
Parity = 0x03,
|
Parity = 0x03,
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
let mut j = 0;
|
let mut j = 0;
|
||||||
cmd[j] = FELICA_CMD_REQUEST_SERVICE;
|
cmd[j] = FELICA_CMD_REQUEST_SERVICE;
|
||||||
j += 1;
|
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;
|
j += 8;
|
||||||
cmd[j] = num_node as u8;
|
cmd[j] = num_node as u8;
|
||||||
j += 1;
|
j += 1;
|
||||||
@@ -153,7 +153,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
pub fn felica_request_response(&mut self, card: &PollingResponse) -> Result<u8, Error<B::TransportError>> {
|
pub fn felica_request_response(&mut self, card: &PollingResponse) -> Result<u8, Error<B::TransportError>> {
|
||||||
let mut cmd = [0u8; 9];
|
let mut cmd = [0u8; 9];
|
||||||
cmd[0] = FELICA_CMD_REQUEST_RESPONSE;
|
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 mut response = [0u8; 10];
|
||||||
let response_len = self.felica_send_command(&cmd, &mut response, Duration::from_millis(200))?;
|
let response_len = self.felica_send_command(&cmd, &mut response, Duration::from_millis(200))?;
|
||||||
@@ -202,7 +202,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
// command
|
// command
|
||||||
let mut cmd = heapless::Vec::<u8, COMMAND_SIZE>::new();
|
let mut cmd = heapless::Vec::<u8, COMMAND_SIZE>::new();
|
||||||
cmd.push(FELICA_CMD_READ_WITHOUT_ENCRYPTION).unwrap();
|
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();
|
cmd.push(num_service as u8).unwrap();
|
||||||
for sc in service_code_list {
|
for sc in service_code_list {
|
||||||
let sc: [u8; 2] = sc.as_service_code().to_le_bytes();
|
let sc: [u8; 2] = sc.as_service_code().to_le_bytes();
|
||||||
@@ -228,7 +228,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
return Err(Error::InvalidFrame);
|
return Err(Error::InvalidFrame);
|
||||||
}
|
}
|
||||||
if response[9] != 0 || response[10] != 0 {
|
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;
|
let mut k = 12;
|
||||||
@@ -275,7 +275,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
// command
|
// command
|
||||||
let mut cmd = heapless::Vec::<u8, COMMAND_SIZE>::new();
|
let mut cmd = heapless::Vec::<u8, COMMAND_SIZE>::new();
|
||||||
cmd.push(FELICA_CMD_WRITE_WITHOUT_ENCRYPTION).unwrap();
|
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();
|
cmd.push(num_service as u8).unwrap();
|
||||||
for sc in service_code_list {
|
for sc in service_code_list {
|
||||||
let sc = sc.as_service_code().to_le_bytes();
|
let sc = sc.as_service_code().to_le_bytes();
|
||||||
@@ -301,7 +301,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
return Err(Error::InvalidFrame);
|
return Err(Error::InvalidFrame);
|
||||||
}
|
}
|
||||||
if response[9] != 0 || response[10] != 0 {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -316,7 +316,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
) -> Result<usize, Error<B::TransportError>> {
|
) -> Result<usize, Error<B::TransportError>> {
|
||||||
let mut cmd = [0u8; 9];
|
let mut cmd = [0u8; 9];
|
||||||
cmd[0] = FELICA_CMD_REQUEST_SYSTEM_CODE;
|
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 mut response = [0u8; 10 + 2 * 16];
|
||||||
let response_len = self.felica_send_command(&cmd, &mut response, Duration::from_millis(200))?;
|
let response_len = self.felica_send_command(&cmd, &mut response, Duration::from_millis(200))?;
|
||||||
|
|||||||
@@ -1,30 +1,8 @@
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
use bitfields::bitfield;
|
||||||
|
|
||||||
|
#[bitfield([u8; 8])]
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct IDm {
|
pub struct IDm {
|
||||||
pub manufacturer: u8,
|
pub manufacturer: u8,
|
||||||
pub card_id: [u8; 7]
|
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -2,20 +2,21 @@ mod polling;
|
|||||||
mod pmm;
|
mod pmm;
|
||||||
mod idm;
|
mod idm;
|
||||||
|
|
||||||
|
use bitfields::bitflag;
|
||||||
pub use idm::*;
|
pub use idm::*;
|
||||||
pub use pmm::*;
|
pub use pmm::*;
|
||||||
pub use polling::*;
|
pub use polling::*;
|
||||||
|
|
||||||
use strum::FromRepr;
|
|
||||||
|
|
||||||
pub trait AsServiceCode {
|
pub trait AsServiceCode {
|
||||||
fn as_service_code(&self) -> u16;
|
fn as_service_code(&self) -> u16;
|
||||||
fn from_service_code(val: u16) -> Self;
|
fn from_service_code(val: u16) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[repr(u16)]
|
#[bitflag(u16)]
|
||||||
pub enum ServiceCode {
|
pub enum ServiceCode {
|
||||||
|
#[base]
|
||||||
|
Unknown = 0,
|
||||||
/// FeliCa Lite read service code (read without key).
|
/// FeliCa Lite read service code (read without key).
|
||||||
Read = 0x000B,
|
Read = 0x000B,
|
||||||
/// FeliCa Lite write service code (write without key).
|
/// FeliCa Lite write service code (write without key).
|
||||||
@@ -28,7 +29,7 @@ impl AsServiceCode for ServiceCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn from_service_code(val: u16) -> Self {
|
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.
|
/// FeliCa Lite system block numbers.
|
||||||
#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
#[repr(u16)]
|
#[bitflag(u16)]
|
||||||
pub enum Block {
|
pub enum Block {
|
||||||
|
#[base]
|
||||||
|
Unknown = 0,
|
||||||
/// Random challenge block.
|
/// Random challenge block.
|
||||||
RC = 0x8080,
|
RC = 0x8080,
|
||||||
/// MAC block.
|
/// MAC block.
|
||||||
@@ -80,4 +83,39 @@ impl AsBlock for u16 {
|
|||||||
// 2-byte element (access mode 0 = standard area, service list order 0).
|
// 2-byte element (access mode 0 = standard area, service list order 0).
|
||||||
*self | 0x8000
|
*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
|
||||||
}
|
}
|
||||||
@@ -1,42 +1,28 @@
|
|||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
use bitfields::bitfield;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[bitfield([u8; 8])]
|
||||||
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct PMm {
|
pub struct PMm {
|
||||||
pub rom_type: u8,
|
pub rom_type: u8,
|
||||||
pub ic_type: u8,
|
pub ic_type: u8,
|
||||||
|
_f1: u8,
|
||||||
|
_f2: u8,
|
||||||
|
_f3: u8,
|
||||||
pub read_timeout: u8,
|
pub read_timeout: u8,
|
||||||
pub write_timeout: u8,
|
pub write_timeout: u8,
|
||||||
}
|
_f4: 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],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PMm {
|
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:
|
/// Maximum response time for a Read command over `block_len` blocks:
|
||||||
pub fn get_read_timeout(&self, block_len: usize, margin: Option<Duration>) -> Duration {
|
pub fn get_read_timeout(&self, block_len: usize, margin: Option<Duration>) -> 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.
|
/// Maximum response time for a Write command over `block_len` blocks.
|
||||||
pub fn get_write_timeout(&self, block_len: usize, margin: Option<Duration>) -> Duration {
|
pub fn get_write_timeout(&self, block_len: usize, margin: Option<Duration>) -> 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`.
|
/// `T x [(B+1)*n + (A+1)] x 4^E`, with `T = 256*16/fc ~= 302.06 us`.
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
|
use bitfields::bitflag;
|
||||||
use super::{IDm, PMm};
|
use super::{IDm, PMm};
|
||||||
use strum::FromRepr;
|
|
||||||
|
|
||||||
#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq, Default)]
|
#[derive(Debug, PartialEq, Eq, Default)]
|
||||||
#[repr(u8)]
|
#[bitflag(u8)]
|
||||||
pub enum PollingRequestCode {
|
pub enum PollingRequestCode {
|
||||||
NoRequest,
|
NoRequest = 0x00,
|
||||||
#[default]
|
#[default]
|
||||||
SystemCode,
|
SystemCode = 0x01,
|
||||||
CommunicationPerformance
|
CommunicationPerformance = 0x02
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(FromRepr, Copy, Clone, Debug, PartialEq, Eq, Default)]
|
#[derive(Debug, PartialEq, Eq, Default)]
|
||||||
#[repr(u8)]
|
#[bitflag(u8)]
|
||||||
pub enum PollingTimeSlot {
|
pub enum PollingTimeSlot {
|
||||||
#[default]
|
#[default]
|
||||||
_1 = 0x00,
|
_1 = 0x00,
|
||||||
|
|||||||
+2
-2
@@ -42,7 +42,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
return Ok(0);
|
return Ok(0);
|
||||||
}
|
}
|
||||||
if self.buffer[0] != 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 data_len = len - 1;
|
||||||
let copy_len = data_len.min(buf.len());
|
let copy_len = data_len.min(buf.len());
|
||||||
@@ -68,7 +68,7 @@ impl<B: Interface, const N: usize> Pn532<B, N> {
|
|||||||
|
|
||||||
let len = self.read_timeout(Duration::from_millis(3000))?;
|
let len = self.read_timeout(Duration::from_millis(3000))?;
|
||||||
if len == 0 || self.buffer[0] != 0 {
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user