Merge branch 'pn532_spi'

* pn532_spi:
  SPI: remove dead code
  SPI: add 1ms sleep in wakeup()
  SPI: update NEWS & Changelog
  Add connstring example for SPI on RPi
  Add PN532 SPI driver to CMake
  spi: fix doc typos
  spi: remove spi_posix.c, exotic platform implementations will have to be done in their respective contrib subdir
  Only include SPI related files when (at least) one SPI driver is enabled
  pn532_spi: missing malloc() checks, spi_close(), nfc_device_close() on some error handling branches
  pn532_spi: fix missing free(ndd.port)
  pn532_spi: fix double free() of spi port info
  Add pn532_spi author to AUTHORS
  Unify copyright notices
  pn532_spi: use new connstring_decode()
  Fix cppcheck warning "Non reentrant function 'readdir' called"
  Fix cppcheck warning "scanf without field width limits can crash with huge input data"
  Fix cppcheck warning "Obsolete function 'usleep' called"
  spi driver: remove compilation warnings
  make style
  Adding a SPI driver for pn532
This commit is contained in:
Philippe Teuwen 2013-04-01 13:24:28 +02:00
commit 0625544cc3
17 changed files with 1177 additions and 10 deletions

View file

@ -5,6 +5,7 @@ Alex Lian <alian@alum.mit.edu>
Anugrah Redja Kusuma <anugrah.redja@gmail.com>
Audrey Diacre <adiacre@il4p.fr>
Emanuele Bertoldi <emanuele.bertoldi@gmail.com>
Eugeny Boger <eugenyboger@gmail.com>
Francois Kooman <fkooman@tuxed.net>
Ludovic Rousseau <ludovic.rousseau@gmail.com>
Nobuhiro Iwamatsu <iwamatsu@nigauri.org>

View file

@ -25,6 +25,7 @@ Fixes:
- nfc-mfclassic: detect MIFARE Plus 2K as 2K instead of 1K
Improvements:
- New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample
- Devels HACKING file: introduce clang/scan-build & cppcheck for better code
- Better internal dependencies handling (bus <> drivers)
- Cleaner handling of portability patches

4
NEWS
View file

@ -1,5 +1,9 @@
New in 1.7.0-***:
Drivers:
* New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample
API Changes:
* Functions

View file

@ -2,6 +2,11 @@ SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on
SET(LIBNFC_DRIVER_ACR122_USB ON CACHE BOOL "Enable ACR122 support (Direct USB connection)")
SET(LIBNFC_DRIVER_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)")
SET(LIBNFC_DRIVER_ARYGON ON CACHE BOOL "Enable ARYGON support (Use serial port)")
IF(WIN32)
SET(LIBNFC_DRIVER_PN532_SPI OFF CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ELSE(WIN32)
SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ENDIF(WIN32)
SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)")
SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)")
@ -29,6 +34,12 @@ IF(LIBNFC_DRIVER_ARYGON)
SET(UART_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_ARYGON)
IF(LIBNFC_DRIVER_PN532_SPI)
ADD_DEFINITIONS("-DDRIVER_PN532_SPI_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_spi")
SET(SPI_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_PN532_SPI)
IF(LIBNFC_DRIVER_PN532_UART)
ADD_DEFINITIONS("-DDRIVER_PN532_UART_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn532_uart")

View file

@ -118,9 +118,12 @@ fi
# Handle --with-drivers option
LIBNFC_ARG_WITH_DRIVERS
# Enable UART if
# Enable UART if
AM_CONDITIONAL(UART_ENABLED, [test x"$uart_required" = x"yes"])
# Enable SPI if
AM_CONDITIONAL(SPI_ENABLED, [test x"$spi_required" = x"yes"])
# Documentation (default: no)
AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"])

View file

@ -0,0 +1,5 @@
## Typical configuration file for PN532 device on R-Pi connected using SPI
## Note: to use SPI port on R-Pi, you have to load kernel module spi-bcm2708:
## Edit /etc/modprobe.d/raspi-blacklist.conf and comment: #blacklist spi-bcm2708
name = "PN532 board via SPI"
connstring = pn532_spi:/dev/spidev0.0:500000

View file

@ -1,5 +1,5 @@
## Typical configuration file for PN532 device on R-Pi connected using UART
## Note: to use UART port on R-Pi, you have to disable linux serial console:
## http://learn.adafruit.com/adafruit-nfc-rfid-on-raspberry-pi/freeing-uart-on-the-pi
name = "PN532 board"
name = "PN532 board via UART"
connstring = pn532_uart:/dev/ttyAMA0

View file

@ -1,3 +1,3 @@
## Typical configuration file for PN532 board (ie. microbuilder.eu / Adafruit) device
name = "Adafruit PN532 board"
name = "Adafruit PN532 board via UART"
connstring = pn532_uart:/dev/ttyUSB0

View file

@ -25,6 +25,16 @@ IF(UART_REQUIRED)
ENDIF(WIN32)
ENDIF(UART_REQUIRED)
IF(SPI_REQUIRED)
IF(WIN32)
# Windows is not supported at the moment
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi)
MESSAGE( FATAL_ERROR "SPI not (yet) supported under Windows!" )
ELSE(WIN32)
LIST(APPEND BUSES_SOURCES buses/spi)
ENDIF(WIN32)
ENDIF(SPI_REQUIRED)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
IF(WIN32)

View file

@ -8,6 +8,13 @@ libnfcbuses_la_CFLAGS = -I$(top_srcdir)/libnfc
libnfcbuses_la_LIBADD =
EXTRA_DIST =
if SPI_ENABLED
libnfcbuses_la_SOURCES += spi.c spi.h
libnfcbuses_la_CFLAGS +=
libnfcbuses_la_LIBADD +=
endif
EXTRA_DIST = spi.c spi.h
if UART_ENABLED
libnfcbuses_la_SOURCES += uart.c uart.h
libnfcbuses_la_CFLAGS +=

316
libnfc/buses/spi.c Normal file
View file

@ -0,0 +1,316 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors of this file:
* Copyright (C) 2013 Evgeny Boger
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
/**
* @file spi.c
* @brief SPI driver
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include "spi.h"
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/types.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
#include <nfc/nfc.h>
#include "nfc-internal.h"
#define LOG_GROUP NFC_LOG_GROUP_COM
#define LOG_CATEGORY "libnfc.bus.spi"
# if defined(__APPLE__)
const char *spi_ports_device_radix[] = { "spidev", NULL };
# elif defined (__FreeBSD__) || defined (__OpenBSD__)
const char *spi_ports_device_radix[] = { "spidev", NULL };
# elif defined (__linux__)
const char *spi_ports_device_radix[] = { "spidev", NULL };
# else
# error "Can't determine spi port string for your system"
# endif
struct spi_port_unix {
int fd; // Serial port file descriptor
//~ struct termios termios_backup; // Terminal info before using the port
//~ struct termios termios_new; // Terminal info during the transaction
};
#define SPI_DATA( X ) ((struct spi_port_unix *) X)
spi_port
spi_open(const char *pcPortName)
{
struct spi_port_unix *sp = malloc(sizeof(struct spi_port_unix));
if (sp == 0)
return INVALID_SPI_PORT;
sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (sp->fd == -1) {
spi_close(sp);
return INVALID_SPI_PORT;
}
return sp;
}
void
spi_set_speed(spi_port sp, const uint32_t uiPortSpeed)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "SPI port speed requested to be set to %d Hz.", uiPortSpeed);
int ret;
ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_WR_MAX_SPEED_HZ, &uiPortSpeed);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ret %d", ret);
if (ret == -1) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error setting SPI speed.");
}
void
spi_set_mode(spi_port sp, const uint32_t uiPortMode)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "SPI port mode requested to be set to %d.", uiPortMode);
int ret;
ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_WR_MODE, &uiPortMode);
if (ret == -1) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error setting SPI mode.");
}
uint32_t
spi_get_speed(spi_port sp)
{
uint32_t uiPortSpeed = 0;
int ret;
ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_RD_MAX_SPEED_HZ, &uiPortSpeed);
if (ret == -1) log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Error reading SPI speed.");
return uiPortSpeed;
}
void
spi_close(const spi_port sp)
{
close(SPI_DATA(sp)->fd);
free(sp);
}
/**
* @brief Perform bit reversal on one byte \a x
*
* @return reversed byte
*/
static uint8_t
bit_reversal(const uint8_t x)
{
uint8_t ret = x;
ret = (((ret & 0xaa) >> 1) | ((ret & 0x55) << 1));
ret = (((ret & 0xcc) >> 2) | ((ret & 0x33) << 2));
ret = (((ret & 0xf0) >> 4) | ((ret & 0x0f) << 4));
return ret;
}
/**
* @brief Send \a pbtTx content to SPI then receive data from SPI and copy data to \a pbtRx. CS line stays active between transfers as well as during transfers.
*
* @return 0 on success, otherwise a driver error is returned
*/
int
spi_send_receive(spi_port sp, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, bool lsb_first)
{
size_t transfers = 0;
struct spi_ioc_transfer tr[2];
uint8_t *pbtTxLSB = 0;
if (szTx) {
LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx);
if (lsb_first) {
pbtTxLSB = malloc(szTx * sizeof(uint8_t));
if (!pbtTxLSB) {
return NFC_ESOFT;
}
size_t i;
for (i = 0; i < szTx; ++i) {
pbtTxLSB[i] = bit_reversal(pbtTx[i]);
}
pbtTx = pbtTxLSB;
}
struct spi_ioc_transfer tr_send = {
.tx_buf = (unsigned long) pbtTx,
.rx_buf = 0,
.len = szTx ,
.delay_usecs = 0,
.speed_hz = 0,
.bits_per_word = 0,
};
tr[transfers] = tr_send;
++transfers;
}
if (szRx) {
struct spi_ioc_transfer tr_receive = {
.tx_buf = 0,
.rx_buf = (unsigned long) pbtRx,
.len = szRx,
.delay_usecs = 0,
.speed_hz = 0,
.bits_per_word = 0,
};
tr[transfers] = tr_receive;
++transfers;
}
if (transfers) {
int ret = ioctl(SPI_DATA(sp)->fd, SPI_IOC_MESSAGE(transfers), tr);
if (szTx && lsb_first) {
free(pbtTxLSB);
}
if (ret != (int)(szRx + szTx)) {
return NFC_EIO;
}
// Reverse received bytes if needed
if (szRx) {
if (lsb_first) {
size_t i;
for (i = 0; i < szRx; ++i) {
pbtRx[i] = bit_reversal(pbtRx[i]);
}
}
LOG_HEX(LOG_GROUP, "RX", pbtRx, szRx);
}
}
return NFC_SUCCESS;
}
/**
* @brief Receive data from SPI and copy data to \a pbtRx
*
* @return 0 on success, otherwise driver error code
*/
int
spi_receive(spi_port sp, uint8_t *pbtRx, const size_t szRx, bool lsb_first)
{
return spi_send_receive(sp, 0, 0, pbtRx, szRx, lsb_first);
}
/**
* @brief Send \a pbtTx content to SPI
*
* @return 0 on success, otherwise a driver error is returned
*/
int
spi_send(spi_port sp, const uint8_t *pbtTx, const size_t szTx, bool lsb_first)
{
return spi_send_receive(sp, pbtTx, szTx, 0, 0, lsb_first);
}
char **
spi_list_ports(void)
{
char **res = malloc(sizeof(char *));
size_t szRes = 1;
res[0] = NULL;
DIR *pdDir = opendir("/dev");
struct dirent *pdDirEnt;
struct dirent entry;
struct dirent *result;
while ((readdir_r(pdDir, &entry, &result) == 0) && (result != NULL)) {
pdDirEnt = &entry;
#if !defined(__APPLE__)
if (!isdigit(pdDirEnt->d_name[strlen(pdDirEnt->d_name) - 1]))
continue;
#endif
const char **p = spi_ports_device_radix;
while (*p) {
if (!strncmp(pdDirEnt->d_name, *p, strlen(*p))) {
char **res2 = realloc(res, (szRes + 1) * sizeof(char *));
if (!res2)
goto oom;
res = res2;
if (!(res[szRes - 1] = malloc(6 + strlen(pdDirEnt->d_name))))
goto oom;
sprintf(res[szRes - 1], "/dev/%s", pdDirEnt->d_name);
szRes++;
res[szRes - 1] = NULL;
}
p++;
}
}
oom:
closedir(pdDir);
return res;
}

64
libnfc/buses/spi.h Normal file
View file

@ -0,0 +1,64 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors of this file:
* Copyright (C) 2013 Evgeny Boger
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
/**
* @file spi.h
* @brief SPI driver header
*/
#ifndef __NFC_BUS_SPI_H__
# define __NFC_BUS_SPI_H__
# include <sys/time.h>
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <linux/spi/spidev.h>
# include <nfc/nfc-types.h>
// Define shortcut to types to make code more readable
typedef void *spi_port;
# define INVALID_SPI_PORT (void*)(~1)
# define CLAIMED_SPI_PORT (void*)(~2)
spi_port spi_open(const char *pcPortName);
void spi_close(const spi_port sp);
void spi_set_speed(spi_port sp, const uint32_t uiPortSpeed);
void spi_set_mode(spi_port sp, const uint32_t uiPortMode);
uint32_t spi_get_speed(const spi_port sp);
int spi_receive(spi_port sp, uint8_t *pbtRx, const size_t szRx, bool lsb_first);
int spi_send(spi_port sp, const uint8_t *pbtTx, const size_t szTx, bool lsb_first);
int spi_send_receive(spi_port sp, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, bool lsb_first);
char **spi_list_ports(void);
#endif // __NFC_BUS_SPI_H__

View file

@ -3,9 +3,9 @@ AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS)
noinst_LTLIBRARIES = libnfcdrivers.la
libnfcdrivers_la_SOURCES =
libnfcdrivers_la_SOURCES =
libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses
libnfcdrivers_la_LIBADD =
libnfcdrivers_la_LIBADD =
if DRIVER_ACR122_PCSC_ENABLED
libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h
@ -31,6 +31,10 @@ if DRIVER_PN532_UART_ENABLED
libnfcdrivers_la_SOURCES += pn532_uart.c pn532_uart.h
endif
if DRIVER_PN532_SPI_ENABLED
libnfcdrivers_la_SOURCES += pn532_spi.c pn532_spi.h
endif
if PCSC_ENABLED
libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@
libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@

687
libnfc/drivers/pn532_spi.c Normal file
View file

@ -0,0 +1,687 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors of this file:
* Copyright (C) 2013 Evgeny Boger
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file pn532_spi.c
* @brief PN532 driver using SPI bus
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include "pn532_spi.h"
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <nfc/nfc.h>
#include "drivers.h"
#include "nfc-internal.h"
#include "chips/pn53x.h"
#include "chips/pn53x-internal.h"
#include "spi.h"
#define PN532_SPI_DEFAULT_SPEED 1000000 // 1 MHz
#define PN532_SPI_DRIVER_NAME "pn532_spi"
#define PN532_SPI_MODE SPI_MODE_0
#define LOG_CATEGORY "libnfc.driver.pn532_spi"
#define LOG_GROUP NFC_LOG_GROUP_DRIVER
#ifndef _WIN32
// Needed by sleep() under Unix
# include <unistd.h>
# include <time.h>
# define msleep(x) do { \
struct timespec xsleep; \
xsleep.tv_sec = x / 1000; \
xsleep.tv_nsec = (x - xsleep.tv_sec * 1000) * 1000 * 1000; \
nanosleep(&xsleep, NULL); \
} while (0)
#else
// Needed by Sleep() under Windows
# include <winbase.h>
# define msleep Sleep
#endif
// Internal data structs
const struct pn53x_io pn532_spi_io;
struct pn532_spi_data {
spi_port port;
volatile bool abort_flag;
};
static const uint8_t pn532_spi_cmd_dataread = 0x03;
static const uint8_t pn532_spi_cmd_datawrite = 0x01;
// Prototypes
int pn532_spi_ack(nfc_device *pnd);
int pn532_spi_wakeup(nfc_device *pnd);
#define DRIVER_DATA(pnd) ((struct pn532_spi_data*)(pnd->driver_data))
static size_t
pn532_spi_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
{
size_t device_found = 0;
spi_port sp;
char **acPorts = spi_list_ports();
const char *acPort;
int iDevice = 0;
while ((acPort = acPorts[iDevice++])) {
sp = spi_open(acPort);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find PN532 device on SPI port: %s at %d Hz.", acPort, PN532_SPI_DEFAULT_SPEED);
if ((sp != INVALID_SPI_PORT) && (sp != CLAIMED_SPI_PORT)) {
// Serial port claimed but we need to check if a PN532_SPI is opened.
spi_set_speed(sp, PN532_SPI_DEFAULT_SPEED);
spi_set_mode(sp, PN532_SPI_MODE);
nfc_connstring connstring;
snprintf(connstring, sizeof(nfc_connstring), "%s:%s:%"PRIu32, PN532_SPI_DRIVER_NAME, acPort, PN532_SPI_DEFAULT_SPEED);
nfc_device *pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
spi_close(sp);
return 0;
}
pnd->driver = &pn532_spi_driver;
pnd->driver_data = malloc(sizeof(struct pn532_spi_data));
if (!pnd->driver_data) {
perror("malloc");
spi_close(sp);
nfc_device_free(pnd);
return 0;
}
DRIVER_DATA(pnd)->port = sp;
// Alloc and init chip's data
if (pn53x_data_new(pnd, &pn532_spi_io) == NULL) {
perror("malloc");
spi_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return 0;
}
// SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532
CHIP_DATA(pnd)->type = PN532;
// This device starts in LowVBat power mode
CHIP_DATA(pnd)->power_mode = LOWVBAT;
DRIVER_DATA(pnd)->abort_flag = false;
// Check communication using "Diagnose" command, with "Communication test" (0x00)
int res = pn53x_check_communication(pnd);
spi_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
if (res < 0) {
continue;
}
memcpy(connstrings[device_found], connstring, sizeof(nfc_connstring));
device_found++;
// Test if we reach the maximum "wanted" devices
if (device_found >= connstrings_len)
break;
}
}
iDevice = 0;
while ((acPort = acPorts[iDevice++])) {
free((void *)acPort);
}
free(acPorts);
return device_found;
}
struct pn532_spi_descriptor {
char *port;
uint32_t speed;
};
static void
pn532_spi_close(nfc_device *pnd)
{
pn53x_idle(pnd);
// Release SPI port
spi_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd);
nfc_device_free(pnd);
}
static nfc_device *
pn532_spi_open(const nfc_context *context, const nfc_connstring connstring)
{
struct pn532_spi_descriptor ndd;
char *speed_s;
int connstring_decode_level = connstring_decode(connstring, PN532_SPI_DRIVER_NAME, NULL, &ndd.port, &speed_s);
if (connstring_decode_level == 3) {
ndd.speed = 0;
if (sscanf(speed_s, "%10"PRIu32, &ndd.speed) != 1) {
// speed_s is not a number
free(ndd.port);
free(speed_s);
return NULL;
}
free(speed_s);
}
if (connstring_decode_level < 2) {
return NULL;
}
if (connstring_decode_level < 3) {
ndd.speed = PN532_SPI_DEFAULT_SPEED;
}
spi_port sp;
nfc_device *pnd = NULL;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d Hz.", ndd.port, ndd.speed);
sp = spi_open(ndd.port);
if (sp == INVALID_SPI_PORT)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Invalid SPI port: %s", ndd.port);
if (sp == CLAIMED_SPI_PORT)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "SPI port already claimed: %s", ndd.port);
if ((sp == CLAIMED_SPI_PORT) || (sp == INVALID_SPI_PORT)) {
free(ndd.port);
return NULL;
}
spi_set_speed(sp, ndd.speed);
spi_set_mode(sp, PN532_SPI_MODE);
// We have a connection
pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
free(ndd.port);
spi_close(sp);
return NULL;
}
snprintf(pnd->name, sizeof(pnd->name), "%s:%s", PN532_SPI_DRIVER_NAME, ndd.port);
free(ndd.port);
pnd->driver_data = malloc(sizeof(struct pn532_spi_data));
if (!pnd->driver_data) {
perror("malloc");
spi_close(sp);
nfc_device_free(pnd);
return NULL;
}
DRIVER_DATA(pnd)->port = sp;
// Alloc and init chip's data
if (pn53x_data_new(pnd, &pn532_spi_io) == NULL) {
perror("malloc");
spi_close(DRIVER_DATA(pnd)->port);
nfc_device_free(pnd);
return NULL;
}
// SAMConfiguration command if needed to wakeup the chip and pn53x_SAMConfiguration check if the chip is a PN532
CHIP_DATA(pnd)->type = PN532;
// This device starts in LowVBat mode
CHIP_DATA(pnd)->power_mode = LOWVBAT;
// empirical tuning
CHIP_DATA(pnd)->timer_correction = 48;
pnd->driver = &pn532_spi_driver;
DRIVER_DATA(pnd)->abort_flag = false;
// Check communication using "Diagnose" command, with "Communication test" (0x00)
if (pn53x_check_communication(pnd) < 0) {
nfc_perror(pnd, "pn53x_check_communication");
pn532_spi_close(pnd);
return NULL;
}
pn53x_init(pnd);
return pnd;
}
static int
pn532_spi_read_spi_status(nfc_device *pnd)
{
static const uint8_t pn532_spi_statread_cmd = 0x02;
uint8_t spi_status = 0;
int res = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_statread_cmd, 1, &spi_status, 1, true);
if (res != NFC_SUCCESS) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to read SPI status");
return res;
}
return spi_status;
}
int
pn532_spi_wakeup(nfc_device *pnd)
{
/* SPI wakeup is basically activating chipselect for several ms.
* To do so, we are sending harmless command at very low speed */
int res;
const uint32_t prev_port_speed = spi_get_speed(DRIVER_DATA(pnd)->port);
// Try to get byte from the SPI line. If PN532 is powered down, the byte will be 0xff (MISO line is high)
uint8_t spi_byte = 0;
res = spi_receive(DRIVER_DATA(pnd)->port, &spi_byte, 1, true);
if (res != NFC_SUCCESS) {
return res;
}
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Got %x byte from SPI line before wakeup", spi_byte);
CHIP_DATA(pnd)->power_mode = NORMAL; // PN532 will be awake soon
msleep(1);
if (spi_byte == 0xff) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Wakeup is needed");
spi_set_speed(DRIVER_DATA(pnd)->port, 5000); // set slow speed
res = pn532_SAMConfiguration(pnd, PSM_NORMAL, 1000); // wakeup by sending SAMConfiguration, which works just fine
spi_set_speed(DRIVER_DATA(pnd)->port, prev_port_speed);
}
return res;
}
#define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD)
static int
pn532_spi_wait_for_data(nfc_device *pnd, int timeout)
{
static const uint8_t pn532_spi_ready = 0x01;
static const int pn532_spi_poll_interval = 10; //ms
int timer = 0;
int ret;
while ((ret = pn532_spi_read_spi_status(pnd)) != pn532_spi_ready) {
if (ret < 0) {
return ret;
}
if (DRIVER_DATA(pnd)->abort_flag) {
DRIVER_DATA(pnd)->abort_flag = false;
return NFC_EOPABORTED;
}
if (timeout > 0) {
timer += pn532_spi_poll_interval;
if (timer > timeout) {
return NFC_ETIMEOUT;
}
msleep(pn532_spi_poll_interval);
}
}
return NFC_SUCCESS;
}
static int
pn532_spi_receive_next_chunk(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen)
{
// According to datasheet, the entire read operation should be done at once
// However, it seems impossible to do since the length of the frame is stored in the frame
// itself and it's impossible to manually set CS to low between two read operations
// It's possible to read the response frame in a series of read operations, provided
// each read operation is preceded by SPI_DATAREAD byte from the host.
// Unfortunately, the PN532 sends first byte of the second and successive response chunks
// at the same time as host sends SPI_DATAREAD byte
// Many hardware SPI implementations are half-duplex, so it's became impossible to read this
// first response byte
// The following hack is used here: we first try to receive data from PN532 without SPI_DATAREAD
// and then begin full-featured read operation
// The PN532 does not shift the internal register on the receive operation, which allows us to read the whole response
// The example transfer log is as follows:
// CS ..._/---\___________________________/---\________/------\_____________/-----\_________/---\____________/---...
// MOSI (host=>pn532) ... 0x03 0x00 0x00 0x00 0x00 0x00 0x03 0x00 0x00 0x03 0x00
// MISO (pn532<=host) ... 0x01 0x00 0xff 0x02 0xfe 0xd5 0xd5 0x15 0x16 0x16 0x00
// linux send/receive s r r r r r s r r s r
// |<-- data -->| |<-data->| |<-data->| |<-data->| |<-data->|
// |<-- first chunk -->| |<-- second chunk -->| |<-- third chunk -->|
// The response frame is 0x00 0xff 0x02 0xfe 0xd5 0x15 0x16 0x00
int res = spi_receive(DRIVER_DATA(pnd)->port, pbtData, 1, true);
if (res != NFC_SUCCESS) {
return res;
}
res = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, pbtData + 1, szDataLen - 1, true);
return res;
}
static int
pn532_spi_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int timeout)
{
uint8_t abtRxBuf[5];
size_t len;
pnd->last_error = pn532_spi_wait_for_data(pnd, timeout);
if (NFC_EOPABORTED == pnd->last_error) {
return pn532_spi_ack(pnd);
}
if (pnd->last_error != NFC_SUCCESS) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to wait for SPI data. (RX)");
goto error;
}
pnd->last_error = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf , 4, true);
if (pnd->last_error < 0) {
goto error;
}
const uint8_t pn53x_long_preamble[3] = { 0x00, 0x00, 0xff };
if (0 == (memcmp(abtRxBuf, pn53x_long_preamble, 3))) {
// long preamble
// omit first byte
for (size_t i = 0; i < 3; ++i) {
abtRxBuf[i] = abtRxBuf[i + 1];
}
// need one more byte
pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf + 3, 1);
if (pnd->last_error != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive one more byte for long preamble frame. (RX)");
goto error;
}
}
const uint8_t pn53x_preamble[2] = { 0x00, 0xff };
if (0 != (memcmp(abtRxBuf, pn53x_preamble, 2))) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", " preamble+start code mismatch");
pnd->last_error = NFC_EIO;
goto error;
}
if ((0x01 == abtRxBuf[2]) && (0xff == abtRxBuf[3])) {
// Error frame
pn532_spi_receive_next_chunk(pnd, abtRxBuf, 3);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Application level error detected");
pnd->last_error = NFC_EIO;
goto error;
} else if ((0xff == abtRxBuf[2]) && (0xff == abtRxBuf[3])) {
// Extended frame
pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf, 3);
if (pnd->last_error != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
goto error;
}
// (abtRxBuf[0] << 8) + abtRxBuf[1] (LEN) include TFI + (CC+1)
len = (abtRxBuf[0] << 8) + abtRxBuf[1] - 2;
if (((abtRxBuf[0] + abtRxBuf[1] + abtRxBuf[2]) % 256) != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch");
pnd->last_error = NFC_EIO;
goto error;
}
} else {
// Normal frame
if (256 != (abtRxBuf[2] + abtRxBuf[3])) {
// TODO: Retry
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Length checksum mismatch");
pnd->last_error = NFC_EIO;
goto error;
}
// abtRxBuf[3] (LEN) include TFI + (CC+1)
len = abtRxBuf[2] - 2;
}
if (len > szDataLen) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %zu, len: %zu)", szDataLen, len);
pnd->last_error = NFC_EIO;
goto error;
}
// TFI + PD0 (CC+1)
pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf, 2);
if (pnd->last_error != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
goto error;
}
if (abtRxBuf[0] != 0xD5) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "TFI Mismatch");
pnd->last_error = NFC_EIO;
goto error;
}
if (abtRxBuf[1] != CHIP_DATA(pnd)->last_command + 1) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Command Code verification failed");
pnd->last_error = NFC_EIO;
goto error;
}
if (len) {
pnd->last_error = pn532_spi_receive_next_chunk(pnd, pbtData, len);
if (pnd->last_error != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
goto error;
}
}
pnd->last_error = pn532_spi_receive_next_chunk(pnd, abtRxBuf, 2);
if (pnd->last_error != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to receive data. (RX)");
goto error;
}
uint8_t btDCS = (256 - 0xD5);
btDCS -= CHIP_DATA(pnd)->last_command + 1;
for (size_t szPos = 0; szPos < len; szPos++) {
btDCS -= pbtData[szPos];
}
if (btDCS != abtRxBuf[0]) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Data checksum mismatch");
pnd->last_error = NFC_EIO;
goto error;
}
if (0x00 != abtRxBuf[1]) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame postamble mismatch");
pnd->last_error = NFC_EIO;
goto error;
}
// The PN53x command is done and we successfully received the reply
return len;
error:
return pnd->last_error;
}
static int
pn532_spi_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout)
{
int res = 0;
switch (CHIP_DATA(pnd)->power_mode) {
case LOWVBAT: {
/** PN532C106 wakeup. */
if ((res = pn532_spi_wakeup(pnd)) < 0) {
return res;
}
// According to PN532 application note, C106 appendix: to go out Low Vbat mode and enter in normal mode we need to send a SAMConfiguration command
if ((res = pn532_SAMConfiguration(pnd, PSM_NORMAL, 1000)) < 0) {
return res;
}
}
break;
case POWERDOWN: {
if ((res = pn532_spi_wakeup(pnd)) < 0) {
return res;
}
}
break;
case NORMAL:
// Nothing to do :)
break;
};
uint8_t abtFrame[PN532_BUFFER_LEN + 1] = { pn532_spi_cmd_datawrite, 0x00, 0x00, 0xff }; // SPI data transfer starts with DATAWRITE (0x01) byte, Every packet must start with "00 00 ff"
size_t szFrame = 0;
if ((res = pn53x_build_frame(abtFrame + 1, &szFrame, pbtData, szData)) < 0) {
pnd->last_error = res;
return pnd->last_error;
}
res = spi_send(DRIVER_DATA(pnd)->port, abtFrame, szFrame, true);
if (res != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)");
pnd->last_error = res;
return pnd->last_error;
}
res = pn532_spi_wait_for_data(pnd, timeout);
if (res != NFC_SUCCESS) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to wait for SPI data. (RX)");
pnd->last_error = res;
return pnd->last_error;
}
uint8_t abtRxBuf[6];
res = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf, 6, true);
if (res != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Unable to read ACK");
pnd->last_error = res;
return pnd->last_error;
}
if (pn53x_check_ack_frame(pnd, abtRxBuf, sizeof(abtRxBuf)) == 0) {
// The PN53x is running the sent command
} else {
return pnd->last_error;
}
return NFC_SUCCESS;
}
int
pn532_spi_ack(nfc_device *pnd)
{
const size_t ack_frame_len = (sizeof(pn53x_ack_frame) / sizeof(pn53x_ack_frame[0]));
uint8_t ack_tx_buf [1 + ack_frame_len];
ack_tx_buf[0] = pn532_spi_cmd_datawrite;
memcpy(ack_tx_buf + 1, pn53x_ack_frame, ack_frame_len);
int res = spi_send(DRIVER_DATA(pnd)->port, ack_tx_buf, ack_frame_len + 1, true);
return res;
}
static int
pn532_spi_abort_command(nfc_device *pnd)
{
if (pnd) {
DRIVER_DATA(pnd)->abort_flag = true;
}
return NFC_SUCCESS;
}
const struct pn53x_io pn532_spi_io = {
.send = pn532_spi_send,
.receive = pn532_spi_receive,
};
const struct nfc_driver pn532_spi_driver = {
.name = PN532_SPI_DRIVER_NAME,
.scan_type = INTRUSIVE,
.scan = pn532_spi_scan,
.open = pn532_spi_open,
.close = pn532_spi_close,
.strerror = pn53x_strerror,
.initiator_init = pn53x_initiator_init,
.initiator_init_secure_element = pn532_initiator_init_secure_element,
.initiator_select_passive_target = pn53x_initiator_select_passive_target,
.initiator_poll_target = pn53x_initiator_poll_target,
.initiator_select_dep_target = pn53x_initiator_select_dep_target,
.initiator_deselect_target = pn53x_initiator_deselect_target,
.initiator_transceive_bytes = pn53x_initiator_transceive_bytes,
.initiator_transceive_bits = pn53x_initiator_transceive_bits,
.initiator_transceive_bytes_timed = pn53x_initiator_transceive_bytes_timed,
.initiator_transceive_bits_timed = pn53x_initiator_transceive_bits_timed,
.initiator_target_is_present = pn53x_initiator_target_is_present,
.target_init = pn53x_target_init,
.target_send_bytes = pn53x_target_send_bytes,
.target_receive_bytes = pn53x_target_receive_bytes,
.target_send_bits = pn53x_target_send_bits,
.target_receive_bits = pn53x_target_receive_bits,
.device_set_property_bool = pn53x_set_property_bool,
.device_set_property_int = pn53x_set_property_int,
.get_supported_modulation = pn53x_get_supported_modulation,
.get_supported_baud_rate = pn53x_get_supported_baud_rate,
.device_get_information_about = pn53x_get_information_about,
.abort_command = pn532_spi_abort_command,
.idle = pn53x_idle,
.powerdown = pn53x_PowerDown,
};

View file

@ -0,0 +1,39 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors of this file:
* Copyright (C) 2013 Evgeny Boger
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file pn532_spi.h
* @brief Driver for PN532 connected in SPI
*/
#ifndef __NFC_DRIVER_PN532_SPI_H__
#define __NFC_DRIVER_PN532_SPI_H__
#include <nfc/nfc-types.h>
extern const struct nfc_driver pn532_spi_driver;
#endif // ! __NFC_DRIVER_PN532_SPI_H__

View file

@ -109,6 +109,10 @@
# include "drivers/pn532_uart.h"
#endif /* DRIVER_PN532_UART_ENABLED */
#if defined (DRIVER_PN532_SPI_ENABLED)
# include "drivers/pn532_spi.h"
#endif /* DRIVER_PN532_SPI_ENABLED */
#define LOG_CATEGORY "libnfc.general"
#define LOG_GROUP NFC_LOG_GROUP_GENERAL
@ -138,6 +142,9 @@ nfc_drivers_init(void)
#if defined (DRIVER_PN532_UART_ENABLED)
nfc_register_driver(&pn532_uart_driver);
#endif /* DRIVER_PN532_UART_ENABLED */
#if defined (DRIVER_PN532_SPI_ENABLED)
nfc_register_driver(&pn532_spi_driver);
#endif /* DRIVER_PN532_SPI_ENABLED */
#if defined (DRIVER_ARYGON_ENABLED)
nfc_register_driver(&arygon_driver);
#endif /* DRIVER_ARYGON_ENABLED */

View file

@ -4,7 +4,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
[
AC_MSG_CHECKING(which drivers to build)
AC_ARG_WITH(drivers,
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_uart' and 'pn53x_usb'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]),
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a comma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_spi', 'pn532_uart' and 'pn53x_usb'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]),
[ case "${withval}" in
yes | no)
dnl ignore calls without any arguments
@ -22,16 +22,16 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
AC_MSG_RESULT(default drivers)
]
)
case "${DRIVER_BUILD_LIST}" in
default)
DRIVER_BUILD_LIST="acr122_usb acr122s arygon pn53x_usb pn532_uart"
DRIVER_BUILD_LIST="acr122_usb acr122s arygon pn53x_usb pn532_uart pn532_spi"
;;
all)
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart"
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart pn532_spi"
;;
esac
DRIVERS_CFLAGS=""
driver_acr122_pcsc_enabled="no"
@ -40,6 +40,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
driver_pn53x_usb_enabled="no"
driver_arygon_enabled="no"
driver_pn532_uart_enabled="no"
driver_pn532_spi_enabled="no"
for driver in ${DRIVER_BUILD_LIST}
do
@ -74,6 +75,11 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
driver_pn532_uart_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_UART_ENABLED"
;;
pn532_spi)
spi_required="yes"
driver_pn532_spi_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_SPI_ENABLED"
;;
*)
AC_MSG_ERROR([Unknow driver: $driver])
;;
@ -86,6 +92,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
AM_CONDITIONAL(DRIVER_PN53X_USB_ENABLED, [test x"$driver_pn53x_usb_enabled" = xyes])
AM_CONDITIONAL(DRIVER_ARYGON_ENABLED, [test x"$driver_arygon_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN532_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes])
])
AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[
@ -97,4 +104,5 @@ echo " acr122s.......... $driver_acr122s_enabled"
echo " arygon........... $driver_arygon_enabled"
echo " pn53x_usb........ $driver_pn53x_usb_enabled"
echo " pn532_uart....... $driver_pn532_uart_enabled"
echo " pn532_spi....... $driver_pn532_spi_enabled"
])