Finish pn532 crate

This commit is contained in:
2026-09-13 20:51:26 +08:00
parent 89dfed231f
commit 70194f98c1
23 changed files with 610 additions and 204 deletions
Binary file not shown.
+25 -18
View File
@@ -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<RST, IRQ, DELAY, B, const N: usize = 64>
@@ -16,7 +16,7 @@ where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
B: Interface<RST, IRQ, DELAY>,
{
pub(crate) interface: B,
pub(crate) in_listed_tag: u8,
@@ -31,7 +31,7 @@ where
RST: OutputPin,
IRQ: InputPin,
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
B: Interface<RST, IRQ, DELAY>,
{
/// 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<B::TransportError>> {
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<B::TransportError>> {
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<usize, Error<B::TransportError>> {
self.interface.read_response(&mut self.buffer, timeout.as_millis() as u16)
pub(crate) fn read_timeout(
&mut self,
timeout: Duration,
) -> Result<usize, Error<B::TransportError>> {
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<B::TransportError>> {
let pinstate = pinstate | (1 << PN532_GPIO_P32) | (1 << PN532_GPIO_P34);
pub fn write_gpio(&mut self, pin_state: u8) -> Result<(), Error<B::TransportError>> {
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<B::TransportError>> {
if len == 0 || (self.buffer[0] & 0x3F) != 0 {
@@ -190,8 +199,6 @@ where
}
}
/// Release the card.
pub fn release(&mut self) -> Result<(), Error<B::TransportError>> {
self.buffer[0] = PN532Command::InRelease.into_bits();
-13
View File
@@ -118,11 +118,7 @@ where
buf: &mut [u8],
timeout_ms: u16,
) -> Result<usize, Error<Self::TransportError>> {
// 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<I2C::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 {
+33 -45
View File
@@ -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<const U: usize>(
/// 2-key Triple DES-CBC MAC over `block_list` followed by `block_data`.
pub(crate) fn compute_mac(
&mut self,
session: &AuthSession,
input: &MacInput<U>
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::<TdesEde2>::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::<TdesEde2>::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::<TdesEde2>::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::<TdesEde2>::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())
}
}
@@ -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<RST, IRQ, DELAY, B, const N: usize> Pn532<RST, IRQ, DELAY, B, N>
where
@@ -9,7 +12,92 @@ where
DELAY: DelayNs,
B: Interface<RST, IRQ, DELAY>
{
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<B::TransportError>> {
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<B::TransportError>> {
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<B::TransportError>> {
self.write_block(
card,
&[FelicaLiteSBlock::CK],
&[**key]
)
}
pub fn set_ck_with_mac(&mut self, card: &CardSession, session: &AuthSession, key: &CardKey) -> Result<(), Error<B::TransportError>> {
self.write_with_mac(
card,
session,
FelicaLiteSBlock::CK,
&**key
)
}
pub fn set_ckv(&mut self, card: &CardSession, version: &CardKeyVersion) -> Result<(), Error<B::TransportError>> {
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<B::TransportError>> {
self.write_with_mac(
card,
session,
FelicaLiteSBlock::CKV,
&version.as_block()
)
}
pub fn get_ckv(&mut self, card: &CardSession) -> Result<CardKeyVersion, Error<B::TransportError>> {
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<MemoryConfig, Error<B::TransportError>> {
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<B::TransportError>> {
let block: [u8; 16] = config.into();
self.write_block(
card,
&[FelicaLiteSBlock::MemoryConfig],
&[block]
)
}
}
+52 -5
View File
@@ -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<B::TransportError>> {
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<B::TransportError>> {
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<const U: usize>(
&mut self,
card: &CardSession,
+8 -6
View File
@@ -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(())
}
}
@@ -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)
}
}
}
@@ -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
}
@@ -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,
}
@@ -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(),
}
}
}
+5 -2
View File
@@ -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 {
+2 -19
View File
@@ -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
+1 -1
View File
@@ -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 {
+1 -1
View File
@@ -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 {