mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
drivers/pn532: add NFC reader PN532 driver
This commit is contained in:
parent
5da88f794a
commit
d8d8d55e72
384
drivers/include/pn532.h
Normal file
384
drivers/include/pn532.h
Normal file
@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (C) 2016 TriaGnoSys GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup drivers_pn532 PN532 NFC Reader
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief PN532 driver
|
||||
* @author Víctor Ariño <victor.arino@triagnosys.com>
|
||||
*/
|
||||
|
||||
#ifndef NFC_READER_INCLUDE_PN532_H_
|
||||
#define NFC_READER_INCLUDE_PN532_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "mutex.h"
|
||||
#include "periph/i2c.h"
|
||||
#include "periph/spi.h"
|
||||
#include "periph/gpio.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if !defined(PN532_SUPPORT_I2C) && !defined(PN532_SUPPORT_SPI)
|
||||
#error Please define PN532_SUPPORT_I2C and/or PN532_SUPPORT_SPI to enable \
|
||||
the functionality on this device
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Data structure with the configuration parameters
|
||||
*/
|
||||
typedef struct {
|
||||
union {
|
||||
#if defined(PN532_SUPPORT_I2C) || DOXYGEN
|
||||
i2c_t i2c; /**< I2C device */
|
||||
#endif
|
||||
#if defined(PN532_SUPPORT_SPI) || DOXYGEN
|
||||
spi_t spi; /**< SPI device */
|
||||
#endif
|
||||
};
|
||||
gpio_t reset; /**< Reset pin */
|
||||
gpio_t irq; /**< Interrupt pin */
|
||||
#if defined(PN532_SUPPORT_SPI) || DOXYGEN
|
||||
gpio_t nss; /**< Chip Select pin (only SPI) */
|
||||
#endif
|
||||
} pn532_params_t;
|
||||
|
||||
/**
|
||||
* @brief Working mode of the PN532
|
||||
*/
|
||||
typedef enum {
|
||||
PN532_I2C,
|
||||
PN532_SPI
|
||||
} pn532_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Device descriptor for the PN532
|
||||
*/
|
||||
typedef struct {
|
||||
const pn532_params_t *conf; /**< Configuration struct */
|
||||
pn532_mode_t mode; /**< Working mode (i2c, spi) */
|
||||
mutex_t trap; /**< Mutex to wait for chip response */
|
||||
} pn532_t;
|
||||
|
||||
/**
|
||||
* @brief Internal buffer size
|
||||
*
|
||||
* A small buffer size is enough for most applications, however if large NDEF
|
||||
* files are to be written this size shall be increased. Otherwise the files
|
||||
* can be written in chunks.
|
||||
*/
|
||||
#ifndef PN532_BUFFER_LEN
|
||||
#define PN532_BUFFER_LEN (64)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Helpers to extract firmware information from word
|
||||
* @{
|
||||
*/
|
||||
#define PN532_IC_VERSION(fwver) ((fwver >> 24) & 0xff)
|
||||
#define PN532_FW_VERSION(fwver) ((fwver >> 16) & 0xff)
|
||||
#define PN532_FW_REVISION(fwver) ((fwver >> 8) & 0xff)
|
||||
#define PN532_FW_FEATURES(fwver) ((fwver) & 0xff)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Possible SAM configurations
|
||||
*/
|
||||
typedef enum {
|
||||
PN532_SAM_NORMAL = 1,
|
||||
PN532_SAM_VIRTUAL,
|
||||
PN532_SAM_WIRED,
|
||||
PN532_SAM_DUAL
|
||||
} pn532_sam_conf_mode_t;
|
||||
|
||||
/**
|
||||
* @brief PN532 supported targets
|
||||
*/
|
||||
typedef enum {
|
||||
PN532_BR_106_ISO_14443_A = 0,
|
||||
PN532_BR_212_FELICA,
|
||||
PN532_BR_424_FELICA,
|
||||
PN532_BR_106_ISO_14443_B,
|
||||
PN532_BR_106_JEWEL
|
||||
} pn532_target_t;
|
||||
|
||||
/**
|
||||
* @brief ISO14443A Card types
|
||||
*/
|
||||
typedef enum {
|
||||
ISO14443A_UNKNOWN,
|
||||
ISO14443A_MIFARE,
|
||||
ISO14443A_TYPE4
|
||||
} nfc_iso14443a_type_t;
|
||||
|
||||
/**
|
||||
* @brief ISO14443A tag description
|
||||
*/
|
||||
typedef struct {
|
||||
char target; /**< Target */
|
||||
char auth; /**< Card has been authenticated. Do not modify manually */
|
||||
char id_len; /**< Length of the ID field */
|
||||
char sel_res; /**< SEL_RES */
|
||||
unsigned sns_res; /**< SNS_RES */
|
||||
nfc_iso14443a_type_t type; /**< Type of ISO14443A card */
|
||||
char id[8]; /**< Card ID (length given by id_len) */
|
||||
} nfc_iso14443a_t;
|
||||
|
||||
/**
|
||||
* @brief Mifare keys
|
||||
*/
|
||||
typedef enum {
|
||||
PN532_MIFARE_KEY_A = 0x60,
|
||||
PN532_MIFARE_KEY_B = 0x61
|
||||
} pn532_mifare_key_t;
|
||||
|
||||
/**
|
||||
* @brief Obtain Tag 4 data length from buffer
|
||||
*
|
||||
* This is useful in case the length has been read and one intents to read the
|
||||
* data.
|
||||
*/
|
||||
#define PN532_ISO14443A_4_LEN_FROM_BUFFER(b) ((b[0] << 8) | b[1])
|
||||
|
||||
/**
|
||||
* @brief Hard reset the chipset
|
||||
*
|
||||
* The chipset is reset by toggling the reset pins
|
||||
*
|
||||
* @param[in] dev target device
|
||||
*
|
||||
*/
|
||||
void pn532_reset(pn532_t *dev);
|
||||
|
||||
/**
|
||||
* @brief Initialize the module and peripherals
|
||||
*
|
||||
* This is the first method to be called in order to interact with the pn532.
|
||||
* It configures the GPIOs and the i2c/spi interface (depending on @p mode).
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] params configuration parameters
|
||||
* @param[in] mode initialization mode
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return <0 i2c/spi initialization error, the value is given
|
||||
* by the i2c/spi init method.
|
||||
*/
|
||||
int pn532_init(pn532_t *dev, const pn532_params_t *params, pn532_mode_t mode);
|
||||
|
||||
|
||||
#if defined(PN532_SUPPORT_I2C) || DOXYGEN
|
||||
/**
|
||||
* @brief Initialization of PN532 using i2c
|
||||
*
|
||||
* @see pn532_init for parameter and return value details
|
||||
*/
|
||||
static inline int pn532_init_i2c(pn532_t *dev, const pn532_params_t *params)
|
||||
{
|
||||
return pn532_init(dev, params, PN532_I2C);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(PN532_SUPPORT_SPI) || DOXYGEN
|
||||
/**
|
||||
* @brief Initialization of PN532 using spi
|
||||
*
|
||||
* @see pn532_init for parameter and return value details
|
||||
*/
|
||||
static inline int pn532_init_spi(pn532_t *dev, const pn532_params_t *params)
|
||||
{
|
||||
return pn532_init(dev, params, PN532_SPI);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Get the firmware version of the pn532
|
||||
*
|
||||
* The firmware version returned is a 4 byte long value:
|
||||
* - ic version,
|
||||
* - fw version,
|
||||
* - fw revision
|
||||
* - feature support
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[out] fw_ver encoded firmware version
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_fw_version(pn532_t *dev, uint32_t *fw_ver);
|
||||
|
||||
/**
|
||||
* @brief Read register of the pn532
|
||||
*
|
||||
* Refer to the datasheet for a comprehensive list of registers and meanings.
|
||||
* For SFR registers the high byte must be set to 0xff.
|
||||
*
|
||||
* http://www.nxp.com/documents/user_manual/141520.pdf
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[out] out value of the register
|
||||
* @param[in] addr address of the register to read
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_read_reg(pn532_t *dev, char *out, unsigned addr);
|
||||
|
||||
/**
|
||||
* @brief Write register of the pn532
|
||||
*
|
||||
* Refer to the datasheet for a comprehensive list of registers and meanings.
|
||||
*
|
||||
* http://www.nxp.com/documents/user_manual/141520.pdf
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] addr address of the register to read
|
||||
* @param[in] val value to write in the register
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_write_reg(pn532_t *dev, unsigned addr, char val);
|
||||
|
||||
/**
|
||||
* @brief Set new settings for the Security Access Module
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] mode new mode for the SAM
|
||||
* @param[in] timeout timeout for Virtual Card mode with LSB of 50ms.
|
||||
* (0 = infinite and 0xFF = 12.75s)
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_sam_configuration(pn532_t *dev, pn532_sam_conf_mode_t mode, unsigned timeout);
|
||||
|
||||
/**
|
||||
* @brief Get one ISO14443-A passive target
|
||||
*
|
||||
* This method blocks until a target is detected.
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[out] out target to be stored
|
||||
* @param[in] max_retries maximum number of attempts to activate a target
|
||||
* (0xff blocks indefinitely)
|
||||
*
|
||||
* @return 0 on success
|
||||
* @return -1 when no card detected (if non blocking)
|
||||
*/
|
||||
int pn532_get_passive_iso14443a(pn532_t *dev, nfc_iso14443a_t *out, unsigned max_retries);
|
||||
|
||||
/**
|
||||
* @brief Authenticate a Mifare classic card
|
||||
*
|
||||
* This operation must be done before reading or writing the segment.
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] card card to use
|
||||
* @param[in] keyid which key to use
|
||||
* @param[in] key buffer containing the key
|
||||
* @param[in] block which block to authenticate
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_mifareclassic_authenticate(pn532_t *dev, nfc_iso14443a_t *card,
|
||||
pn532_mifare_key_t keyid, char *key, unsigned block);
|
||||
|
||||
/**
|
||||
* @brief Read a block of a Mifare classic card
|
||||
*
|
||||
* The block size is 16 bytes and it must be authenticated before read.
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[out] odata buffer where to store the data
|
||||
* @param[in] card card to use
|
||||
* @param[in] block which block to read
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_mifareclassic_read(pn532_t *dev, char *odata, nfc_iso14443a_t *card, unsigned block);
|
||||
|
||||
/**
|
||||
* @brief Write a block of a Mifare classic card
|
||||
*
|
||||
* The block size is 16 bytes and it must be authenticated before written.
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] idata buffer containing the data to write
|
||||
* @param[in] card card to use
|
||||
* @param[in] block which block to write to
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_mifareclassic_write(pn532_t *dev, char *idata, nfc_iso14443a_t *card, unsigned block);
|
||||
|
||||
/**
|
||||
* @brief Read a block of a Mifare Ultralight card
|
||||
*
|
||||
* The block size is 32 bytes and it must be authenticated before read.
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[out] odata buffer where to store the data
|
||||
* @param[in] card card to use
|
||||
* @param[in] page which block to read
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_mifareulight_read(pn532_t *dev, char *odata, nfc_iso14443a_t *card, unsigned page);
|
||||
|
||||
/**
|
||||
* @brief Activate the NDEF file of a ISO14443-A Type 4 tag
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] card card to activate
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_iso14443a_4_activate(pn532_t *dev, nfc_iso14443a_t *card);
|
||||
|
||||
/**
|
||||
* @brief Read data from the NDEF file of a ISO14443-A Type 4 tag
|
||||
*
|
||||
* The first two bytes of an NDEF file are the length of the data. Afterwards,
|
||||
* at offset 0x02 starts the data itself. If one tries to read further than the
|
||||
* end of the data no data is returned.
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[out] odata buffer where to store the data
|
||||
* @param[in] card card to activate
|
||||
* @param[in] offset offset where to start reading
|
||||
* @param[in] len length to read
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
int pn532_iso14443a_4_read(pn532_t *dev, char *odata, nfc_iso14443a_t *card, unsigned offset,
|
||||
char len);
|
||||
|
||||
/**
|
||||
* @brief Deselect a previously selected passive card
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] target_id id of the target to deselect (0x00 for all)
|
||||
*/
|
||||
void pn532_deselect_passive(pn532_t *dev, unsigned target_id);
|
||||
|
||||
/**
|
||||
* @brief Release an active passive card
|
||||
*
|
||||
* @param[in] dev target device
|
||||
* @param[in] target_id id of the target to release (0x00 for all)
|
||||
*/
|
||||
void pn532_release_passive(pn532_t *dev, unsigned target_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NFC_READER_INCLUDE_PN532_H_ */
|
||||
/** @} */
|
3
drivers/pn532/Makefile
Normal file
3
drivers/pn532/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
MODULE = pn532
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
703
drivers/pn532/pn532.c
Normal file
703
drivers/pn532/pn532.c
Normal file
@ -0,0 +1,703 @@
|
||||
/*
|
||||
* Copyright (C) 2016 TriaGnoSys GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup drivers_pn532
|
||||
*
|
||||
* @{
|
||||
* @file
|
||||
* @brief PN532 driver
|
||||
*
|
||||
* @author Víctor Ariño <victor.arino@triagnosys.com>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "assert.h"
|
||||
#include "xtimer.h"
|
||||
#include "mutex.h"
|
||||
#include "pn532.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "periph/i2c.h"
|
||||
#include "periph/spi.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define PN532_I2C_ADDRESS (0x24)
|
||||
|
||||
/* Commands */
|
||||
#define CMD_FIRMWARE_VERSION (0x02)
|
||||
#define CMD_READ_REG (0x06)
|
||||
#define CMD_WRITE_REG (0x08)
|
||||
#define CMD_READ_GPIO (0x0c)
|
||||
#define CMD_WRITE_GPIO (0x0E)
|
||||
#define CMD_SAM_CONFIG (0x14)
|
||||
#define CMD_RF_CONFIG (0x32)
|
||||
#define CMD_DATA_EXCHANGE (0x40)
|
||||
#define CMD_DESELECT (0x44)
|
||||
#define CMD_LIST_PASSIVE (0x4a)
|
||||
#define CMD_RELEASE (0x52)
|
||||
|
||||
/* Mifare specific commands */
|
||||
#define MIFARE_CMD_READ (0x30)
|
||||
#define MIFARE_CMD_WRITE (0xA0)
|
||||
|
||||
/* RF register settings */
|
||||
#define RF_CONFIG_MAX_RETRIES (0x05)
|
||||
|
||||
/* Buffer operations */
|
||||
#define BUFF_CMD_START (6)
|
||||
#define BUFF_DATA_START (BUFF_CMD_START + 1)
|
||||
#define RAPDU_DATA_BEGIN (1)
|
||||
#define RAPDU_MAX_DATA_LEN (PN532_BUFFER_LEN - BUFF_DATA_START - 5)
|
||||
#define CAPDU_MAX_DATA_LEN (PN532_BUFFER_LEN - BUFF_DATA_START - 1)
|
||||
|
||||
/* Constants and magic numbers */
|
||||
#define MIFARE_CLASSIC_BLOCK_SIZE (16)
|
||||
#define RESET_TOGGLE_SLEEP (400000)
|
||||
#define RESET_BACKOFF (10000)
|
||||
#define HOST_TO_PN532 (0xD4)
|
||||
#define PN532_TO_HOST (0xD5)
|
||||
#define SPI_DATA_WRITE (0x80)
|
||||
#define SPI_STATUS_READING (0x40)
|
||||
#define SPI_DATA_READ (0xC0)
|
||||
#define SPI_WRITE_DELAY_US (2000)
|
||||
|
||||
/* Length for passive listings */
|
||||
#define LIST_PASSIVE_LEN_14443(num) (num * 20)
|
||||
|
||||
#if ENABLE_DEBUG
|
||||
#define PRINTBUFF printbuff
|
||||
static void printbuff(char *buff, unsigned len)
|
||||
{
|
||||
while (len) {
|
||||
len--;
|
||||
printf("%02x ", *buff++);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#else
|
||||
#define PRINTBUFF(...)
|
||||
#endif
|
||||
|
||||
static void _nfc_event(void *dev)
|
||||
{
|
||||
mutex_unlock(&((pn532_t *)dev)->trap);
|
||||
}
|
||||
|
||||
void pn532_reset(pn532_t *dev)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
DEBUG("pn532: reset\n");
|
||||
gpio_clear(dev->conf->reset);
|
||||
xtimer_usleep(RESET_TOGGLE_SLEEP);
|
||||
gpio_set(dev->conf->reset);
|
||||
xtimer_usleep(RESET_BACKOFF);
|
||||
}
|
||||
|
||||
int pn532_init(pn532_t *dev, const pn532_params_t *params, pn532_mode_t mode)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
int ret = -1;
|
||||
|
||||
dev->conf = params;
|
||||
|
||||
gpio_init_int(dev->conf->irq, GPIO_IN_PU, GPIO_FALLING,
|
||||
_nfc_event, (void *)dev);
|
||||
|
||||
gpio_init(dev->conf->reset, GPIO_OUT);
|
||||
gpio_set(dev->conf->reset);
|
||||
dev->mode = mode;
|
||||
if (mode == PN532_I2C) {
|
||||
#ifdef PN532_SUPPORT_I2C
|
||||
ret = i2c_init_master(dev->conf->i2c, I2C_SPEED_FAST);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef PN532_SUPPORT_SPI
|
||||
ret = spi_init_master(dev->conf->spi, SPI_CONF_FIRST_RISING,
|
||||
SPI_SPEED_1MHZ);
|
||||
gpio_init(dev->conf->nss, GPIO_OUT);
|
||||
gpio_set(dev->conf->nss);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* cppcheck-suppress knownConditionTrueFalse
|
||||
* (reason: variable set when PN532_SUPPORT_{I2C,SPI} defined) */
|
||||
if (ret == 0) {
|
||||
pn532_reset(dev);
|
||||
}
|
||||
|
||||
mutex_init(&dev->trap);
|
||||
mutex_lock(&dev->trap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static unsigned char chksum(char *b, unsigned len)
|
||||
{
|
||||
unsigned char c = 0x00;
|
||||
|
||||
while (len--) {
|
||||
c -= *b++;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifdef PN532_SUPPORT_SPI
|
||||
static void reverse(char *buff, unsigned len)
|
||||
{
|
||||
while (len--) {
|
||||
buff[len] = (buff[len] & 0xF0) >> 4 | (buff[len] & 0x0F) << 4;
|
||||
buff[len] = (buff[len] & 0xCC) >> 2 | (buff[len] & 0x33) << 2;
|
||||
buff[len] = (buff[len] & 0xAA) >> 1 | (buff[len] & 0x55) << 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int _write(pn532_t *dev, char *buff, unsigned len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
(void)buff;
|
||||
(void)len;
|
||||
|
||||
if (dev->mode == PN532_I2C) {
|
||||
#ifdef PN532_SUPPORT_I2C
|
||||
i2c_acquire(dev->conf->i2c);
|
||||
ret = i2c_write_bytes(dev->conf->i2c, PN532_I2C_ADDRESS, buff, len);
|
||||
i2c_release(dev->conf->i2c);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef PN532_SUPPORT_SPI
|
||||
spi_acquire(dev->conf->spi);
|
||||
gpio_clear(dev->conf->nss);
|
||||
xtimer_usleep(SPI_WRITE_DELAY_US);
|
||||
reverse(buff, len);
|
||||
spi_transfer_byte(dev->conf->spi, SPI_DATA_WRITE, NULL);
|
||||
ret = spi_transfer_bytes(dev->conf->spi, buff, NULL, len);
|
||||
gpio_set(dev->conf->nss);
|
||||
spi_release(dev->conf->spi);
|
||||
#endif
|
||||
}
|
||||
DEBUG("pn532: -> ");
|
||||
PRINTBUFF(buff, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int _read(pn532_t *dev, char *buff, unsigned len)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
(void)buff;
|
||||
(void)len;
|
||||
|
||||
if (dev->mode == PN532_I2C) {
|
||||
#ifdef PN532_SUPPORT_I2C
|
||||
i2c_acquire(dev->conf->i2c);
|
||||
/* len+1 for RDY after read is accepted */
|
||||
ret = i2c_read_bytes(dev->conf->i2c, PN532_I2C_ADDRESS, buff, len + 1);
|
||||
i2c_release(dev->conf->i2c);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef PN532_SUPPORT_SPI
|
||||
spi_acquire(dev->conf->spi);
|
||||
gpio_clear(dev->conf->nss);
|
||||
spi_transfer_byte(dev->conf->spi, SPI_DATA_READ, NULL);
|
||||
ret = spi_transfer_bytes(dev->conf->spi, 0x00, &buff[1], len);
|
||||
gpio_set(dev->conf->nss);
|
||||
spi_release(dev->conf->spi);
|
||||
if (ret >= 0) {
|
||||
buff[0] = 0x80;
|
||||
reverse(buff, ret);
|
||||
ret += 1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
DEBUG("pn532: <- ");
|
||||
PRINTBUFF(buff, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int send_cmd(pn532_t *dev, char *buff, unsigned len)
|
||||
{
|
||||
unsigned pos, checksum;
|
||||
|
||||
buff[0] = 0x00;
|
||||
buff[1] = 0x00;
|
||||
buff[2] = 0xFF;
|
||||
|
||||
len += 1;
|
||||
if (len < 0xff) {
|
||||
buff[3] = (char)len;
|
||||
buff[4] = 0x00 - buff[3];
|
||||
pos = 5;
|
||||
|
||||
}
|
||||
else {
|
||||
buff[3] = 0xff;
|
||||
buff[4] = 0xff;
|
||||
buff[5] = (len >> 8) & 0xff;
|
||||
buff[6] = (len) & 0xff;
|
||||
buff[7] = 0x00 - buff[5] - buff[6];
|
||||
pos = 8;
|
||||
}
|
||||
|
||||
buff[pos] = HOST_TO_PN532;
|
||||
checksum = chksum(&buff[pos], len);
|
||||
|
||||
len += pos;
|
||||
buff[len++] = checksum;
|
||||
buff[len++] = 0x00;
|
||||
|
||||
return _write(dev, buff, len);
|
||||
}
|
||||
|
||||
static void wait_ready(pn532_t *dev)
|
||||
{
|
||||
mutex_lock(&dev->trap);
|
||||
}
|
||||
|
||||
/* Returns >0 payload len (or <0 received len but not as expected) */
|
||||
static int read_command(pn532_t *dev, char *buff, unsigned len, int expected_cmd)
|
||||
{
|
||||
int r;
|
||||
unsigned j, fi, lp, lc;
|
||||
|
||||
/* apply framing overhead */
|
||||
len += 8;
|
||||
if (len >= 0xff) {
|
||||
len += 3;
|
||||
}
|
||||
|
||||
r = _read(dev, buff, len);
|
||||
|
||||
/* Validate frame structure and CRCs
|
||||
*
|
||||
* Note that all offsets are shifted by one since the first byte is always
|
||||
* 0x01. */
|
||||
if ((r < len) || (buff[1] != 0x00) || (buff[2] != 0x00) || (buff[3] != 0xFF)) {
|
||||
return -r;
|
||||
}
|
||||
|
||||
if (buff[4] == 0xff && buff[5] == 0xff) {
|
||||
/* extended frame */
|
||||
lp = buff[6] << 8 | buff[7];
|
||||
lc = (buff[6] + buff[7] + buff[8]) & 0xff;
|
||||
fi = 9;
|
||||
|
||||
}
|
||||
else {
|
||||
/* normal frame */
|
||||
lp = buff[4];
|
||||
lc = (buff[4] + buff[5]) & 0xff;
|
||||
fi = 6;
|
||||
}
|
||||
|
||||
if (lc != 0 || lp >= 265 || buff[fi] != PN532_TO_HOST) {
|
||||
return -r;
|
||||
}
|
||||
|
||||
if (lp == 0) {
|
||||
return -r;
|
||||
}
|
||||
|
||||
if (chksum(&buff[fi], lp) != buff[fi + lp]) {
|
||||
return -r;
|
||||
}
|
||||
|
||||
if (buff[fi + 1] != expected_cmd) {
|
||||
return -r;
|
||||
}
|
||||
|
||||
/* Move the meaningful data to the beginning of the buffer */
|
||||
/* start copying after command byte */
|
||||
for (j = 0, fi += 2, lp -= 2; j < lp; fi++, j++) {
|
||||
buff[j] = buff[fi];
|
||||
}
|
||||
|
||||
DEBUG("pn532: in cmd ");
|
||||
PRINTBUFF(buff, lp);
|
||||
|
||||
return lp;
|
||||
}
|
||||
|
||||
/* Returns 0 if OK, <0 otherwise */
|
||||
static int send_check_ack(pn532_t *dev, char *buff, unsigned len)
|
||||
{
|
||||
if (send_cmd(dev, buff, len) > 0) {
|
||||
static char ack[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
|
||||
|
||||
wait_ready(dev);
|
||||
if (_read(dev, buff, sizeof(ack)) != sizeof(ack) + 1) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (memcmp(&buff[1], ack, sizeof(ack)) != 0) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
wait_ready(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* sendl: send length, recvl: receive payload length */
|
||||
static int send_rcv(pn532_t *dev, char *buff, unsigned sendl, unsigned recvl)
|
||||
{
|
||||
assert(dev != NULL);
|
||||
|
||||
int expected_cmd = buff[BUFF_CMD_START] + 1;
|
||||
|
||||
if (send_check_ack(dev, buff, sendl + 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
recvl += 1; /* cmd response */
|
||||
return read_command(dev, buff, recvl, expected_cmd);
|
||||
}
|
||||
|
||||
int pn532_fw_version(pn532_t *dev, uint32_t *fw_ver)
|
||||
{
|
||||
unsigned ret = -1;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START] = CMD_FIRMWARE_VERSION;
|
||||
|
||||
if (send_rcv(dev, buff, 0, 4) == 4) {
|
||||
*fw_ver = (buff[0] << 24); /* ic version */
|
||||
*fw_ver += (buff[1] << 16); /* fw ver */
|
||||
*fw_ver += (buff[2] << 8); /* fw rev */
|
||||
*fw_ver += (buff[3]); /* feature support */
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pn532_read_reg(pn532_t *dev, char *out, unsigned addr)
|
||||
{
|
||||
int ret = -1;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_READ_REG;
|
||||
buff[BUFF_DATA_START ] = (addr >> 8) & 0xff;
|
||||
buff[BUFF_DATA_START + 1] = addr & 0xff;
|
||||
|
||||
if (send_rcv(dev, buff, 2, 1) == 1) {
|
||||
*out = buff[0];
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pn532_write_reg(pn532_t *dev, unsigned addr, char val)
|
||||
{
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_WRITE_REG;
|
||||
buff[BUFF_DATA_START ] = (addr >> 8) & 0xff;
|
||||
buff[BUFF_DATA_START + 1] = addr & 0xff;
|
||||
buff[BUFF_DATA_START + 2] = val;
|
||||
|
||||
return send_rcv(dev, buff, 3, 0);
|
||||
}
|
||||
|
||||
static int _rf_configure(pn532_t *dev, char *buff, unsigned cfg_item, char *config,
|
||||
unsigned cfg_len)
|
||||
{
|
||||
buff[BUFF_CMD_START ] = CMD_RF_CONFIG;
|
||||
buff[BUFF_DATA_START] = cfg_item;
|
||||
for (int i = 1; i <= cfg_len; i++) {
|
||||
buff[BUFF_DATA_START + i] = *config++;
|
||||
}
|
||||
|
||||
return send_rcv(dev, buff, cfg_len + 1, 0);
|
||||
}
|
||||
|
||||
static int _set_act_retries(pn532_t *dev, char *buff, unsigned max_retries)
|
||||
{
|
||||
char rtrcfg[] = { 0xff, 0x01, max_retries & 0xff };
|
||||
|
||||
return _rf_configure(dev, buff, RF_CONFIG_MAX_RETRIES, rtrcfg, sizeof(rtrcfg));
|
||||
}
|
||||
|
||||
int pn532_sam_configuration(pn532_t *dev, pn532_sam_conf_mode_t mode, unsigned timeout)
|
||||
{
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_SAM_CONFIG;
|
||||
buff[BUFF_DATA_START ] = (char)mode;
|
||||
buff[BUFF_DATA_START + 1] = (char)(timeout / 50);
|
||||
buff[BUFF_DATA_START + 2] = 0x01;
|
||||
|
||||
return send_rcv(dev, buff, 3, 0);
|
||||
}
|
||||
|
||||
static int _list_passive_targets(pn532_t *dev, char *buff, pn532_target_t target,
|
||||
unsigned max, unsigned recvl)
|
||||
{
|
||||
buff[BUFF_CMD_START] = CMD_LIST_PASSIVE;
|
||||
buff[BUFF_DATA_START] = (char) max;
|
||||
buff[BUFF_DATA_START + 1] = (char)target;
|
||||
|
||||
/* requested len depends on expected target num and type */
|
||||
return send_rcv(dev, buff, 2, recvl);
|
||||
}
|
||||
|
||||
int pn532_get_passive_iso14443a(pn532_t *dev, nfc_iso14443a_t *out,
|
||||
unsigned max_retries)
|
||||
{
|
||||
int ret = -1;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
if (_set_act_retries(dev, buff, max_retries) == 0) {
|
||||
ret = _list_passive_targets(dev, buff, PN532_BR_106_ISO_14443_A, 1,
|
||||
LIST_PASSIVE_LEN_14443(1));
|
||||
}
|
||||
|
||||
if (ret > 0 && buff[0] > 0) {
|
||||
out->target = buff[1];
|
||||
out->sns_res = (buff[2] << 8) | buff[3];
|
||||
out->sel_res = buff[4];
|
||||
out->id_len = buff[5];
|
||||
out->type = ISO14443A_UNKNOWN;
|
||||
|
||||
for (int i = 0; i < out->id_len; i++) {
|
||||
out->id[i] = buff[6 + i];
|
||||
}
|
||||
|
||||
/* try to find out the type */
|
||||
if (out->id_len == 4) {
|
||||
out->type = ISO14443A_MIFARE;
|
||||
}
|
||||
else if (out->id_len == 7) {
|
||||
/* In the case of type 4, the first byte of RATS is the length
|
||||
* of RATS including the length itself (6+7) */
|
||||
if (buff[13] == ret - 13) {
|
||||
out->type = ISO14443A_TYPE4;
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
else {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void pn532_deselect_passive(pn532_t *dev, unsigned target_id)
|
||||
{
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_DESELECT;
|
||||
buff[BUFF_DATA_START] = target_id;
|
||||
|
||||
send_rcv(dev, buff, 1, 1);
|
||||
}
|
||||
|
||||
void pn532_release_passive(pn532_t *dev, unsigned target_id)
|
||||
{
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_RELEASE;
|
||||
buff[BUFF_DATA_START] = target_id;
|
||||
|
||||
send_rcv(dev, buff, 1, 1);
|
||||
}
|
||||
|
||||
int pn532_mifareclassic_authenticate(pn532_t *dev, nfc_iso14443a_t *card,
|
||||
pn532_mifare_key_t keyid, char *key, unsigned block)
|
||||
{
|
||||
int ret = -1;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_DATA_EXCHANGE;
|
||||
buff[BUFF_DATA_START ] = card->target;
|
||||
buff[BUFF_DATA_START + 1] = keyid;
|
||||
buff[BUFF_DATA_START + 2] = block; /* current block */
|
||||
|
||||
/*
|
||||
* The card ID directly follows the key in the buffer
|
||||
* The key consists of 6 bytes and starts at offset 3
|
||||
*/
|
||||
for (int i = 0; i < 6; i++) {
|
||||
buff[BUFF_DATA_START + 3 + i] = key[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < card->id_len; i++) {
|
||||
buff[BUFF_DATA_START + 9 + i] = card->id[i];
|
||||
}
|
||||
|
||||
ret = send_rcv(dev, buff, 9 + card->id_len, 1);
|
||||
if (ret == 1) {
|
||||
ret = buff[0];
|
||||
card->auth = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pn532_mifareclassic_write(pn532_t *dev, char *idata, nfc_iso14443a_t *card,
|
||||
unsigned block)
|
||||
{
|
||||
int ret = -1;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
if (card->auth) {
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_DATA_EXCHANGE;
|
||||
buff[BUFF_DATA_START ] = card->target;
|
||||
buff[BUFF_DATA_START + 1] = MIFARE_CMD_WRITE;
|
||||
buff[BUFF_DATA_START + 2] = block; /* current block */
|
||||
memcpy(&buff[BUFF_DATA_START + 3], idata, MIFARE_CLASSIC_BLOCK_SIZE);
|
||||
|
||||
if (send_rcv(dev, buff, 19, 1) == 1) {
|
||||
ret = buff[0];
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int pn532_mifare_read(pn532_t *dev, char *odata, nfc_iso14443a_t *card,
|
||||
unsigned block, unsigned len)
|
||||
{
|
||||
int ret = -1;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_DATA_EXCHANGE;
|
||||
buff[BUFF_DATA_START ] = card->target;
|
||||
buff[BUFF_DATA_START + 1] = MIFARE_CMD_READ;
|
||||
buff[BUFF_DATA_START + 2] = block; /* current block */
|
||||
|
||||
if (send_rcv(dev, buff, 3, len + 1) == len + 1) {
|
||||
memcpy(odata, &buff[1], len);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pn532_mifareclassic_read(pn532_t *dev, char *odata, nfc_iso14443a_t *card,
|
||||
unsigned block)
|
||||
{
|
||||
if (card->auth) {
|
||||
return pn532_mifare_read(dev, odata, card, block, MIFARE_CLASSIC_BLOCK_SIZE);
|
||||
}
|
||||
else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int pn532_mifareulight_read(pn532_t *dev, char *odata, nfc_iso14443a_t *card,
|
||||
unsigned page)
|
||||
{
|
||||
return pn532_mifare_read(dev, odata, card, page, 32);
|
||||
}
|
||||
|
||||
static int send_rcv_apdu(pn532_t *dev, char *buff, unsigned slen, unsigned rlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
rlen += 3;
|
||||
if (rlen >= RAPDU_MAX_DATA_LEN) {
|
||||
return -1;
|
||||
|
||||
}
|
||||
else if (slen >= CAPDU_MAX_DATA_LEN) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = send_rcv(dev, buff, slen, rlen);
|
||||
if (ret == rlen && buff[0] == 0x00) {
|
||||
ret = (buff[rlen - 2] << 8) | buff[rlen - 1];
|
||||
if (ret == 0x9000) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pn532_iso14443a_4_activate(pn532_t *dev, nfc_iso14443a_t *card)
|
||||
{
|
||||
int ret;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
/* select app ndef tag */
|
||||
buff[BUFF_CMD_START ] = CMD_DATA_EXCHANGE;
|
||||
buff[BUFF_DATA_START ] = card->target;
|
||||
buff[BUFF_DATA_START + 1] = 0x00;
|
||||
buff[BUFF_DATA_START + 2] = 0xa4;
|
||||
buff[BUFF_DATA_START + 3] = 0x04;
|
||||
buff[BUFF_DATA_START + 4] = 0x00;
|
||||
buff[BUFF_DATA_START + 5] = 0x07;
|
||||
buff[BUFF_DATA_START + 6] = 0xD2;
|
||||
buff[BUFF_DATA_START + 7] = 0x76;
|
||||
buff[BUFF_DATA_START + 8] = 0x00;
|
||||
buff[BUFF_DATA_START + 9] = 0x00;
|
||||
buff[BUFF_DATA_START + 10] = 0x85;
|
||||
buff[BUFF_DATA_START + 11] = 0x01;
|
||||
buff[BUFF_DATA_START + 12] = 0x01;
|
||||
buff[BUFF_DATA_START + 13] = 0x00;
|
||||
|
||||
DEBUG("pn532: select app\n");
|
||||
ret = send_rcv_apdu(dev, buff, 14, 0);
|
||||
|
||||
/* select ndef file */
|
||||
buff[BUFF_CMD_START ] = CMD_DATA_EXCHANGE;
|
||||
buff[BUFF_DATA_START ] = card->target;
|
||||
buff[BUFF_DATA_START + 1] = 0x00;
|
||||
buff[BUFF_DATA_START + 2] = 0xa4;
|
||||
buff[BUFF_DATA_START + 3] = 0x00;
|
||||
buff[BUFF_DATA_START + 4] = 0x0c;
|
||||
buff[BUFF_DATA_START + 5] = 0x02;
|
||||
buff[BUFF_DATA_START + 6] = 0x00;
|
||||
buff[BUFF_DATA_START + 7] = 0x01;
|
||||
|
||||
if (ret == 0) {
|
||||
DEBUG("pn532: select file\n");
|
||||
ret = send_rcv_apdu(dev, buff, 8, 0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pn532_iso14443a_4_read(pn532_t *dev, char *odata, nfc_iso14443a_t *card,
|
||||
unsigned offset, char len)
|
||||
{
|
||||
int ret;
|
||||
char buff[PN532_BUFFER_LEN];
|
||||
|
||||
buff[BUFF_CMD_START ] = CMD_DATA_EXCHANGE;
|
||||
buff[BUFF_DATA_START ] = card->target;
|
||||
buff[BUFF_DATA_START + 1] = 0x00;
|
||||
buff[BUFF_DATA_START + 2] = 0xb0;
|
||||
buff[BUFF_DATA_START + 3] = (offset >> 8) & 0xff;
|
||||
buff[BUFF_DATA_START + 4] = offset & 0xff;
|
||||
buff[BUFF_DATA_START + 5] = len;
|
||||
|
||||
ret = send_rcv_apdu(dev, buff, 6, len);
|
||||
if (ret == 0) {
|
||||
memcpy(odata, &buff[RAPDU_DATA_BEGIN], len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
22
tests/driver_pn532/Makefile
Normal file
22
tests/driver_pn532/Makefile
Normal file
@ -0,0 +1,22 @@
|
||||
APPLICATION = driver_pn532
|
||||
include ../Makefile.tests_common
|
||||
|
||||
FEATURES_REQUIRED = periph_i2c periph_gpio
|
||||
|
||||
USEMODULE += xtimer
|
||||
USEMODULE += pn532
|
||||
|
||||
# set default device parameters in case they are undefined
|
||||
TEST_PN532_I2C ?= I2C_DEV\(0\)
|
||||
TEST_PN532_RESET ?= GPIO_PIN\(0,0\)
|
||||
TEST_PN532_IRQ ?= GPIO_PIN\(0,1\)
|
||||
|
||||
# export parameters
|
||||
CFLAGS += -DTEST_PN532_I2C=$(TEST_PN532_I2C)
|
||||
CFLAGS += -DTEST_PN532_RESET=$(TEST_PN532_RESET)
|
||||
CFLAGS += -DTEST_PN532_IRQ=$(TEST_PN532_IRQ)
|
||||
CFLAGS += -DPN532_SUPPORT_I2C
|
||||
|
||||
CFLAGS += -I$(CURDIR)
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
7
tests/driver_pn532/README.md
Normal file
7
tests/driver_pn532/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# About
|
||||
This is a manual test application for the PN532 NFC reader driver.
|
||||
|
||||
# Usage
|
||||
This test application initializes the PN532 and waits for a card to be placed
|
||||
under the reader. When the card is detected, the content of the card is
|
||||
printed.
|
131
tests/driver_pn532/main.c
Normal file
131
tests/driver_pn532/main.c
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2016 TriaGnoSys GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Test application for the PN532 NFC reader
|
||||
*
|
||||
* @author Víctor Ariño <victor.arino@triagnosys.com>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#include "pn532.h"
|
||||
#include "pn532_params.h"
|
||||
#include "xtimer.h"
|
||||
|
||||
#define LOG_LEVEL LOG_INFO
|
||||
#include "log.h"
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static void printbuff(char *buff, unsigned len)
|
||||
{
|
||||
while (len) {
|
||||
len--;
|
||||
printf("%02x ", *buff++);
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static char data[16];
|
||||
static nfc_iso14443a_t card;
|
||||
static pn532_t pn532;
|
||||
unsigned len;
|
||||
|
||||
int ret = pn532_init_i2c(&pn532, &pn532_conf[0]);
|
||||
|
||||
if (ret != 0) {
|
||||
LOG_INFO("init error %d\n", ret);
|
||||
}
|
||||
|
||||
xtimer_usleep(200000);
|
||||
LOG_INFO("awake\n");
|
||||
|
||||
uint32_t fwver;
|
||||
pn532_fw_version(&pn532, &fwver);
|
||||
LOG_INFO("ver %d.%d\n", (unsigned)PN532_FW_VERSION(fwver), (unsigned)PN532_FW_REVISION(fwver));
|
||||
|
||||
|
||||
ret = pn532_sam_configuration(&pn532, PN532_SAM_NORMAL, 1000);
|
||||
LOG_INFO("set sam %d\n", ret);
|
||||
|
||||
while (1) {
|
||||
/* Delay not to be always polling the interface */
|
||||
xtimer_usleep(250000UL);
|
||||
|
||||
ret = pn532_get_passive_iso14443a(&pn532, &card, 0x50);
|
||||
if (ret < 0) {
|
||||
LOG_DEBUG("no card\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (card.type == ISO14443A_TYPE4) {
|
||||
if (pn532_iso14443a_4_activate(&pn532, &card) != 0) {
|
||||
LOG_ERROR("act\n");
|
||||
continue;
|
||||
|
||||
}
|
||||
else if (pn532_iso14443a_4_read(&pn532, data, &card, 0x00, 2) != 0) {
|
||||
LOG_ERROR("len\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
len = PN532_ISO14443A_4_LEN_FROM_BUFFER(data);
|
||||
len = MIN(len, sizeof(data));
|
||||
|
||||
if (pn532_iso14443a_4_read(&pn532, data, &card, 0x02, len) != 0) {
|
||||
LOG_ERROR("read\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG_INFO("dumping card contents (%d bytes)\n", len);
|
||||
printbuff(data, len);
|
||||
pn532_release_passive(&pn532, card.target);
|
||||
|
||||
}
|
||||
else if (card.type == ISO14443A_MIFARE) {
|
||||
char key[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
char data[32];
|
||||
|
||||
for (int i = 0; i < 64; i++) {
|
||||
LOG_INFO("sector %02d, block %02d | ", i / 4, i);
|
||||
if ((i & 0x03) == 0) {
|
||||
ret = pn532_mifareclassic_authenticate(&pn532, &card,
|
||||
PN532_MIFARE_KEY_A, key, i);
|
||||
if (ret != 0) {
|
||||
LOG_ERROR("auth\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = pn532_mifareclassic_read(&pn532, data, &card, i);
|
||||
if (ret == 0) {
|
||||
printbuff(data, 16);
|
||||
}
|
||||
else {
|
||||
LOG_ERROR("read\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
LOG_ERROR("unknown\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
39
tests/driver_pn532/pn532_params.h
Normal file
39
tests/driver_pn532/pn532_params.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2016 TriaGnoSys GmbH
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU Lesser
|
||||
* General Public License v2.1. See the file LICENSE in the top level
|
||||
* directory for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ingroup tests
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief PN532 board configuration example
|
||||
*
|
||||
* @author Víctor Ariño <victor.arino@triagnosys.com>
|
||||
*/
|
||||
|
||||
#ifndef PN532_PARAMS_H
|
||||
#define PN532_PARAMS_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static const pn532_params_t pn532_conf[] = {
|
||||
{
|
||||
.i2c = TEST_PN532_I2C,
|
||||
.reset = TEST_PN532_RESET,
|
||||
.irq = TEST_PN532_IRQ,
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PN532_PARAMS_H */
|
||||
/** @} */
|
Loading…
Reference in New Issue
Block a user