pn532.h 10.7 KB
/*
 * 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
 * @ingroup     drivers_netdev
 * @brief       PN532 NFC radio device driver
 *
 * @{
 * @file
 * @brief       PN532 driver
 *
 * @author      Víctor Ariño <victor.arino@triagnosys.com>
 */

#ifndef PN532_H
#define 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

/**
 * @name    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(const 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 /* PN532_H */
/** @} */