mfrc522/
lib.rs

1//! Driver library for interfacing with the MFRC522 contacless communication IC,
2//! based on the [embedded-hal](https://docs.rs/embedded-hal/latest/embedded_hal/) traits.
3//!
4//! The MFRC522 is a *Proximity Coupling Device* (PCD) and communicates with a
5//! *Proximity Integrated Circuit Card* (PICC).
6//! The main purpose of the MFRC522 is to give the connected device
7//! (where we're running this driver) the ability to read and write data from/to the card.
8//!
9//! The MFRC522 supports 3 communication interfaces:
10//! - SPI
11//! - I2C
12//! - UART
13//!
14//! However, currently only SPI communication is implemented in this crate.
15//!
16//! # Quickstart
17//! ```rust
18//!# pub mod spi {
19//!#     use embedded_hal_1::spi::{self, SpiDevice, Operation};
20//!#     pub struct Spi;
21//!#     #[derive(Debug)]
22//!#     pub struct Error;
23//!#     impl spi::Error for Error {
24//!#         fn kind(&self) -> spi::ErrorKind { spi::ErrorKind::Other }
25//!#     }
26//!#     impl spi::ErrorType for Spi {
27//!#         type Error = Error;
28//!#     }
29//!#     impl SpiDevice for Spi {
30//!#         fn transaction(
31//!#             &mut self,
32//!#             operations: &mut [Operation<u8>]
33//!#         ) -> Result<(), Self::Error> { Ok(()) }
34//!#     }
35//!# }
36//! use mfrc522::comm::blocking::spi::SpiInterface;
37//! use mfrc522::Mfrc522;
38//!
39//! // Use your HAL to create an SPI device that implements the embedded-hal `SpiDevice` trait.
40//! // This device manages the SPI bus and CS pin.
41//! let spi = spi::Spi;
42//!
43//! let itf = SpiInterface::new(spi);
44//! let mut mfrc522 = Mfrc522::new(itf).init().unwrap();
45//!
46//! // The reported version is expected to be 0x91 or 0x92
47//! let mfrc522_version = mfrc522.version().unwrap();
48//! ```
49//!
50//! Take a look at [SpiInterface](comm::blocking::spi::SpiInterface) for options when creating
51//! the communication interface, and [Mfrc522] for information on the functions
52//! that are available after initialization.
53//!
54//! # Example applications
55//!
56//! - [Raspberry Pi 4](https://gitlab.com/jspngh/mfrc522/-/tree/main/examples/rpi4)
57//! - [Raspberry Pi Pico](https://gitlab.com/jspngh/mfrc522/-/tree/main/examples/rp2040)
58//! - [STM32L4](https://gitlab.com/jspngh/mfrc522/-/tree/main/examples/stm32l4)
59
60#![deny(unsafe_code, missing_docs)]
61#![cfg_attr(not(feature = "std"), no_std)]
62
63pub mod comm;
64mod error;
65mod picc;
66mod register;
67mod tests;
68mod util;
69
70pub use error::Error;
71pub use picc::Type;
72pub use register::RxGain;
73
74use comm::Interface;
75use register::*;
76use util::Sealed;
77
78/// Key used for MIFARE authentication
79pub type MifareKey = [u8; 6];
80
81/// The unique identifier returned by a PICC
82pub enum Uid {
83    /// Single sized UID, 4 bytes long
84    Single(GenericUid<4>),
85    /// Double sized UID, 7 bytes long
86    Double(GenericUid<7>),
87    /// Triple sized UID, 10 bytes long
88    Triple(GenericUid<10>),
89}
90
91impl Uid {
92    /// Get the UID as a byte slice
93    pub fn as_bytes(&self) -> &[u8] {
94        match self {
95            Uid::Single(u) => u.as_bytes(),
96            Uid::Double(u) => u.as_bytes(),
97            Uid::Triple(u) => u.as_bytes(),
98        }
99    }
100
101    /// Get the type of the PICC that returned the UID
102    pub fn get_type(&self) -> Type {
103        match self {
104            Uid::Single(u) => u.get_type(),
105            Uid::Double(u) => u.get_type(),
106            Uid::Triple(u) => u.get_type(),
107        }
108    }
109}
110
111/// An identifier that is generic over the size.
112///
113/// This is used internally in the [Uid] enum.
114pub struct GenericUid<const T: usize>
115where
116    [u8; T]: Sized,
117{
118    /// The UID can have 4, 7 or 10 bytes.
119    bytes: [u8; T],
120    /// The SAK (Select acknowledge) byte returned from the PICC after successful selection.
121    sak: picc::Sak,
122}
123
124impl<const T: usize> GenericUid<T> {
125    /// Create a GenericUid from a byte array and a SAK byte.
126    ///
127    /// You shouldn't typically need to use this function as an end-user.
128    /// Instead use the [Uid] returned by the [select](Mfrc522::select) function.
129    pub fn new(bytes: [u8; T], sak_byte: u8) -> Self {
130        Self {
131            bytes,
132            sak: picc::Sak::from(sak_byte),
133        }
134    }
135
136    /// Get the underlying bytes of the UID
137    pub fn as_bytes(&self) -> &[u8] {
138        &self.bytes
139    }
140
141    /// Is the PICC compliant?
142    pub fn is_compliant(&self) -> bool {
143        self.sak.is_compliant()
144    }
145
146    /// Get the type of the PICC
147    pub fn get_type(&self) -> Type {
148        self.sak.get_type()
149    }
150}
151
152/// Answer To reQuest type A
153pub struct AtqA {
154    bytes: [u8; 2],
155}
156
157/// Implemented by the different states of the MFRC522 driver.
158///
159/// This trait cannot be implemented outside of this crate.
160pub trait State: Sealed {}
161
162/// The MFRC522 driver starts in this state and needs to be initialized before it can be used.
163pub enum Uninitialized {}
164/// The MFRC522 driver is ready for use.
165pub enum Initialized {}
166
167impl State for Uninitialized {}
168impl State for Initialized {}
169impl Sealed for Uninitialized {}
170impl Sealed for Initialized {}
171
172/// MFRC522 driver
173pub struct Mfrc522<COMM: Interface, S: State> {
174    comm: COMM,
175    state: core::marker::PhantomData<S>,
176}
177
178impl<COMM: Interface> Mfrc522<COMM, Uninitialized> {
179    /// Create a new MFRC522 driver from the communication interface.
180    pub fn new(comm: COMM) -> Self {
181        Self {
182            comm,
183            state: core::marker::PhantomData,
184        }
185    }
186}
187
188impl<COMM: Interface, S: State> Mfrc522<COMM, S> {
189    /// Release the underlying communication channel
190    pub fn release(self) -> COMM {
191        self.comm
192    }
193}
194
195// The driver can transition to the `Initialized` state using this function
196impl<E, COMM: Interface<Error = E>> Mfrc522<COMM, Uninitialized> {
197    /// Initialize the MFRC522.
198    ///
199    /// This needs to be called before you can do any other operation.
200    pub fn init(mut self) -> Result<Mfrc522<COMM, Initialized>, Error<E>> {
201        self.reset()?;
202        self.write(Register::TxModeReg, 0x00)?;
203        self.write(Register::RxModeReg, 0x00)?;
204        // Reset ModWidthReg to default value
205        self.write(Register::ModWidthReg, 0x26)?;
206
207        // Configure the timer, so we can get a timeout if something goes wrong
208        // when communicating with a PICC:
209        // - Set timer to start automatically at the end of the transmission
210        self.write(Register::TModeReg, 0x80)?;
211        // - Configure the prescaler to determine the timer frequency:
212        //   f_timer = 13.56 MHz / (2 * TPreScaler + 1)
213        //   so for 40kHz frequency (25μs period), TPreScaler = 0x0A9
214        self.write(Register::TPrescalerReg, 0xA9)?;
215        // - Set the reload value to determine the timeout
216        //   for a 25ms timeout, we need a value of 1000 = 0x3E8
217        self.write(Register::TReloadRegHigh, 0x03)?;
218        self.write(Register::TReloadRegLow, 0xE8)?;
219
220        // TODO: may not be necessary?
221        self.write(Register::TxASKReg, FORCE_100_ASK)?;
222        // Set preset value of CRC coprocessor according to ISO 14443-3 part 6.2.4
223        self.write(Register::ModeReg, (0x3f & (!0b11)) | 0b01)?;
224        // Enable antenna
225        self.rmw(Register::TxControlReg, |b| b | 0b11)?;
226
227        Ok(Mfrc522 {
228            comm: self.comm,
229            state: core::marker::PhantomData,
230        })
231    }
232}
233
234// The public functions can only be used after initializing
235impl<E, COMM: Interface<Error = E>> Mfrc522<COMM, Initialized> {
236    /// Sends a REQuest type A to nearby PICCs
237    pub fn reqa(&mut self) -> Result<AtqA, Error<E>> {
238        // NOTE REQA is a short frame (7 bits)
239        let fifo_data = self.transceive(&[picc::Command::ReqA as u8], 7, 0)?;
240        if fifo_data.valid_bytes != 2 || fifo_data.valid_bits != 0 {
241            Err(Error::IncompleteFrame)
242        } else {
243            Ok(AtqA {
244                bytes: fifo_data.buffer,
245            })
246        }
247    }
248
249    /// Sends a Wake UP type A to nearby PICCs
250    pub fn wupa(&mut self) -> Result<AtqA, Error<E>> {
251        // NOTE WUPA is a short frame (7 bits)
252        let fifo_data = self.transceive(&[picc::Command::WupA as u8], 7, 0)?;
253        if fifo_data.valid_bytes != 2 || fifo_data.valid_bits != 0 {
254            Err(Error::IncompleteFrame)
255        } else {
256            Ok(AtqA {
257                bytes: fifo_data.buffer,
258            })
259        }
260    }
261
262    /// Sends command to enter HALT state
263    pub fn hlta(&mut self) -> Result<(), Error<E>> {
264        let mut buffer: [u8; 4] = [picc::Command::HltA as u8, 0, 0, 0];
265        let crc = self.calculate_crc(&buffer[..2])?;
266        buffer[2..].copy_from_slice(&crc);
267
268        // The standard says:
269        //   If the PICC responds with any modulation during a period of 1 ms
270        //   after the end of the frame containing the HLTA command,
271        //   this response shall be interpreted as 'not acknowledge'.
272        // We interpret that this way: only Error::Timeout is a success.
273        match self.transceive::<0>(&buffer, 0, 0) {
274            Err(Error::Timeout) => Ok(()),
275            Ok(_) => Err(Error::Nak),
276            Err(e) => Err(e),
277        }
278    }
279
280    /// Selects a PICC in the READY state
281    // TODO add optional UID to select a specific PICC
282    pub fn select(&mut self, atqa: &AtqA) -> Result<Uid, Error<E>> {
283        // check for proprietary anticollision
284        if (atqa.bytes[0] & 0b00011111).count_ones() != 1 {
285            return Err(Error::Proprietary);
286        }
287
288        // clear `ValuesAfterColl`
289        self.rmw(Register::CollReg, |b| b & !0x80)?;
290
291        let mut cascade_level: u8 = 0;
292        let mut uid_bytes: [u8; 10] = [0u8; 10];
293        let mut uid_idx: usize = 0;
294
295        let sak = 'cascade: loop {
296            let cmd = match cascade_level {
297                0 => picc::Command::SelCl1,
298                1 => picc::Command::SelCl2,
299                2 => picc::Command::SelCl3,
300                _ => unreachable!(),
301            };
302            let mut known_bits = 0;
303            let mut tx = [0u8; 9];
304            tx[0] = cmd as u8;
305
306            // TODO: limit to 32 iterations (as spec dictates)
307            'anticollision: loop {
308                let tx_last_bits = known_bits % 8;
309                let tx_bytes = 2 + known_bits / 8;
310                let end = tx_bytes as usize + if tx_last_bits > 0 { 1 } else { 0 };
311                tx[1] = (tx_bytes << 4) + tx_last_bits;
312
313                // Tell transceive the only send `tx_last_bits` of the last byte
314                // and also to put the first received bit at location `tx_last_bits`.
315                // This makes it easier to append the received bits to the uid (in `tx`).
316                match self.transceive::<5>(&tx[0..end], tx_last_bits, tx_last_bits) {
317                    Ok(fifo_data) => {
318                        fifo_data.copy_bits_to(&mut tx[2..=6], known_bits)?;
319                        break 'anticollision;
320                    }
321                    Err(Error::Collision) => {
322                        let coll_reg = self.read(Register::CollReg)?;
323                        if coll_reg & (1 << 5) != 0 {
324                            // CollPosNotValid
325                            return Err(Error::Collision);
326                        }
327                        let mut coll_pos = coll_reg & 0x1F;
328                        if coll_pos == 0 {
329                            coll_pos = 32;
330                        }
331                        if coll_pos < known_bits {
332                            // No progress
333                            return Err(Error::Collision);
334                        }
335                        let fifo_data = self.fifo_data::<5>()?;
336                        fifo_data.copy_bits_to(&mut tx[2..=6], known_bits)?;
337                        known_bits = coll_pos;
338
339                        // Set the bit of collision position to 1
340                        let count = known_bits % 8;
341                        let check_bit = (known_bits - 1) % 8;
342                        let index: usize =
343                            1 + (known_bits / 8) as usize + if count != 0 { 1 } else { 0 };
344                        tx[index] |= 1 << check_bit;
345                    }
346                    Err(e) => return Err(e),
347                }
348            }
349
350            // send select
351            tx[1] = 0x70; // NVB: 7 valid bytes
352            tx[6] = tx[2] ^ tx[3] ^ tx[4] ^ tx[5]; // BCC
353
354            let crc = self.calculate_crc(&tx[..7])?;
355            tx[7..].copy_from_slice(&crc);
356
357            let rx = self.transceive::<3>(&tx[0..9], 0, 0)?;
358            if rx.valid_bytes != 3 || rx.valid_bits != 0 {
359                return Err(Error::IncompleteFrame);
360            }
361
362            let sak = picc::Sak::from(rx.buffer[0]);
363            let crc_a = &rx.buffer[1..];
364            let crc_verify = self.calculate_crc(&rx.buffer[..1])?;
365            if crc_a != crc_verify {
366                return Err(Error::Crc);
367            }
368
369            if !sak.is_complete() {
370                uid_bytes[uid_idx..uid_idx + 3].copy_from_slice(&tx[3..6]);
371                uid_idx += 3;
372                cascade_level += 1;
373            } else {
374                uid_bytes[uid_idx..uid_idx + 4].copy_from_slice(&tx[2..6]);
375                break 'cascade sak;
376            }
377        };
378
379        match cascade_level {
380            0 => Ok(Uid::Single(GenericUid {
381                bytes: uid_bytes[0..4].try_into().unwrap(),
382                sak,
383            })),
384            1 => Ok(Uid::Double(GenericUid {
385                bytes: uid_bytes[0..7].try_into().unwrap(),
386                sak,
387            })),
388            2 => Ok(Uid::Triple(GenericUid {
389                bytes: uid_bytes,
390                sak,
391            })),
392            _ => unreachable!(),
393        }
394    }
395
396    /// Switch off the MIFARE Crypto1 unit.
397    ///
398    /// Must be done after communication with an authenticated PICC
399    pub fn stop_crypto1(&mut self) -> Result<(), Error<E>> {
400        self.rmw(Register::Status2Reg, |b| b & !0x08)
401    }
402
403    /// Perform MIFARE authentication with a PICC.
404    ///
405    /// In order to successfully authenticate, you need to specify the correct key for the block
406    /// you are trying to read/write.
407    pub fn mf_authenticate(
408        &mut self,
409        uid: &Uid,
410        block: u8,
411        key: &MifareKey,
412    ) -> Result<(), Error<E>> {
413        // stop any ongoing command
414        self.command(Command::Idle)?;
415        // clear all interrupt flags
416        self.write(Register::ComIrqReg, 0x7f)?;
417        // flush FIFO buffer
418        self.fifo_flush()?;
419        // clear bit framing
420        self.write(Register::BitFramingReg, 0)?;
421
422        let mut tx_buffer = [0u8; 12];
423        tx_buffer[0] = picc::Command::MfAuthKeyA as u8;
424        tx_buffer[1] = block;
425        tx_buffer[2..8].copy_from_slice(key);
426        match uid {
427            Uid::Single(u) => tx_buffer[8..12].copy_from_slice(&u.bytes[0..4]),
428            Uid::Double(u) => tx_buffer[8..12].copy_from_slice(&u.bytes[0..4]),
429            Uid::Triple(u) => tx_buffer[8..12].copy_from_slice(&u.bytes[0..4]),
430        };
431        // write data to transmit to the FIFO buffer
432        self.write_many(Register::FIFODataReg, &tx_buffer)?;
433
434        // signal command
435        self.command(Command::MFAuthent)?;
436
437        let mut irq;
438        loop {
439            irq = self.read(Register::ComIrqReg)?;
440
441            if irq & (ERR_IRQ | IDLE_IRQ) != 0 {
442                break;
443            } else if irq & TIMER_IRQ != 0 {
444                return Err(Error::Timeout);
445            }
446        }
447
448        self.check_error_register()?;
449        Ok(())
450    }
451
452    /// Send the MIFARE Read command to the PICC to read the given block.
453    ///
454    /// This should be done after [authentication](Mfrc522::mf_authenticate).
455    pub fn mf_read(&mut self, block: u8) -> Result<[u8; 16], Error<E>> {
456        let mut tx = [picc::Command::MfRead as u8, block, 0u8, 0u8];
457
458        let crc = self.calculate_crc(&tx[0..2])?;
459        tx[2..].copy_from_slice(&crc);
460
461        let rx = self.transceive::<18>(&tx, 0, 0)?.buffer;
462
463        // verify CRC
464        let crc = self.calculate_crc(&rx[..16])?;
465        if crc != rx[16..] {
466            return Err(Error::Crc);
467        }
468        Ok(rx[..16].try_into().unwrap())
469    }
470
471    /// Send the MIFARE Write command to the PICC to write data to the given block.
472    ///
473    /// This should be done after [authentication](Mfrc522::mf_authenticate).
474    pub fn mf_write(&mut self, block: u8, data: [u8; 16]) -> Result<(), Error<E>> {
475        let mut cmd = [picc::Command::MfWrite as u8, block, 0, 0];
476        let crc = self.calculate_crc(&cmd[0..2])?;
477        cmd[2..].copy_from_slice(&crc);
478        let fifo_data = self.transceive::<1>(&cmd, 0, 0)?;
479        if fifo_data.valid_bytes != 1 || fifo_data.valid_bits != 4 {
480            return Err(Error::Nak);
481        }
482
483        let mut tx = [0u8; 18];
484        let crc = self.calculate_crc(&data)?;
485        tx[..16].copy_from_slice(&data);
486        tx[16..].copy_from_slice(&crc);
487        let fifo_data = self.transceive::<1>(&tx, 0, 0)?;
488        if fifo_data.valid_bytes != 1 || fifo_data.valid_bits != 4 {
489            return Err(Error::Nak);
490        }
491
492        Ok(())
493    }
494
495    /// Returns the version reported by the MFRC522
496    pub fn version(&mut self) -> Result<u8, Error<E>> {
497        self.read(Register::VersionReg)
498    }
499
500    /// Has a card been detected?
501    pub fn new_card_present(&mut self) -> Result<AtqA, Error<E>> {
502        self.write(Register::TxModeReg, 0x00)?;
503        self.write(Register::RxModeReg, 0x00)?;
504        self.write(Register::ModWidthReg, 0x26)?;
505
506        self.reqa()
507    }
508
509    /// Sets the antenna gain of the receiver
510    ///
511    /// Setting this to a high value could help if you have issues communicating with a card.
512    /// This should increase the *sensitivity* of the antenna, so it is able to detect weaker signals.
513    pub fn set_antenna_gain(&mut self, gain: RxGain) -> Result<(), Error<E>> {
514        self.write(Register::RFCfgReg, gain.into())
515    }
516
517    /// Perform a low-level transceive operation, which both transmits and receives data.
518    ///
519    /// This function is generic over the maximum number of bytes that can be received.
520    ///
521    /// It is used to implement higher-level functions like [Mfrc522::mf_read] and [Mfrc522::mf_write].
522    /// Typically, you don't need to call this function directly,
523    /// but it was made part of the public interface to allow for custom commands.
524    pub fn transceive<const RX: usize>(
525        &mut self,
526        // the data to be sent
527        tx_buffer: &[u8],
528        // number of bits in the last byte that will be transmitted
529        tx_last_bits: u8,
530        // bit position for the first received bit to be stored in the FIFO buffer
531        rx_align_bits: u8,
532    ) -> Result<FifoData<RX>, Error<E>>
533    where
534        [u8; RX]: Sized,
535    {
536        // stop any ongoing command
537        self.command(Command::Idle)?;
538
539        // clear all interrupt flags
540        self.write(Register::ComIrqReg, 0x7f)?;
541
542        // flush FIFO buffer
543        self.fifo_flush()?;
544
545        // write data to transmit to the FIFO buffer
546        self.write_many(Register::FIFODataReg, tx_buffer)?;
547
548        // signal command
549        self.command(Command::Transceive)?;
550
551        // configure short frame and start transmission
552        self.write(
553            Register::BitFramingReg,
554            (1 << 7) | ((rx_align_bits & 0b0111) << 4) | (tx_last_bits & 0b0111),
555        )?;
556
557        // TODO timeout when connection to the MFRC522 is lost (?)
558        // wait for transmission + reception to complete
559        loop {
560            let irq = self.read(Register::ComIrqReg)?;
561
562            if irq & (RX_IRQ | ERR_IRQ | IDLE_IRQ) != 0 {
563                break;
564            } else if irq & TIMER_IRQ != 0 {
565                return Err(Error::Timeout);
566            }
567        }
568
569        self.check_error_register()?;
570        self.fifo_data()
571    }
572}
573
574// The private functions are implemented for all states.
575impl<E, COMM: Interface<Error = E>, S: State> Mfrc522<COMM, S> {
576    fn calculate_crc(&mut self, data: &[u8]) -> Result<[u8; 2], Error<E>> {
577        // stop any ongoing command
578        self.command(Command::Idle)?;
579
580        // clear the CRC_IRQ interrupt flag
581        self.write(Register::DivIrqReg, 1 << 2)?;
582
583        // flush FIFO buffer
584        self.fifo_flush()?;
585
586        // write data to transmit to the FIFO buffer
587        self.write_many(Register::FIFODataReg, data)?;
588
589        self.command(Command::CalcCRC)?;
590
591        // Wait for the CRC calculation to complete.
592        let mut irq;
593        for _ in 0..5000 {
594            irq = self.read(Register::DivIrqReg)?;
595
596            if irq & CRC_IRQ != 0 {
597                self.command(Command::Idle)?;
598                let crc = [
599                    self.read(Register::CRCResultRegLow)?,
600                    self.read(Register::CRCResultRegHigh)?,
601                ];
602
603                return Ok(crc);
604            }
605        }
606        Err(Error::Timeout)
607    }
608
609    fn check_error_register(&mut self) -> Result<(), Error<E>> {
610        let err = self.read(Register::ErrorReg)?;
611
612        if err & PROTOCOL_ERR != 0 {
613            Err(Error::Protocol)
614        } else if err & PARITY_ERR != 0 {
615            Err(Error::Parity)
616        } else if err & CRC_ERR != 0 {
617            Err(Error::Crc)
618        } else if err & COLL_ERR != 0 {
619            Err(Error::Collision)
620        } else if err & BUFFER_OVFL != 0 {
621            Err(Error::BufferOverflow)
622        } else if err & TEMP_ERR != 0 {
623            Err(Error::Overheating)
624        } else if err & WR_ERR != 0 {
625            Err(Error::Wr)
626        } else {
627            Ok(())
628        }
629    }
630
631    /// Get the data from the internal FIFO buffer
632    fn fifo_data<const RX: usize>(&mut self) -> Result<FifoData<RX>, Error<E>> {
633        let mut buffer = [0u8; RX];
634        let mut valid_bytes = 0;
635        let mut valid_bits = 0;
636
637        if RX > 0 {
638            valid_bytes = self.read(Register::FIFOLevelReg)? as usize;
639            if valid_bytes > RX {
640                return Err(Error::NoRoom);
641            }
642            if valid_bytes > 0 {
643                self.read_many(Register::FIFODataReg, &mut buffer[0..valid_bytes])?;
644                valid_bits = (self.read(Register::ControlReg)? & 0x07) as usize;
645            }
646        }
647
648        Ok(FifoData {
649            buffer,
650            valid_bytes,
651            valid_bits,
652        })
653    }
654
655    /// Flush the internal FIFO buffer
656    fn fifo_flush(&mut self) -> Result<(), Error<E>> {
657        self.write(Register::FIFOLevelReg, FLUSH_BUFFER)
658    }
659
660    /// Request to execute the given command
661    fn command(&mut self, command: Command) -> Result<(), Error<E>> {
662        self.write(Register::CommandReg, command.into())
663    }
664
665    /// Perform a software reset
666    fn reset(&mut self) -> Result<(), Error<E>> {
667        self.command(Command::SoftReset)?;
668        while self.read(Register::CommandReg)? & POWER_DOWN != 0 {}
669        Ok(())
670    }
671}
672
673// Convenience wrappers for the `Interface` methods
674impl<E, COMM: Interface<Error = E>, S: State> Mfrc522<COMM, S> {
675    fn read(&mut self, reg: Register) -> Result<u8, Error<E>> {
676        self.comm.read(reg).map_err(Error::Comm)
677    }
678
679    fn read_many<'b>(&mut self, reg: Register, buffer: &'b mut [u8]) -> Result<&'b [u8], Error<E>> {
680        self.comm.read_many(reg, buffer).map_err(Error::Comm)
681    }
682
683    fn write(&mut self, reg: Register, val: u8) -> Result<(), Error<E>> {
684        self.comm.write(reg, val).map_err(Error::Comm)
685    }
686
687    fn write_many(&mut self, reg: Register, bytes: &[u8]) -> Result<(), Error<E>> {
688        self.comm.write_many(reg, bytes).map_err(Error::Comm)
689    }
690
691    fn rmw<F>(&mut self, reg: Register, f: F) -> Result<(), Error<E>>
692    where
693        F: FnOnce(u8) -> u8,
694    {
695        self.comm.rmw(reg, f).map_err(Error::Comm)
696    }
697}
698
699/// Data read from the internal FIFO buffer
700#[derive(Debug, PartialEq)]
701pub struct FifoData<const L: usize> {
702    /// The contents of the FIFO buffer
703    pub buffer: [u8; L],
704    /// The number of valid bytes in the buffer
705    pub valid_bytes: usize,
706    /// The number of valid bits in the last byte
707    pub valid_bits: usize,
708}
709
710impl<const L: usize> FifoData<L> {
711    /// Copies FIFO data to destination buffer.
712    /// Assumes the FIFO data is aligned properly to append directly to the current known bits.
713    /// Returns the number of valid bits in the destination buffer after copy.
714    fn copy_bits_to<E>(&self, dst: &mut [u8], dst_valid_bits: u8) -> Result<u8, Error<E>> {
715        if self.valid_bytes == 0 {
716            // nothing to copy
717            return Ok(dst_valid_bits);
718        }
719
720        let dst_valid_bytes = dst_valid_bits / 8;
721        let dst_valid_last_bits = dst_valid_bits % 8;
722        let mask: u8 = 0xFF << dst_valid_last_bits;
723        let mut idx = dst_valid_bytes as usize;
724        dst[idx] = (self.buffer[0] & mask) | (dst[idx] & !mask);
725        idx += 1;
726        let len = self.valid_bytes - 1;
727        if len + idx > dst.len() {
728            // TODO: this should not happen, but has been reported nonetheless...
729            return Err(Error::NoRoom);
730        }
731        if len > 0 {
732            dst[idx..idx + len].copy_from_slice(&self.buffer[1..=len]);
733        }
734        Ok(dst_valid_bits + (len * 8) as u8 + self.valid_bits as u8)
735    }
736}