diff --git a/configs/nucleo-l073rz/include/board.h b/configs/nucleo-l073rz/include/board.h index 6461f2ab4d..62d0e6fc09 100644 --- a/configs/nucleo-l073rz/include/board.h +++ b/configs/nucleo-l073rz/include/board.h @@ -175,12 +175,18 @@ #define GPIO_I2C1_SCL GPIO_I2C1_SCL_2 /* D15 - PB8 */ #define GPIO_I2C1_SDA GPIO_I2C1_SDA_2 /* D14 - PB9 */ -/* SPI */ +/* SPI1 */ #define GPIO_SPI1_MISO GPIO_SPI1_MISO_2 /* D12 - PA6 */ #define GPIO_SPI1_MOSI GPIO_SPI1_MOSI_2 /* D11 - PA7 */ #define GPIO_SPI1_SCK GPIO_SPI1_SCK_1 /* D13 - PA5 */ +/* SPI2 */ + +#define GPIO_SPI2_MISO GPIO_SPI2_MISO_1 /* PB14 */ +#define GPIO_SPI2_MOSI GPIO_SPI2_MOSI_1 /* PB15 */ +#define GPIO_SPI2_SCK GPIO_SPI2_SCK_1 /* PB10 */ + /* USART */ /* By default the USART2 is connected to STLINK Virtual COM Port: diff --git a/configs/nucleo-l073rz/src/Makefile b/configs/nucleo-l073rz/src/Makefile index 1d2a20c705..eb04a71a45 100644 --- a/configs/nucleo-l073rz/src/Makefile +++ b/configs/nucleo-l073rz/src/Makefile @@ -64,4 +64,8 @@ ifeq ($(CONFIG_LPWAN_SX127X),y) CSRCS += stm32_sx127x.c endif +ifeq ($(CONFIG_CL_MFRC522),y) +CSRCS += stm32_mfrc522.c +endif + include $(TOPDIR)/configs/Board.mk diff --git a/configs/nucleo-l073rz/src/nucleo-l073rz.h b/configs/nucleo-l073rz/src/nucleo-l073rz.h index 298a179a04..c770ad0c50 100644 --- a/configs/nucleo-l073rz/src/nucleo-l073rz.h +++ b/configs/nucleo-l073rz/src/nucleo-l073rz.h @@ -111,6 +111,16 @@ #define GPIO_SX127X_DIO0 (GPIO_INPUT | GPIO_FLOAT | GPIO_EXTI | \ GPIO_PORTA | GPIO_PIN10) +/* MFRC522 + * CS - PB4 + * RESET - PB11 + */ + +#define GPIO_MFRC522_CS (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_HIGH| \ + GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN4) +#define GPIO_MFRC522_RESET (GPIO_OUTPUT|GPIO_PUSHPULL|GPIO_SPEED_HIGH| \ + GPIO_OUTPUT_SET|GPIO_PORTB|GPIO_PIN11) + /**************************************************************************** * Public Data ****************************************************************************/ @@ -119,7 +129,7 @@ * Public Function Prototypes ****************************************************************************/ -/************************************************************************************ +/***************************************************************************** * Name: stm32_bringup * * Description: @@ -135,13 +145,13 @@ int stm32_bringup(void); -/************************************************************************************ +/***************************************************************************** * Name: stm32_spidev_initialize * * Description: * Called to configure SPI chip select GPIO pins for the Nucleo-H743ZI board. * - ************************************************************************************/ + ****************************************************************************/ #ifdef CONFIG_STM32F0L0_SPI void stm32_spidev_initialize(void); @@ -169,4 +179,16 @@ int stm32_wlinitialize(void); int stm32_lpwaninitialize(void); #endif +/***************************************************************************** + * Name: stm32_mfrc522initialize + * + * Description: + * Function used to initialize the MFRC522 RFID Transceiver + * + ****************************************************************************/ + +#ifdef CONFIG_CL_MFRC522 +int stm32_mfrc522initialize(FAR const char *devpath); +#endif + #endif /* __CONFIGS_NUCLEO_L073RZ_SRC_NUCLEO_L073RZ_H */ diff --git a/configs/nucleo-l073rz/src/stm32_bringup.c b/configs/nucleo-l073rz/src/stm32_bringup.c index 207da302bd..713fe5e425 100644 --- a/configs/nucleo-l073rz/src/stm32_bringup.c +++ b/configs/nucleo-l073rz/src/stm32_bringup.c @@ -151,6 +151,14 @@ int stm32_bringup(void) } #endif /* CONFIG_LPWAN_SX127X */ +#ifdef CONFIG_CL_MFRC522 + ret = stm32_mfrc522initialize("/dev/rfid0"); + if (ret < 0) + { + syslog(LOG_ERR, "ERROR: stm32_mfrc522initialize() failed: %d\n", ret); + } +#endif /* CONFIG_CL_MFRC522 */ + UNUSED(ret); return OK; } diff --git a/configs/nucleo-l073rz/src/stm32_mfrc522.c b/configs/nucleo-l073rz/src/stm32_mfrc522.c new file mode 100644 index 0000000000..e6ccb66807 --- /dev/null +++ b/configs/nucleo-l073rz/src/stm32_mfrc522.c @@ -0,0 +1,110 @@ +/************************************************************************************ + * configs/nucleo-l073rz/src/stm32_mfrc522.c + * + * Copyright (C) 2019 Gregory Nutt. All rights reserved. + * Author: Mateusz Szafoni + * + * 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 "stm32.h" +#include "stm32_spi.h" +#include "nucleo-l073rz.h" + +#if defined(CONFIG_SPI) && defined(CONFIG_STM32F0L0_SPI2) && defined(CONFIG_CL_MFRC522) + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ + +#define MFRC522_SPI_PORTNO 2 /* On SPI2 */ + +/************************************************************************************ + * Public Functions + ************************************************************************************/ + +/************************************************************************************ + * Name: stm32_mfrc522initialize + * + * Description: + * Initialize and register the MFRC522 RFID driver. + * + * Input Parameters: + * devpath - The full path to the driver to register. E.g., "/dev/rfid0" + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. + * + ************************************************************************************/ + +int stm32_mfrc522initialize(FAR const char *devpath) +{ + FAR struct spi_dev_s *spi; + int ret; + + /* Configure MFRC522 reset */ + + stm32_configgpio(GPIO_MFRC522_RESET); + + /* MFRC522 hardware reset on rising edge */ + + stm32_gpiowrite(GPIO_MFRC522_RESET, true); + + /* Initialize SPI */ + + spi = stm32_spibus_initialize(MFRC522_SPI_PORTNO); + if (!spi) + { + return -ENODEV; + } + + /* Then register the MFRC522 */ + + ret = mfrc522_register(devpath, spi); + if (ret < 0) + { + snerr("ERROR: Error registering MFRC522\n"); + } + + return ret; +} + +#endif /* CONFIG_SPI && CONFIG_MFRC522 */ diff --git a/configs/nucleo-l073rz/src/stm32_spi.c b/configs/nucleo-l073rz/src/stm32_spi.c index 2d377898ea..de68edcdfa 100644 --- a/configs/nucleo-l073rz/src/stm32_spi.c +++ b/configs/nucleo-l073rz/src/stm32_spi.c @@ -113,6 +113,15 @@ void stm32_spidev_initialize(void) # endif #endif /* CONFIG_STM32F0L0_SPI1 */ + +#ifdef CONFIG_STM32F0L0_SPI2 + /* Configure the SPI-based MFRC522 chip select GPIO */ + +# ifdef CONFIG_CL_MFRC522 + (void)stm32_configgpio(GPIO_MFRC522_CS); +# endif + +#endif /* CONFIG_STM32F0L0_SPI2 */ } /**************************************************************************** @@ -213,11 +222,42 @@ void stm32_spi2select(FAR struct spi_dev_s *dev, uint32_t devid, bool selected) { spiinfo("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); + + switch (devid) + { +#ifdef CONFIG_CL_MFRC522 + case SPIDEV_CONTACTLESS(0): + { + stm32_gpiowrite(GPIO_MFRC522_CS, !selected); + } +#endif + default: + { + break; + } + } } uint8_t stm32_spi2status(FAR struct spi_dev_s *dev, uint32_t devid) { - return 0; + uint8_t status = 0; + + switch (devid) + { +#ifdef CONFIG_CL_MFRC522 + case SPIDEV_CONTACTLESS(0): + { + status |= SPI_STATUS_PRESENT; + break; + } +#endif + default: + { + break; + } + } + + return status; } #endif /* CONFIG_STM32F0L0_SPI2 */ diff --git a/drivers/contactless/mfrc522.c b/drivers/contactless/mfrc522.c index 069d4805c2..0721624e4c 100644 --- a/drivers/contactless/mfrc522.c +++ b/drivers/contactless/mfrc522.c @@ -772,7 +772,7 @@ int mfrc522_picc_select(FAR struct mfrc522_dev_s *dev, /* The number of known UID bits in the current Cascade Level. */ - uint8_t curr_level_known_bits; + int8_t curr_level_known_bits; /* The SELECT/ANTICOLLISION uses a 7 byte standard frame + 2 bytes CRC_A */ @@ -1225,6 +1225,51 @@ void mfrc522_setantennagain(FAR struct mfrc522_dev_s *dev, uint8_t mask) } } +/**************************************************************************** + * Name: mfrc522_mifare_read + ****************************************************************************/ + +int mfrc522_mifare_read(FAR struct mfrc522_dev_s *dev, + FAR struct mifare_tag_data_s *data) +{ + uint8_t buffer[18]; + uint8_t command[4]; + uint8_t length = 18; + uint8_t validbits = 0; + int ret = OK; + + /* Read block from address */ + + command[0] = PICC_CMD_MF_READ; + command[1] = data->address; + + /* Get CRC */ + + ret = mfrc522_calc_crc(dev, command, 2, &command[2]); + if (ret != OK) + { + goto errout; + } + + /* Send data and read response. + * We read back 16 bytes block data nad 2 bytes CRC. + */ + + ret = mfrc522_transcv_data(dev, command, 4, buffer, &length, + &validbits, 0, false); + if (ret < 0) + { + goto errout; + } + + /* Copy block data */ + + memcpy(data->data, buffer, 16); + +errout: + return ret; +} + /**************************************************************************** * Name: mfrc522_init * @@ -1464,8 +1509,10 @@ static ssize_t mfrc522_read(FAR struct file *filep, FAR char *buffer, mfrc522_picc_select(dev, &uid, 0); - if (uid.sak != 0) + if (uid.sak != PICC_TYPE_NOT_COMPLETE) { + /* TODO: double/triple UID */ + if (buffer) { snprintf(buffer, buflen, "0x%02X%02X%02X%02X", @@ -1517,29 +1564,59 @@ static int mfrc522_ioctl(FAR struct file *filep, int cmd, unsigned long arg) switch (cmd) { - case MFRC522IOC_GET_PICC_UID: - { - struct picc_uid_s *uid = (struct picc_uid_s *)arg; + case MFRC522IOC_GET_PICC_UID: + { + FAR struct picc_uid_s *uid = (FAR struct picc_uid_s *)arg; - /* Is a card near? */ + /* Is a card near? */ - if (mfrc522_picc_detect(dev)) - { - ret = mfrc522_picc_select(dev, uid, 0); - } - } - break; + ret = mfrc522_picc_detect(dev); + if (ret < 0) + { + goto errout; + } - case MFRC522IOC_GET_STATE: - ret = dev->state; - break; + /* Get UID and select card */ - default: - mfrc522err("ERROR: Unrecognized cmd: %d\n", cmd); - ret = -ENOTTY; - break; + ret = mfrc522_picc_select(dev, uid, 0); + if (ret < 0) + { + goto errout; + } + + break; + } + + case CLIOC_READ_MIFARE_DATA: + { + FAR struct mifare_tag_data_s *data = (struct mifare_tag_data_s *)arg; + + /* We assume that tag is selected! + * + * TODO: authentication for MIFARE Classic. + * Without authentication this will works only for MIFARE Ultralight. + */ + + ret = mfrc522_mifare_read(dev, data); + + break; + } + + case MFRC522IOC_GET_STATE: + { + ret = dev->state; + break; + } + + default: + { + mfrc522err("ERROR: Unrecognized cmd: %d\n", cmd); + ret = -ENOTTY; + break; + } } +errout: return ret; } diff --git a/include/nuttx/contactless/ioctl.h b/include/nuttx/contactless/ioctl.h index 7c7916c1c7..959f698a71 100644 --- a/include/nuttx/contactless/ioctl.h +++ b/include/nuttx/contactless/ioctl.h @@ -64,10 +64,45 @@ #define PN532IOC_READ_TAG_DATA _CLIOC(0x000a) #define PN532IOC_WRITE_TAG_DATA _CLIOC(0x000b) +/* Contactless common IOCTL Commands ****************************************/ + +#define CLIOC_READ_MIFARE_DATA _CLIOC(0x000c) +#define CLIOC_WRITE_MIFARE_DATA _CLIOC(0x000d) + /**************************************************************************** * Public Types ****************************************************************************/ +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 */ +}; + +/* Coding of Select Acknowledge (SAK) according to: + * http://www.nxp.com/documents/application_note/AN10833.pdf + */ + +enum picc_cardid_e +{ + PICC_TYPE_NOT_COMPLETE = 0x04, /* UID not complete */ + PICC_TYPE_ISO_14443_4 = 0x20, /* PICC compliant with ISO/IEC 14443-4 */ + PICC_TYPE_ISO_18092 = 0x40, /* PICC compliant with ISO/IEC 18092 (NFC) */ + PICC_TYPE_MIFARE_MINI = 0x09, + PICC_TYPE_MIFARE_1K = 0x08, + PICC_TYPE_MIFARE_4K = 0x18, + PICC_TYPE_MIFARE_UL = 0x00, + PICC_TYPE_MIFARE_PLUS = 0x11, + PICC_TYPE_TNP3XXX = 0x01 +}; + +struct mifare_tag_data_s +{ + uint8_t data[16]; + uint8_t address; +}; + /**************************************************************************** * Public Functions ****************************************************************************/ diff --git a/include/nuttx/contactless/mfrc522.h b/include/nuttx/contactless/mfrc522.h index 982ed17c8c..dc590be935 100644 --- a/include/nuttx/contactless/mfrc522.h +++ b/include/nuttx/contactless/mfrc522.h @@ -67,13 +67,6 @@ enum mfrc522_state_e 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 ****************************************************************************/