Broke whole the libnfc :-)
use a new way to handle drivers use absolute include path instead of relative ones move some nfc_device_t members in a better place nfc_device_t now embeddeds driver data and chip data pointers (useful to be more generic) use more readable variables instead of strange coding convention move PRINT_HEX macro into nfc-internal.h silent warnings with more strict CFLAGS chips/pn53x: use the powerful C99 writing to construct PN53x commands chips/pn53x: remove almost all memcpy() chips/pn53x: WriteRegister, ReadRegister and SetParameters command wrappers are correctly named chips/pn53x: introduce chip state (SLEEP, NORMAL or EXECUTE) chips/pn53x: add SAMConfiguration command wrapper (need to be improved) chips/pn53x: remove almost all const arrays chips/pn53x: use human readable defines for commands instead of hex values chips/pn53x: in debug mode, the PN53x command is shown in human-readable string, awesome isn't it? ;-) drivers: split transceive() into send() and receive() to be able to handle more cases (differed replies, abort commands, etc) later drivers: use a const structure of functions instead of -dirty- callbacks array drivers/pn532_uart: major improvement of UART handling drivers/pn532_uart: check PN53x frames when received buses/uart: receive() is now based on expected bytes instead of calculated timeouts.. buses/uart: use a smart way to determine available ports on POSIX systems (tested on Linux and FreeBSD)
This commit is contained in:
parent
f1d909ae74
commit
5af845cdfc
20 changed files with 937 additions and 775 deletions
|
@ -56,10 +56,6 @@ nfc_initiator_mifare_cmd (nfc_device_t * pnd, const mifare_cmd mc, const uint8_t
|
||||||
byte_t abtCmd[265];
|
byte_t abtCmd[265];
|
||||||
bool bEasyFraming;
|
bool bEasyFraming;
|
||||||
|
|
||||||
// Make sure we are dealing with a active device
|
|
||||||
if (!pnd->bActive)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
abtCmd[0] = mc; // The MIFARE Classic command
|
abtCmd[0] = mc; // The MIFARE Classic command
|
||||||
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,10 @@
|
||||||
|
|
||||||
#include "nfc-utils.h"
|
#include "nfc-utils.h"
|
||||||
#include "chips/pn53x.h"
|
#include "chips/pn53x.h"
|
||||||
|
#include "chips/pn53x-internal.h"
|
||||||
|
|
||||||
#define MAX_DEVICE_COUNT 16
|
#define MAX_DEVICE_COUNT 16
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, const char *argv[])
|
main (int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -54,7 +54,7 @@ main (int argc, const char *argv[])
|
||||||
const char *acLibnfcVersion;
|
const char *acLibnfcVersion;
|
||||||
bool result;
|
bool result;
|
||||||
|
|
||||||
byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN];
|
byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
|
||||||
size_t szRx;
|
size_t szRx;
|
||||||
const byte_t pncmd_diagnose_communication_line_test[] = { 0xD4, 0x00, 0x00, 0x06, 'l', 'i', 'b', 'n', 'f', 'c' };
|
const byte_t pncmd_diagnose_communication_line_test[] = { 0xD4, 0x00, 0x00, 0x06, 'l', 'i', 'b', 'n', 'f', 'c' };
|
||||||
const byte_t pncmd_diagnose_rom_test[] = { 0xD4, 0x00, 0x01 };
|
const byte_t pncmd_diagnose_rom_test[] = { 0xD4, 0x00, 0x01 };
|
||||||
|
@ -88,19 +88,19 @@ main (int argc, const char *argv[])
|
||||||
|
|
||||||
printf ("NFC device [%s] connected.\n", pnd->acName);
|
printf ("NFC device [%s] connected.\n", pnd->acName);
|
||||||
|
|
||||||
result = pn53x_transceive (pnd, pncmd_diagnose_communication_line_test, sizeof (pncmd_diagnose_communication_line_test), abtRx, &szRx);
|
result = pn53x_transceive (pnd, pncmd_diagnose_communication_line_test, sizeof (pncmd_diagnose_communication_line_test), abtRx, &szRx, false);
|
||||||
if (result) {
|
if (result) {
|
||||||
result = (memcmp (pncmd_diagnose_communication_line_test + 2, abtRx, sizeof (pncmd_diagnose_communication_line_test) - 2) == 0);
|
result = (memcmp (pncmd_diagnose_communication_line_test + 2, abtRx, sizeof (pncmd_diagnose_communication_line_test) - 2) == 0);
|
||||||
}
|
}
|
||||||
printf (" Communication line test: %s\n", result ? "OK" : "Failed");
|
printf (" Communication line test: %s\n", result ? "OK" : "Failed");
|
||||||
|
|
||||||
result = pn53x_transceive (pnd, pncmd_diagnose_rom_test, sizeof (pncmd_diagnose_rom_test), abtRx, &szRx);
|
result = pn53x_transceive (pnd, pncmd_diagnose_rom_test, sizeof (pncmd_diagnose_rom_test), abtRx, &szRx, false);
|
||||||
if (result) {
|
if (result) {
|
||||||
result = ((szRx == 1) && (abtRx[0] == 0x00));
|
result = ((szRx == 1) && (abtRx[0] == 0x00));
|
||||||
}
|
}
|
||||||
printf (" ROM test: %s\n", result ? "OK" : "Failed");
|
printf (" ROM test: %s\n", result ? "OK" : "Failed");
|
||||||
|
|
||||||
result = pn53x_transceive (pnd, pncmd_diagnose_ram_test, sizeof (pncmd_diagnose_ram_test), abtRx, &szRx);
|
result = pn53x_transceive (pnd, pncmd_diagnose_ram_test, sizeof (pncmd_diagnose_ram_test), abtRx, &szRx, false);
|
||||||
if (result) {
|
if (result) {
|
||||||
result = ((szRx == 1) && (abtRx[0] == 0x00));
|
result = ((szRx == 1) && (abtRx[0] == 0x00));
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ sam_connection (nfc_device_t * pnd, int mode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pn53x_transceive (pnd, pncmd_sam_config, szCmd, abtRx, &szRx)) {
|
if (!pn53x_transceive (pnd, pncmd_sam_config, szCmd, abtRx, &szRx, false)) {
|
||||||
nfc_perror(pnd, "pn53x_transceive");
|
nfc_perror(pnd, "pn53x_transceive");
|
||||||
ERR ("%s %d", "Unable to execute SAMConfiguration command with mode byte:", mode);
|
ERR ("%s %d", "Unable to execute SAMConfiguration command with mode byte:", mode);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -167,7 +167,7 @@ int main(int argc, const char* argv[])
|
||||||
printf("Tx: ");
|
printf("Tx: ");
|
||||||
print_hex((byte_t*)abtTx+1,szTx-1);
|
print_hex((byte_t*)abtTx+1,szTx-1);
|
||||||
|
|
||||||
if (!pn53x_transceive (pnd, abtTx, szTx, abtRx, &szRx)) {
|
if (!pn53x_transceive (pnd, abtTx, szTx, abtRx, &szRx, false)) {
|
||||||
free(cmd);
|
free(cmd);
|
||||||
nfc_perror (pnd, "Rx");
|
nfc_perror (pnd, "Rx");
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, Roel Verdult
|
* Copyright (C) 2009, Roel Verdult
|
||||||
* Copyright (C) 2010, Romain Tartière, Romuald Conty
|
* Copyright (C) 2010, Romain Tartière, Romuald Conty
|
||||||
|
* Copyright (C) 2011, Romain Tartière, Romuald Conty
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -16,8 +17,9 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Lesser General Public License
|
* 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/>
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
*
|
*/
|
||||||
*
|
|
||||||
|
/**
|
||||||
* @file nfc-types.h
|
* @file nfc-types.h
|
||||||
* @brief Define NFC types
|
* @brief Define NFC types
|
||||||
*/
|
*/
|
||||||
|
@ -25,12 +27,6 @@
|
||||||
#ifndef __NFC_TYPES_H__
|
#ifndef __NFC_TYPES_H__
|
||||||
# define __NFC_TYPES_H__
|
# define __NFC_TYPES_H__
|
||||||
|
|
||||||
/**
|
|
||||||
* @file types.h
|
|
||||||
* @brief libnfc-defined types
|
|
||||||
*
|
|
||||||
* Define libnfc specific types: typedef, enum, struct, etc.
|
|
||||||
*/
|
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <stdbool.h>
|
# include <stdbool.h>
|
||||||
|
@ -38,32 +34,19 @@
|
||||||
|
|
||||||
typedef uint8_t byte_t;
|
typedef uint8_t byte_t;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
NC_PN531 = 0x10,
|
|
||||||
NC_PN532 = 0x20,
|
|
||||||
NC_PN533 = 0x30,
|
|
||||||
} nfc_chip_t;
|
|
||||||
|
|
||||||
struct driver_callbacks; // Prototype the callback struct
|
|
||||||
|
|
||||||
typedef void *nfc_device_spec_t; // Device connection specification
|
|
||||||
|
|
||||||
# define DEVICE_NAME_LENGTH 256
|
# define DEVICE_NAME_LENGTH 256
|
||||||
/**
|
/**
|
||||||
* @struct nfc_device_t
|
* @struct nfc_device_t
|
||||||
* @brief NFC device information
|
* @brief NFC device information
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** Callback functions for handling device specific wrapping */
|
/** Driver's functions for handling device specific wrapping */
|
||||||
const struct driver_callbacks *pdc;
|
const struct nfc_driver_t *driver;
|
||||||
|
void* driver_data;
|
||||||
|
void* chip_data;
|
||||||
|
|
||||||
/** Device name string, including device wrapper firmware */
|
/** Device name string, including device wrapper firmware */
|
||||||
char acName[DEVICE_NAME_LENGTH];
|
char acName[DEVICE_NAME_LENGTH];
|
||||||
/** PN53X chip type, this is useful for some "bug" work-arounds */
|
|
||||||
nfc_chip_t nc;
|
|
||||||
/** Pointer to the device connection specification */
|
|
||||||
nfc_device_spec_t nds;
|
|
||||||
/** This represents if the PN53X device was initialized succesful */
|
|
||||||
bool bActive;
|
|
||||||
/** Is the crc automaticly added, checked and removed from the frames */
|
/** Is the crc automaticly added, checked and removed from the frames */
|
||||||
bool bCrc;
|
bool bCrc;
|
||||||
/** Does the PN53x chip handles parity bits, all parities are handled as data */
|
/** Does the PN53x chip handles parity bits, all parities are handled as data */
|
||||||
|
@ -87,8 +70,10 @@ typedef struct {
|
||||||
* +----------- Driver-level general error (common to all drivers)
|
* +----------- Driver-level general error (common to all drivers)
|
||||||
*/
|
*/
|
||||||
int iLastError;
|
int iLastError;
|
||||||
|
/** Last sent command */
|
||||||
|
int iLastCommand;
|
||||||
} nfc_device_t;
|
} nfc_device_t;
|
||||||
|
// TODO: Move chip's specifics in a chips structure (e.g. iLastCommand, ui8Parameters, ui8TxBits)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @struct nfc_device_desc_t
|
* @struct nfc_device_desc_t
|
||||||
|
@ -118,29 +103,6 @@ struct chip_callbacks {
|
||||||
const char *(*strerror) (const nfc_device_t * pnd);
|
const char *(*strerror) (const nfc_device_t * pnd);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @struct driver_callbacks
|
|
||||||
* @brief Generic structure to handle NFC device functions.
|
|
||||||
*/
|
|
||||||
struct driver_callbacks {
|
|
||||||
/** Driver name */
|
|
||||||
const char *acDriver;
|
|
||||||
/** Chip specific callback functions */
|
|
||||||
const struct chip_callbacks *pcc;
|
|
||||||
/** Pick devices callback */
|
|
||||||
nfc_device_desc_t *(*pick_device) (void);
|
|
||||||
/** List devices callback */
|
|
||||||
bool (*list_devices) (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound);
|
|
||||||
/** Connect callback */
|
|
||||||
nfc_device_t *(*connect) (const nfc_device_desc_t * pndd);
|
|
||||||
/** Init callback */
|
|
||||||
void (*init) (nfc_device_t * pnd);
|
|
||||||
/** Transceive callback */
|
|
||||||
bool (*transceive) (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t * pszRx);
|
|
||||||
/** Disconnect callback */
|
|
||||||
void (*disconnect) (nfc_device_t * pnd);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Compiler directive, set struct alignment to 1 byte_t for compatibility
|
// Compiler directive, set struct alignment to 1 byte_t for compatibility
|
||||||
# pragma pack(1)
|
# pragma pack(1)
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ SUBDIRS = chips buses drivers .
|
||||||
# set the include path found by configure
|
# set the include path found by configure
|
||||||
INCLUDES = $(all_includes) $(LIBNFC_CFLAGS)
|
INCLUDES = $(all_includes) $(LIBNFC_CFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = chips.h buses.h drivers.h mirror-subr.h
|
noinst_HEADERS = chips.h buses.h drivers.h mirror-subr.h nfc-internal.h
|
||||||
lib_LTLIBRARIES = libnfc.la
|
lib_LTLIBRARIES = libnfc.la
|
||||||
libnfc_la_SOURCES = nfc.c iso14443-subr.c mirror-subr.c
|
libnfc_la_SOURCES = nfc.c iso14443-subr.c mirror-subr.c
|
||||||
libnfc_la_LDFLAGS = -no-undefined -version-info 1:0:0
|
libnfc_la_LDFLAGS = -no-undefined -version-info 1:0:0
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
/*-
|
/*-
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
|
* Copyright (C) 2009, Roel Verdult, Romuald Conty
|
||||||
|
* Copyright (C) 2010, Roel Verdult, Romuald Conty
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -54,17 +56,7 @@
|
||||||
// Try to guess what we should use.
|
// Try to guess what we should use.
|
||||||
# if defined (_WIN32)
|
# if defined (_WIN32)
|
||||||
# define DEFAULT_SERIAL_PORTS { "COM1", "COM2", "COM3", "COM4", NULL }
|
# define DEFAULT_SERIAL_PORTS { "COM1", "COM2", "COM3", "COM4", NULL }
|
||||||
# elif defined(__APPLE__)
|
# endif
|
||||||
// XXX: find UART connection string for PN53X device on Mac OS X when multiples devices are used
|
|
||||||
# define DEFAULT_SERIAL_PORTS { "/dev/tty.SLAB_USBtoUART", NULL }
|
|
||||||
# elif defined (__FreeBSD__) || defined (__OpenBSD__)
|
|
||||||
// XXX: Not tested
|
|
||||||
# define DEFAULT_SERIAL_PORTS { "/dev/cuau0", "/dev/cuau1", "/dev/cuau2", "/dev/cuau3", NULL }
|
|
||||||
# elif defined (__linux__)
|
|
||||||
# define DEFAULT_SERIAL_PORTS { "/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyUSB2", "/dev/ttyUSB3", "/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3", NULL }
|
|
||||||
# else
|
|
||||||
# error "Can't determine serial string for your system"
|
|
||||||
# endif
|
|
||||||
|
|
||||||
// Define shortcut to types to make code more readable
|
// Define shortcut to types to make code more readable
|
||||||
typedef void *serial_port;
|
typedef void *serial_port;
|
||||||
|
@ -77,7 +69,9 @@ void uart_close (const serial_port sp);
|
||||||
void uart_set_speed (serial_port sp, const uint32_t uiPortSpeed);
|
void uart_set_speed (serial_port sp, const uint32_t uiPortSpeed);
|
||||||
uint32_t uart_get_speed (const serial_port sp);
|
uint32_t uart_get_speed (const serial_port sp);
|
||||||
|
|
||||||
int uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx);
|
int uart_receive (serial_port sp, byte_t * pbtRx, const size_t szRx);
|
||||||
int uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx);
|
int uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx);
|
||||||
|
|
||||||
|
char **uart_list_ports (void);
|
||||||
|
|
||||||
#endif // __NFC_BUS_UART_H__
|
#endif // __NFC_BUS_UART_H__
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
|
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
|
||||||
|
* Copyright (C) 2010, Roel Verdult, Romuald Conty
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -23,9 +25,29 @@
|
||||||
* @brief POSIX UART driver
|
* @brief POSIX UART driver
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* vim: set ts=2 sw=2 et: */
|
||||||
|
|
||||||
|
# include <sys/types.h>
|
||||||
# include <sys/select.h>
|
# include <sys/select.h>
|
||||||
# include <sys/param.h>
|
# include <sys/param.h>
|
||||||
|
# include <ctype.h>
|
||||||
# include <termios.h>
|
# include <termios.h>
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <dirent.h>
|
||||||
|
|
||||||
|
# include "nfc-internal.h"
|
||||||
|
|
||||||
|
# if defined(__APPLE__)
|
||||||
|
// FIXME: find UART connection string for PN53X device on Mac OS X when multiples devices are used
|
||||||
|
char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", NULL };
|
||||||
|
# elif defined (__FreeBSD__) || defined (__OpenBSD__)
|
||||||
|
char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL };
|
||||||
|
# elif defined (__linux__)
|
||||||
|
char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", NULL };
|
||||||
|
# else
|
||||||
|
# error "Can't determine serial string for your system"
|
||||||
|
# endif
|
||||||
|
|
||||||
typedef struct termios term_info;
|
typedef struct termios term_info;
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int fd; // Serial port file descriptor
|
int fd; // Serial port file descriptor
|
||||||
|
@ -33,12 +55,6 @@ typedef struct {
|
||||||
term_info tiNew; // Terminal info during the transaction
|
term_info tiNew; // Terminal info during the transaction
|
||||||
} serial_port_unix;
|
} serial_port_unix;
|
||||||
|
|
||||||
// timeval struct that define timeout delay for serial port:
|
|
||||||
// first is constant and currently related to PN53x response delay
|
|
||||||
static const unsigned long int uiTimeoutStatic = 15000; // 15 ms to allow device to respond
|
|
||||||
// second is a per-byte timeout (sets when setting baudrate)
|
|
||||||
static unsigned long int uiTimeoutPerByte = 0;
|
|
||||||
|
|
||||||
// Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
|
// Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
|
||||||
# define CCLAIMED 0x80000000
|
# define CCLAIMED 0x80000000
|
||||||
|
|
||||||
|
@ -85,25 +101,10 @@ uart_open (const char *pcPortName)
|
||||||
return sp;
|
return sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @note This define convert a Baud rate in a per-byte duration (in µs)
|
|
||||||
* Bauds are "symbols per second", so each symbol is bit here.
|
|
||||||
* We want to convert Bd to bytes/s in first time,
|
|
||||||
* 1 serial-transmitted byte is (in 8N1):
|
|
||||||
* - 1 start bit,
|
|
||||||
* - 8 data bits,
|
|
||||||
* - 1 stop bit.
|
|
||||||
*
|
|
||||||
* In 8N1 mode, byte-rate = baud-rate / 10
|
|
||||||
*/
|
|
||||||
#define UART_BAUDRATE_T0_BYTE_DURATION(X) ((1000000 * 10)/ X)
|
|
||||||
|
|
||||||
void
|
void
|
||||||
uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
|
uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
|
||||||
{
|
{
|
||||||
// Set per-byte timeout
|
DBG ("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
|
||||||
uiTimeoutPerByte = UART_BAUDRATE_T0_BYTE_DURATION(uiPortSpeed);
|
|
||||||
DBG ("Serial port speed requested to be set to %d bauds (%lu µs).", uiPortSpeed, uiTimeoutPerByte);
|
|
||||||
const serial_port_unix *spu = (serial_port_unix *) sp;
|
const serial_port_unix *spu = (serial_port_unix *) sp;
|
||||||
|
|
||||||
// Portability note: on some systems, B9600 != 9600 so we have to do
|
// Portability note: on some systems, B9600 != 9600 so we have to do
|
||||||
|
@ -203,28 +204,26 @@ uart_close (const serial_port sp)
|
||||||
free (sp);
|
free (sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct timeval tvTimeout = {
|
||||||
|
.tv_sec = 1,
|
||||||
|
.tv_usec = 0
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Receive data from UART and copy data to \a pbtRx
|
* @brief Receive data from UART and copy data to \a pbtRx
|
||||||
*
|
*
|
||||||
* @return 0 on success, otherwise driver error code
|
* @return 0 on success, otherwise driver error code
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
|
uart_receive (serial_port sp, byte_t * pbtRx, const size_t szRx)
|
||||||
{
|
{
|
||||||
int res;
|
|
||||||
int byteCount;
|
|
||||||
fd_set rfds;
|
|
||||||
|
|
||||||
int iExpectedByteCount = (int)*pszRx;
|
|
||||||
DBG ("iExpectedByteCount == %d", iExpectedByteCount);
|
|
||||||
struct timeval tvTimeout = {
|
|
||||||
.tv_sec = 0,
|
|
||||||
.tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * iExpectedByteCount),
|
|
||||||
};
|
|
||||||
struct timeval tv = tvTimeout;
|
struct timeval tv = tvTimeout;
|
||||||
|
int received_bytes_count = 0;
|
||||||
// Reset the output count
|
int available_bytes_count = 0;
|
||||||
*pszRx = 0;
|
const int expected_bytes_count = (int)szRx;
|
||||||
|
int res;
|
||||||
|
fd_set rfds;
|
||||||
do {
|
do {
|
||||||
// Reset file descriptor
|
// Reset file descriptor
|
||||||
FD_ZERO (&rfds);
|
FD_ZERO (&rfds);
|
||||||
|
@ -238,35 +237,25 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
|
||||||
}
|
}
|
||||||
// Read time-out
|
// Read time-out
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
if (*pszRx == 0) {
|
DBG ("Timeout!");
|
||||||
// Error, we received no data
|
return DETIMEOUT;
|
||||||
// DBG ("RX time-out (%lu µs), buffer empty.", tvTimeout.tv_usec);
|
|
||||||
return DETIMEOUT;
|
|
||||||
} else {
|
|
||||||
// We received some data, but nothing more is available
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Retrieve the count of the incoming bytes
|
// Retrieve the count of the incoming bytes
|
||||||
res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &byteCount);
|
res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &available_bytes_count);
|
||||||
if (res < 0) {
|
if (res != 0) {
|
||||||
return DEIO;
|
return DEIO;
|
||||||
}
|
}
|
||||||
// There is something available, read the data
|
// There is something available, read the data
|
||||||
res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRx), MIN(byteCount, iExpectedByteCount));
|
// DBG ("expected bytes: %zu, received bytes: %d, available bytes: %d", szRx, received_bytes_count, available_bytes_count);
|
||||||
iExpectedByteCount -= MIN (byteCount, iExpectedByteCount);
|
res = read (((serial_port_unix *) sp)->fd, pbtRx + received_bytes_count, MIN(available_bytes_count, (expected_bytes_count - received_bytes_count)));
|
||||||
|
|
||||||
// Stop if the OS has some troubles reading the data
|
// Stop if the OS has some troubles reading the data
|
||||||
if (res <= 0) {
|
if (res <= 0) {
|
||||||
return DEIO;
|
return DEIO;
|
||||||
}
|
}
|
||||||
|
received_bytes_count += res;
|
||||||
|
|
||||||
*pszRx += res;
|
} while (expected_bytes_count > received_bytes_count);
|
||||||
// Reload timeout with a low value to prevent from waiting too long on slow devices (16x is enought to took at least 1 byte)
|
PRINT_HEX ("RX", pbtRx, szRx);
|
||||||
tv.tv_usec = uiTimeoutPerByte * MIN( iExpectedByteCount, 16 );
|
|
||||||
// DBG("Timeout reloaded at: %d µs", tv.tv_usec);
|
|
||||||
} while (byteCount && (iExpectedByteCount > 0));
|
|
||||||
DBG ("byteCount == %d, iExpectedByteCount == %d", byteCount, iExpectedByteCount);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,13 +267,16 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
|
||||||
int
|
int
|
||||||
uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
|
uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
|
||||||
{
|
{
|
||||||
|
PRINT_HEX ("TX", pbtTx, szTx);
|
||||||
|
#if 0
|
||||||
|
if ((int) szTx == write (((serial_port_unix *) sp)->fd, pbtTx, szTx))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return DEIO;
|
||||||
|
#endif
|
||||||
int32_t res;
|
int32_t res;
|
||||||
size_t szPos = 0;
|
size_t szPos = 0;
|
||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
struct timeval tvTimeout = {
|
|
||||||
.tv_sec = 0,
|
|
||||||
.tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * szTx),
|
|
||||||
};
|
|
||||||
struct timeval tv = tvTimeout;
|
struct timeval tv = tvTimeout;
|
||||||
|
|
||||||
while (szPos < szTx) {
|
while (szPos < szTx) {
|
||||||
|
@ -312,10 +304,45 @@ uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
szPos += res;
|
szPos += res;
|
||||||
|
|
||||||
// Reload timeout with a low value to prevent from waiting too long on slow devices (16x is enought to took at least 1 byte)
|
|
||||||
tv.tv_usec = uiTimeoutStatic + uiTimeoutPerByte * MIN( szTx - szPos, 16 );
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char **
|
||||||
|
uart_list_ports (void)
|
||||||
|
{
|
||||||
|
char **res = malloc (sizeof (char *));
|
||||||
|
size_t szRes = 1;
|
||||||
|
|
||||||
|
res[0] = NULL;
|
||||||
|
|
||||||
|
DIR *pdDir = opendir("/dev");
|
||||||
|
struct dirent *pdDirEnt;
|
||||||
|
while ((pdDirEnt = readdir(pdDir)) != NULL) {
|
||||||
|
if (!isdigit (pdDirEnt->d_name[strlen (pdDirEnt->d_name) - 1]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char **p = serial_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;
|
||||||
|
}
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
# set the include path found by configure
|
# set the include path found by configure
|
||||||
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
||||||
|
|
||||||
noinst_HEADERS = pn53x.h
|
noinst_HEADERS = pn53x.h pn53x-internal.h
|
||||||
noinst_LTLIBRARIES = libnfcchips.la
|
noinst_LTLIBRARIES = libnfcchips.la
|
||||||
libnfcchips_la_SOURCES = pn53x.c
|
libnfcchips_la_SOURCES = pn53x.c
|
||||||
libnfcchips_la_CFLAGS = -I$(top_srcdir)/libnfc
|
libnfcchips_la_CFLAGS = -I$(top_srcdir)/libnfc
|
||||||
|
|
||||||
|
|
190
libnfc/chips/pn53x-internal.h
Normal file
190
libnfc/chips/pn53x-internal.h
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
/*-
|
||||||
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
|
*
|
||||||
|
* 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 pn53x-internal.h
|
||||||
|
* @brief PN531, PN532 and PN533 defines and compatibility
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PN53X_INTERNAL_H__
|
||||||
|
#define __PN53X_INTERNAL_H__
|
||||||
|
|
||||||
|
#include "pn53x.h"
|
||||||
|
|
||||||
|
// Miscellaneous
|
||||||
|
#define Diagnose 0x00
|
||||||
|
#define GetFirmwareVersion 0x02
|
||||||
|
#define GetGeneralStatus 0x04
|
||||||
|
#define ReadRegister 0x06
|
||||||
|
#define WriteRegister 0x08
|
||||||
|
#define ReadGPIO 0x0C
|
||||||
|
#define WriteGPIO 0x0E
|
||||||
|
#define SetSerialBaudRate 0x10
|
||||||
|
#define SetParameters 0x12
|
||||||
|
#define SAMConfiguration 0x14
|
||||||
|
#define PowerDown 0x16
|
||||||
|
#define AlparCommandForTDA 0x18
|
||||||
|
|
||||||
|
// RF communication
|
||||||
|
#define RFConfiguration 0x32
|
||||||
|
#define RFRegulationTest 0x58
|
||||||
|
|
||||||
|
// Initiator
|
||||||
|
#define InJumpForDEP 0x56
|
||||||
|
#define InJumpForPSL 0x46
|
||||||
|
#define InListPassiveTarget 0x4A
|
||||||
|
#define InATR 0x50
|
||||||
|
#define InPSL 0x4E
|
||||||
|
#define InDataExchange 0x40
|
||||||
|
#define InCommunicateThru 0x42
|
||||||
|
#define InQuartetByteExchange 0x38
|
||||||
|
#define InDeselect 0x44
|
||||||
|
#define InRelease 0x52
|
||||||
|
#define InSelect 0x54
|
||||||
|
#define InActivateDeactivatePaypass 0x48
|
||||||
|
#define InAutoPoll 0x60
|
||||||
|
|
||||||
|
// Target
|
||||||
|
#define TgInitAsTarget 0x8C
|
||||||
|
#define TgSetGeneralBytes 0x92
|
||||||
|
#define TgGetData 0x86
|
||||||
|
#define TgSetData 0x8E
|
||||||
|
#define TgSetDataSecure 0x96
|
||||||
|
#define TgSetMetaData 0x94
|
||||||
|
#define TgSetMetaDataSecure 0x98
|
||||||
|
#define TgGetInitiatorCommand 0x88
|
||||||
|
#define TgResponseToInitiator 0x90
|
||||||
|
#define TgGetTargetStatus 0x8A
|
||||||
|
|
||||||
|
/** @note PN53x's normal frame:
|
||||||
|
*
|
||||||
|
* .-- Start
|
||||||
|
* | .-- Packet lenght
|
||||||
|
* | | .-- Lenght checksum
|
||||||
|
* | | | .-- Direction (D4 Host to PN, D5 PN to Host)
|
||||||
|
* | | | | .-- Code
|
||||||
|
* | | | | | .-- Packet checksum
|
||||||
|
* | | | | | | .-- Postamble
|
||||||
|
* V | | | | | |
|
||||||
|
* ----- V V V V V V
|
||||||
|
* 00 FF 02 FE D4 02 2A 00
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @note PN53x's extended frame:
|
||||||
|
*
|
||||||
|
* .-- Start
|
||||||
|
* | .-- Fixed to FF to enable extended frame
|
||||||
|
* | | .-- Packet lenght
|
||||||
|
* | | | .-- Lenght checksum
|
||||||
|
* | | | | .-- Direction (D4 Host to PN, D5 PN to Host)
|
||||||
|
* | | | | | .-- Code
|
||||||
|
* | | | | | | .-- Packet checksum
|
||||||
|
* | | | | | | | .-- Postamble
|
||||||
|
* V V V | | | | |
|
||||||
|
* ----- ----- ----- V V V V V
|
||||||
|
* 00 FF FF FF 00 02 FE D4 02 2A 00
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start bytes, packet lenght, lenght checksum, direction, packet checksum and postamble are overhead
|
||||||
|
*/
|
||||||
|
// The TFI is considered part of the overhead
|
||||||
|
# define PN53x_NORMAL_FRAME__DATA_MAX_LEN 254
|
||||||
|
# define PN53x_NORMAL_FRAME__OVERHEAD 8
|
||||||
|
# define PN53x_EXTENDED_FRAME__DATA_MAX_LEN 264
|
||||||
|
# define PN53x_EXTENDED_FRAME__OVERHEAD 11
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t ui8Code;
|
||||||
|
uint8_t ui8CompatFlags;
|
||||||
|
#ifdef DEBUG
|
||||||
|
const char * abtCommandText;
|
||||||
|
#endif
|
||||||
|
} pn53x_command;
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define PN531 0x01
|
||||||
|
#define PN532 0x02
|
||||||
|
#define PN533 0X04
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DEBUG
|
||||||
|
# define PNCMD( X, Y ) { X , Y }
|
||||||
|
# define PNCMD_DBG( X ) do { \
|
||||||
|
} while(0)
|
||||||
|
#else
|
||||||
|
# define PNCMD( X, Y ) { X , Y, #X }
|
||||||
|
# define PNCMD_DBG( X ) do { \
|
||||||
|
for (size_t i=0; i<(sizeof(pn53x_commands)/sizeof(pn53x_command)); i++) { \
|
||||||
|
if ( X == pn53x_commands[i].ui8Code ) { \
|
||||||
|
DBG( "%s", pn53x_commands[i].abtCommandText ); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const pn53x_command pn53x_commands[] = {
|
||||||
|
// Miscellaneous
|
||||||
|
PNCMD( Diagnose, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( GetFirmwareVersion, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( GetGeneralStatus, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( ReadRegister, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( WriteRegister, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( ReadGPIO, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( WriteGPIO, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( SetSerialBaudRate, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( SetParameters, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( SAMConfiguration, PN531|PN532 ),
|
||||||
|
PNCMD( PowerDown, PN531|PN532 ),
|
||||||
|
PNCMD( AlparCommandForTDA, PN533 ),
|
||||||
|
|
||||||
|
// RF communication
|
||||||
|
PNCMD( RFConfiguration, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( RFRegulationTest, PN531|PN532|PN533 ),
|
||||||
|
|
||||||
|
// Initiator
|
||||||
|
PNCMD( InJumpForDEP, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InJumpForPSL, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InListPassiveTarget, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InATR, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InPSL, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InDataExchange, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InCommunicateThru, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InQuartetByteExchange, PN533 ),
|
||||||
|
PNCMD( InDeselect, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InRelease, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InSelect, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( InAutoPoll, PN532 ),
|
||||||
|
PNCMD( InActivateDeactivatePaypass, PN533 ),
|
||||||
|
|
||||||
|
// Target
|
||||||
|
PNCMD( TgInitAsTarget, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( TgSetGeneralBytes, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( TgGetData, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( TgSetData, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( TgSetDataSecure, PN533 ),
|
||||||
|
PNCMD( TgSetMetaData, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( TgSetMetaDataSecure, PN533 ),
|
||||||
|
PNCMD( TgGetInitiatorCommand, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( TgResponseToInitiator, PN531|PN532|PN533 ),
|
||||||
|
PNCMD( TgGetTargetStatus, PN531|PN532|PN533 ),
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __PN53X_INTERNAL_H__ */
|
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,9 @@
|
||||||
/*-
|
/*-
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
|
* Copyright (C) 2009, Roel Verdult, Romuald Conty
|
||||||
|
* Copyright (C) 2010, Roel Verdult, Romuald Conty, Romain Tartière
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -27,11 +29,6 @@
|
||||||
|
|
||||||
# include <nfc/nfc-types.h>
|
# include <nfc/nfc-types.h>
|
||||||
|
|
||||||
# define PN53x_NORMAL_FRAME_MAX_LEN 255
|
|
||||||
# define PN53x_NORMAL_FRAME_OVERHEAD 7
|
|
||||||
# define PN53x_EXTENDED_FRAME_MAX_LEN 264
|
|
||||||
# define PN53x_EXTENDED_FRAME_OVERHEAD 10
|
|
||||||
|
|
||||||
// Registers and symbols masks used to covers parts within a register
|
// Registers and symbols masks used to covers parts within a register
|
||||||
# define REG_CIU_TX_MODE 0x6302
|
# define REG_CIU_TX_MODE 0x6302
|
||||||
# define SYMBOL_TX_CRC_ENABLE 0x80
|
# define SYMBOL_TX_CRC_ENABLE 0x80
|
||||||
|
@ -98,6 +95,24 @@
|
||||||
# define DEISERRFRAME 0x0300/* Error frame */
|
# define DEISERRFRAME 0x0300/* Error frame */
|
||||||
# define DENOTSUP 0x0400/* Not supported */
|
# define DENOTSUP 0x0400/* Not supported */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PN531 = 0x01,
|
||||||
|
PN532 = 0x02,
|
||||||
|
PN533 = 0x04
|
||||||
|
} pn53x_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SLEEP = 0x00, // Need to be wake up to process commands
|
||||||
|
NORMAL = 0x01, // Ready to process command
|
||||||
|
EXECUTE = 0x02, // Need to cancel the running command to process new one
|
||||||
|
} pn53x_state;
|
||||||
|
|
||||||
|
struct pn53x_data {
|
||||||
|
pn53x_type type;
|
||||||
|
pn53x_state state;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* PN53x specific types */
|
/* PN53x specific types */
|
||||||
/**
|
/**
|
||||||
* @enum pn53x_modulation_t
|
* @enum pn53x_modulation_t
|
||||||
|
@ -185,18 +200,17 @@ bool pn53x_check_ack_frame_callback (nfc_device_t * pnd, const byte_t * pbtRx
|
||||||
const size_t szRxFrameLen);
|
const size_t szRxFrameLen);
|
||||||
bool pn53x_check_error_frame_callback (nfc_device_t * pnd, const byte_t * pbtRxFrame,
|
bool pn53x_check_error_frame_callback (nfc_device_t * pnd, const byte_t * pbtRxFrame,
|
||||||
const size_t szRxFrameLen);
|
const size_t szRxFrameLen);
|
||||||
bool pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx,
|
bool pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t *pszRx, bool toto);
|
||||||
size_t * pszRx);
|
bool pn53x_read_register (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t * ui8Value);
|
||||||
bool pn53x_get_reg (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t * ui8Value);
|
bool pn53x_write_register (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t ui8SymbolMask, uint8_t ui8Value);
|
||||||
bool pn53x_set_reg (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t ui8SymbolMask, uint8_t ui8Value);
|
bool pn53x_set_parameters (nfc_device_t * pnd, const uint8_t ui8Value, const bool bEnable);
|
||||||
bool pn53x_set_parameter (nfc_device_t * pnd, const uint8_t ui8Value, const bool bEnable);
|
|
||||||
bool pn53x_set_tx_bits (nfc_device_t * pnd, const uint8_t ui8Bits);
|
bool pn53x_set_tx_bits (nfc_device_t * pnd, const uint8_t ui8Bits);
|
||||||
bool pn53x_wrap_frame (const byte_t * pbtTx, const size_t szTxBits, const byte_t * pbtTxPar, byte_t * pbtFrame,
|
bool pn53x_wrap_frame (const byte_t * pbtTx, const size_t szTxBits, const byte_t * pbtTxPar, byte_t * pbtFrame,
|
||||||
size_t * pszFrameBits);
|
size_t * pszFrameBits);
|
||||||
bool pn53x_unwrap_frame (const byte_t * pbtFrame, const size_t szFrameBits, byte_t * pbtRx, size_t * pszRxBits,
|
bool pn53x_unwrap_frame (const byte_t * pbtFrame, const size_t szFrameBits, byte_t * pbtRx, size_t * pszRxBits,
|
||||||
byte_t * pbtRxPar);
|
byte_t * pbtRxPar);
|
||||||
bool pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData,
|
bool pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData,
|
||||||
nfc_chip_t nc, nfc_modulation_type_t nmt,
|
pn53x_type chip_type, nfc_modulation_type_t nmt,
|
||||||
nfc_target_info_t * pnti);
|
nfc_target_info_t * pnti);
|
||||||
bool pn53x_get_firmware_version (nfc_device_t * pnd, char abtFirmwareText[18]);
|
bool pn53x_get_firmware_version (nfc_device_t * pnd, char abtFirmwareText[18]);
|
||||||
bool pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable);
|
bool pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable);
|
||||||
|
@ -234,6 +248,7 @@ static const struct chip_callbacks pn53x_callbacks_list = {
|
||||||
|
|
||||||
// C wrappers for PN53x commands
|
// C wrappers for PN53x commands
|
||||||
bool pn53x_SetParameters (nfc_device_t * pnd, const uint8_t ui8Value);
|
bool pn53x_SetParameters (nfc_device_t * pnd, const uint8_t ui8Value);
|
||||||
|
bool pn53x_SAMConfiguration (nfc_device_t * pnd, const uint8_t ui8Mode);
|
||||||
bool pn53x_InListPassiveTarget (nfc_device_t * pnd, const pn53x_modulation_t pmInitModulation,
|
bool pn53x_InListPassiveTarget (nfc_device_t * pnd, const pn53x_modulation_t pmInitModulation,
|
||||||
const byte_t szMaxTargets, const byte_t * pbtInitiatorData,
|
const byte_t szMaxTargets, const byte_t * pbtInitiatorData,
|
||||||
const size_t szInitiatorDataLen, byte_t * pbtTargetsData, size_t * pszTargetsData);
|
const size_t szInitiatorDataLen, byte_t * pbtTargetsData, size_t * pszTargetsData);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, Roel Verdult
|
* Copyright (C) 2009, Roel Verdult
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -27,8 +28,6 @@
|
||||||
|
|
||||||
# include <nfc/nfc-types.h>
|
# include <nfc/nfc-types.h>
|
||||||
|
|
||||||
# include "chips/pn53x.h"
|
|
||||||
|
|
||||||
# if defined (DRIVER_ACR122_ENABLED)
|
# if defined (DRIVER_ACR122_ENABLED)
|
||||||
# include "drivers/acr122.h"
|
# include "drivers/acr122.h"
|
||||||
# endif /* DRIVER_ACR122_ENABLED */
|
# endif /* DRIVER_ACR122_ENABLED */
|
||||||
|
@ -54,46 +53,7 @@
|
||||||
# endif /* DRIVER_PN532_UART_ENABLED */
|
# endif /* DRIVER_PN532_UART_ENABLED */
|
||||||
|
|
||||||
# define DRIVERS_MAX_DEVICES 16
|
# define DRIVERS_MAX_DEVICES 16
|
||||||
# define MAX_FRAME_LEN 264
|
|
||||||
|
|
||||||
static const struct driver_callbacks drivers_callbacks_list[] = {
|
extern const struct nfc_driver_t *nfc_drivers[];
|
||||||
// Driver Name Chip callbacks Pick Device List Devices Connect Transceive Disconnect
|
|
||||||
# if defined (DRIVER_PN531_USB_ENABLED)
|
|
||||||
{PN531_USB_DRIVER_NAME, &pn53x_callbacks_list, pn531_usb_pick_device, pn531_usb_list_devices, pn531_usb_connect,
|
|
||||||
NULL, pn53x_usb_transceive, pn53x_usb_disconnect},
|
|
||||||
# endif /* DRIVER_PN531_USB_ENABLED */
|
|
||||||
# if defined (DRIVER_PN533_USB_ENABLED)
|
|
||||||
{PN533_USB_DRIVER_NAME, &pn53x_callbacks_list, pn533_usb_pick_device, pn533_usb_list_devices, pn533_usb_connect,
|
|
||||||
pn533_usb_init, pn53x_usb_transceive, pn53x_usb_disconnect},
|
|
||||||
# endif /* DRIVER_PN533_USB_ENABLED */
|
|
||||||
# if defined (DRIVER_ACR122_ENABLED)
|
|
||||||
{ACR122_DRIVER_NAME, &pn53x_callbacks_list, acr122_pick_device, acr122_list_devices, acr122_connect,
|
|
||||||
NULL, acr122_transceive, acr122_disconnect},
|
|
||||||
# endif /* DRIVER_ACR122_ENABLED */
|
|
||||||
# if defined (DRIVER_ARYGON_ENABLED)
|
|
||||||
{ARYGON_DRIVER_NAME, &pn53x_callbacks_list, arygon_pick_device, arygon_list_devices, arygon_connect,
|
|
||||||
NULL, arygon_transceive, arygon_disconnect},
|
|
||||||
# endif /* DRIVER_ARYGON_ENABLED */
|
|
||||||
# if defined (DRIVER_PN532_UART_ENABLED)
|
|
||||||
{PN532_UART_DRIVER_NAME, &pn53x_callbacks_list, pn532_uart_pick_device, pn532_uart_list_devices, pn532_uart_connect,
|
|
||||||
NULL, pn532_uart_transceive, pn532_uart_disconnect},
|
|
||||||
# endif /* DRIVER_PN532_UART_ENABLED */
|
|
||||||
};
|
|
||||||
|
|
||||||
# ifdef DEBUG
|
|
||||||
/*
|
|
||||||
* TODO Move this helper macro for dumping drivers messages.
|
|
||||||
* Here is not the best place for such a macro, however, I
|
|
||||||
* can't see any convenient place ATM.
|
|
||||||
*/
|
|
||||||
# define PRINT_HEX(pcTag, pbtData, szBytes) do { \
|
|
||||||
size_t __szPos; \
|
|
||||||
printf(" %s: ", pcTag); \
|
|
||||||
for (__szPos=0; __szPos < (size_t)(szBytes); __szPos++) { \
|
|
||||||
printf("%02x ",pbtData[__szPos]); \
|
|
||||||
} \
|
|
||||||
printf("\n"); \
|
|
||||||
} while (0);
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif // __NFC_DRIVERS_H__
|
#endif // __NFC_DRIVERS_H__
|
||||||
|
|
|
@ -119,7 +119,7 @@ arygon_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *
|
||||||
*pszDeviceFound = 0;
|
*pszDeviceFound = 0;
|
||||||
|
|
||||||
serial_port sp;
|
serial_port sp;
|
||||||
const char *pcPorts[] = DEFAULT_SERIAL_PORTS;
|
char **pcPorts = uart_list_ports ();
|
||||||
const char *pcPort;
|
const char *pcPort;
|
||||||
int iDevice = 0;
|
int iDevice = 0;
|
||||||
|
|
||||||
|
@ -155,6 +155,7 @@ arygon_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *
|
||||||
# endif
|
# endif
|
||||||
/* DEBUG */
|
/* DEBUG */
|
||||||
}
|
}
|
||||||
|
free (pcPorts);
|
||||||
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/*-
|
/*-
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, Roel Verdult
|
* Copyright (C) 2010, Roel Verdult, Romuald Conty
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -22,11 +23,13 @@
|
||||||
* @brief PN532 driver using UART bus (UART, RS232, etc.)
|
* @brief PN532 driver using UART bus (UART, RS232, etc.)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* vim: set ts=2 sw=2 et: */
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif // HAVE_CONFIG_H
|
#endif // HAVE_CONFIG_H
|
||||||
|
|
||||||
#include "../drivers.h"
|
#include "libnfc/drivers.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -36,44 +39,26 @@
|
||||||
#include <nfc/nfc.h>
|
#include <nfc/nfc.h>
|
||||||
#include <nfc/nfc-messages.h>
|
#include <nfc/nfc-messages.h>
|
||||||
|
|
||||||
// Bus
|
|
||||||
#include "uart.h"
|
#include "uart.h"
|
||||||
|
#include "libnfc/nfc-internal.h"
|
||||||
|
#include "libnfc/chips/pn53x.h"
|
||||||
|
#include "libnfc/chips/pn53x-internal.h"
|
||||||
|
|
||||||
#define SERIAL_DEFAULT_PORT_SPEED 115200
|
#define SERIAL_DEFAULT_PORT_SPEED 115200
|
||||||
|
|
||||||
// TODO Move this one level up for libnfc-1.6
|
// TODO Move this one level up for libnfc-1.6
|
||||||
static const byte_t ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
|
static const byte_t ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
|
||||||
|
|
||||||
void pn532_uart_ack (const nfc_device_spec_t nds);
|
void pn532_uart_ack (nfc_device_t * pnd);
|
||||||
void pn532_uart_wakeup (const nfc_device_spec_t nds);
|
// void pn532_uart_wakeup (const nfc_device_spec_t nds);
|
||||||
bool pn532_uart_check_communication (const nfc_device_spec_t nds, bool * success);
|
bool pn532_uart_check_communication (nfc_device_t *pnd);
|
||||||
|
|
||||||
nfc_device_desc_t *
|
struct pn532_uart_data {
|
||||||
pn532_uart_pick_device (void)
|
serial_port port;
|
||||||
{
|
};
|
||||||
nfc_device_desc_t *pndd;
|
|
||||||
|
|
||||||
if ((pndd = malloc (sizeof (*pndd)))) {
|
|
||||||
size_t szN;
|
|
||||||
|
|
||||||
if (!pn532_uart_list_devices (pndd, 1, &szN)) {
|
|
||||||
DBG ("%s", "pn532_uart_list_devices failed");
|
|
||||||
free (pndd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (szN == 0) {
|
|
||||||
DBG ("%s", "No device found");
|
|
||||||
free (pndd);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pndd;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pn532_uart_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
|
pn532_uart_probe (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
|
||||||
{
|
{
|
||||||
/** @note: Due to UART bus we can't know if its really a pn532 without
|
/** @note: Due to UART bus we can't know if its really a pn532 without
|
||||||
* sending some PN53x commands. But using this way to probe devices, we can
|
* sending some PN53x commands. But using this way to probe devices, we can
|
||||||
|
@ -88,7 +73,7 @@ pn532_uart_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size
|
||||||
*pszDeviceFound = 0;
|
*pszDeviceFound = 0;
|
||||||
|
|
||||||
serial_port sp;
|
serial_port sp;
|
||||||
const char *pcPorts[] = DEFAULT_SERIAL_PORTS;
|
char **pcPorts = uart_list_ports ();
|
||||||
const char *pcPort;
|
const char *pcPort;
|
||||||
int iDevice = 0;
|
int iDevice = 0;
|
||||||
|
|
||||||
|
@ -97,15 +82,24 @@ pn532_uart_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size
|
||||||
DBG ("Trying to find PN532 device on serial port: %s at %d bauds.", pcPort, SERIAL_DEFAULT_PORT_SPEED);
|
DBG ("Trying to find PN532 device on serial port: %s at %d bauds.", pcPort, SERIAL_DEFAULT_PORT_SPEED);
|
||||||
|
|
||||||
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) {
|
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) {
|
||||||
bool bComOk;
|
|
||||||
// Serial port claimed but we need to check if a PN532_UART is connected.
|
// Serial port claimed but we need to check if a PN532_UART is connected.
|
||||||
uart_set_speed (sp, SERIAL_DEFAULT_PORT_SPEED);
|
uart_set_speed (sp, SERIAL_DEFAULT_PORT_SPEED);
|
||||||
|
|
||||||
|
nfc_device_t nd;
|
||||||
|
nd.driver = &pn532_uart_driver;
|
||||||
|
nd.driver_data = malloc(sizeof(struct pn532_uart_data));
|
||||||
|
((struct pn532_uart_data*)(nd.driver_data))->port = sp;
|
||||||
|
nd.chip_data = malloc(sizeof(struct pn53x_data));
|
||||||
|
((struct pn53x_data*)(nd.chip_data))->type = PN532;
|
||||||
|
((struct pn53x_data*)(nd.chip_data))->state = SLEEP;
|
||||||
|
|
||||||
// PN532 could be powered down, we need to wake it up before line testing.
|
// PN532 could be powered down, we need to wake it up before line testing.
|
||||||
pn532_uart_wakeup ((nfc_device_spec_t) sp);
|
// TODO pn532_uart_wakeup ((nfc_device_spec_t) sp);
|
||||||
// Check communication using "Diagnose" command, with "Communication test" (0x00)
|
// Check communication using "Diagnose" command, with "Communication test" (0x00)
|
||||||
if (!pn532_uart_check_communication ((nfc_device_spec_t) sp, &bComOk))
|
bool res = pn532_uart_check_communication (&nd);
|
||||||
continue;
|
free(nd.driver_data);
|
||||||
if (!bComOk)
|
free(nd.chip_data);
|
||||||
|
if(!res)
|
||||||
continue;
|
continue;
|
||||||
uart_close (sp);
|
uart_close (sp);
|
||||||
|
|
||||||
|
@ -129,6 +123,7 @@ pn532_uart_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size
|
||||||
# endif
|
# endif
|
||||||
/* DEBUG */
|
/* DEBUG */
|
||||||
}
|
}
|
||||||
|
free (pcPorts);
|
||||||
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +133,6 @@ pn532_uart_connect (const nfc_device_desc_t * pndd)
|
||||||
{
|
{
|
||||||
serial_port sp;
|
serial_port sp;
|
||||||
nfc_device_t *pnd = NULL;
|
nfc_device_t *pnd = NULL;
|
||||||
bool bComOk;
|
|
||||||
|
|
||||||
DBG ("Attempt to connect to: %s at %d bauds.", pndd->pcPort, pndd->uiSpeed);
|
DBG ("Attempt to connect to: %s at %d bauds.", pndd->pcPort, pndd->uiSpeed);
|
||||||
sp = uart_open (pndd->pcPort);
|
sp = uart_open (pndd->pcPort);
|
||||||
|
@ -152,24 +146,23 @@ pn532_uart_connect (const nfc_device_desc_t * pndd)
|
||||||
|
|
||||||
uart_set_speed (sp, pndd->uiSpeed);
|
uart_set_speed (sp, pndd->uiSpeed);
|
||||||
|
|
||||||
// PN532 could be powered down, we need to wake it up before line testing.
|
|
||||||
pn532_uart_wakeup ((nfc_device_spec_t) sp);
|
|
||||||
// Check communication using "Diagnose" command, with "Communication test" (0x00)
|
|
||||||
if (!pn532_uart_check_communication ((nfc_device_spec_t) sp, &bComOk))
|
|
||||||
return NULL;
|
|
||||||
if (!bComOk)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
DBG ("Successfully connected to: %s", pndd->pcPort);
|
|
||||||
|
|
||||||
// We have a connection
|
// We have a connection
|
||||||
pnd = malloc (sizeof (nfc_device_t));
|
pnd = malloc (sizeof (nfc_device_t));
|
||||||
strncpy (pnd->acName, pndd->acDevice, DEVICE_NAME_LENGTH - 1);
|
strncpy (pnd->acName, pndd->acDevice, DEVICE_NAME_LENGTH - 1);
|
||||||
pnd->acName[DEVICE_NAME_LENGTH - 1] = '\0';
|
pnd->acName[DEVICE_NAME_LENGTH - 1] = '\0';
|
||||||
|
|
||||||
pnd->nc = NC_PN532;
|
pnd->driver_data = malloc(sizeof(struct pn532_uart_data));
|
||||||
pnd->nds = (nfc_device_spec_t) sp;
|
((struct pn532_uart_data*)(pnd->driver_data))->port = sp;
|
||||||
pnd->bActive = true;
|
pnd->chip_data = malloc(sizeof(struct pn53x_data));
|
||||||
|
((struct pn53x_data*)(pnd->chip_data))->type = PN532;
|
||||||
|
((struct pn53x_data*)(pnd->chip_data))->state = SLEEP;
|
||||||
|
pnd->driver = &pn532_uart_driver;
|
||||||
|
|
||||||
|
// Check communication using "Diagnose" command, with "Communication test" (0x00)
|
||||||
|
if (!pn532_uart_check_communication (pnd))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
DBG ("Successfully connected to: %s", pndd->pcPort);
|
||||||
|
|
||||||
return pnd;
|
return pnd;
|
||||||
}
|
}
|
||||||
|
@ -177,196 +170,220 @@ pn532_uart_connect (const nfc_device_desc_t * pndd)
|
||||||
void
|
void
|
||||||
pn532_uart_disconnect (nfc_device_t * pnd)
|
pn532_uart_disconnect (nfc_device_t * pnd)
|
||||||
{
|
{
|
||||||
uart_close ((serial_port) pnd->nds);
|
uart_close (((struct pn532_uart_data*)(pnd->driver_data))->port);
|
||||||
|
free (pnd->driver_data);
|
||||||
|
free (pnd->chip_data);
|
||||||
free (pnd);
|
free (pnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TX_BUFFER_LEN (256)
|
#define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD)
|
||||||
#define RX_BUFFER_LEN (PN53x_EXTENDED_FRAME_MAX_LEN + PN53x_EXTENDED_FRAME_OVERHEAD)
|
|
||||||
bool
|
bool
|
||||||
pn532_uart_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx,
|
pn532_uart_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData)
|
||||||
size_t * pszRx)
|
|
||||||
{
|
{
|
||||||
byte_t abtTxBuf[TX_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
DBG ("state: %d (SLEEP: %d, NORMAL: %d, EXECUTE: %d)", ((struct pn53x_data*)(pnd->chip_data))->state, SLEEP, NORMAL, EXECUTE);
|
||||||
byte_t abtRxBuf[RX_BUFFER_LEN];
|
if (((struct pn53x_data*)(pnd->chip_data))->state == SLEEP) {
|
||||||
size_t szRxBufLen = MIN( RX_BUFFER_LEN, *pszRx );
|
// if (1) {
|
||||||
size_t szPos;
|
/** PN532C106 wakeup. */
|
||||||
int res;
|
/** High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for PN532 being wakeup. */
|
||||||
|
const byte_t pn532_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00 };
|
||||||
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
|
//, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||||
abtTxBuf[3] = szTx;
|
uart_send (((struct pn532_uart_data*)(pnd->driver_data))->port, pn532_wakeup_preamble, sizeof (pn532_wakeup_preamble));
|
||||||
// Packet length checksum
|
((struct pn53x_data*)(pnd->chip_data))->state = NORMAL; // PN532 should now be awake
|
||||||
abtTxBuf[4] = 256 - abtTxBuf[3];
|
// 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
|
||||||
// Copy the PN53X command into the packet buffer
|
if (!pn53x_SAMConfiguration (pnd, 0x01)) {
|
||||||
memmove (abtTxBuf + 5, pbtTx, szTx);
|
return false;
|
||||||
|
}
|
||||||
// Calculate data payload checksum
|
|
||||||
abtTxBuf[szTx + 5] = 0;
|
|
||||||
for (szPos = 0; szPos < szTx; szPos++) {
|
|
||||||
abtTxBuf[szTx + 5] -= abtTxBuf[szPos + 5];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of stream marker
|
byte_t abtTxBuf[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||||
abtTxBuf[szTx + 6] = 0;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
pnd->iLastCommand = pbtData[0];
|
||||||
PRINT_HEX ("TX", abtTxBuf, szTx + 7);
|
size_t szFrame = 0;
|
||||||
#endif
|
|
||||||
res = uart_send ((serial_port) pnd->nds, abtTxBuf, szTx + 7);
|
if (szData <= PN53x_NORMAL_FRAME__DATA_MAX_LEN) {
|
||||||
|
// LEN - Packet length = data length (len) + checksum (1) + end of stream marker (1)
|
||||||
|
abtTxBuf[3] = szData + 1;
|
||||||
|
// LCS - Packet length checksum
|
||||||
|
abtTxBuf[4] = 256 - (szData + 1);
|
||||||
|
// TFI
|
||||||
|
abtTxBuf[5] = 0xD4;
|
||||||
|
// DATA - Copy the PN53X command into the packet buffer
|
||||||
|
memcpy (abtTxBuf + 6, pbtData, szData);
|
||||||
|
|
||||||
|
// DCS - Calculate data payload checksum
|
||||||
|
byte_t btDCS = (256 - 0xD4);
|
||||||
|
for (size_t szPos = 0; szPos < szData; szPos++) {
|
||||||
|
btDCS -= pbtData[szPos];
|
||||||
|
}
|
||||||
|
abtTxBuf[6 + szData] = btDCS;
|
||||||
|
|
||||||
|
// 0x00 - End of stream marker
|
||||||
|
abtTxBuf[szData + 7] = 0x00;
|
||||||
|
|
||||||
|
szFrame = szData + PN53x_NORMAL_FRAME__OVERHEAD;
|
||||||
|
} else {
|
||||||
|
// FIXME: Build extended frame
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
int res = uart_send (((struct pn532_uart_data*)(pnd->driver_data))->port, abtTxBuf, szFrame);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
ERR ("%s", "Unable to transmit data. (TX)");
|
ERR ("%s", "Unable to transmit data. (TX)");
|
||||||
pnd->iLastError = res;
|
pnd->iLastError = res;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = uart_receive ((serial_port) pnd->nds, abtRxBuf, &szRxBufLen);
|
byte_t abtRxBuf[6];
|
||||||
|
res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 6);
|
||||||
|
if (res != 0) {
|
||||||
|
ERR ("%s", "Unable to read ACK");
|
||||||
|
pnd->iLastError = res;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pn53x_check_ack_frame_callback (pnd, abtRxBuf, sizeof(abtRxBuf))) {
|
||||||
|
((struct pn53x_data*)(pnd->chip_data))->state = EXECUTE;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pn532_uart_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen)
|
||||||
|
{
|
||||||
|
byte_t abtRxBuf[5];
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
int res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 5);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
ERR ("%s", "Unable to receive data. (RX)");
|
ERR ("%s", "Unable to receive data. (RX)");
|
||||||
pnd->iLastError = res;
|
pnd->iLastError = res;
|
||||||
return false;
|
return -1;
|
||||||
}
|
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("RX", abtRxBuf, szRxBufLen);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// WARN: UART is a per byte reception, so you usually receive ACK and next frame the same time
|
|
||||||
if (!pn53x_check_ack_frame_callback (pnd, abtRxBuf, szRxBufLen))
|
|
||||||
return false;
|
|
||||||
szRxBufLen -= sizeof (ack_frame);
|
|
||||||
memmove (abtRxBuf, abtRxBuf + sizeof (ack_frame), szRxBufLen);
|
|
||||||
|
|
||||||
if (szRxBufLen == 0) {
|
|
||||||
szRxBufLen = RX_BUFFER_LEN;
|
|
||||||
do {
|
|
||||||
delay_ms (10);
|
|
||||||
res = uart_receive ((serial_port) pnd->nds, abtRxBuf, &szRxBufLen);
|
|
||||||
} while (res != 0);
|
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("RX", abtRxBuf, szRxBufLen);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
|
||||||
PRINT_HEX ("TX", ack_frame, sizeof(ack_frame));
|
if (0 != (memcmp (abtRxBuf, pn53x_preamble, 3))) {
|
||||||
#endif
|
ERR ("%s", "Frame preamble+start code mismatch");
|
||||||
res = uart_send ((serial_port) pnd->nds, ack_frame, sizeof(ack_frame));
|
pnd->iLastError = DEIO;
|
||||||
if (res != 0) {
|
return -1;
|
||||||
ERR ("%s", "Unable to transmit data. (TX)");
|
|
||||||
pnd->iLastError = res;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pn53x_check_error_frame_callback (pnd, abtRxBuf, szRxBufLen))
|
if ((0x01 == abtRxBuf[3]) && (0xff == abtRxBuf[4])) {
|
||||||
return false;
|
// Error frame
|
||||||
|
uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 3);
|
||||||
// When the answer should be ignored, just return a successful result
|
ERR ("%s", "Application level error detected");
|
||||||
if (pbtRx == NULL || pszRx == NULL)
|
pnd->iLastError = DEISERRFRAME;
|
||||||
return true;
|
return -1;
|
||||||
|
} else if ((0xff == abtRxBuf[3]) && (0xff == abtRxBuf[4])) {
|
||||||
// Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
|
// Extended frame
|
||||||
if (szRxBufLen < 9) {
|
// FIXME: Code this
|
||||||
pnd->iLastError = DEINVAL;
|
abort ();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Remove the preceding and appending bytes 00 00 ff 00 ff 00 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
|
|
||||||
*pszRx = szRxBufLen - 9;
|
|
||||||
memcpy (pbtRx, abtRxBuf + 7, *pszRx);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
pn532_uart_ack (const nfc_device_spec_t nds)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("TX", ack_frame, sizeof (ack_frame));
|
|
||||||
#endif
|
|
||||||
uart_send ((serial_port) nds, ack_frame, sizeof (ack_frame));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
pn532_uart_wait_for_ack(const nfc_device_spec_t nds)
|
|
||||||
{
|
|
||||||
byte_t abtRx[RX_BUFFER_LEN];
|
|
||||||
size_t szRx = sizeof(ack_frame);
|
|
||||||
if (0 == uart_receive ((serial_port) nds, abtRx, &szRx)) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("RX", abtRx, szRx);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
ERR ("No ACK.");
|
// Normal frame
|
||||||
return false;
|
if (256 != (abtRxBuf[3] + abtRxBuf[4])) {
|
||||||
}
|
// TODO: Retry
|
||||||
if (0 != memcmp (ack_frame, abtRx, szRx))
|
ERR ("%s", "Length checksum mismatch");
|
||||||
return false;
|
pnd->iLastError = DEIO;
|
||||||
return true;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PN53X_RX_OVERHEAD 6
|
// abtRxBuf[3] (LEN) include TFI + (CC+1)
|
||||||
void
|
len = abtRxBuf[3] - 2;
|
||||||
pn532_uart_wakeup (const nfc_device_spec_t nds)
|
|
||||||
{
|
|
||||||
byte_t abtRx[RX_BUFFER_LEN];
|
|
||||||
size_t szRx = PN53x_NORMAL_FRAME_OVERHEAD + 2;
|
|
||||||
/** PN532C106 wakeup. */
|
|
||||||
/** High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for PN532 being wakeup. */
|
|
||||||
/** After the preamble we request the PN532C106 chip to switch to "normal" mode (SAM is not used) */
|
|
||||||
const byte_t pncmd_pn532c106_wakeup_preamble[] =
|
|
||||||
{ 0x55, 0x55, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00 }; // Here we send a SAMConfiguration command (Normal mode, the SAM is not used; this is the default mode)
|
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("TX", pncmd_pn532c106_wakeup_preamble, sizeof (pncmd_pn532c106_wakeup_preamble));
|
|
||||||
#endif
|
|
||||||
uart_send ((serial_port) nds, pncmd_pn532c106_wakeup_preamble, sizeof (pncmd_pn532c106_wakeup_preamble));
|
|
||||||
|
|
||||||
pn532_uart_wait_for_ack(nds);
|
|
||||||
|
|
||||||
if (0 == uart_receive ((serial_port) nds, abtRx, &szRx)) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("RX", abtRx, szRx);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
ERR ("Unable to wakeup the PN532.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
pn532_uart_check_communication (const nfc_device_spec_t nds, bool * success)
|
|
||||||
{
|
|
||||||
byte_t abtRx[RX_BUFFER_LEN];
|
|
||||||
const byte_t attempted_result[] =
|
|
||||||
{ 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x09, 0xf7, 0xD5, 0x01, 0x00, 'l', 'i', 'b', 'n', 'f', 'c',
|
|
||||||
0xbc, 0x00 };
|
|
||||||
size_t szRx = sizeof(attempted_result);
|
|
||||||
int res;
|
|
||||||
|
|
||||||
/** To be sure that PN532 is alive, we have put a "Diagnose" command to execute a "Communication Line Test" */
|
|
||||||
const byte_t pncmd_communication_test[] =
|
|
||||||
{ 0x00, 0x00, 0xff, 0x09, 0xf7, 0xd4, 0x00, 0x00, 'l', 'i', 'b', 'n', 'f', 'c', 0xbe, 0x00 };
|
|
||||||
|
|
||||||
*success = false;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("TX", pncmd_communication_test, sizeof (pncmd_communication_test));
|
|
||||||
#endif
|
|
||||||
res = uart_send ((serial_port) nds, pncmd_communication_test, sizeof (pncmd_communication_test));
|
|
||||||
if (res != 0) {
|
|
||||||
ERR ("%s", "Unable to transmit data. (TX)");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res = uart_receive ((serial_port) nds, abtRx, &szRx);
|
if (len > szDataLen) {
|
||||||
|
ERR ("Unable to receive data: buffer too small. (szDataLen: %zu, len: %zu)", szDataLen, len);
|
||||||
|
pnd->iLastError = DEIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TFI + PD0 (CC+1)
|
||||||
|
res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 2);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
ERR ("%s", "Unable to receive data. (RX)");
|
ERR ("%s", "Unable to receive data. (RX)");
|
||||||
return false;
|
pnd->iLastError = res;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
|
||||||
PRINT_HEX ("RX", abtRx, szRx);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (0 == memcmp (abtRx, attempted_result, sizeof (attempted_result)))
|
if (abtRxBuf[0] != 0xD5) {
|
||||||
*success = true;
|
ERR ("%s", "TFI Mismatch");
|
||||||
|
pnd->iLastError = DEIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
if (abtRxBuf[1] != pnd->iLastCommand + 1) {
|
||||||
|
ERR ("%s", "Command Code verification failed");
|
||||||
|
pnd->iLastError = DEIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, pbtData, len);
|
||||||
|
if (res != 0) {
|
||||||
|
ERR ("%s", "Unable to receive data. (RX)");
|
||||||
|
pnd->iLastError = res;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 2);
|
||||||
|
if (res != 0) {
|
||||||
|
ERR ("%s", "Unable to receive data. (RX)");
|
||||||
|
pnd->iLastError = res;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_t btDCS = (256 - 0xD5);
|
||||||
|
btDCS -= pnd->iLastCommand + 1;
|
||||||
|
for (size_t szPos = 0; szPos < len; szPos++) {
|
||||||
|
btDCS -= pbtData[szPos];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btDCS != abtRxBuf[0]) {
|
||||||
|
ERR ("%s", "Data checksum mismatch");
|
||||||
|
pnd->iLastError = DEIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0x00 != abtRxBuf[1]) {
|
||||||
|
ERR ("%s", "Frame postamble mismatch");
|
||||||
|
pnd->iLastError = DEIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
((struct pn53x_data*)(pnd->chip_data))->state = NORMAL;
|
||||||
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pn532_uart_ack (nfc_device_t * pnd)
|
||||||
|
{
|
||||||
|
uart_send (((struct pn532_uart_data*)(pnd->driver_data))->port, ack_frame, sizeof (ack_frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
pn532_uart_check_communication (nfc_device_t *pnd)
|
||||||
|
{
|
||||||
|
const byte_t abtMsg[] = { Diagnose, 0x00, 'l', 'i', 'b', 'n', 'f', 'c' };
|
||||||
|
if (!pn532_uart_send (pnd, abtMsg, sizeof (abtMsg)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const byte_t abtExpectedRes[] = { 0x00, 'l', 'i', 'b', 'n', 'f', 'c' };
|
||||||
|
|
||||||
|
byte_t abtRes[sizeof(abtExpectedRes)];
|
||||||
|
int res;
|
||||||
|
if ((res = pn532_uart_receive (pnd, abtRes, sizeof(abtRes))) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return ((sizeof(abtRes) == res) && (0 == memcmp (abtRes, abtExpectedRes, sizeof(abtExpectedRes))));
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct nfc_driver_t pn532_uart_driver = {
|
||||||
|
.name = PN532_UART_DRIVER_NAME,
|
||||||
|
.probe = pn532_uart_probe,
|
||||||
|
.connect = pn532_uart_connect,
|
||||||
|
.send = pn532_uart_send,
|
||||||
|
.receive = pn532_uart_receive,
|
||||||
|
.disconnect = pn532_uart_disconnect,
|
||||||
|
.strerror = pn53x_strerror,
|
||||||
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
/**
|
/**
|
||||||
* Public platform independent Near Field Communication (NFC) library
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, Roel Verdult
|
* Copyright (C) 2010, Roel Verdult, Romuald Conty
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -30,13 +31,15 @@
|
||||||
|
|
||||||
// Functions used by developer to handle connection to this device
|
// Functions used by developer to handle connection to this device
|
||||||
nfc_device_desc_t *pn532_uart_pick_device (void);
|
nfc_device_desc_t *pn532_uart_pick_device (void);
|
||||||
bool pn532_uart_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound);
|
bool pn532_uart_probe (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound);
|
||||||
|
|
||||||
nfc_device_t *pn532_uart_connect (const nfc_device_desc_t * pndd);
|
nfc_device_t *pn532_uart_connect (const nfc_device_desc_t * pndd);
|
||||||
void pn532_uart_disconnect (nfc_device_t * pnd);
|
void pn532_uart_disconnect (nfc_device_t * pnd);
|
||||||
|
|
||||||
// Callback function used by libnfc to transmit commands to the PN53X chip
|
// Callback function used by libnfc to transmit commands to the PN53X chip
|
||||||
bool pn532_uart_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx,
|
bool pn532_uart_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData);
|
||||||
size_t * pszRx);
|
int pn532_uart_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen);
|
||||||
|
|
||||||
|
extern const struct nfc_driver_t pn532_uart_driver;
|
||||||
|
|
||||||
#endif // ! __NFC_DRIVER_PN532_UART_H__
|
#endif // ! __NFC_DRIVER_PN532_UART_H__
|
||||||
|
|
56
libnfc/nfc-internal.h
Normal file
56
libnfc/nfc-internal.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*-
|
||||||
|
* Public platform independent Near Field Communication (NFC) library
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011, Romain Tartière, Romuald Conty
|
||||||
|
*
|
||||||
|
* 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 nfc-internal.h
|
||||||
|
* @brief Internal defines and macros
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NFC_INTERNAL_H__
|
||||||
|
# define __NFC_INTERNAL_H__
|
||||||
|
|
||||||
|
# ifdef DEBUG
|
||||||
|
//# if 1
|
||||||
|
# define PRINT_HEX(pcTag, pbtData, szBytes) do { \
|
||||||
|
size_t __szPos; \
|
||||||
|
printf(" %s: ", pcTag); \
|
||||||
|
for (__szPos=0; __szPos < (size_t)(szBytes); __szPos++) { \
|
||||||
|
printf("%02x ",pbtData[__szPos]); \
|
||||||
|
} \
|
||||||
|
printf("\n"); \
|
||||||
|
} while (0);
|
||||||
|
# else
|
||||||
|
# define PRINT_HEX(pcTag, pbtData, szBytes) do { \
|
||||||
|
(void) pcTag; \
|
||||||
|
(void) pbtData; \
|
||||||
|
(void) szBytes; \
|
||||||
|
} while (0);
|
||||||
|
# endif
|
||||||
|
|
||||||
|
struct nfc_driver_t {
|
||||||
|
const char *name;
|
||||||
|
bool (*probe)(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound);
|
||||||
|
nfc_device_t * (*connect)(const nfc_device_desc_t * pndd);
|
||||||
|
bool (*send)(nfc_device_t * pnd, const byte_t * pbtData, const size_t szData);
|
||||||
|
int (*receive)(nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen);
|
||||||
|
void (*disconnect)(nfc_device_t * pnd);
|
||||||
|
const char *(*strerror)(const nfc_device_t * pnd);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __NFC_INTERNAL_H__
|
122
libnfc/nfc.c
122
libnfc/nfc.c
|
@ -3,6 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009, Roel Verdult, Romuald Conty
|
* Copyright (C) 2009, Roel Verdult, Romuald Conty
|
||||||
* Copyright (C) 2010, Roel Verdult, Romuald Conty, Romain Tartière
|
* Copyright (C) 2010, Roel Verdult, Romuald Conty, Romain Tartière
|
||||||
|
* Copyright (C) 2011, Romuald Conty, Romain Tartière
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it
|
* 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
|
* under the terms of the GNU Lesser General Public License as published by the
|
||||||
|
@ -23,6 +24,8 @@
|
||||||
* @brief NFC library implementation
|
* @brief NFC library implementation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* vim:set ts=2 sw=2 et: */
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
# include "config.h"
|
# include "config.h"
|
||||||
#endif // HAVE_CONFIG_H
|
#endif // HAVE_CONFIG_H
|
||||||
|
@ -40,11 +43,19 @@
|
||||||
|
|
||||||
#include "chips.h"
|
#include "chips.h"
|
||||||
#include "drivers.h"
|
#include "drivers.h"
|
||||||
|
#include "nfc-internal.h"
|
||||||
|
|
||||||
#include <nfc/nfc-messages.h>
|
#include <nfc/nfc-messages.h>
|
||||||
|
|
||||||
nfc_device_desc_t *nfc_pick_device (void);
|
nfc_device_desc_t *nfc_pick_device (void);
|
||||||
|
|
||||||
|
const struct nfc_driver_t *nfc_drivers[] = {
|
||||||
|
# if defined (DRIVER_PN532_UART_ENABLED)
|
||||||
|
&pn532_uart_driver,
|
||||||
|
# endif /* DRIVER_PN532_UART_ENABLED */
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Connect to a NFC device
|
* @brief Connect to a NFC device
|
||||||
* @param pndd device description if specific device is wanted, \c NULL otherwise
|
* @param pndd device description if specific device is wanted, \c NULL otherwise
|
||||||
|
@ -71,50 +82,32 @@ nfc_device_t *
|
||||||
nfc_connect (nfc_device_desc_t * pndd)
|
nfc_connect (nfc_device_desc_t * pndd)
|
||||||
{
|
{
|
||||||
nfc_device_t *pnd = NULL;
|
nfc_device_t *pnd = NULL;
|
||||||
uint32_t uiDriver;
|
|
||||||
|
if (pndd == NULL)
|
||||||
|
pndd = nfc_pick_device ();
|
||||||
|
|
||||||
|
if (pndd == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
// Search through the device list for an available device
|
// Search through the device list for an available device
|
||||||
for (uiDriver = 0; uiDriver < sizeof (drivers_callbacks_list) / sizeof (drivers_callbacks_list[0]); uiDriver++) {
|
const struct nfc_driver_t *ndr;
|
||||||
if (pndd == NULL) {
|
const struct nfc_driver_t **pndr = nfc_drivers;
|
||||||
// No device description specified: try to automatically claim a device
|
while ((ndr = *pndr)) {
|
||||||
if (drivers_callbacks_list[uiDriver].pick_device != NULL) {
|
// Specific device is requested: using device description pndd
|
||||||
DBG ("Autodetecting available devices using %s driver.", drivers_callbacks_list[uiDriver].acDriver);
|
if (0 != strcmp (ndr->name, pndd->pcDriver)) {
|
||||||
pndd = drivers_callbacks_list[uiDriver].pick_device ();
|
continue;
|
||||||
|
|
||||||
if (pndd != NULL) {
|
|
||||||
DBG ("Auto-connecting to %s using %s driver", pndd->acDevice, drivers_callbacks_list[uiDriver].acDriver);
|
|
||||||
pnd = drivers_callbacks_list[uiDriver].connect (pndd);
|
|
||||||
if (pnd == NULL) {
|
|
||||||
DBG ("No device available using %s driver", drivers_callbacks_list[uiDriver].acDriver);
|
|
||||||
pndd = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free (pndd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Specific device is requested: using device description pndd
|
pnd = ndr->connect (pndd);
|
||||||
if (0 != strcmp (drivers_callbacks_list[uiDriver].acDriver, pndd->pcDriver)) {
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
pnd = drivers_callbacks_list[uiDriver].connect (pndd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test if the connection was successful
|
// Test if the connection was successful
|
||||||
if (pnd != NULL) {
|
if (pnd != NULL) {
|
||||||
DBG ("[%s] has been claimed.", pnd->acName);
|
DBG ("[%s] has been claimed.", pnd->acName);
|
||||||
// Great we have claimed a device
|
|
||||||
pnd->pdc = &(drivers_callbacks_list[uiDriver]);
|
|
||||||
|
|
||||||
// TODO: Put this pn53x related in driver_init()
|
// TODO: Put this pn53x related in driver_init()
|
||||||
if (!pn53x_init (pnd))
|
if (!pn53x_init (pnd))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (pnd->pdc->init) {
|
|
||||||
pnd->pdc->init (pnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default configuration options
|
// Set default configuration options
|
||||||
// Make sure we reset the CRC and parity to chip handling.
|
// Make sure we reset the CRC and parity to chip handling.
|
||||||
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true))
|
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true))
|
||||||
|
@ -144,8 +137,9 @@ nfc_connect (nfc_device_desc_t * pndd)
|
||||||
|
|
||||||
return pnd;
|
return pnd;
|
||||||
} else {
|
} else {
|
||||||
DBG ("No device found using driver: %s", drivers_callbacks_list[uiDriver].acDriver);
|
DBG ("No device found using driver: %s", ndr->name);
|
||||||
}
|
}
|
||||||
|
pndr++;
|
||||||
}
|
}
|
||||||
// Too bad, no reader is ready to be claimed
|
// Too bad, no reader is ready to be claimed
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -166,7 +160,7 @@ nfc_disconnect (nfc_device_t * pnd)
|
||||||
// Disable RF field to avoid heating
|
// Disable RF field to avoid heating
|
||||||
nfc_configure (pnd, NDO_ACTIVATE_FIELD, false);
|
nfc_configure (pnd, NDO_ACTIVATE_FIELD, false);
|
||||||
// Disconnect, clean up and release the device
|
// Disconnect, clean up and release the device
|
||||||
pnd->pdc->disconnect (pnd);
|
pnd->driver->disconnect (pnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,17 +171,31 @@ nfc_disconnect (nfc_device_t * pnd)
|
||||||
nfc_device_desc_t *
|
nfc_device_desc_t *
|
||||||
nfc_pick_device (void)
|
nfc_pick_device (void)
|
||||||
{
|
{
|
||||||
uint32_t uiDriver;
|
const struct nfc_driver_t *ndr;
|
||||||
nfc_device_desc_t *nddRes;
|
const struct nfc_driver_t **pndr = nfc_drivers;
|
||||||
|
while ((ndr = *pndr)) {
|
||||||
|
nfc_device_desc_t *pndd;
|
||||||
|
|
||||||
for (uiDriver = 0; uiDriver < sizeof (drivers_callbacks_list) / sizeof (drivers_callbacks_list[0]); uiDriver++) {
|
if ((pndd = malloc (sizeof (*pndd)))) {
|
||||||
if (drivers_callbacks_list[uiDriver].pick_device != NULL) {
|
size_t szN;
|
||||||
nddRes = drivers_callbacks_list[uiDriver].pick_device ();
|
|
||||||
if (nddRes != NULL)
|
if (!ndr->probe (pndd, 1, &szN)) {
|
||||||
return nddRes;
|
DBG ("%s probe failed", ndr->name);
|
||||||
|
free (pndd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (szN == 0) {
|
||||||
|
DBG ("No %s device found", ndr->name);
|
||||||
|
free (pndd);
|
||||||
|
} else {
|
||||||
|
return pndd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
pndr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DBG ("%s", "No device found with any driver :-(");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,22 +208,19 @@ nfc_pick_device (void)
|
||||||
void
|
void
|
||||||
nfc_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
|
nfc_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
|
||||||
{
|
{
|
||||||
uint32_t uiDriver;
|
|
||||||
size_t szN;
|
size_t szN;
|
||||||
|
|
||||||
*pszDeviceFound = 0;
|
*pszDeviceFound = 0;
|
||||||
|
|
||||||
for (uiDriver = 0; uiDriver < sizeof (drivers_callbacks_list) / sizeof (drivers_callbacks_list[0]); uiDriver++) {
|
const struct nfc_driver_t *ndr;
|
||||||
if (drivers_callbacks_list[uiDriver].list_devices != NULL) {
|
const struct nfc_driver_t **pndr = nfc_drivers;
|
||||||
szN = 0;
|
while ((ndr = *pndr)) {
|
||||||
if (drivers_callbacks_list[uiDriver].list_devices
|
szN = 0;
|
||||||
(pnddDevices + (*pszDeviceFound), szDevices - (*pszDeviceFound), &szN)) {
|
if (ndr->probe (pnddDevices + (*pszDeviceFound), szDevices - (*pszDeviceFound), &szN)) {
|
||||||
*pszDeviceFound += szN;
|
*pszDeviceFound += szN;
|
||||||
DBG ("%ld device(s) found using %s driver", (unsigned long) szN, drivers_callbacks_list[uiDriver].acDriver);
|
DBG ("%ld device(s) found using %s driver", (unsigned long) szN, ndr->name);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DBG ("No listing function avaible for %s driver", drivers_callbacks_list[uiDriver].acDriver);
|
|
||||||
}
|
}
|
||||||
|
pndr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,16 +258,12 @@ nfc_initiator_init (nfc_device_t * pnd)
|
||||||
{
|
{
|
||||||
pnd->iLastError = 0;
|
pnd->iLastError = 0;
|
||||||
|
|
||||||
// Make sure we are dealing with a active device
|
|
||||||
if (!pnd->bActive)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards)
|
// Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards)
|
||||||
if (!pn53x_set_reg (pnd, REG_CIU_TX_AUTO, SYMBOL_FORCE_100_ASK, 0x40))
|
if (!pn53x_write_register (pnd, REG_CIU_TX_AUTO, SYMBOL_FORCE_100_ASK, 0x40))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Configure the PN53X to be an Initiator or Reader/Writer
|
// Configure the PN53X to be an Initiator or Reader/Writer
|
||||||
if (!pn53x_set_reg (pnd, REG_CIU_CONTROL, SYMBOL_INITIATOR, 0x10))
|
if (!pn53x_write_register (pnd, REG_CIU_CONTROL, SYMBOL_INITIATOR, 0x10))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -294,14 +295,11 @@ nfc_initiator_select_passive_target (nfc_device_t * pnd,
|
||||||
const byte_t * pbtInitData, const size_t szInitData,
|
const byte_t * pbtInitData, const size_t szInitData,
|
||||||
nfc_target_t * pnt)
|
nfc_target_t * pnt)
|
||||||
{
|
{
|
||||||
byte_t abtInit[MAX_FRAME_LEN];
|
byte_t abtInit[MAX(12, szInitData)];
|
||||||
size_t szInit;
|
size_t szInit;
|
||||||
|
|
||||||
pnd->iLastError = 0;
|
pnd->iLastError = 0;
|
||||||
|
|
||||||
// Make sure we are dealing with a active device
|
|
||||||
if (!pnd->bActive)
|
|
||||||
return false;
|
|
||||||
// TODO Put this in a function: this part is defined by ISO14443-3 (UID and Cascade levels)
|
// TODO Put this in a function: this part is defined by ISO14443-3 (UID and Cascade levels)
|
||||||
switch (nm.nmt) {
|
switch (nm.nmt) {
|
||||||
case NMT_ISO14443A:
|
case NMT_ISO14443A:
|
||||||
|
@ -662,7 +660,7 @@ nfc_target_receive_bits (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxBits,
|
||||||
const char *
|
const char *
|
||||||
nfc_strerror (const nfc_device_t * pnd)
|
nfc_strerror (const nfc_device_t * pnd)
|
||||||
{
|
{
|
||||||
return pnd->pdc->pcc->strerror (pnd);
|
return pnd->driver->strerror (pnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
#include <cutter.h>
|
#include <cutter.h>
|
||||||
|
|
||||||
#include <nfc/nfc.h>
|
#include <nfc/nfc.h>
|
||||||
#include "../libnfc/chips/pn53x.h"
|
#include "libnfc/chips/pn53x.h"
|
||||||
|
|
||||||
#define MAX_DEVICE_COUNT 1
|
#define MAX_DEVICE_COUNT 1
|
||||||
#define MAX_TARGET_COUNT 1
|
#define MAX_TARGET_COUNT 1
|
||||||
|
|
||||||
bool pn53x_get_reg(nfc_device_t* pnd, uint16_t ui16Reg, uint8_t* ui8Value);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
test_register_endianness (void)
|
test_register_endianness (void)
|
||||||
{
|
{
|
||||||
|
@ -27,21 +25,21 @@ test_register_endianness (void)
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
|
|
||||||
/* Set a 0xAA test value in writable register memory to test register access */
|
/* Set a 0xAA test value in writable register memory to test register access */
|
||||||
res = pn53x_set_reg (device, REG_CIU_TX_MODE, 0xFF, 0xAA);
|
res = pn53x_write_register (device, REG_CIU_TX_MODE, 0xFF, 0xAA);
|
||||||
cut_assert_true (res, cut_message ("set a register value to 0xAA"));
|
cut_assert_true (res, cut_message ("write register value to 0xAA"));
|
||||||
|
|
||||||
/* Get test value from register memory */
|
/* Get test value from register memory */
|
||||||
res = pn53x_get_reg (device, REG_CIU_TX_MODE, &value);
|
res = pn53x_read_register (device, REG_CIU_TX_MODE, &value);
|
||||||
cut_assert_true (res, cut_message ("get register value"));
|
cut_assert_true (res, cut_message ("read register value"));
|
||||||
cut_assert_equal_uint (0xAA, value, cut_message ("check register value"));
|
cut_assert_equal_uint (0xAA, value, cut_message ("check register value"));
|
||||||
|
|
||||||
/* Set a 0x55 test value in writable register memory to test register access */
|
/* Set a 0x55 test value in writable register memory to test register access */
|
||||||
res = pn53x_set_reg (device, REG_CIU_TX_MODE, 0xFF, 0x55);
|
res = pn53x_write_register (device, REG_CIU_TX_MODE, 0xFF, 0x55);
|
||||||
cut_assert_true (res, cut_message ("set a register value to 0x55"));
|
cut_assert_true (res, cut_message ("write register value to 0x55"));
|
||||||
|
|
||||||
/* Get test value from register memory */
|
/* Get test value from register memory */
|
||||||
res = pn53x_get_reg (device, REG_CIU_TX_MODE, &value);
|
res = pn53x_read_register (device, REG_CIU_TX_MODE, &value);
|
||||||
cut_assert_true (res, cut_message ("get register value"));
|
cut_assert_true (res, cut_message ("read register value"));
|
||||||
cut_assert_equal_uint (0x55, value, cut_message ("check register value"));
|
cut_assert_equal_uint (0x55, value, cut_message ("check register value"));
|
||||||
|
|
||||||
nfc_disconnect (device);
|
nfc_disconnect (device);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#define MAX_DEVICE_COUNT 1
|
#define MAX_DEVICE_COUNT 1
|
||||||
#define MAX_TARGET_COUNT 1
|
#define MAX_TARGET_COUNT 1
|
||||||
|
|
||||||
bool pn53x_get_reg(nfc_device_t* pnd, uint16_t ui16Reg, uint8_t* ui8Value);
|
#include "libnfc/chips/pn53x.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
test_register_endianness (void)
|
test_register_endianness (void)
|
||||||
|
@ -26,11 +26,11 @@ test_register_endianness (void)
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
|
|
||||||
/* Read valid XRAM memory */
|
/* Read valid XRAM memory */
|
||||||
res = pn53x_get_reg (device, 0xF0FF, &value);
|
res = pn53x_read_register (device, 0xF0FF, &value);
|
||||||
cut_assert_true (res, cut_message ("read register 0xF0FF"));
|
cut_assert_true (res, cut_message ("read register 0xF0FF"));
|
||||||
|
|
||||||
/* Read invalid SFR register */
|
/* Read invalid SFR register */
|
||||||
res = pn53x_get_reg (device, 0xFFF0, &value);
|
res = pn53x_read_register (device, 0xFFF0, &value);
|
||||||
cut_assert_false (res, cut_message ("read register 0xFFF0"));
|
cut_assert_false (res, cut_message ("read register 0xFFF0"));
|
||||||
|
|
||||||
nfc_disconnect (device);
|
nfc_disconnect (device);
|
||||||
|
|
Loading…
Add table
Reference in a new issue