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];
|
||||
bool bEasyFraming;
|
||||
|
||||
// Make sure we are dealing with a active device
|
||||
if (!pnd->bActive)
|
||||
return false;
|
||||
|
||||
abtCmd[0] = mc; // The MIFARE Classic command
|
||||
abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff)
|
||||
|
||||
|
|
|
@ -40,10 +40,10 @@
|
|||
|
||||
#include "nfc-utils.h"
|
||||
#include "chips/pn53x.h"
|
||||
#include "chips/pn53x-internal.h"
|
||||
|
||||
#define MAX_DEVICE_COUNT 16
|
||||
|
||||
|
||||
int
|
||||
main (int argc, const char *argv[])
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ main (int argc, const char *argv[])
|
|||
const char *acLibnfcVersion;
|
||||
bool result;
|
||||
|
||||
byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN];
|
||||
byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN];
|
||||
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_rom_test[] = { 0xD4, 0x00, 0x01 };
|
||||
|
@ -88,19 +88,19 @@ main (int argc, const char *argv[])
|
|||
|
||||
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) {
|
||||
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");
|
||||
|
||||
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) {
|
||||
result = ((szRx == 1) && (abtRx[0] == 0x00));
|
||||
}
|
||||
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) {
|
||||
result = ((szRx == 1) && (abtRx[0] == 0x00));
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ sam_connection (nfc_device_t * pnd, int mode)
|
|||
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");
|
||||
ERR ("%s %d", "Unable to execute SAMConfiguration command with mode byte:", mode);
|
||||
return false;
|
||||
|
|
|
@ -167,7 +167,7 @@ int main(int argc, const char* argv[])
|
|||
printf("Tx: ");
|
||||
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);
|
||||
nfc_perror (pnd, "Rx");
|
||||
continue;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
* 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
|
||||
* 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
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file nfc-types.h
|
||||
* @brief Define NFC types
|
||||
*/
|
||||
|
@ -25,12 +27,6 @@
|
|||
#ifndef __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 <stdint.h>
|
||||
# include <stdbool.h>
|
||||
|
@ -38,32 +34,19 @@
|
|||
|
||||
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
|
||||
/**
|
||||
* @struct nfc_device_t
|
||||
* @brief NFC device information
|
||||
*/
|
||||
typedef struct {
|
||||
/** Callback functions for handling device specific wrapping */
|
||||
const struct driver_callbacks *pdc;
|
||||
/** Driver's functions for handling device specific wrapping */
|
||||
const struct nfc_driver_t *driver;
|
||||
void* driver_data;
|
||||
void* chip_data;
|
||||
|
||||
/** Device name string, including device wrapper firmware */
|
||||
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 */
|
||||
bool bCrc;
|
||||
/** 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)
|
||||
*/
|
||||
int iLastError;
|
||||
/** Last sent command */
|
||||
int iLastCommand;
|
||||
} nfc_device_t;
|
||||
|
||||
// TODO: Move chip's specifics in a chips structure (e.g. iLastCommand, ui8Parameters, ui8TxBits)
|
||||
|
||||
/**
|
||||
* @struct nfc_device_desc_t
|
||||
|
@ -118,29 +103,6 @@ struct chip_callbacks {
|
|||
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
|
||||
# pragma pack(1)
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ SUBDIRS = chips buses drivers .
|
|||
# set the include path found by configure
|
||||
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
|
||||
libnfc_la_SOURCES = nfc.c iso14443-subr.c mirror-subr.c
|
||||
libnfc_la_LDFLAGS = -no-undefined -version-info 1:0:0
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
/*-
|
||||
* 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
|
||||
* 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.
|
||||
# if defined (_WIN32)
|
||||
# define DEFAULT_SERIAL_PORTS { "COM1", "COM2", "COM3", "COM4", NULL }
|
||||
# elif defined(__APPLE__)
|
||||
// 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
|
||||
# endif
|
||||
|
||||
// Define shortcut to types to make code more readable
|
||||
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);
|
||||
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);
|
||||
|
||||
char **uart_list_ports (void);
|
||||
|
||||
#endif // __NFC_BUS_UART_H__
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* 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
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -23,9 +25,29 @@
|
|||
* @brief POSIX UART driver
|
||||
*/
|
||||
|
||||
/* vim: set ts=2 sw=2 et: */
|
||||
|
||||
# include <sys/types.h>
|
||||
# include <sys/select.h>
|
||||
# include <sys/param.h>
|
||||
# include <ctype.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 {
|
||||
int fd; // Serial port file descriptor
|
||||
|
@ -33,12 +55,6 @@ typedef struct {
|
|||
term_info tiNew; // Terminal info during the transaction
|
||||
} 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
|
||||
# define CCLAIMED 0x80000000
|
||||
|
||||
|
@ -85,25 +101,10 @@ uart_open (const char *pcPortName)
|
|||
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
|
||||
uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
|
||||
{
|
||||
// Set per-byte timeout
|
||||
uiTimeoutPerByte = UART_BAUDRATE_T0_BYTE_DURATION(uiPortSpeed);
|
||||
DBG ("Serial port speed requested to be set to %d bauds (%lu µs).", uiPortSpeed, uiTimeoutPerByte);
|
||||
DBG ("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
|
||||
const serial_port_unix *spu = (serial_port_unix *) sp;
|
||||
|
||||
// Portability note: on some systems, B9600 != 9600 so we have to do
|
||||
|
@ -203,28 +204,26 @@ uart_close (const serial_port 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
|
||||
*
|
||||
* @return 0 on success, otherwise driver error code
|
||||
*/
|
||||
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;
|
||||
|
||||
// Reset the output count
|
||||
*pszRx = 0;
|
||||
int received_bytes_count = 0;
|
||||
int available_bytes_count = 0;
|
||||
const int expected_bytes_count = (int)szRx;
|
||||
int res;
|
||||
fd_set rfds;
|
||||
do {
|
||||
// Reset file descriptor
|
||||
FD_ZERO (&rfds);
|
||||
|
@ -238,35 +237,25 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
|
|||
}
|
||||
// Read time-out
|
||||
if (res == 0) {
|
||||
if (*pszRx == 0) {
|
||||
// Error, we received no data
|
||||
// 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;
|
||||
}
|
||||
DBG ("Timeout!");
|
||||
return DETIMEOUT;
|
||||
}
|
||||
// Retrieve the count of the incoming bytes
|
||||
res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &byteCount);
|
||||
if (res < 0) {
|
||||
res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &available_bytes_count);
|
||||
if (res != 0) {
|
||||
return DEIO;
|
||||
}
|
||||
// There is something available, read the data
|
||||
res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRx), MIN(byteCount, iExpectedByteCount));
|
||||
iExpectedByteCount -= MIN (byteCount, iExpectedByteCount);
|
||||
|
||||
// DBG ("expected bytes: %zu, received bytes: %d, available bytes: %d", szRx, received_bytes_count, available_bytes_count);
|
||||
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
|
||||
if (res <= 0) {
|
||||
return DEIO;
|
||||
}
|
||||
received_bytes_count += res;
|
||||
|
||||
*pszRx += 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 = uiTimeoutPerByte * MIN( iExpectedByteCount, 16 );
|
||||
// DBG("Timeout reloaded at: %d µs", tv.tv_usec);
|
||||
} while (byteCount && (iExpectedByteCount > 0));
|
||||
DBG ("byteCount == %d, iExpectedByteCount == %d", byteCount, iExpectedByteCount);
|
||||
} while (expected_bytes_count > received_bytes_count);
|
||||
PRINT_HEX ("RX", pbtRx, szRx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -278,13 +267,16 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
|
|||
int
|
||||
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;
|
||||
size_t szPos = 0;
|
||||
fd_set rfds;
|
||||
struct timeval tvTimeout = {
|
||||
.tv_sec = 0,
|
||||
.tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * szTx),
|
||||
};
|
||||
struct timeval tv = tvTimeout;
|
||||
|
||||
while (szPos < szTx) {
|
||||
|
@ -312,10 +304,45 @@ uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
||||
|
||||
noinst_HEADERS = pn53x.h
|
||||
noinst_HEADERS = pn53x.h pn53x-internal.h
|
||||
noinst_LTLIBRARIES = libnfcchips.la
|
||||
libnfcchips_la_SOURCES = pn53x.c
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,11 +29,6 @@
|
|||
|
||||
# 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
|
||||
# define REG_CIU_TX_MODE 0x6302
|
||||
# define SYMBOL_TX_CRC_ENABLE 0x80
|
||||
|
@ -98,6 +95,24 @@
|
|||
# define DEISERRFRAME 0x0300/* Error frame */
|
||||
# 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 */
|
||||
/**
|
||||
* @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);
|
||||
bool pn53x_check_error_frame_callback (nfc_device_t * pnd, const byte_t * pbtRxFrame,
|
||||
const size_t szRxFrameLen);
|
||||
bool pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx,
|
||||
size_t * pszRx);
|
||||
bool pn53x_get_reg (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t * ui8Value);
|
||||
bool pn53x_set_reg (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t ui8SymbolMask, uint8_t ui8Value);
|
||||
bool pn53x_set_parameter (nfc_device_t * pnd, const uint8_t ui8Value, const bool bEnable);
|
||||
bool pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t *pszRx, bool toto);
|
||||
bool pn53x_read_register (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_parameters (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_wrap_frame (const byte_t * pbtTx, const size_t szTxBits, const byte_t * pbtTxPar, byte_t * pbtFrame,
|
||||
size_t * pszFrameBits);
|
||||
bool pn53x_unwrap_frame (const byte_t * pbtFrame, const size_t szFrameBits, byte_t * pbtRx, size_t * pszRxBits,
|
||||
byte_t * pbtRxPar);
|
||||
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);
|
||||
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);
|
||||
|
@ -234,6 +248,7 @@ static const struct chip_callbacks pn53x_callbacks_list = {
|
|||
|
||||
// C wrappers for PN53x commands
|
||||
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,
|
||||
const byte_t szMaxTargets, const byte_t * pbtInitiatorData,
|
||||
const size_t szInitiatorDataLen, byte_t * pbtTargetsData, size_t * pszTargetsData);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* 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
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -27,8 +28,6 @@
|
|||
|
||||
# include <nfc/nfc-types.h>
|
||||
|
||||
# include "chips/pn53x.h"
|
||||
|
||||
# if defined (DRIVER_ACR122_ENABLED)
|
||||
# include "drivers/acr122.h"
|
||||
# endif /* DRIVER_ACR122_ENABLED */
|
||||
|
@ -54,46 +53,7 @@
|
|||
# endif /* DRIVER_PN532_UART_ENABLED */
|
||||
|
||||
# define DRIVERS_MAX_DEVICES 16
|
||||
# define MAX_FRAME_LEN 264
|
||||
|
||||
static const struct driver_callbacks drivers_callbacks_list[] = {
|
||||
// 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
|
||||
extern const struct nfc_driver_t *nfc_drivers[];
|
||||
|
||||
#endif // __NFC_DRIVERS_H__
|
||||
|
|
|
@ -119,7 +119,7 @@ arygon_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *
|
|||
*pszDeviceFound = 0;
|
||||
|
||||
serial_port sp;
|
||||
const char *pcPorts[] = DEFAULT_SERIAL_PORTS;
|
||||
char **pcPorts = uart_list_ports ();
|
||||
const char *pcPort;
|
||||
int iDevice = 0;
|
||||
|
||||
|
@ -155,6 +155,7 @@ arygon_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *
|
|||
# endif
|
||||
/* DEBUG */
|
||||
}
|
||||
free (pcPorts);
|
||||
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/*-
|
||||
* 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
|
||||
* 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.)
|
||||
*/
|
||||
|
||||
/* vim: set ts=2 sw=2 et: */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include "../drivers.h"
|
||||
#include "libnfc/drivers.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -36,44 +39,26 @@
|
|||
#include <nfc/nfc.h>
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
// Bus
|
||||
#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
|
||||
|
||||
// TODO Move this one level up for libnfc-1.6
|
||||
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_wakeup (const nfc_device_spec_t nds);
|
||||
bool pn532_uart_check_communication (const nfc_device_spec_t nds, bool * success);
|
||||
|
||||
nfc_device_desc_t *
|
||||
pn532_uart_pick_device (void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
void pn532_uart_ack (nfc_device_t * pnd);
|
||||
// void pn532_uart_wakeup (const nfc_device_spec_t nds);
|
||||
bool pn532_uart_check_communication (nfc_device_t *pnd);
|
||||
|
||||
struct pn532_uart_data {
|
||||
serial_port port;
|
||||
};
|
||||
|
||||
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
|
||||
* 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;
|
||||
|
||||
serial_port sp;
|
||||
const char *pcPorts[] = DEFAULT_SERIAL_PORTS;
|
||||
char **pcPorts = uart_list_ports ();
|
||||
const char *pcPort;
|
||||
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);
|
||||
|
||||
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.
|
||||
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_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)
|
||||
if (!pn532_uart_check_communication ((nfc_device_spec_t) sp, &bComOk))
|
||||
continue;
|
||||
if (!bComOk)
|
||||
bool res = pn532_uart_check_communication (&nd);
|
||||
free(nd.driver_data);
|
||||
free(nd.chip_data);
|
||||
if(!res)
|
||||
continue;
|
||||
uart_close (sp);
|
||||
|
||||
|
@ -129,6 +123,7 @@ pn532_uart_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size
|
|||
# endif
|
||||
/* DEBUG */
|
||||
}
|
||||
free (pcPorts);
|
||||
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
||||
return true;
|
||||
}
|
||||
|
@ -138,7 +133,6 @@ pn532_uart_connect (const nfc_device_desc_t * pndd)
|
|||
{
|
||||
serial_port sp;
|
||||
nfc_device_t *pnd = NULL;
|
||||
bool bComOk;
|
||||
|
||||
DBG ("Attempt to connect to: %s at %d bauds.", pndd->pcPort, pndd->uiSpeed);
|
||||
sp = uart_open (pndd->pcPort);
|
||||
|
@ -152,24 +146,23 @@ pn532_uart_connect (const nfc_device_desc_t * pndd)
|
|||
|
||||
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
|
||||
pnd = malloc (sizeof (nfc_device_t));
|
||||
strncpy (pnd->acName, pndd->acDevice, DEVICE_NAME_LENGTH - 1);
|
||||
pnd->acName[DEVICE_NAME_LENGTH - 1] = '\0';
|
||||
|
||||
pnd->nc = NC_PN532;
|
||||
pnd->nds = (nfc_device_spec_t) sp;
|
||||
pnd->bActive = true;
|
||||
pnd->driver_data = malloc(sizeof(struct pn532_uart_data));
|
||||
((struct pn532_uart_data*)(pnd->driver_data))->port = sp;
|
||||
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;
|
||||
}
|
||||
|
@ -177,196 +170,220 @@ pn532_uart_connect (const nfc_device_desc_t * pndd)
|
|||
void
|
||||
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);
|
||||
}
|
||||
|
||||
#define TX_BUFFER_LEN (256)
|
||||
#define RX_BUFFER_LEN (PN53x_EXTENDED_FRAME_MAX_LEN + PN53x_EXTENDED_FRAME_OVERHEAD)
|
||||
#define PN532_BUFFER_LEN (PN53x_EXTENDED_FRAME__DATA_MAX_LEN + PN53x_EXTENDED_FRAME__OVERHEAD)
|
||||
bool
|
||||
pn532_uart_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx,
|
||||
size_t * pszRx)
|
||||
pn532_uart_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData)
|
||||
{
|
||||
byte_t abtTxBuf[TX_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||
byte_t abtRxBuf[RX_BUFFER_LEN];
|
||||
size_t szRxBufLen = MIN( RX_BUFFER_LEN, *pszRx );
|
||||
size_t szPos;
|
||||
int res;
|
||||
|
||||
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
|
||||
abtTxBuf[3] = szTx;
|
||||
// Packet length checksum
|
||||
abtTxBuf[4] = 256 - abtTxBuf[3];
|
||||
// Copy the PN53X command into the packet buffer
|
||||
memmove (abtTxBuf + 5, pbtTx, szTx);
|
||||
|
||||
// Calculate data payload checksum
|
||||
abtTxBuf[szTx + 5] = 0;
|
||||
for (szPos = 0; szPos < szTx; szPos++) {
|
||||
abtTxBuf[szTx + 5] -= abtTxBuf[szPos + 5];
|
||||
DBG ("state: %d (SLEEP: %d, NORMAL: %d, EXECUTE: %d)", ((struct pn53x_data*)(pnd->chip_data))->state, SLEEP, NORMAL, EXECUTE);
|
||||
if (((struct pn53x_data*)(pnd->chip_data))->state == SLEEP) {
|
||||
// if (1) {
|
||||
/** PN532C106 wakeup. */
|
||||
/** 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 };
|
||||
//, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uart_send (((struct pn532_uart_data*)(pnd->driver_data))->port, pn532_wakeup_preamble, sizeof (pn532_wakeup_preamble));
|
||||
((struct pn53x_data*)(pnd->chip_data))->state = NORMAL; // PN532 should now be awake
|
||||
// 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 (!pn53x_SAMConfiguration (pnd, 0x01)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// End of stream marker
|
||||
abtTxBuf[szTx + 6] = 0;
|
||||
byte_t abtTxBuf[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||
|
||||
#ifdef DEBUG
|
||||
PRINT_HEX ("TX", abtTxBuf, szTx + 7);
|
||||
#endif
|
||||
res = uart_send ((serial_port) pnd->nds, abtTxBuf, szTx + 7);
|
||||
pnd->iLastCommand = pbtData[0];
|
||||
size_t szFrame = 0;
|
||||
|
||||
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) {
|
||||
ERR ("%s", "Unable to transmit data. (TX)");
|
||||
pnd->iLastError = res;
|
||||
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) {
|
||||
ERR ("%s", "Unable to receive data. (RX)");
|
||||
pnd->iLastError = res;
|
||||
return false;
|
||||
}
|
||||
#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
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
PRINT_HEX ("TX", ack_frame, sizeof(ack_frame));
|
||||
#endif
|
||||
res = uart_send ((serial_port) pnd->nds, ack_frame, sizeof(ack_frame));
|
||||
if (res != 0) {
|
||||
ERR ("%s", "Unable to transmit data. (TX)");
|
||||
pnd->iLastError = res;
|
||||
return false;
|
||||
const byte_t pn53x_preamble[3] = { 0x00, 0x00, 0xff };
|
||||
if (0 != (memcmp (abtRxBuf, pn53x_preamble, 3))) {
|
||||
ERR ("%s", "Frame preamble+start code mismatch");
|
||||
pnd->iLastError = DEIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!pn53x_check_error_frame_callback (pnd, abtRxBuf, szRxBufLen))
|
||||
return false;
|
||||
|
||||
// When the answer should be ignored, just return a successful result
|
||||
if (pbtRx == NULL || pszRx == NULL)
|
||||
return true;
|
||||
|
||||
// Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
|
||||
if (szRxBufLen < 9) {
|
||||
pnd->iLastError = DEINVAL;
|
||||
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
|
||||
if ((0x01 == abtRxBuf[3]) && (0xff == abtRxBuf[4])) {
|
||||
// Error frame
|
||||
uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 3);
|
||||
ERR ("%s", "Application level error detected");
|
||||
pnd->iLastError = DEISERRFRAME;
|
||||
return -1;
|
||||
} else if ((0xff == abtRxBuf[3]) && (0xff == abtRxBuf[4])) {
|
||||
// Extended frame
|
||||
// FIXME: Code this
|
||||
abort ();
|
||||
} else {
|
||||
ERR ("No ACK.");
|
||||
return false;
|
||||
}
|
||||
if (0 != memcmp (ack_frame, abtRx, szRx))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// Normal frame
|
||||
if (256 != (abtRxBuf[3] + abtRxBuf[4])) {
|
||||
// TODO: Retry
|
||||
ERR ("%s", "Length checksum mismatch");
|
||||
pnd->iLastError = DEIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define PN53X_RX_OVERHEAD 6
|
||||
void
|
||||
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;
|
||||
// abtRxBuf[3] (LEN) include TFI + (CC+1)
|
||||
len = abtRxBuf[3] - 2;
|
||||
}
|
||||
|
||||
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) {
|
||||
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)))
|
||||
*success = true;
|
||||
if (abtRxBuf[0] != 0xD5) {
|
||||
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
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
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);
|
||||
void pn532_uart_disconnect (nfc_device_t * pnd);
|
||||
|
||||
// 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,
|
||||
size_t * pszRx);
|
||||
bool pn532_uart_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData);
|
||||
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__
|
||||
|
|
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) 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
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
|
@ -23,6 +24,8 @@
|
|||
* @brief NFC library implementation
|
||||
*/
|
||||
|
||||
/* vim:set ts=2 sw=2 et: */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
@ -40,11 +43,19 @@
|
|||
|
||||
#include "chips.h"
|
||||
#include "drivers.h"
|
||||
#include "nfc-internal.h"
|
||||
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
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
|
||||
* @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_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
|
||||
for (uiDriver = 0; uiDriver < sizeof (drivers_callbacks_list) / sizeof (drivers_callbacks_list[0]); uiDriver++) {
|
||||
if (pndd == NULL) {
|
||||
// No device description specified: try to automatically claim a device
|
||||
if (drivers_callbacks_list[uiDriver].pick_device != NULL) {
|
||||
DBG ("Autodetecting available devices using %s driver.", drivers_callbacks_list[uiDriver].acDriver);
|
||||
pndd = drivers_callbacks_list[uiDriver].pick_device ();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
const struct nfc_driver_t *ndr;
|
||||
const struct nfc_driver_t **pndr = nfc_drivers;
|
||||
while ((ndr = *pndr)) {
|
||||
// Specific device is requested: using device description pndd
|
||||
if (0 != strcmp (ndr->name, pndd->pcDriver)) {
|
||||
continue;
|
||||
} else {
|
||||
// Specific device is requested: using device description pndd
|
||||
if (0 != strcmp (drivers_callbacks_list[uiDriver].acDriver, pndd->pcDriver)) {
|
||||
continue;
|
||||
} else {
|
||||
pnd = drivers_callbacks_list[uiDriver].connect (pndd);
|
||||
}
|
||||
pnd = ndr->connect (pndd);
|
||||
}
|
||||
|
||||
// Test if the connection was successful
|
||||
if (pnd != NULL) {
|
||||
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()
|
||||
if (!pn53x_init (pnd))
|
||||
return NULL;
|
||||
|
||||
if (pnd->pdc->init) {
|
||||
pnd->pdc->init (pnd);
|
||||
}
|
||||
|
||||
// Set default configuration options
|
||||
// Make sure we reset the CRC and parity to chip handling.
|
||||
if (!nfc_configure (pnd, NDO_HANDLE_CRC, true))
|
||||
|
@ -144,8 +137,9 @@ nfc_connect (nfc_device_desc_t * pndd)
|
|||
|
||||
return pnd;
|
||||
} 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
|
||||
return NULL;
|
||||
|
@ -166,7 +160,7 @@ nfc_disconnect (nfc_device_t * pnd)
|
|||
// Disable RF field to avoid heating
|
||||
nfc_configure (pnd, NDO_ACTIVATE_FIELD, false);
|
||||
// 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_pick_device (void)
|
||||
{
|
||||
uint32_t uiDriver;
|
||||
nfc_device_desc_t *nddRes;
|
||||
const struct nfc_driver_t *ndr;
|
||||
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 (drivers_callbacks_list[uiDriver].pick_device != NULL) {
|
||||
nddRes = drivers_callbacks_list[uiDriver].pick_device ();
|
||||
if (nddRes != NULL)
|
||||
return nddRes;
|
||||
if ((pndd = malloc (sizeof (*pndd)))) {
|
||||
size_t szN;
|
||||
|
||||
if (!ndr->probe (pndd, 1, &szN)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -200,22 +208,19 @@ nfc_pick_device (void)
|
|||
void
|
||||
nfc_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
|
||||
{
|
||||
uint32_t uiDriver;
|
||||
size_t szN;
|
||||
|
||||
*pszDeviceFound = 0;
|
||||
|
||||
for (uiDriver = 0; uiDriver < sizeof (drivers_callbacks_list) / sizeof (drivers_callbacks_list[0]); uiDriver++) {
|
||||
if (drivers_callbacks_list[uiDriver].list_devices != NULL) {
|
||||
szN = 0;
|
||||
if (drivers_callbacks_list[uiDriver].list_devices
|
||||
(pnddDevices + (*pszDeviceFound), szDevices - (*pszDeviceFound), &szN)) {
|
||||
*pszDeviceFound += szN;
|
||||
DBG ("%ld device(s) found using %s driver", (unsigned long) szN, drivers_callbacks_list[uiDriver].acDriver);
|
||||
}
|
||||
} else {
|
||||
DBG ("No listing function avaible for %s driver", drivers_callbacks_list[uiDriver].acDriver);
|
||||
const struct nfc_driver_t *ndr;
|
||||
const struct nfc_driver_t **pndr = nfc_drivers;
|
||||
while ((ndr = *pndr)) {
|
||||
szN = 0;
|
||||
if (ndr->probe (pnddDevices + (*pszDeviceFound), szDevices - (*pszDeviceFound), &szN)) {
|
||||
*pszDeviceFound += szN;
|
||||
DBG ("%ld device(s) found using %s driver", (unsigned long) szN, ndr->name);
|
||||
}
|
||||
pndr++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -253,16 +258,12 @@ nfc_initiator_init (nfc_device_t * pnd)
|
|||
{
|
||||
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)
|
||||
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;
|
||||
|
||||
// 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 true;
|
||||
|
@ -294,14 +295,11 @@ nfc_initiator_select_passive_target (nfc_device_t * pnd,
|
|||
const byte_t * pbtInitData, const size_t szInitData,
|
||||
nfc_target_t * pnt)
|
||||
{
|
||||
byte_t abtInit[MAX_FRAME_LEN];
|
||||
byte_t abtInit[MAX(12, szInitData)];
|
||||
size_t szInit;
|
||||
|
||||
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)
|
||||
switch (nm.nmt) {
|
||||
case NMT_ISO14443A:
|
||||
|
@ -662,7 +660,7 @@ nfc_target_receive_bits (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxBits,
|
|||
const char *
|
||||
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 <nfc/nfc.h>
|
||||
#include "../libnfc/chips/pn53x.h"
|
||||
#include "libnfc/chips/pn53x.h"
|
||||
|
||||
#define MAX_DEVICE_COUNT 1
|
||||
#define MAX_TARGET_COUNT 1
|
||||
|
||||
bool pn53x_get_reg(nfc_device_t* pnd, uint16_t ui16Reg, uint8_t* ui8Value);
|
||||
|
||||
void
|
||||
test_register_endianness (void)
|
||||
{
|
||||
|
@ -27,21 +25,21 @@ test_register_endianness (void)
|
|||
uint8_t value;
|
||||
|
||||
/* Set a 0xAA test value in writable register memory to test register access */
|
||||
res = pn53x_set_reg (device, REG_CIU_TX_MODE, 0xFF, 0xAA);
|
||||
cut_assert_true (res, cut_message ("set a register value to 0xAA"));
|
||||
res = pn53x_write_register (device, REG_CIU_TX_MODE, 0xFF, 0xAA);
|
||||
cut_assert_true (res, cut_message ("write register value to 0xAA"));
|
||||
|
||||
/* Get test value from register memory */
|
||||
res = pn53x_get_reg (device, REG_CIU_TX_MODE, &value);
|
||||
cut_assert_true (res, cut_message ("get register value"));
|
||||
res = pn53x_read_register (device, REG_CIU_TX_MODE, &value);
|
||||
cut_assert_true (res, cut_message ("read 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 */
|
||||
res = pn53x_set_reg (device, REG_CIU_TX_MODE, 0xFF, 0x55);
|
||||
cut_assert_true (res, cut_message ("set a register value to 0x55"));
|
||||
res = pn53x_write_register (device, REG_CIU_TX_MODE, 0xFF, 0x55);
|
||||
cut_assert_true (res, cut_message ("write register value to 0x55"));
|
||||
|
||||
/* Get test value from register memory */
|
||||
res = pn53x_get_reg (device, REG_CIU_TX_MODE, &value);
|
||||
cut_assert_true (res, cut_message ("get register value"));
|
||||
res = pn53x_read_register (device, REG_CIU_TX_MODE, &value);
|
||||
cut_assert_true (res, cut_message ("read register value"));
|
||||
cut_assert_equal_uint (0x55, value, cut_message ("check register value"));
|
||||
|
||||
nfc_disconnect (device);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
#define MAX_DEVICE_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
|
||||
test_register_endianness (void)
|
||||
|
@ -26,11 +26,11 @@ test_register_endianness (void)
|
|||
uint8_t value;
|
||||
|
||||
/* 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"));
|
||||
|
||||
/* 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"));
|
||||
|
||||
nfc_disconnect (device);
|
||||
|
|
Loading…
Add table
Reference in a new issue