From bfac90f7205f0bcbec9e2bc6ba99cb066d86e59c Mon Sep 17 00:00:00 2001 From: Alan Carvalho de Assis Date: Sat, 6 Aug 2016 08:45:52 -0600 Subject: [PATCH] Add MFRC522 RFID ISO14443 and Mifare transceiver driver --- drivers/wireless/Kconfig | 31 + drivers/wireless/Make.defs | 4 + drivers/wireless/mfrc522.c | 1616 ++++++++++++++++++++++++++++++ drivers/wireless/mfrc522.h | 430 ++++++++ include/nuttx/wireless/mfrc522.h | 116 +++ 5 files changed, 2197 insertions(+) create mode 100644 drivers/wireless/mfrc522.c create mode 100644 drivers/wireless/mfrc522.h create mode 100644 include/nuttx/wireless/mfrc522.h diff --git a/drivers/wireless/Kconfig b/drivers/wireless/Kconfig index e978ef6e82..42eda1941c 100644 --- a/drivers/wireless/Kconfig +++ b/drivers/wireless/Kconfig @@ -73,6 +73,37 @@ config WL_NRF24L01_RXFIFO_LEN endif # WL_NRF24L01_RXSUPPORT endif # WL_NRF24L01 +config WL_MFRC522 + bool "NXP MFRC522 ISO14443/Mifare Transceiver" + default n + select SPI + ---help--- + This options adds driver support for the MFRC522 ISO14443/Mifare chip. + +if WL_MFRC522 + +config MFRC522_SPI_FREQ + int "SPI frequency for MFRC522" + default 1000000 + depends on WL_MFRC522 + +config MFRC522_DEBUG + bool "Enable MFRC522 debug" + default n + depends on WL_MFRC522 + +config MFRC522_DEBUG_TX + bool "trace TX frames" + default n + depends on MFRC522_DEBUG + +config MFRC522_DEBUG_RX + bool "trace RX frames" + default n + depends on MFRC522_DEBUG + +endif # WL_MFRC522 + config WL_PN532 bool "pn532 NFC-chip support" default n diff --git a/drivers/wireless/Make.defs b/drivers/wireless/Make.defs index 6322a5c0b0..48b356e7ac 100644 --- a/drivers/wireless/Make.defs +++ b/drivers/wireless/Make.defs @@ -55,6 +55,10 @@ ifeq ($(CONFIG_WL_CC3000),y) include wireless$(DELIM)cc3000$(DELIM)Make.defs endif +ifeq ($(CONFIG_WL_MFRC522),y) +CSRCS += mfrc522.c +endif + ifeq ($(CONFIG_WL_PN532),y) CSRCS += pn532.c endif diff --git a/drivers/wireless/mfrc522.c b/drivers/wireless/mfrc522.c new file mode 100644 index 0000000000..26d02b1286 --- /dev/null +++ b/drivers/wireless/mfrc522.c @@ -0,0 +1,1616 @@ +/**************************************************************************** + * drivers/wireless/mfrc522.c + * + * Copyright(C) 2016 Uniquix Ltda. All rights reserved. + * Author: Alan Carvalho de Assis + * + * This driver is based on Arduino library for MFRC522 from Miguel + * Balboa released into the public domain: + * https://github.com/miguelbalboa/rfid/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mfrc522.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifdef CONFIG_MFRC522_DEBUG +# define mfrc522err _err +# define mfrc522info _info +#else +# ifdef CONFIG_CPP_HAVE_VARARGS +# define mfrc522err(x...) +# define mfrc522info(x...) +# else +# define mfrc522err (void) +# define mfrc522info (void) +# endif +#endif + +#ifdef CONFIG_MFRC522_DEBUG_TX +# define tracetx errdumpbuffer +#else +# define tracetx(x...) +#endif + +#ifdef CONFIG_MFRC522_DEBUG_RX +# define tracerx errdumpbuffer +#else +# define tracerx(x...) +#endif + +#define FRAME_SIZE(f) (sizeof(struct mfrc522_frame) + f->len + 2) +#define FRAME_POSTAMBLE(f) (f->data[f->len + 1]) + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline void mfrc522_configspi(FAR struct spi_dev_s *spi); +static void mfrc522_lock(FAR struct spi_dev_s *spi); +static void mfrc522_unlock(FAR struct spi_dev_s *spi); + +/* Character driver methods */ + +static int mfrc522_open(FAR struct file *filep); +static int mfrc522_close(FAR struct file *filep); +static ssize_t mfrc522_read(FAR struct file *, FAR char *, size_t); +static ssize_t mfrc522_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen); +static int mfrc522_ioctl(FAR struct file *filep, int cmd, + unsigned long arg); + +uint8_t mfrc522_readu8(FAR struct mfrc522_dev_s *dev, uint8_t regaddr); +void mfrc522_writeu8(FAR struct mfrc522_dev_s *dev, uint8_t regaddr, + FAR uint8_t regval); +void mfrc522_writeblk(FAR struct mfrc522_dev_s *dev, uint8_t regaddr, + uint8_t *regval, int length); +void mfrc522_readblk(FAR struct mfrc522_dev_s *dev, uint8_t regaddr, + FAR uint8_t *regval, int length, uint8_t rxalign); + +void mfrc522_softreset(FAR struct mfrc522_dev_s *dev); + +int mfrc522_picc_select(FAR struct mfrc522_dev_s *dev, + FAR struct picc_uid_s *uid, uint8_t validbits); + +/* IRQ Handling TODO: +static int mfrc522_irqhandler(FAR int irq, FAR void *context, FAR void* dev); +static inline int mfrc522_attachirq(FAR struct mfrc522_dev_s *dev, xcpt_t isr); +*/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct file_operations g_mfrc522fops = +{ + mfrc522_open, + mfrc522_close, + mfrc522_read, + mfrc522_write, + 0, + mfrc522_ioctl +#ifndef CONFIG_DISABLE_POLL + , 0 +#endif +#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS + , 0 +#endif +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void mfrc522_lock(FAR struct spi_dev_s *spi) +{ + (void)SPI_LOCK(spi, true); + + SPI_SETMODE(spi, SPIDEV_MODE0); + SPI_SETBITS(spi, 8); + (void)SPI_HWFEATURES(spi, 0); + (void)SPI_SETFREQUENCY(spi, CONFIG_MFRC522_SPI_FREQ); +} + +static void mfrc522_unlock(FAR struct spi_dev_s *spi) +{ + (void)SPI_LOCK(spi, false); +} + +static inline void mfrc522_configspi(FAR struct spi_dev_s *spi) +{ + /* Configure SPI for the MFRC522 module. */ + + SPI_SETMODE(spi, SPIDEV_MODE0); + SPI_SETBITS(spi, 8); + (void)SPI_HWFEATURES(spi, 0); + (void)SPI_SETFREQUENCY(spi, CONFIG_MFRC522_SPI_FREQ); +} + +static inline void mfrc522_select(struct mfrc522_dev_s *dev) +{ + SPI_SELECT(dev->spi, SPIDEV_WIRELESS, true); +} + +static inline void mfrc522_deselect(struct mfrc522_dev_s *dev) +{ + SPI_SELECT(dev->spi, SPIDEV_WIRELESS, false); +} + +/**************************************************************************** + * Name: mfrc522_readu8 + * + * Description: + * Read a byte from a register address. + * + * Input Parameters: + * + * Returned Value: the read byte from the register + * + ****************************************************************************/ + +uint8_t mfrc522_readu8(FAR struct mfrc522_dev_s *dev, uint8_t regaddr) +{ + uint8_t regval; + uint8_t address = (0x80 | (regaddr & 0x7E)); + + mfrc522_lock(dev->spi); + mfrc522_select(dev); + SPI_SEND(dev->spi, address); + regval = SPI_SEND(dev->spi, 0); + mfrc522_deselect(dev); + mfrc522_unlock(dev->spi); + + tracerx("read", regval, 1); + return regval; +} + +/**************************************************************************** + * Name: mfrc522_write8 + * + * Description: + * Write a byte to a register address. + * + * Input Parameters: + * + * Returned Value: + * + ****************************************************************************/ + +void mfrc522_writeu8(FAR struct mfrc522_dev_s *dev, uint8_t regaddr, + FAR uint8_t regval) +{ + mfrc522_lock(dev->spi); + mfrc522_select(dev); + SPI_SEND(dev->spi, regaddr & 0x7E); + SPI_SEND(dev->spi, regval); + mfrc522_deselect(dev); + mfrc522_unlock(dev->spi); + + tracerx("write", ®val, 1); +} + +/**************************************************************************** + * Name: mfrc522_readblk + * + * Description: + * Read a block of bytes from a register address. Align the bit positions of + * regval[0] from rxalign..7. + * + * Input Parameters: + * + * Returned Value: none + * + ****************************************************************************/ + +void mfrc522_readblk(FAR struct mfrc522_dev_s *dev, uint8_t regaddr, + FAR uint8_t *regval, int length, uint8_t rxalign) +{ + uint8_t i = 0; + uint8_t address = (0x80 | (regaddr & 0x7E)); + + mfrc522_lock(dev->spi); + mfrc522_select(dev); + + /* Inform the MFRC522 the address we want to read */ + + SPI_SEND(dev->spi, address); + + while (i < length) + { + if (i == 0 && rxalign) + { + uint8_t mask = 0; + uint8_t value; + uint8_t j; + + for (j = rxalign; j <= 7; j++) + { + mask |= (1 << j); + } + + /* Read the first byte */ + + value = SPI_SEND(dev->spi, address); + + /* Apply mask to current regval[0] with the read value */ + + regval[0] = (regval[0] & ~mask) | (value & mask); + } + else + { + /* Read the remaining bytes */ + + regval[i] = SPI_SEND(dev->spi, address); + } + i++; + } + + /* Read the last byte. Send 0 to stop reading (it maybe wrong, 1 byte out) */ + + regval[i] = SPI_SEND(dev->spi, 0); + + mfrc522_deselect(dev); + mfrc522_unlock(dev->spi); + + tracerx("readblk", regval, size); +} + +/**************************************************************************** + * Name: mfrc522_writeblk + * + * Description: + * Write a block of bytes to a register address. + * + * Input Parameters: + * + * Returned Value: none + * + ****************************************************************************/ + +void mfrc522_writeblk(FAR struct mfrc522_dev_s *dev, uint8_t regaddr, + uint8_t *regval, int length) +{ + uint8_t address = (regaddr & 0x7E); + + mfrc522_lock(dev->spi); + mfrc522_select(dev); + + /* Inform the MFRC522 the address we want write to */ + + SPI_SEND(dev->spi, address); + + /* Send the block of bytes */ + + SPI_SNDBLOCK(dev->spi, regval, length); + + mfrc522_deselect(dev); + mfrc522_unlock(dev->spi); + + tracerx("writeblk", regval, size); +} + +/**************************************************************************** + * Name: mfrc522_calc_crc + * + * Description: + * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. + * + * Input Parameters: + * + * Returned Value: OK or -ETIMEDOUT + * + ****************************************************************************/ + +int mfrc522_calc_crc(FAR struct mfrc522_dev_s *dev, uint8_t *buffer, + int length, uint8_t *result) +{ + struct timespec tstart; + struct timespec tend; + + /* Stop any command in execution */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_IDLE_CMD); + + /* Clear the CRCIRq interrupt request bit */ + + mfrc522_writeu8(dev, MFRC522_DIV_IRQ_REG, MFRC522_CRC_IRQ); + + /* Flush all bytes in the FIFO */ + + mfrc522_writeu8(dev, MFRC522_FIFO_LEVEL_REG, MFRC522_FLUSH_BUFFER); + + /* Write data to the FIFO */ + + mfrc522_writeblk(dev, MFRC522_FIFO_DATA_REG, buffer, length); + + /* Start the calculation */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_CALC_CRC_CMD); + + /* Wait for CRC completion or 200ms time-out */ + + clock_gettime(CLOCK_REALTIME, &tstart); + tstart.tv_nsec += 200000; + if (tstart.tv_nsec >= 1000 * 1000 * 1000) + { + tstart.tv_sec++; + tstart.tv_nsec -= 1000 * 1000 * 1000; + } + + while(1) + { + uint8_t irqreg; + + irqreg = mfrc522_readu8(dev, MFRC522_DIV_IRQ_REG); + if ( irqreg & MFRC522_CRC_IRQ) + { + break; + } + + /* Get time now */ + + clock_gettime(CLOCK_REALTIME, &tend); + + if ((tend.tv_sec > tstart.tv_sec) && (tend.tv_nsec > tstart.tv_nsec)) + { + return -ETIMEDOUT; + } + } + + /* Stop calculating CRC for new content of FIFO */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_IDLE_CMD); + + result[0] = mfrc522_readu8(dev, MFRC522_CRC_RESULT_REGL); + result[1] = mfrc522_readu8(dev, MFRC522_CRC_RESULT_REGH); + + return OK; +} + +/**************************************************************************** + * Name: mfrc522_comm_picc + * + * Description: + * Transfers data to the MFRC522 FIFO, executes a command, waits for + * completion and transfers data back from the FIFO. + * CRC validation can only be done if back_data and back_len are specified. + * + * Input Parameters: + * + * Returned Value: OK or -ETIMEDOUT + * + ****************************************************************************/ + +int mfrc522_comm_picc(FAR struct mfrc522_dev_s *dev, uint8_t command, + uint8_t waitirq, uint8_t *send_data, uint8_t send_len, + uint8_t *back_data, uint8_t *back_len, + uint8_t *validbits, uint8_t rxalign, bool checkcrc) +{ + int ret; + uint8_t errors; + uint8_t vbits; + uint8_t value; + struct timespec tstart; + struct timespec tend; + + /* Prepare values for BitFramingReg */ + + uint8_t txlastbits = validbits ? *validbits : 0; + uint8_t bitframing = (rxalign << 4) + txlastbits; + + /* Stop any active command */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_IDLE_CMD); + + /* Clear all seven interrupt request bits */ + + value = mfrc522_readu8(dev, MFRC522_COM_IRQ_REG); + mfrc522_writeu8(dev, MFRC522_COM_IRQ_REG, value | MFRC522_COM_IRQ_MASK); + + /* Flush all bytes in the FIFO */ + + mfrc522_writeu8(dev, MFRC522_FIFO_LEVEL_REG, MFRC522_FLUSH_BUFFER); + + /* Write data to FIFO */ + + mfrc522_writeblk(dev, MFRC522_FIFO_DATA_REG, send_data, send_len); + + /* Bit adjustments */ + + mfrc522_writeu8(dev, MFRC522_BIT_FRAMING_REG, bitframing); + + /* Execute command */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, command); + + /* We setup the TAuto flag in the mfrc522_init() then we could use the + * internal MFC522 Timer to detect timeout, but because there could be some + * hardware fault, let us to use a NuttX timeout as well. + */ + + clock_gettime(CLOCK_REALTIME, &tstart); + tstart.tv_nsec += 200000; + if (tstart.tv_nsec >= 1000 * 1000 * 1000) + { + tstart.tv_sec++; + tstart.tv_nsec -= 1000 * 1000 * 1000; + } + + /* If it is a Transceive command, then start transmittion */ + + if (command == MFRC522_TRANSCV_CMD) + { + value = mfrc522_readu8(dev, MFRC522_BIT_FRAMING_REG); + mfrc522_writeu8(dev, MFRC522_BIT_FRAMING_REG, value | MFRC522_START_SEND); + } + + /* Wait for the command to complete */ + + while (1) + { + uint8_t irqsreg; + + irqsreg = mfrc522_readu8(dev, MFRC522_COM_IRQ_REG); + + /* If at least an of selected IRQ happened */ + + if (irqsreg & waitirq) + { + break; + } + + /* Timer expired */ + + if (irqsreg & MFRC522_TIMER_IRQ) + { + return -ETIMEDOUT; + } + + /* Get time now */ + + clock_gettime(CLOCK_REALTIME, &tend); + + if ((tend.tv_sec > tstart.tv_sec) && (tend.tv_nsec > tstart.tv_nsec)) + { + return -ETIMEDOUT; + } + } + + /* Read error register to verify if there are any issue */ + + errors = mfrc522_readu8(dev, MFRC522_ERROR_REG); + + /* Check for Protocol error */ + + if (errors & (MFRC522_PROTO_ERR)) + { + return -EPROTO; + } + + /* Check for Parity and Buffer Overflow errors */ + + if (errors & (MFRC522_PARITY_ERR | MFRC522_BUF_OVFL_ERR)) + { + return -EIO; + } + + /* Check collision error */ + + if (errors & MFRC522_COLL_ERR) + { + return -EBUSY; /* should it be EAGAIN ? */ + } + + /* If the caller wants data back, get it from the MFRC522 */ + + if (back_data && back_len) + { + uint8_t nbytes; + + /* Number of bytes in the FIFO */ + + nbytes = mfrc522_readu8(dev, MFRC522_FIFO_LEVEL_REG); + + /* Returned more bytes than the expected */ + + if (nbytes > *back_len) + { + return -ENOMEM; + } + + *back_len = nbytes; + + /* Read the data from FIFO */ + + mfrc522_readblk(dev, MFRC522_FIFO_DATA_REG, back_data, nbytes, rxalign); + + /* RxLastBits[2:0] indicates the number of valid bits received */ + + vbits = mfrc522_readu8(dev, MFRC522_CONTROL_REG) + & MFRC522_RX_LAST_BITS_MASK; + + if (validbits) + { + *validbits = vbits; + } + } + + /* Perform CRC_A validation if requested */ + + if (back_data && back_len && checkcrc) + { + uint8_t ctrlbuf[2]; + + /* In this case a MIFARE Classic NAK is not OK */ + + if (*back_len == 1 && vbits == 4) + { + return -EACCES; + } + + /* We need the CRC_A value or all 8 bits of the last byte */ + + if (*back_len < 2 || vbits != 0) + { + return -EPERM; + } + + /* Verify CRC_A */ + + ret = mfrc522_calc_crc(dev, &back_data[0], *back_len - 2, &ctrlbuf[0]); + if (ret != OK) + { + return ret; + } + + if ((back_data[*back_len - 2] != ctrlbuf[0]) || + (back_data[*back_len - 1] != ctrlbuf[1])) + { + return -EFAULT; + } + } + + return OK; +} + +/**************************************************************************** + * Name: mfrc522_transcv_data + * + * Description: + * Executes the Transceive command + * + * Input Parameters: + * + * Returned Value: OK or -ETIMEDOUT + * + ****************************************************************************/ + +int mfrc522_transcv_data(FAR struct mfrc522_dev_s *dev, uint8_t *senddata, + uint8_t sendlen, uint8_t *backdata, uint8_t *backlen, + uint8_t *validbits, uint8_t rxalign, bool check_crc) +{ + uint8_t waitirq = MFRC522_RX_IRQ | MFRC522_IDLE_IRQ; + + return mfrc522_comm_picc(dev, MFRC522_TRANSCV_CMD, waitirq, senddata, + sendlen, backdata, backlen, validbits, rxalign, + check_crc); +} + +/**************************************************************************** + * Name: mfrc522_picc_reqa_wupa + * + * Description: + * Transmits REQA or WUPA commands + * + * Input Parameters: + * + * Returned Value: OK or -ETIMEDOUT + * + ****************************************************************************/ + +int mfrc522_picc_reqa_wupa(FAR struct mfrc522_dev_s *dev, uint8_t command, + uint8_t *buffer, uint8_t length) +{ + uint8_t validbits; + uint8_t value; + int status; + + if (!buffer || length < 2) + { + return -EINVAL; + } + + /* Force clear of received bits if a collision is detected */ + + value = mfrc522_readu8(dev, MFRC522_COLL_REG); + mfrc522_writeu8(dev, MFRC522_COLL_REG, value & MFRC522_VALUES_AFTER_COLL); + + validbits = 7; + status = mfrc522_transcv_data(dev, &command, 1, buffer, &length, &validbits, + 0, false); + + /* For REQA and WUPA we need to transmit only 7 bits */ + + if (status != OK) + { + return status; + } + + /* ATQA must be exactly 16 bits */ + + if (length != 2 || validbits != 0) + { + return -EAGAIN; + } + + mfrc522info("buffer[0]=0x%02X | buffer[1]=0x%02X\n", buffer[0], buffer[1]); + return OK; +} + +/**************************************************************************** + * Name: mfrc522_picc_request_a + * + * Description: + * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to + * READY and prepare for anticollision or selection. + * + * Input Parameters: + * + * Returned Value: OK or -ETIMEDOUT + * + ****************************************************************************/ + +int mfrc522_picc_request_a(FAR struct mfrc522_dev_s *dev, uint8_t *buffer, + uint8_t length) +{ + return mfrc522_picc_reqa_wupa(dev, PICC_CMD_REQA, buffer, length); +} + +/**************************************************************************** + * Name: mfrc522_picc_detect + * + * Description: + * Detects if a Contactless Card is near + * + * Input Parameters: + * + * Returned Value: OK or -ETIMEDOUT + * + ****************************************************************************/ + +int mfrc522_picc_detect(FAR struct mfrc522_dev_s *dev) +{ + int ret; + uint8_t buffer_atqa[2]; + uint8_t length = sizeof(buffer_atqa); + + /* Send a REQA command */ + + ret = mfrc522_picc_request_a(dev, buffer_atqa, length); + return (ret == OK || ret == -EBUSY); +} + +/**************************************************************************** + * Name: mfrc522_picc_select + * + * Description: + * Selects a near Card and read its UID. + * + * Input Parameters: + * + * Returned Value: OK or -ETIMEDOUT + * + ****************************************************************************/ + +int mfrc522_picc_select(FAR struct mfrc522_dev_s *dev, + FAR struct picc_uid_s *uid, uint8_t validbits) +{ + bool uid_complete; + bool select_done; + bool use_cascade_tag; + uint8_t cascade_level = 1; + int result; + uint8_t i; + uint8_t value; + uint8_t count; + + /* The first index in uid->data[] that is used in the current Cascade Level */ + + uint8_t uid_index; + + /* The number of known UID bits in the current Cascade Level. */ + + uint8_t curr_level_known_bits; + + /* The SELECT/ANTICOLLISION uses a 7 byte standard frame + 2 bytes CRC_A */ + + uint8_t buffer[9]; + + /* The number of bytes used in the buffer, number bytes on FIFO */ + + uint8_t buffer_used; + + /* Used to defines the bit position for the first bit received */ + + uint8_t rxalign; + + /* The number of valid bits in the last transmitted byte. */ + + uint8_t txlastbits; + + uint8_t *resp_buf; + uint8_t resp_len; + + /* Sanity check */ + + if (validbits > 80) + { + return -EINVAL; + } + + /* Force clear of received bits if a collision is detected */ + + value = mfrc522_readu8(dev, MFRC522_COLL_REG); + mfrc522_writeu8(dev, MFRC522_COLL_REG, value & MFRC522_VALUES_AFTER_COLL); + + /* Repeat cascade level loop until we have a complete UID */ + + uid_complete = false; + while (!uid_complete) + { + uint8_t bytes_to_copy; + + /* Set the Cascade Level in the SEL byte, find out if we need to use the + * Cascade Tag in byte 2. + */ + + switch (cascade_level) + { + case 1: + buffer[0] = PICC_CMD_SEL_CL1; + uid_index = 0; + + /* When we know that the UID has more than 4 bytes */ + + use_cascade_tag = validbits && (uid->size > 4); + break; + + case 2: + buffer[0] = PICC_CMD_SEL_CL2; + uid_index = 3; + + /* When we know that the UID has more than 7 bytes */ + + use_cascade_tag = validbits && (uid->size > 7); + break; + + case 3: + buffer[0] = PICC_CMD_SEL_CL3; + uid_index = 6; + use_cascade_tag = false; + break; + + default: + return -EIO; /* Internal error */ + } + + /* How many UID bits are known in this Cascade Level? */ + + curr_level_known_bits = validbits - (8 * uid_index); + if (curr_level_known_bits < 0) + { + curr_level_known_bits = 0; + } + + /* Copy the known bits from uid->uid_data[] to buffer[] */ + + i = 2; /* destination index in buffer[] */ + if (use_cascade_tag) + { + buffer[i++] = PICC_CMD_CT; + } + + /* Number of bytes needed to represent the known bits for this level */ + + bytes_to_copy = curr_level_known_bits / 8 + + (curr_level_known_bits % 8 ? 1 : 0); + + if (bytes_to_copy) + { + /* Max 4 bytes in each Cascade Level. Only 3 left if we use the + * Cascade Tag. + */ + + uint8_t max_bytes = use_cascade_tag ? 3 : 4; + + if (bytes_to_copy > max_bytes) + { + bytes_to_copy = max_bytes; + } + + for (count = 0; count < bytes_to_copy; count++) + { + buffer[i++] = uid->uid_data[uid_index + count]; + } + } + + /* Now that the data has been copied we need to include the 8 bits in CT + * in curr_level_known_bits. + */ + + if (use_cascade_tag) + { + curr_level_known_bits += 8; + } + + /* Repeat anti collision loop until we can transmit all UID bits + BCC + * and receive a SAK - max 32 iterations. + */ + + select_done = false; + while (!select_done) + { + /* Find out how many bits and bytes to send and receive. */ + + if (curr_level_known_bits >= 32) + { + /* All UID bits in this Cascade Level are known. This is a + * SELECT. + */ + + /* NVB - Number of Valid Bits: Seven whole bytes */ + + buffer[1] = 0x70; + + /* Calculate BCC - Block Check Character */ + + buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; + + /* Calculate CRC_A */ + + result = mfrc522_calc_crc(dev, buffer, 7, &buffer[7]); + if (result != OK) + { + return result; + } + + txlastbits = 0; /* 0 => All 8 bits are valid. */ + buffer_used = 9; + + /* Store response in the last 3 bytes of buffer (BCC and CRC_A - + * not needed after tx). + */ + + resp_buf = &buffer[6]; + resp_len = 3; + } + else + { + /* This is an ANTICOLLISION */ + + txlastbits = curr_level_known_bits % 8; + + /* Number of whole bytes in the UID part. */ + + count = curr_level_known_bits / 8; + i = 2 + count; + + /* NVB - Number of Valid Bits */ + + buffer[1] = (i << 4) + txlastbits; + buffer_used = i + (txlastbits ? 1 : 0); + + /* Store response in the unused part of buffer */ + + resp_buf = &buffer[i]; + resp_len = sizeof(buffer) - i; + } + + /* Set bit adjustments */ + + rxalign = txlastbits; + mfrc522_writeu8(dev, MFRC522_BIT_FRAMING_REG, + (rxalign << 4) + txlastbits); + + /* Transmit the buffer and receive the response */ + + result = mfrc522_transcv_data(dev, buffer, buffer_used, resp_buf, + &resp_len, &txlastbits, rxalign, false); + + /* More than one PICC in the field => collision */ + + if (result == -EBUSY) + { + uint8_t coll_pos; + uint8_t coll_reg = mfrc522_readu8(dev, MFRC522_COLL_REG); + + /* CollPosNotValid */ + + if (coll_reg & 0x20) + { + /* Without a valid collision position we cannot continue */ + + return -EBUSY; + } + + coll_pos = coll_reg & 0x1F; /* Values 0-31, 0 means bit 32. */ + if (coll_pos == 0) + { + coll_pos = 32; + } + + if (coll_pos <= curr_level_known_bits) + { + /* No progress - should not happen */ + + return -EIO; + } + + /* Choose the PICC with the bit set. */ + + curr_level_known_bits = coll_pos; + + /* The bit to modify */ + + count = (curr_level_known_bits - 1) % 8; + + /* First byte is index 0. */ + + i = 1 + (curr_level_known_bits / 8) + (count ? 1 : 0); + buffer[i] |= (1 << count); + } + else if (result != OK) + { + return result; + } + else /* OK */ + { + /* This was a SELECT. */ + + if (curr_level_known_bits >= 32) + { + /* No more collision */ + + select_done = true; + } + else + { + /* This was an ANTICOLLISION. */ + /* We have all 32 bits of the UID in this Cascade Level */ + + curr_level_known_bits = 32; + + /* Run loop again to do the SELECT */ + } + } + } + + /* We do not check the CBB - it was constructed by us above. */ + /* Copy the found UID bytes from buffer[] to uid->uid_data[] */ + + i = (buffer[2] == PICC_CMD_CT) ? 3 : 2; /* source index in buffer[] */ + bytes_to_copy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; + + for (count = 0; count < bytes_to_copy; count++) + { + uid->uid_data[uid_index + count] = buffer[i++]; + } + + /* Check response SAK (Select Acknowledge) */ + + if (resp_len != 3 || txlastbits != 0) + { + /* SAK must be exactly 24 bits (1 byte + CRC_A). */ + + return -EIO; + } + + /* Verify CRC_A - do our own calculation and store the control in + * buffer[2..3] - those bytes are not needed anymore. + */ + + result = mfrc522_calc_crc(dev, resp_buf, 1, &buffer[2]); + if (result != OK) + { + return result; + } + + /* Is it correct */ + + if ((buffer[2] != resp_buf[1]) || (buffer[3] != resp_buf[2])) + { + return -EINVAL; + } + + /* Cascade bit set - UID not complete yes */ + + if (resp_buf[0] & 0x04) + { + cascade_level++; + } + else + { + uid_complete = true; + uid->sak = resp_buf[0]; + } + } + + /* Set correct uid->size */ + + uid->size = 3 * cascade_level + 1; + + return OK; +} + +/**************************************************************************** + * Name: mfrc522_softreset + * + * Description: + * Send a software reset command + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: none + * + ****************************************************************************/ + +void mfrc522_softreset(FAR struct mfrc522_dev_s *dev) +{ + /* Send a software reset command */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_SOFTRST_CMD); + + /* Wait the internal state machine to initialize */ + + usleep(50000); + + /* Wait for the PowerDown bit in COMMAND_REG to be cleared */ + + while (mfrc522_readu8(dev, MFRC522_COMMAND_REG) & MFRC522_POWER_DOWN); +} + +/**************************************************************************** + * Name: mfrc522_enableantenna + * + * Description: + * Turns the antenna on by enabling the pins TX1 and TX2 + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: none + * + ****************************************************************************/ + +void mfrc522_enableantenna(FAR struct mfrc522_dev_s *dev) +{ + uint8_t value = mfrc522_readu8(dev, MFRC522_TX_CTRL_REG); + + if ((value & (MFRC522_TX1_RF_EN | MFRC522_TX2_RF_EN)) != 0x03) + { + mfrc522_writeu8(dev, MFRC522_TX_CTRL_REG, value | 0x03); + } +} + +/**************************************************************************** + * Name: mfrc522_disableantenna + * + * Description: + * Turns the antenna off cutting the signals on TX1 and TX2 + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: none + * + ****************************************************************************/ + +void mfrc522_disableantenna(FAR struct mfrc522_dev_s *dev) +{ + uint8_t value = mfrc522_readu8(dev, MFRC522_TX_CTRL_REG); + + value &= ~(MFRC522_TX1_RF_EN | MFRC522_TX2_RF_EN); + mfrc522_writeu8(dev, MFRC522_TX_CTRL_REG, value); +} + +/**************************************************************************** + * Name: mfrc522_getfwversion + * + * Description: + * Read the MFRC522 firmware version. + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: the firmware version byte + * + ****************************************************************************/ + +uint8_t mfrc522_getfwversion(FAR struct mfrc522_dev_s *dev) +{ + return mfrc522_readu8(dev, MFRC522_VERSION_REG); +} + +/**************************************************************************** + * Name: mfrc522_getantennagain + * + * Description: + * Read the MFRC522 receiver gain (RxGain). + * See 9.3.3.6 / table 98 in MFRC522 datasheet. + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: none + * + ****************************************************************************/ + +uint8_t mfrc522_getantennagain(FAR struct mfrc522_dev_s *dev) +{ + return mfrc522_readu8(dev, MFRC522_RF_CFG_REG) & MFRC522_RX_GAIN_MASK; +} + +/**************************************************************************** + * Name: mfrc522_setantennagain + * + * Description: + * Set the MFRC522 receiver gain (RxGain) to value value specified in mask. + * See 9.3.3.6 / table 98 in MFRC522 datasheet. + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: none + * + ****************************************************************************/ + +void mfrc522_setantennagain(FAR struct mfrc522_dev_s *dev, uint8_t mask) +{ + uint8_t value; + + if ((value = mfrc522_getantennagain(dev)) != mask) + { + mfrc522_writeu8(dev, MFRC522_RF_CFG_REG, value & ~MFRC522_RX_GAIN_MASK); + mfrc522_writeu8(dev, MFRC522_RF_CFG_REG, mask & MFRC522_RX_GAIN_MASK); + } +} + +/**************************************************************************** + * Name: mfrc522_init + * + * Description: + * Initializes the MFRC522 chip + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: none + * + ****************************************************************************/ + +void mfrc522_init(FAR struct mfrc522_dev_s *dev) +{ + /* Force a reset */ + + mfrc522_softreset(dev); + + /* We need a timeout if something when communicating with a TAG case + * something goes wrong. f_timer = 13.56 MHz / (2*TPreScaler+1) where: + * TPreScaler = [TPrescaler_Hi:Tprescaler_Lo]. Tprescaler_Hi are the four + * low bits in TmodeReg. Tprescaler_Lo is on TPrescalerReg. + * + * TAuto=1; timer starts automatically at the end of the transmission in + * all communication modes at all speeds. + */ + + mfrc522_writeu8(dev, MFRC522_TMODE_REG, MFRC522_TAUTO); + + /* TPreScaler = TModeReg[3..0]:TPrescalerReg, ie: 0x0A9 = 169 => + * f_timer=40kHz, then the timer period will be 25us. + */ + + mfrc522_writeu8(dev, MFRC522_TPRESCALER_REG, 0xA9); + + /* Reload timer with 0x3E8 = 1000, ie 25ms before timeout. */ + + mfrc522_writeu8(dev, MFRC522_TRELOAD_REGH, 0x06); + mfrc522_writeu8(dev, MFRC522_TRELOAD_REGL, 0xE8); + + /* Force 100% ASK modulation independent of the ModGsPReg setting */ + + mfrc522_writeu8(dev, MFRC522_TX_ASK_REG, MFRC522_FORCE_100ASK); + + /* Set the preset value for the CRC to 0x6363 (ISO 14443-3 part 6.2.4) */ + + mfrc522_writeu8(dev, MFRC522_MODE_REG, 0x3D); + + /* Enable the Antenna pins */ + + mfrc522_enableantenna(dev); +} + +/**************************************************************************** + * Name: mfrc522_selftest + * + * Description: + * Executes a self-test of the MFRC522 chip + * + * See 16.1.1 in the MFRC522 datasheet + * + * Input Parameters: a pointer to mfrc522_dev_s structure + * + * Returned Value: none + * + ****************************************************************************/ + +int mfrc522_selftest(FAR struct mfrc522_dev_s *dev) +{ + uint8_t i; + uint8_t result[64]; + uint8_t zeros[25] = {0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; + + /* Execute a software reset */ + + mfrc522_softreset(dev); + + /* Flush the FIFO buffer */ + + mfrc522_writeu8(dev, MFRC522_FIFO_LEVEL_REG, MFRC522_FLUSH_BUFFER); + + /* Clear the internal buffer by writing 25 bytes 0x00 */ + + mfrc522_writeblk(dev, MFRC522_FIFO_DATA_REG, zeros, 25); + + /* Transfer to internal buffer */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_MEM_CMD); + + /* Enable self-test */ + + mfrc522_writeu8(dev, MFRC522_AUTOTEST_REG, MFRC522_SELFTEST_EN); + + /* Write 0x00 to FIFO buffer */ + + mfrc522_writeu8(dev, MFRC522_FIFO_DATA_REG, 0x00); + + /* Start self-test by issuing the CalcCRC command */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_CALC_CRC_CMD); + + /* Wait for self-test to complete */ + + for (i = 0; i < 255; i++) + { + uint8_t n; + + n = mfrc522_readu8(dev, MFRC522_DIV_IRQ_REG); + if (n & MFRC522_CRC_IRQ) + { + break; + } + } + + /* Stop calculating CRC for new content in the FIFO */ + + mfrc522_writeu8(dev, MFRC522_COMMAND_REG, MFRC522_IDLE_CMD); + + /* Read out the 64 bytes result from the FIFO buffer */ + + mfrc522_readblk(dev, MFRC522_FIFO_DATA_REG, result, 64, 0); + + /* Self-test done. Reset AutoTestReg register to normal operation */ + + mfrc522_writeu8(dev, MFRC522_AUTOTEST_REG, 0x00); + + mfrc522info("Self Test Result:\n"); + for (i = 1; i <= 64; i++) + { + printf("0x%02X ", result[i - 1]); + + if ((i % 8) == 0) + { + printf("\n"); + } + } + + mfrc522info("Done!\n"); + return OK; +} + +/**************************************************************************** + * Name: mfrc522_open + * + * Description: + * This function is called whenever the MFRC522 device is opened. + * + ****************************************************************************/ + +static int mfrc522_open(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct mfrc522_dev_s *dev; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = inode->i_private; + + mfrc522_configspi(dev->spi); + + usleep(10000); + + mfrc522_getfwversion(dev); + + dev->state = MFRC522_STATE_IDLE; + return OK; +} + +/**************************************************************************** + * Name: mfrc522_close + * + * Description: + * This routine is called when the MFRC522 device is closed. + * + ****************************************************************************/ + +static int mfrc522_close(FAR struct file *filep) +{ + FAR struct inode *inode; + FAR struct mfrc522_dev_s *dev; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = inode->i_private; + + dev->state = MFRC522_STATE_NOT_INIT; + + return OK; +} + +/**************************************************************************** + * Name: mfrc522_read + * + * Description: + * This routine is called when the device is read. + * + * Returns TAG id as string to buffer. + * or -EIO if no TAG found + * + ****************************************************************************/ + +static ssize_t mfrc522_read(FAR struct file *filep, FAR char *buffer, + size_t buflen) +{ + FAR struct inode *inode; + FAR struct mfrc522_dev_s *dev; + FAR struct picc_uid_s uid; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = inode->i_private; + + /* Is a card near? */ + + if (!mfrc522_picc_detect(dev)) + { + mfrc522err("Card is not present!\n"); + return -EAGAIN; + } + + /* Now read the UID */ + + mfrc522_picc_select(dev, &uid, 0); + + if (uid.sak != 0) + { + if (buffer) + { + snprintf(buffer, buflen, "0x%02X%02X%02X%02X", + uid.uid_data[0], uid.uid_data[1], + uid.uid_data[2], uid.uid_data[3]); + return buflen; + } + } + + return OK; +} + +/**************************************************************************** + * Name: mfrc522_write + ****************************************************************************/ + +static ssize_t mfrc522_write(FAR struct file *filep, FAR const char *buffer, + size_t buflen) +{ + FAR struct inode *inode; + FAR struct mfrc522_dev_s *dev; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = inode->i_private; + + (void)dev; + + return -ENOSYS; +} + +/**************************************************************************** + * Name: mfrc522_ioctl + ****************************************************************************/ + +static int mfrc522_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode; + FAR struct mfrc522_dev_s *dev; + int ret = OK; + + DEBUGASSERT(filep); + inode = filep->f_inode; + + DEBUGASSERT(inode && inode->i_private); + dev = inode->i_private; + + switch (cmd) + { + case MFRC522IOC_GET_PICC_UID: + { + struct picc_uid_s *uid = (struct picc_uid_s *)arg; + + /* Is a card near? */ + + if (mfrc522_picc_detect(dev)) + { + ret = mfrc522_picc_select(dev, uid, 0); + } + } + break; + + case MFRC522IOC_GET_STATE: + ret = dev->state; + break; + + default: + mfrc522err("ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mfrc522_register + * + * Description: + * Register the MFRC522 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. + * E.g., "/dev/rfid0" + * spi - An instance of the SPI interface to use to communicate with + * MFRC522. + * config - chip config + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int mfrc522_register(FAR const char *devpath, FAR struct spi_dev_s *spi) +{ + FAR struct mfrc522_dev_s *dev; + uint8_t fwver; + int ret = 0; + + /* Initialize the MFRC522 device structure */ + + dev = (FAR struct mfrc522_dev_s *)kmm_malloc(sizeof(struct mfrc522_dev_s)); + if (!dev) + { + mfrc522err("ERROR: Failed to allocate instance\n"); + return -ENOMEM; + } + + dev->spi = spi; + + /* Device is not initialized yet */ + + dev->state = MFRC522_STATE_NOT_INIT; + +#if defined CONFIG_PM + dev->pm_level = PM_IDLE; +#endif + + /* mfrc522_attachirq(dev, mfrc522_irqhandler); */ + + /* Initialize the MFRC522 */ + + mfrc522_init(dev); + + /* Device initialized and idle */ + + dev->state = MFRC522_STATE_IDLE; + + /* Read the Firmware Version */ + + fwver = mfrc522_getfwversion(dev); + + mfrc522info("MFRC522 Firmware Version: 0x%02X!\n", fwver); + + /* If returned firmware version is unknown don't register the device */ + + if (fwver != 0x90 && fwver != 0x91 && fwver != 0x92 && fwver != 0x88 ) + { + mfrc522err("None supported device detected!\n"); + goto firmware_error; + } + + /* Register the character driver */ + + ret = register_driver(devpath, &g_mfrc522fops, 0666, dev); + if (ret < 0) + { + mfrc522err("ERROR: Failed to register driver: %d\n", ret); + kmm_free(dev); + } + + return ret; + +firmware_error: + free(dev); + return -ENODEV; +} diff --git a/drivers/wireless/mfrc522.h b/drivers/wireless/mfrc522.h new file mode 100644 index 0000000000..821b82c0a4 --- /dev/null +++ b/drivers/wireless/mfrc522.h @@ -0,0 +1,430 @@ +/**************************************************************************** + * drivers/wireless/mfrc522.h + * + * Copyright(C) 2016 Uniquix Ltda. All rights reserved. + * Authors: Alan Carvalho de Assis + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __DRIVERS_WIRELESS_MFRC522_H +#define __DRIVERS_WIRELESS_MFRC522_H 1 + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +/* The commands used by the PCD to manage communication with several PICCs + * (ISO 14443-3, Type A, section 6.4) + */ + +#define PICC_CMD_REQA 0x26 /* REQuest command, Type A */ +#define PICC_CMD_WUPA 0x52 /* Wake-UP command, Type A */ +#define PICC_CMD_CT 0x88 /* Cascade Tag, used during anti collision. */ +#define PICC_CMD_SEL_CL1 0x93 /* Anti collision/Select, Cascade Level 1 */ +#define PICC_CMD_SEL_CL2 0x95 /* Anti collision/Select, Cascade Level 2 */ +#define PICC_CMD_SEL_CL3 0x97 /* Anti collision/Select, Cascade Level 3 */ +#define PICC_CMD_HLTA 0x50 /* HaLT command, Type A */ + +/* The commands used for MIFARE Classic + * (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9) + * Use PCD_MFAuthent to authenticate access to a sector, then use these + * commands to read/write/modify the blocks on the sector. + * The read/write commands can also be used for MIFARE Ultralight. + */ + +#define PICC_CMD_MF_AUTH_KEY_A 0x60 /* Perform authentication with Key A */ +#define PICC_CMD_MF_AUTH_KEY_B 0x61 /* Perform authentication with Key B */ +#define PICC_CMD_MF_READ 0x30 /* Reads one 16 byte block from auth sector */ +#define PICC_CMD_MF_WRITE 0xA0 /* Writes one 16 byte block to auth senctor */ +#define PICC_CMD_MF_DECREMENT 0xC0 /* Decrements contents of a block */ +#define PICC_CMD_MF_INCREMENT 0xC1 /* Increments contents of a block */ +#define PICC_CMD_MF_RESTORE 0xC2 /* Reads the contents of a block */ +#define PICC_CMD_MF_TRANSFER 0xB0 /* Writes the contents of a block */ + +/* The commands used for MIFARE Ultralight + * (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) + * The PICC_CMD_MF_READ/_MF_WRITE can also be used for MIFARE Ultralight. + */ + +#define PICC_CMD_UL_WRITE 0xA2 /* Writes one 4 byte page to the PICC. */ + +/* MFRC522 Registers */ + +/* NOTE: All SPI addresses are shifted one bit left in the SPI address byte + * See section 8.1.2.3 from MFRC522 datasheet + */ + +/* Page 0: Commands and status */ + /* 0x00 - reserved for future use */ +#define MFRC522_COMMAND_REG (0x01 << 1) /* starts/stops command execution */ +#define MFRC522_COM_IEN_REG (0x02 << 1) /* dis/enable int. req. ctrl bits */ +#define MFRC522_DIV_IEN_REG (0x03 << 1) /* dis/enable int. req. ctrl bits */ +#define MFRC522_COM_IRQ_REG (0x04 << 1) /* interrupt request bits */ +#define MFRC522_DIV_IRQ_REG (0x05 << 1) /* interrupt request bits */ +#define MFRC522_ERROR_REG (0x06 << 1) /* error bits status of last cmd */ +#define MFRC522_STATUS1_REG (0x07 << 1) /* communication status bits */ +#define MFRC522_STATUS2_REG (0x08 << 1) /* rcvr and transmitter status */ +#define MFRC522_FIFO_DATA_REG (0x09 << 1) /* input/output of FIFO buffer */ +#define MFRC522_FIFO_LEVEL_REG (0x0A << 1) /* number of bytes stored in the FIFO */ +#define MFRC522_WATER_LEVEL_REG (0x0B << 1) /* level for FIFO under/overflow */ +#define MFRC522_CONTROL_REG (0x0C << 1) /* miscellaneos control register */ +#define MFRC522_BIT_FRAMING_REG (0x0D << 1) /* adjustments for bit-oriented frames */ +#define MFRC522_COLL_REG (0x0E << 1) /* bit position of first bit-collision detected */ + /* 0x0F - reserved for future use */ +/* Page 1: Commands */ + /* 0x10 - reserved for future use */ +#define MFRC522_MODE_REG (0x11 << 1) /* defines general modes for transmit/receive */ +#define MFRC522_TX_MODE_REG (0x12 << 1) /* defines transmission data rate and framing */ +#define MFRC522_RX_MODE_REG (0x13 << 1) /* defines reception data rate and framing */ +#define MFRC522_TX_CTRL_REG (0x14 << 1) /* controls antenna driver pins TX1 and TX2 */ +#define MFRC522_TX_ASK_REG (0x15 << 1) /* controls the setting of transmission modulation */ +#define MFRC522_TX_SEL_REG (0x16 << 1) /* selects the internal sources for antenna driver */ +#define MFRC522_RX_SEL_REG (0x17 << 1) /* selects the internal receiver settings */ +#define MFRC522_RX_THLD_REG (0x18 << 1) /* selects the thresholds for bit decoder */ +#define MFRC522_DEMOD_REG (0x19 << 1) /* defines demodulator settings */ + /* 0x1A - reserved for future use */ + /* 0x1B - reserved for future use */ +#define MFRC522_MF_TX_REG (0x1C << 1) /* controls some MIFARE comm tx param */ +#define MFRC522_MF_RX_REG (0x1D << 1) /* controls some MIFARE comm rx param */ + /* 0x1E - reserved for future use */ +#define MFRC522_SERIAL_SPD_REG (0x1F << 1) /* selects the speed of the serial UART */ + +/* Page 2: Configuration */ + /* 0x20 - reserved for future use */ +#define MFRC522_CRC_RESULT_REGH (0x21 << 1) /* shows the MSB values of CRC calc. */ +#define MFRC522_CRC_RESULT_REGL (0x22 << 1) /* shows the LSB values of CRC calc. */ + /* 0x23 - reserved for future use */ +#define MFRC522_MOD_WIDTH_REG (0x24 << 1) /* controls the ModWidth setting */ + /* 0x25 - reserved for future use */ +#define MFRC522_RF_CFG_REG (0x26 << 1) /* configures the receiver gain */ +#define MFRC522_GSN_REG (0x27 << 1) /* selects the conductance of n-driver TX1/2 */ +#define MFRC522_CW_GSP_REG (0x28 << 1) /* defines the conductance of p-driver during no modulation */ +#define MFRC522_MOD_GSP_REG (0x29 << 1) /* defines the conductance of p-driver during modulation */ +#define MFRC522_TMODE_REG (0x2A << 1) /* defines settings for the internal timer */ +#define MFRC522_TPRESCALER_REG (0x2B << 1) /* the lower 8 bits of TPrescaler value */ +#define MFRC522_TRELOAD_REGH (0x2C << 1) /* defines the 16-bit timer reload value */ +#define MFRC522_TRELOAD_REGL (0x2D << 1) /* defines the 16-bit timer reload value */ +#define MFRC522_TCOUNT_VAL_REGH (0x2E << 1) /* shows the 16-bit timer value */ +#define MFRC522_TCOUNT_VAL_REGL (0x2F << 1) /* shows the 16-bit timer value */ + +/* Page 3: Test Registers */ + /* 0x30 - reserved for future use */ +#define MFRC522_TEST_SEL1_REG (0x31 << 1) /* general test signal configuration */ +#define MFRC522_TEST_SEL2_REG (0x32 << 1) /* general test signal configuration */ +#define MFRC522_TEST_PIN_EN_REG (0x33 << 1) /* enables pin output driver on pins D1 to D7 */ +#define MFRC522_TEST_PIN_VAL_REG (0x34 << 1) /* defines the values to D1 to D7 */ +#define MFRC522_TEST_BUS_REG (0x35 << 1) /* shows the status of the internal test bus */ +#define MFRC522_AUTOTEST_REG (0x36 << 1) /* controls the digital self test */ +#define MFRC522_VERSION_REG (0x37 << 1) /* shows the software version */ +#define MFRC522_ANALOG_TEST_REG (0x38 << 1) /* controls the pins AUX1 and AUX2 */ +#define MFRC522_TEST_DAC1_REG (0x39 << 1) /* defines the test value for TestDAC1 */ +#define MFRC522_TEST_DAC2_REG (0x3A << 1) /* defines the test value for TestDAC2 */ +#define MFRC522_TEST_ADC_REG (0x3B << 1) /* show the value of ADC I and Q channels */ + +/* Section 9.3.1.2: MFRC522 Command Register */ + +#define MFRC522_CMD_MASK 0x0F +# define MFRC522_IDLE_CMD 0x00 /* no action, cancels current command execution */ +# define MFRC522_MEM_CMD 0x01 /* stores 25 bytes into the internal buffer */ +# define MFRC522_GEN_RND_ID_CMD 0x02 /* generates a 10-bytes random ID number */ +# define MFRC522_CALC_CRC_CMD 0x03 /* activates the CRC coprocessor or self test */ +# define MFRC522_TRANSMIT_CMD 0x04 /* transmits data from the FIFO buffer */ +# define MFRC522_NO_CHANGE_CMD 0x07 /* no command change, used to modify CommandReg */ +# define MFRC522_RECEIVE_CMD 0x08 /* activates the receiver circuits */ +# define MFRC522_TRANSCV_CMD 0x0C /* transmits data from FIFO and receive automatically */ +# define MFRC522_MF_AUTH_CMD 0x0E /* performs the MIFARE stand authentication as a reader */ +# define MFRC522_SOFTRST_CMD 0x0F /* resets the MFRC522 */ +#define MFRC522_POWER_DOWN (1 << 4) /* soft power-down mode entered */ +#define MFRC522_RCV_OFF (1 << 5) /* turns off analog part of receiver */ + +/* Section 9.3.1.3: ComIEnReg register */ + +#define MFRC522_TIMER_IEN (1 << 0) /* allows the timer interrupt request on pin IRQ */ +#define MFRC522_ERR_IEN (1 << 1) /* allows the error interrupt request on pin IRQ */ +#define MFRC522_LO_ALERT_IEN (1 << 2) /* allows the low alert interrupt request on pin IRQ */ +#define MFRC522_HI_ALERT_IEN (1 << 3) /* allows the high alert interrupt request on pin IRQ */ +#define MFRC522_IDLE_IEN (1 << 4) /* allows the idle interrupt request on pin IRQ */ +#define MFRC522_RX_IEN (1 << 5) /* allows the receiver interrupt request on pin IRQ */ +#define MFRC522_TX_IEN (1 << 6) /* allows the transmitter interrupt request on pin IRQ */ +#define MFRC522_IRQ_INV (1 << 7) /* signal on pin IRQ is inverse of IRq bit from Status1Reg */ + +/* Section 9.3.1.4: DivIEnReg register */ + +#define MFRC522_CRC_IEN (1 << 2) /* allows the CRC interrupt request on pin IRQ */ +#define MFRC522_MFIN_ACT_IEN (1 << 4) /* allows the MFIN active interrupt request on pin IRQ */ +#define MFRC522_IRQ_PUSH_PULL (1 << 7) /* 1 = IRQ pin is a standard CMOS output pin, 0 = open-drain */ + +/* Section 9.3.1.5: ComIrqReg register */ + +#define MFRC522_COM_IRQ_MASK (0x7F) +#define MFRC522_TIMER_IRQ (1 << 0) /* enabled when TCounterValReg reaches value 0 */ +#define MFRC522_ERR_IRQ (1 << 1) /* any error bit in the ErrorReg register is set */ +#define MFRC522_LO_ALERT_IRQ (1 << 2) /* Status1Reg register’s LoAlert bit is set */ +#define MFRC522_HI_ALERT_IRQ (1 << 3) /* Status1Reg register’s HiAlert bit is set */ +#define MFRC522_IDLE_IRQ (1 << 4) /* if a command terminates this bit is set */ +#define MFRC522_RX_IRQ (1 << 5) /* receiver has detected the end of a valid data stream */ +#define MFRC522_TX_IRQ (1 << 6) /* set immediately after the last data bit was transmitted */ +#define MFRC522_SET1 (1 << 7) /* indicate the status of ComIrqReg bits */ + +/* Section 9.3.1.6: DivIrqReg register */ + +#define MFRC522_CRC_IRQ (1 << 2) /* the CalcCRC command is active and all data is processed */ +#define MFRC522_MFIN_ACT_IRQ (1 << 4) /* MFIN is active, int is set on rising/falling signal edge */ +#define MFRC522_SET2 (1 << 7) /* indicates the status of the marked bits in the DivIrqReg */ + +/* Section 9.3.1.7: ErrorReg register */ + +#define MFRC522_PROTO_ERR (1 << 0) /* set if the SOF is incorrect or during MFAuthent if data is incorrect */ +#define MFRC522_PARITY_ERR (1 << 1) /* parity check failed */ +#define MFRC522_CRC_ERR (1 << 2) /* the RxCRCEn bit is set and the CRC calculation fails */ +#define MFRC522_COLL_ERR (1 << 3) /* a bit-collision is detected */ +#define MFRC522_BUF_OVFL_ERR (1 << 4) /* FIFO is full and the host or internal state machine try to write data */ +#define MFRC522_TEMP_ERR (1 << 6) /* internal temperature sensor detects overheating */ +#define MFRC522_WR_ERR (1 << 7) /* data write error in the FIFO, host writing to FIFO at the wrong time */ + +/* Section 9.3.1.8: Status1Reg register */ + +#define MFRC522_LO_ALERT (1 << 0) /* number of bytes on FIFO lower than the water-mark */ +#define MFRC522_HI_ALERT (1 << 1) /* number of bytes on FIFO higher than the water-mark */ +#define MFRC522_TRUNNING (1 << 3) /* timer is running */ +#define MFRC522_IRQ (1 << 4) /* indicates if any interrupt source requests attention */ +#define MFRC522_CRC_READY (1 << 5) /* the CRC calculation has finished */ +#define MFRC522_CRC_OK (1 << 6) /* when the calculation is done correctly this bit change to 1 */ + +/* Section 9.3.1.9: Status2Reg register */ + +#define MFRC522_MODEM_STATE_MASK (7 << 0) /* shows the state of the transmitter and receiver state machine */ +#define MFRC522_MODEM_IDLE (0) /* idle */ +#define MFRC522_MODEM_WAIT_BFR (1) /* wait for the BitFramingReg register’s StartSend bit */ +#define MFRC522_MODEM_TXWAIT (2) /* wait until RF field is present if TxWaitRF bit is set to 1 */ +#define MFRC522_MODEM_TXING (3) /* transmitting */ +#define MFRC522_MODEM_RXWAIT (4) /* wait until RF field is present if TxWaitRF bit is set to 1 */ +#define MFRC522_MODEM_WAIT_DATA (5) /* wait for data */ +#define MFRC522_MODEM_RXING (6) /* receiving */ +#define MFRC522_MF_CRYPTO1_ON (1 << 3) /* MIFARE Crypto1 unit is switched on */ +#define MFRC522_I2C_FORCE_HS (1 << 6) /* set the I2C to high-speed mode (R/W bit) */ +#define MFRC522_TEMP_SENS_CLEAR (1 << 7) /* clears the temperature error if it is below 125C (R/W bit) */ + +/* Section 9.3.1.10: FIFODataReg register */ + +#define MFRC522_FIFO_DATA_MASK (0xFF) /* Input and output of 64 byte FIFO buffer */ + +/* Section 9.3.1.11: FIFOLevelReg register */ + +#define MFRC522_FIFOLEVEL_MASK (0x7F) /* indicates the number of bytes stored in the FIFO buffer */ +#define MFRC522_FLUSH_BUFFER (1 << 7) /* immediately clears the internal FIFO buffer */ + +/* Section 9.3.1.12: WaterLevelReg register */ + +#define MFRC522_WATER_LEVEL_MASK (0x3F) /* level for FIFO under- and overflow warning */ + +/* Section 9.3.1.13: ControlReg register */ + +#define MFRC522_RX_LAST_BITS_MASK (7 << 0) /* indicates the number of valid bits in the last received byte */ +#define MFRC522_TSTART_NOW (1 << 6) /* timer starts immediately */ +#define MFRC522_TSTOP_NOW (1 << 7) /* timer stops immediately */ + +/* Section 9.3.1.14: BitFramingReg register */ + +#define MFRC522_TX_LAST_BITS_MASK (7 << 0) /* defines the number of bits of the last byte that will be transmitted */ +#define MFRC522_RX_ALIGN_MASK (7 << 4) /* used for reception of bit-oriented frames */ +#define MFRC522_START_SEND (1 << 7) /* starts the transmission of data */ + +/* Section 9.3.1.15: CollReg register */ + +#define MFRC522_COLL_POS_MASK (0x1F) /* shows the bit position of the first detected collision */ +#define MFRC522_COLL_POS_NOT_VALID (1 << 5) /* no collision detected or it is out of the range of CollPos[4:0] */ +#define MFRC522_VALUES_AFTER_COLL (1 << 7) /* 0 means: all received bits will be cleared after a collision */ + +/* Section 9.3.2.2: ModeReg register */ + +#define MFRC522_CRC_PRESET_MASK (0x3) /* defines the preset value for the CalcCRC */ +#define MFRC522_CRC_PRESET_0000 (0x0) /* 0000h CRC preset value */ +#define MFRC522_CRC_PRESET_6363 (0x1) /* 6363h CRC preset value */ +#define MFRC522_CRC_PRESET_A671 (0x2) /* A671h CRC preset value */ +#define MFRC522_CRC_PRESET_FFFF (0x3) /* FFFFh CRC preset value */ +#define MFRC522_POL_MFIN (1 << 3) /* defines the polarity of pin MFIN */ +#define MFRC522_TX_WAIT_RF (1 << 5) /* transmitter can only be started if an RF field is generated */ +#define MFRC522_MSB_FIRST (1 << 7) /* CRC coprocessor calculates the CRC with MSB first */ + +/* Section 9.3.2.3: TxModeReg register */ + +#define MFRC522_INV_MOD (1 << 3) /* modulation of transmitted data is inverted */ +#define MFRC522_TX_SPEED_MASK (7 << 4) /* defines the bit rate during data transmission */ +#define MFRC522_TX_106KBD (0 << 4) /* 106 kBd */ +#define MFRC522_TX_212KBD (1 << 4) /* 212 kBd */ +#define MFRC522_TX_424KBD (2 << 4) /* 424 kBd */ +#define MFRC522_TX_848KBD (3 << 4) /* 848 kBd */ + /* 4-7 << 4 - reserved */ +#define MFRC522_TX_CRC_EN (1 << 7) /* enables CRC generation during data transmission */ + +/* Section 9.3.2.4: RxModeReg register */ + +#define MFRC522_RX_MULTIPLE (1 << 2) /* enable to receive more than one data frame, only at 106kBd */ +#define MFRC522_RX_NO_ERR (1 << 3) /* ignore invalid data stream error (less than 4 bits received) */ +#define MFRC522_RX_SPEED_MASK (7 << 4) /* defines the bit rate during data reception */ +#define MFRC522_RX_106KBD (0 << 4) /* 106 kBd */ +#define MFRC522_RX_212KBD (1 << 4) /* 212 kBd */ +#define MFRC522_RX_424KBD (2 << 4) /* 424 kBd */ +#define MFRC522_RX_848KBD (3 << 4) /* 848 kBd */ + /* 4-7 << 4 - reserved */ +#define MFRC522_RX_CRC_EN (1 << 7) /* enables CRC generation during data reception */ + +/* Section 9.3.2.5: TxControlReg register */ + +#define MFRC522_TX1_RF_EN (1 << 0) /* output signal on pin TX1 delivers 13.56MHz */ +#define MFRC522_TX2_RF_EN (1 << 1) /* output signal on pin TX2 delivers 13.56MHz */ + /* bit 2 - reserved */ +#define MFRC522_TX2_CW (1 << 3) /* output signal on pin TX2 delivers (un)modulated 13.56MHz */ +#define MFRC522_INV_TX1_RF_OFF (1 << 4) /* output signal on pin TX1 is inverted when driver TX1 is disabled */ +#define MFRC522_INV_TX2_RF_OFF (1 << 5) /* output signal on pin TX2 is inverted when driver TX2 is disabled */ +#define MFRC522_INV_TX1_RF_ON (1 << 6) /* output signal on pin TX1 is inverted when driver TX1 is enabled */ +#define MFRC522_INV_TX2_RF_ON (1 << 7) /* output signal on pin TX2 is inverted when driver TX2 is enabled */ + +/* Section 9.3.2.6: TxASKReg register */ + +#define MFRC522_FORCE_100ASK (1 << 6) /* forces a 100% ASK modulation independent of the ModGsPReg setting */ + +/* Section 9.3.2.7: TxSelReg register */ + +#define MFRC522_MFOUT_SEL_MASK (0xF) /* selects the input for pin MFOUT */ +#define MFRC522_MFOUT_3STATE (0) /* 3-state */ +#define MFRC522_MFOUT_LOW (1) /* constant Low */ +#define MFRC522_MFOUT_HIGH (2) /* constant High */ +#define MFRC522_MFOUT_TEST_BUS (3) /* test bus signal as defined by the TstBusBitSel[2:0] value */ +#define MFRC522_MFOUT_INT_ENV (4) /* modulation signal (envelope) from the internal encoder */ +#define MFRC522_MFOUT_TX_STREAM (5) /* serial data stream to be transmitted, data stream before Miller encoder */ + /* 6 - reserved */ +#define MFRC522_MFOUT_RX_STREAM (7) /* serial data stream received, data stream after Manchester decoder */ + /* 8-15 - reserved */ +#define MFRC522_DRV_SEL_MASK (3 << 4) /* selects the input of drivers TX1 and TX2 */ +#define MFRC522_DRV_SEL_3STATE (0 << 4) /* 3-state */ +#define MFRC522_DRV_SEL_INT_ENV (1 << 4) /* modulation signal (envelope) from the internal encoder */ +#define MFRC522_DVR_SEL_ENV_MFIN (2 << 4) /* modulation signal (envelope) from pin MFIN */ +#define MFRC522_DVR_SEL_HIGH (3 << 4) /* High: depends on InvTx1RFOn/InvTx1RFOff and InvTx2RFOn/InvTx2RFOff */ + +/* Section 9.3.2.8: RxSelReg register */ + +#define MFRC522_RX_WAIT_MASK (0x3F) /* delay the receiver RxWait bit-clocks after transmission */ +#define MFRC522_UART_SEL_MASK (3 << 6) /* selects the input of the contactless UART */ +#define MFRC522_UART_LOW (0 << 6) /* constant Low */ +#define MFRC522_UART_MANCHESTER (1 << 6) /* Manchester with subcarrier from pin MFIN */ +#define MFRC522_UART_INT_MOD (2 << 6) /* modulated signal from the internal analog module, default */ +#define MFRC522_UART_NRZ_CODE (3 << 6) /* NRZ coding without subcarrier from pin MFIN */ + +/* Section 9.3.2.9: RxThresholdReg register */ + +#define MFRC522_COLL_LEVEL_MASK (7) /* the minimum signal strength to generate a bit-collision */ +#define MFRC522_MIN_LEVEL_MASK (0xF << 4) /* the minimum signal strength that will be accepted */ + +/* Section 9.3.2.10: DemodReg register */ + +#define MFRC522_TAU_SYNC_MASK (3 << 0) /* changes the time-constant of the internal PLL during burst */ +#define MFRC522_TAU_RCV_MASK (3 << 2) /* changes the time-constant of the internal PLL during data reception */ +#define MFRC522_TPRESCAL_EVEN (1 << 4) /* defines the Timer Prescaler formula to use */ +#define MFRC522_FIX_IQ (1 << 5) /* defines if reception will be fixed at channel I or Q based on AddIQ[1:0] */ +#define MFRC522_ADD_IQ_MASK (3 << 6) /* defines the use of I and Q channel during reception */ + +/* Section 9.3.2.13: MfTxReg register */ + +#define MFRC522_MF_TX_WAIT_MASK (3 << 0) /* defines the additional response time */ + +/* Section 9.3.2.14 MfRxReg register */ + +#define MFRC522_MF_RX_PARITY_DIS (1 << 4 ) /* disable parity bit to transmittion and reception */ + +/* Section 9.3.2.16: SerialSpeedReg register */ + +#define MFRC522_BR_T1_MASK (0x1F) /* factor BR_T1 adjusts the transfer speed */ +#define MFRC522_BR_T0_MASK (7 << 5) /* factor BR_T0 adjusts the transfer speed */ + +/* Section 9.3.3.6: RFCfgReg register */ + +#define MFRC522_RX_GAIN_MASK (0x7 << 4) +#define MFRC522_RX_GAIN_18DB (0x0 << 4) +#define MFRC522_RX_GAIN_23DB (0x1 << 4) +#define MFRC522_RX_GAIN_18DB_2 (0x2 << 4) +#define MFRC522_RX_GAIN_23DB_2 (0x3 << 4) +#define MFRC522_RX_GAIN_33DB (0x4 << 4) +#define MFRC522_RX_GAIN_38DB (0x5 << 4) +#define MFRC522_RX_GAIN_43DB (0x6 << 4) +#define MFRC522_RX_GAIN_48DB (0x7 << 4) + +/* MFRC522 TModeReg and TPrescalerReg registers */ + +#define MFRC522_TPRESCALER_HI_MASK (0xF) +#define MFRC522_TAUTO_RESTART (1 << 4) +#define MFRC522_TGATED_MASK (3 << 5) +#define MFRC522_TGATED_NONGATED (0 << 5) /* non-gated mode */ +#define MFRC522_TGATED_MFIN (1 << 5) /* gated by pin MFIN */ +#define MFRC522_TGATED_AUX1 (2 << 5) /* gated by pin AUX1 */ +#define MFRC522_TAUTO (1 << 7) /* timer starts automatically at the end of the transmission */ + +/* MFRC522 AutoTestReg register */ + +#define MFRC522_SELFTEST_MASK (0xF) /* for default operation the self test must be disabled by value 0000b */ +#define MFRC522_RFT_MASK (3 << 4) /* reserved for production tests */ +#define MFRC522_AMP_RCV (1 << 6) /* non-linear signal processing mode, increase range distance at 106kBd */ + +#define MFRC522_SELFTEST_EN 9 /* the self test is enabled by value 1001b */ + +#ifndef CONFIG_MFRC522_SPI_FREQ +# define CONFIG_MFRC522_SPI_FREQ (5000000) +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct mfrc522_dev_s +{ + uint8_t state; + FAR struct spi_dev_s *spi; /* SPI interface */ +}; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +bool mfrc522_set_config(struct mfrc522_dev_s *dev, uint8_t flags); + +#endif /* __DRIVERS_WIRELESS_MFRC522_H */ diff --git a/include/nuttx/wireless/mfrc522.h b/include/nuttx/wireless/mfrc522.h new file mode 100644 index 0000000000..cdb55134c1 --- /dev/null +++ b/include/nuttx/wireless/mfrc522.h @@ -0,0 +1,116 @@ +/**************************************************************************** + * include/wireless/mfrc522.h + * + * Copyright(C) 2016 Uniquix Ltda. All rights reserved. + * Author: Alan Carvalho de Assis + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __NUTTX_WIRELESS_MFRC522_H +#define __NUTTX_WIRELESS_MFRC522_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-Processor Definitions + ****************************************************************************/ + +#define MFRC522_MIFARE_ISO14443A (0x00) + +/* IOCTL Commands ***********************************************************/ + +#define MFRC522IOC_GET_PICC_UID _WLIOC_USER(0x0001) +#define MFRC522IOC_GET_STATE _WLIOC_USER(0x0002) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +enum mfrc522_state_E +{ + MFRC522_STATE_NOT_INIT, + MFRC522_STATE_IDLE, + MFRC522_STATE_CMD_SENT, + MFRC522_STATE_DATA_READY, +}; + +struct mfrc522_dev_s; + +struct picc_uid_s +{ + uint8_t size; /* Number of bytes in the UID. 4, 7 or 10 */ + uint8_t uid_data[10]; + uint8_t sak; /* The SAK (Select Acknowledge) return by the PICC */ +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Name: mfrc522_register + * + * Description: + * Register the MFRC522 character device as 'devpath' + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/rfid0" + * spi - An instance of the SPI interface to use to communicate with MFRC522 + * config - Device persistent board data + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ****************************************************************************/ + +int mfrc522_register(FAR const char *devpath, FAR struct spi_dev_s *spi); + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __NUTTX_WIRELESS_MFRC522_H */