From 5af845cdfc21a648388c97eff49c3f6ba3fc4b24 Mon Sep 17 00:00:00 2001 From: Romuald Conty Date: Wed, 2 Mar 2011 15:00:44 +0000 Subject: [PATCH] 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) --- examples/mifare.c | 4 - examples/pn53x-diagnose.c | 10 +- examples/pn53x-sam.c | 2 +- examples/pn53x-tamashell.c | 2 +- include/nfc/nfc-types.h | 62 +--- libnfc/Makefile.am | 2 +- libnfc/buses/uart.h | 20 +- libnfc/buses/uart_posix.c | 149 +++++---- libnfc/chips/Makefile.am | 3 +- libnfc/chips/pn53x-internal.h | 190 ++++++++++++ libnfc/chips/pn53x.c | 524 ++++++++++++++------------------ libnfc/chips/pn53x.h | 39 ++- libnfc/drivers.h | 44 +-- libnfc/drivers/arygon.c | 3 +- libnfc/drivers/pn532_uart.c | 443 ++++++++++++++------------- libnfc/drivers/pn532_uart.h | 11 +- libnfc/nfc-internal.h | 56 ++++ libnfc/nfc.c | 122 ++++---- test/test_register_access.c | 20 +- test/test_register_endianness.c | 6 +- 20 files changed, 937 insertions(+), 775 deletions(-) create mode 100644 libnfc/chips/pn53x-internal.h create mode 100644 libnfc/nfc-internal.h diff --git a/examples/mifare.c b/examples/mifare.c index c828dce..9fcc47e 100644 --- a/examples/mifare.c +++ b/examples/mifare.c @@ -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) diff --git a/examples/pn53x-diagnose.c b/examples/pn53x-diagnose.c index f5995aa..735f21a 100644 --- a/examples/pn53x-diagnose.c +++ b/examples/pn53x-diagnose.c @@ -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)); } diff --git a/examples/pn53x-sam.c b/examples/pn53x-sam.c index a9925be..e981dd3 100644 --- a/examples/pn53x-sam.c +++ b/examples/pn53x-sam.c @@ -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; diff --git a/examples/pn53x-tamashell.c b/examples/pn53x-tamashell.c index b09d4da..4a0410d 100644 --- a/examples/pn53x-tamashell.c +++ b/examples/pn53x-tamashell.c @@ -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; diff --git a/include/nfc/nfc-types.h b/include/nfc/nfc-types.h index 1d9e50c..1663c06 100644 --- a/include/nfc/nfc-types.h +++ b/include/nfc/nfc-types.h @@ -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 - * - * + */ + +/** * @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 # include # include @@ -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) diff --git a/libnfc/Makefile.am b/libnfc/Makefile.am index 7e129ec..d6602ed 100644 --- a/libnfc/Makefile.am +++ b/libnfc/Makefile.am @@ -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 diff --git a/libnfc/buses/uart.h b/libnfc/buses/uart.h index 15bb3f0..9745477 100644 --- a/libnfc/buses/uart.h +++ b/libnfc/buses/uart.h @@ -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__ diff --git a/libnfc/buses/uart_posix.c b/libnfc/buses/uart_posix.c index 07b8de9..2bfad25 100644 --- a/libnfc/buses/uart_posix.c +++ b/libnfc/buses/uart_posix.c @@ -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 # include # include +# include # include +# include +# include + +# 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; +} diff --git a/libnfc/chips/Makefile.am b/libnfc/chips/Makefile.am index 2b8b9ee..94be1fa 100644 --- a/libnfc/chips/Makefile.am +++ b/libnfc/chips/Makefile.am @@ -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 - diff --git a/libnfc/chips/pn53x-internal.h b/libnfc/chips/pn53x-internal.h new file mode 100644 index 0000000..18e911b --- /dev/null +++ b/libnfc/chips/pn53x-internal.h @@ -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 + */ + +/** + * @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__ */ diff --git a/libnfc/chips/pn53x.c b/libnfc/chips/pn53x.c index 7b437f4..6493f90 100644 --- a/libnfc/chips/pn53x.c +++ b/libnfc/chips/pn53x.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 @@ -36,52 +37,27 @@ #include #include "pn53x.h" -#include "../mirror-subr.h" +#include "pn53x-internal.h" +#include "libnfc/mirror-subr.h" +#include "libnfc/nfc-internal.h" #ifdef _WIN32 -# include "../../contrib/windows.h" +# include "contrib/windows.h" #endif #include -// PN53X configuration -const byte_t pncmd_get_firmware_version[2] = { 0xD4, 0x02 }; -const byte_t pncmd_get_general_status[2] = { 0xD4, 0x04 }; -const byte_t pncmd_get_register[4] = { 0xD4, 0x06 }; -const byte_t pncmd_set_register[5] = { 0xD4, 0x08 }; -const byte_t pncmd_set_parameters[3] = { 0xD4, 0x12 }; -const byte_t pncmd_rf_configure[14] = { 0xD4, 0x32 }; - -// Reader -const byte_t pncmd_initiator_list_passive[264] = { 0xD4, 0x4A }; +// TODO: Count max bytes for InJumpForDEP reply const byte_t pncmd_initiator_jump_for_dep[68] = { 0xD4, 0x56 }; -const byte_t pncmd_initiator_select[3] = { 0xD4, 0x54 }; -const byte_t pncmd_initiator_deselect[3] = { 0xD4, 0x44, 0x00 }; -const byte_t pncmd_initiator_release[3] = { 0xD4, 0x52, 0x00 }; -const byte_t pncmd_initiator_set_baud_rate[5] = { 0xD4, 0x4E }; -const byte_t pncmd_initiator_exchange_data[265] = { 0xD4, 0x40 }; -const byte_t pncmd_initiator_exchange_raw_data[266] = { 0xD4, 0x42 }; -const byte_t pncmd_initiator_auto_poll[5] = { 0xD4, 0x60 }; - -// Target -const byte_t pncmd_target_get_data[2] = { 0xD4, 0x86 }; -const byte_t pncmd_target_set_data[264] = { 0xD4, 0x8E }; -const byte_t pncmd_target_init[2] = { 0xD4, 0x8C }; -//Example of default values for PN532 or PN533: -//const byte_t pncmd_target_init[39] = { 0xD4, 0x8C, 0x00, 0x08, 0x00, 0x12, 0x34, 0x56, 0x40, 0x01, 0xFE, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xFF, 0xFF, 0xAA, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00, 0x00 }; -const byte_t pncmd_target_virtual_card[4] = { 0xD4, 0x14 }; -const byte_t pncmd_target_get_initiator_command[2] = { 0xD4, 0x88 }; -const byte_t pncmd_target_response_to_initiator[264] = { 0xD4, 0x90 }; -const byte_t pncmd_target_get_status[2] = { 0xD4, 0x8A }; static const byte_t pn53x_ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 }; static const byte_t pn53x_nack_frame[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 }; static const byte_t pn53x_error_frame[] = { 0x00, 0x00, 0xff, 0x01, 0xff, 0x7f, 0x81, 0x00 }; /* prototypes */ -const nfc_modulation_t pn53x_ptt_to_nm( const pn53x_target_type_t ptt ); -const pn53x_modulation_t pn53x_nm_to_pm(const nfc_modulation_t nm); -const pn53x_target_type_t pn53x_nm_to_ptt(const nfc_modulation_t nm); +nfc_modulation_t pn53x_ptt_to_nm (const pn53x_target_type_t ptt); +pn53x_modulation_t pn53x_nm_to_pm (const nfc_modulation_t nm); +pn53x_target_type_t pn53x_nm_to_ptt (const nfc_modulation_t nm); bool pn53x_init(nfc_device_t * pnd) @@ -93,7 +69,7 @@ pn53x_init(nfc_device_t * pnd) // Reset the ending transmission bits register, it is unknown what the last tranmission used there pnd->ui8TxBits = 0; - if (!pn53x_set_reg (pnd, REG_CIU_BIT_FRAMING, SYMBOL_TX_LAST_BITS, 0x00)) { + if (!pn53x_write_register (pnd, REG_CIU_BIT_FRAMING, SYMBOL_TX_LAST_BITS, 0x00)) { return false; } @@ -125,8 +101,7 @@ pn53x_check_ack_frame_callback (nfc_device_t * pnd, const byte_t * pbtRxFrame, c return true; } else if (0 == memcmp (pbtRxFrame, pn53x_nack_frame, sizeof (pn53x_nack_frame))) { DBG ("%s", "PN53x NACKed"); - // TODO Try to recover when PN53x NACKs ! - // A counter could allow the command to be sent again (e.g. max 3 times) + // TODO Double check in user manual if no PN53x replies NACK then remove this pnd->iLastError = DENACK; return false; } @@ -150,16 +125,16 @@ pn53x_check_error_frame_callback (nfc_device_t * pnd, const byte_t * pbtRxFrame, return false; } } - return true; } -#define PN53x_REPLY_FRAME_MAX_LEN (PN53x_EXTENDED_FRAME_MAX_LEN + PN53x_EXTENDED_FRAME_OVERHEAD + sizeof(pn53x_ack_frame)) bool -pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t * pszRx) +pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t *pszRx, bool toto) { - byte_t abtRx[PN53x_REPLY_FRAME_MAX_LEN]; - size_t szRx = PN53x_EXTENDED_FRAME_MAX_LEN; + (void) toto; + PNCMD_DBG (pbtTx[0]); + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof(abtRx); // Check if receiving buffers are available, if not, replace them if (!pszRx || !pbtRx) { @@ -167,46 +142,40 @@ pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, b pszRx = &szRx; } -#if defined(DEBUG) - if(*pszRx > PN53x_EXTENDED_FRAME_MAX_LEN) { - DBG( "Expected reply bytes count (*pszRx=%zu) is greater than MAX (PN53x_EXTENDED_FRAME_MAX_LEN=%d)", *pszRx, PN53x_EXTENDED_FRAME_MAX_LEN ); - *pszRx=MIN(*pszRx, PN53x_EXTENDED_FRAME_MAX_LEN); -// abort(); - } -#endif - - *pszRx += sizeof(pn53x_ack_frame) + PN53x_EXTENDED_FRAME_OVERHEAD; - - // Call the transceive callback function of the current device - if (!pnd->pdc->transceive (pnd, pbtTx, szTx, pbtRx, pszRx)) + // Call the send/receice callback functions of the current driver + if (!pnd->driver->send (pnd, pbtTx, szTx)) return false; - // TODO Put all these hex-coded command behind a human-readable #define (1.6.x) - // Should be proceed while we will fix Issue 110 (Rework the way that pn53x commands are built) - switch (pbtTx[1]) { - case 0x16: // PowerDown - case 0x40: // InDataExchange - case 0x42: // InCommunicateThru - case 0x44: // InDeselect - case 0x46: // InJumpForPSL - case 0x4e: // InPSL - case 0x50: // InATR - case 0x52: // InRelease - case 0x54: // InSelect - case 0x56: // InJumpForDEP - case 0x86: // TgGetData - case 0x88: // TgGetInitiatorCommand - case 0x8e: // TgSetData - case 0x90: // TgResponseToInitiator - case 0x92: // TgSetGeneralBytes - case 0x94: // TgSetMetaData + int res = pnd->driver->receive (pnd, pbtRx, *pszRx); + if (res < 0) { + return false; + } + + *pszRx = (size_t) res; + + switch (pbtTx[0]) { + case PowerDown: + case InDataExchange: + case InCommunicateThru: + case InDeselect: + case InJumpForPSL: + case InPSL: + case InATR: + case InRelease: + case InSelect: + case InJumpForDEP: + case TgGetData: + case TgGetInitiatorCommand: + case TgSetData: + case TgResponseToInitiator: + case TgSetGeneralBytes: + case TgSetMetaData: pnd->iLastError = pbtRx[0] & 0x3f; break; default: pnd->iLastError = 0; } - if (pnd->nc == NC_PN533) { - if ((pbtTx[1] == 0x06) // ReadRegister - || (pbtTx[1] == 0x08)) { // WriteRegister + if (((struct pn53x_data*)(pnd->chip_data))->type == PN533) { + if ((pbtTx[0] == ReadRegister) || (pbtTx[0] == WriteRegister)) { // PN533 prepends its answer by a status byte pnd->iLastError = pbtRx[0] & 0x3f; } @@ -215,20 +184,16 @@ pn53x_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, b } bool -pn53x_get_reg (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t * ui8Value) +pn53x_read_register (nfc_device_t * pnd, uint16_t ui16Reg, uint8_t * ui8Value) { - byte_t abtCmd[sizeof (pncmd_get_register)]; - memcpy (abtCmd, pncmd_get_register, sizeof (pncmd_get_register)); - - abtCmd[2] = ui16Reg >> 8; - abtCmd[3] = ui16Reg & 0xff; + byte_t abtCmd[] = { ReadRegister, ui16Reg >> 8, ui16Reg & 0xff }; byte_t abtRegValue[2]; - size_t szValueLen = 3 + PN53x_NORMAL_FRAME_OVERHEAD; - if (pn53x_transceive (pnd, abtCmd, sizeof (pncmd_get_register), abtRegValue, &szValueLen)) { - if (pnd->nc == NC_PN533) { + size_t szRegValue = sizeof (abtRegValue); + if (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), abtRegValue, &szRegValue, true)) { + if (((struct pn53x_data*)(pnd->chip_data))->type == PN533) { // PN533 prepends its answer by a status byte - if (abtRegValue[0] == 0) { // 0x00 + if (abtRegValue[0] == 0x00) { *ui8Value = abtRegValue[1]; } else { return false; @@ -242,27 +207,24 @@ 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) +pn53x_write_register (nfc_device_t * pnd, const uint16_t ui16Reg, const uint8_t ui8SymbolMask, const uint8_t ui8Value) { uint8_t ui8Current; - byte_t abtCmd[sizeof (pncmd_set_register)]; - memcpy (abtCmd, pncmd_set_register, sizeof (pncmd_set_register)); + byte_t abtCmd[] = { WriteRegister, ui16Reg >> 8, ui16Reg & 0xff, 0x00 }; - abtCmd[2] = ui16Reg >> 8; - abtCmd[3] = ui16Reg & 0xff; if (ui8SymbolMask != 0xff) { - if (!pn53x_get_reg (pnd, ui16Reg, &ui8Current)) + if (!pn53x_read_register (pnd, ui16Reg, &ui8Current)) return false; - abtCmd[4] = ui8Value | (ui8Current & (~ui8SymbolMask)); - return (abtCmd[4] != ui8Current) ? pn53x_transceive (pnd, abtCmd, sizeof (pncmd_set_register), NULL, NULL) : true; + abtCmd[3] = ui8Value | (ui8Current & (~ui8SymbolMask)); + return (abtCmd[3] != ui8Current) ? pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false) : true; } else { - abtCmd[4] = ui8Value; - return pn53x_transceive (pnd, abtCmd, sizeof (pncmd_set_register), NULL, NULL); + abtCmd[3] = ui8Value; + return pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false); } } bool -pn53x_set_parameter (nfc_device_t * pnd, const uint8_t ui8Parameter, const bool bEnable) +pn53x_set_parameters (nfc_device_t * pnd, const uint8_t ui8Parameter, const bool bEnable) { uint8_t ui8Value = (bEnable) ? (pnd->ui8Parameters | ui8Parameter) : (pnd->ui8Parameters & ~(ui8Parameter)); if (ui8Value != pnd->ui8Parameters) { @@ -274,11 +236,9 @@ pn53x_set_parameter (nfc_device_t * pnd, const uint8_t ui8Parameter, const bool bool pn53x_SetParameters (nfc_device_t * pnd, const uint8_t ui8Value) { - byte_t abtCmd[sizeof (pncmd_set_parameters)]; - memcpy (abtCmd, pncmd_set_parameters, sizeof (pncmd_set_parameters)); + byte_t abtCmd[] = { SetParameters, ui8Value }; - abtCmd[2] = ui8Value; - if(!pn53x_transceive (pnd, abtCmd, sizeof (pncmd_set_parameters), NULL, NULL)) { + if(!pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false)) { return false; } // We save last parameters in register cache @@ -292,7 +252,7 @@ pn53x_set_tx_bits (nfc_device_t * pnd, const uint8_t ui8Bits) // Test if we need to update the transmission bits register setting if (pnd->ui8TxBits != ui8Bits) { // Set the amount of transmission bits in the PN53X chip register - if (!pn53x_set_reg (pnd, REG_CIU_BIT_FRAMING, SYMBOL_TX_LAST_BITS, ui8Bits)) + if (!pn53x_write_register (pnd, REG_CIU_BIT_FRAMING, SYMBOL_TX_LAST_BITS, ui8Bits)) return false; // Store the new setting @@ -405,7 +365,7 @@ pn53x_unwrap_frame (const byte_t * pbtFrame, const size_t szFrameBits, byte_t * } bool -pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData, nfc_chip_t nc, nfc_modulation_type_t nmt, +pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData, pn53x_type type, nfc_modulation_type_t nmt, nfc_target_info_t * pnti) { uint8_t szAttribRes; @@ -416,7 +376,7 @@ pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData, nfc_chip_ pbtRawData++; // Somehow they switched the lower and upper ATQA bytes around for the PN531 chipset - if (nc == NC_PN531) { + if (type == PN531) { pnti->nai.abtAtqa[1] = *(pbtRawData++); pnti->nai.abtAtqa[0] = *(pbtRawData++); } else { @@ -515,8 +475,8 @@ pn53x_initiator_select_passive_target (nfc_device_t * pnd, const byte_t * pbtInitData, const size_t szInitData, nfc_target_t * pnt) { - size_t szTargetsData; - byte_t abtTargetsData[PN53x_EXTENDED_FRAME_MAX_LEN]; + byte_t abtTargetsData[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szTargetsData = sizeof(abtTargetsData); const pn53x_modulation_t pm = pn53x_nm_to_pm(nm); if (PM_UNDEFINED == pm) { @@ -534,7 +494,7 @@ pn53x_initiator_select_passive_target (nfc_device_t * pnd, if (pnt) { pnt->nm = nm; // Fill the tag info struct with the values corresponding to this init modulation - if (!pn53x_decode_target_data (abtTargetsData + 1, szTargetsData - 1, pnd->nc, nm.nmt, &(pnt->nti))) { + if (!pn53x_decode_target_data (abtTargetsData + 1, szTargetsData - 1, ((struct pn53x_data*)(pnd->chip_data))->type, nm.nmt, &(pnt->nti))) { return false; } } @@ -588,13 +548,11 @@ pn53x_InListPassiveTarget (nfc_device_t * pnd, const byte_t * pbtInitiatorData, const size_t szInitiatorData, byte_t * pbtTargetsData, size_t * pszTargetsData) { - size_t szRx; - byte_t abtCmd[sizeof (pncmd_initiator_list_passive)]; - memcpy (abtCmd, pncmd_initiator_list_passive, sizeof (pncmd_initiator_list_passive)); + byte_t abtCmd[15] = { InListPassiveTarget }; - abtCmd[2] = szMaxTargets; // MaxTg + abtCmd[1] = szMaxTargets; // MaxTg - // XXX Is there is a better way to do handle supported modulations ? + // XXX Is there a better way to do handle supported modulations ? switch(pmInitModulation) { case PM_ISO14443A_106: case PM_FELICA_212: @@ -609,7 +567,7 @@ pn53x_InListPassiveTarget (nfc_device_t * pnd, } break; case PM_JEWEL_106: - if(pnd->nc == NC_PN531) { + if(((struct pn53x_data*)(pnd->chip_data))->type == PN531) { // These modulations are not supported by pn531 pnd->iLastError = DENOTSUP; return false; @@ -618,7 +576,7 @@ pn53x_InListPassiveTarget (nfc_device_t * pnd, case PM_ISO14443B_212: case PM_ISO14443B_424: case PM_ISO14443B_847: - if((pnd->nc != NC_PN533) || (!(pnd->btSupportByte & SUPPORT_ISO14443B))) { + if((((struct pn53x_data*)(pnd->chip_data))->type != PN533) || (!(pnd->btSupportByte & SUPPORT_ISO14443B))) { // These modulations are not supported by pn531 neither pn532 pnd->iLastError = DENOTSUP; return false; @@ -628,40 +586,50 @@ pn53x_InListPassiveTarget (nfc_device_t * pnd, pnd->iLastError = DENOTSUP; return false; } - abtCmd[3] = pmInitModulation; // BrTy, the type of init modulation used for polling a passive tag + abtCmd[2] = pmInitModulation; // BrTy, the type of init modulation used for polling a passive tag // Set the optional initiator data (used for Felica, ISO14443B, Topaz Polling or for ISO14443A selecting a specific UID). if (pbtInitiatorData) - memcpy (abtCmd + 4, pbtInitiatorData, szInitiatorData); + memcpy (abtCmd + 3, pbtInitiatorData, szInitiatorData); - // Try to find a tag, call the tranceive callback function of the current device - szRx = PN53x_EXTENDED_FRAME_MAX_LEN; - if (pn53x_transceive (pnd, abtCmd, 4 + szInitiatorData, pbtTargetsData, &szRx)) { - *pszTargetsData = szRx; - return true; - } else { - return false; - } + return pn53x_transceive (pnd, abtCmd, 3 + szInitiatorData, pbtTargetsData, pszTargetsData, false); } bool pn53x_InDeselect (nfc_device_t * pnd, const uint8_t ui8Target) { - byte_t abtCmd[sizeof (pncmd_initiator_deselect)]; - memcpy (abtCmd, pncmd_initiator_deselect, sizeof (pncmd_initiator_deselect)); - abtCmd[2] = ui8Target; + byte_t abtCmd[] = { InDeselect, ui8Target }; - return (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL)); + return (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false)); +} + +bool +pn53x_SAMConfiguration (nfc_device_t * pnd, const uint8_t ui8Mode) +{ + byte_t abtCmd[] = { SAMConfiguration, ui8Mode, 0x00, 0x00 }; + size_t szCmd = sizeof(abtCmd); + switch (ui8Mode) { + case 0x01: // Normal mode + szCmd = 2; + break; + case 0x02: // Virtual card mode + case 0x03: // Wired card mode + case 0x04: // Dual card mode + // TODO: Handle these SAM mode + break; + default: + pnd->iLastError = DENOTSUP; + return false; + } + return (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false)); } bool pn53x_InRelease (nfc_device_t * pnd, const uint8_t ui8Target) { - byte_t abtCmd[sizeof (pncmd_initiator_release)]; - memcpy (abtCmd, pncmd_initiator_release, sizeof (pncmd_initiator_release)); - abtCmd[2] = ui8Target; + byte_t abtCmd[] = { InRelease, ui8Target }; - return (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL)); + return (pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false)); } bool @@ -669,31 +637,22 @@ pn53x_InAutoPoll (nfc_device_t * pnd, const pn53x_target_type_t * ppttTargetTypes, const size_t szTargetTypes, const byte_t btPollNr, const byte_t btPeriod, nfc_target_t * pntTargets, size_t * pszTargetFound) { - size_t szTxInAutoPoll, - n; - byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN]; - size_t szRx = PN53x_EXTENDED_FRAME_MAX_LEN; - bool res; - byte_t *pbtTxInAutoPoll; - - if (pnd->nc != NC_PN532) { + if (((struct pn53x_data*)(pnd->chip_data))->type != PN532) { // This function is not supported by pn531 neither pn533 pnd->iLastError = DENOTSUP; return false; } + // InAutoPoll frame looks like this { 0xd4, 0x60, 0x0f, 0x01, 0x00 } => { direction, command, pollnr, period, types... } - szTxInAutoPoll = 4 + szTargetTypes; - pbtTxInAutoPoll = malloc (szTxInAutoPoll); - pbtTxInAutoPoll[0] = 0xd4; - pbtTxInAutoPoll[1] = 0x60; - pbtTxInAutoPoll[2] = btPollNr; - pbtTxInAutoPoll[3] = btPeriod; - for (n = 0; n < szTargetTypes; n++) { - pbtTxInAutoPoll[4 + n] = ppttTargetTypes[n]; + size_t szTxInAutoPoll = 3 + szTargetTypes; + byte_t abtCmd[3+15] = { InAutoPoll, btPollNr, btPeriod }; + for (size_t n = 0; n < szTargetTypes; n++) { + abtCmd[3 + n] = ppttTargetTypes[n]; } - szRx = PN53x_EXTENDED_FRAME_MAX_LEN; - res = pn53x_transceive (pnd, pbtTxInAutoPoll, szTxInAutoPoll, abtRx, &szRx); + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof(abtRx); + bool res = pn53x_transceive (pnd, abtCmd, szTxInAutoPoll, abtRx, &szRx, false); if ((szRx == 0) || (res == false)) { return false; @@ -708,7 +667,7 @@ pn53x_InAutoPoll (nfc_device_t * pnd, pntTargets[0].nm = pn53x_ptt_to_nm(ptt); // AutoPollTargetData length ln = *(pbt++); - pn53x_decode_target_data (pbt, ln, pnd->nc, pntTargets[0].nm.nmt, &(pntTargets[0].nti)); + pn53x_decode_target_data (pbt, ln, ((struct pn53x_data*)(pnd->chip_data))->type, pntTargets[0].nm.nmt, &(pntTargets[0].nti)); pbt += ln; if (abtRx[0] > 1) { @@ -718,7 +677,7 @@ pn53x_InAutoPoll (nfc_device_t * pnd, pntTargets[1].nm = pn53x_ptt_to_nm(ptt); // AutoPollTargetData length ln = *(pbt++); - pn53x_decode_target_data (pbt, ln, pnd->nc, pntTargets[1].nm.nmt, &(pntTargets[1].nti)); + pn53x_decode_target_data (pbt, ln, ((struct pn53x_data*)(pnd->chip_data))->type, pntTargets[1].nm.nmt, &(pntTargets[1].nti)); } } } @@ -797,30 +756,30 @@ pn53x_strerror (const nfc_device_t * pnd) bool pn53x_get_firmware_version (nfc_device_t * pnd, char abtFirmwareText[18]) { + const byte_t abtCmd[] = { GetFirmwareVersion }; byte_t abtFw[4]; size_t szFwLen = sizeof (abtFw); - if (!pn53x_transceive (pnd, pncmd_get_firmware_version, 2, abtFw, &szFwLen)) { + if (!pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), abtFw, &szFwLen, false)) { // Failed to get firmware revision??, whatever...let's disconnect and clean up and return err - pnd->pdc->disconnect (pnd); + // FIXME: Wtf? + // pnd->pdc->disconnect (pnd); return false; } // Convert firmware info in text, PN531 gives 2 bytes info, but PN532 and PN533 gives 4 - switch (pnd->nc) { - case NC_PN531: + switch (((struct pn53x_data*)(pnd->chip_data))->type) { + case PN531: snprintf (abtFirmwareText, 18, "PN531 v%d.%d", abtFw[0], abtFw[1]); pnd->btSupportByte = SUPPORT_ISO14443A | SUPPORT_ISO18092; break; - case NC_PN532: + case PN532: snprintf (abtFirmwareText, 18, "PN532 v%d.%d (0x%02x)", abtFw[1], abtFw[2], abtFw[3]); pnd->btSupportByte = abtFw[3]; break; - case NC_PN533: + case PN533: snprintf (abtFirmwareText, 18, "PN533 v%d.%d (0x%02x)", abtFw[1], abtFw[2], abtFw[3]); pnd->btSupportByte = abtFw[3]; break; } - // Be sure to have a null end of string - abtFirmwareText[17] = '\0'; return true; } @@ -828,22 +787,15 @@ bool pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable) { byte_t btValue; - byte_t abtCmd[sizeof (pncmd_rf_configure)]; - - memcpy (abtCmd, pncmd_rf_configure, sizeof (pncmd_rf_configure)); - - // Make sure we are dealing with a active device - if (!pnd->bActive) - return false; switch (ndo) { case NDO_HANDLE_CRC: // Enable or disable automatic receiving/sending of CRC bytes // TX and RX are both represented by the symbol 0x80 btValue = (bEnable) ? 0x80 : 0x00; - if (!pn53x_set_reg (pnd, REG_CIU_TX_MODE, SYMBOL_TX_CRC_ENABLE, btValue)) + if (!pn53x_write_register (pnd, REG_CIU_TX_MODE, SYMBOL_TX_CRC_ENABLE, btValue)) return false; - if (!pn53x_set_reg (pnd, REG_CIU_RX_MODE, SYMBOL_RX_CRC_ENABLE, btValue)) + if (!pn53x_write_register (pnd, REG_CIU_RX_MODE, SYMBOL_RX_CRC_ENABLE, btValue)) return false; pnd->bCrc = bEnable; break; @@ -851,7 +803,7 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b case NDO_HANDLE_PARITY: // Handle parity bit by PN53X chip or parse it as data bit btValue = (bEnable) ? 0x00 : SYMBOL_PARITY_DISABLE; - if (!pn53x_set_reg (pnd, REG_CIU_MANUAL_RCV, SYMBOL_PARITY_DISABLE, btValue)) + if (!pn53x_write_register (pnd, REG_CIU_MANUAL_RCV, SYMBOL_PARITY_DISABLE, btValue)) return false; pnd->bPar = bEnable; break; @@ -861,41 +813,47 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b break; case NDO_ACTIVATE_FIELD: - abtCmd[2] = RFCI_FIELD; - abtCmd[3] = (bEnable) ? 1 : 0; - if (!pn53x_transceive (pnd, abtCmd, 4, NULL, NULL)) - return false; + { + byte_t abtCmd[] = { RFConfiguration, RFCI_FIELD, (bEnable) ? 0x01 : 0x00 }; + if (!pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false)) + return false; + } break; case NDO_ACTIVATE_CRYPTO1: btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00; - if (!pn53x_set_reg (pnd, REG_CIU_STATUS2, SYMBOL_MF_CRYPTO1_ON, btValue)) + if (!pn53x_write_register (pnd, REG_CIU_STATUS2, SYMBOL_MF_CRYPTO1_ON, btValue)) return false; break; case NDO_INFINITE_SELECT: - // TODO Made some research around this point: - // timings could be tweak better than this, and maybe we can tweak timings - // to "gain" a sort-of hardware polling (ie. like PN532 does) - - // Retry format: 0x00 means only 1 try, 0xff means infinite - abtCmd[2] = RFCI_RETRY_SELECT; - abtCmd[3] = (bEnable) ? 0xff : 0x00; // MxRtyATR, default: active = 0xff, passive = 0x02 - abtCmd[4] = (bEnable) ? 0xff : 0x00; // MxRtyPSL, default: 0x01 - abtCmd[5] = (bEnable) ? 0xff : 0x00; // MxRtyPassiveActivation, default: 0xff - if (!pn53x_transceive (pnd, abtCmd, 6, NULL, NULL)) - return false; + { + // TODO Made some research around this point: + // timings could be tweak better than this, and maybe we can tweak timings + // to "gain" a sort-of hardware polling (ie. like PN532 does) + + // Retry format: 0x00 means only 1 try, 0xff means infinite + byte_t abtCmd[] = { + RFConfiguration, + RFCI_RETRY_SELECT, + (bEnable) ? 0xff : 0x00, // MxRtyATR, default: active = 0xff, passive = 0x02 + (bEnable) ? 0xff : 0x00, // MxRtyPSL, default: 0x01 + (bEnable) ? 0xff : 0x00 // MxRtyPassiveActivation, default: 0xff + }; + if (!pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), NULL, NULL, false)) + return false; + } break; case NDO_ACCEPT_INVALID_FRAMES: btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00; - if (!pn53x_set_reg (pnd, REG_CIU_RX_MODE, SYMBOL_RX_NO_ERROR, btValue)) + if (!pn53x_write_register (pnd, REG_CIU_RX_MODE, SYMBOL_RX_NO_ERROR, btValue)) return false; break; case NDO_ACCEPT_MULTIPLE_FRAMES: btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00; - if (!pn53x_set_reg (pnd, REG_CIU_RX_MODE, SYMBOL_RX_MULTIPLE, btValue)) + if (!pn53x_write_register (pnd, REG_CIU_RX_MODE, SYMBOL_RX_MULTIPLE, btValue)) return false; return true; break; @@ -903,7 +861,7 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b case NDO_AUTO_ISO14443_4: // TODO Cache activated/disactivated options pnd->bAutoIso14443_4 = bEnable; - return pn53x_set_parameter(pnd, PARAM_AUTO_RATS, bEnable); + return pn53x_set_parameters (pnd, PARAM_AUTO_RATS, bEnable); break; case NDO_FORCE_ISO14443_A: @@ -912,10 +870,10 @@ pn53x_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool b return true; } // Force pn53x to be in ISO14443-A mode - if (!pn53x_set_reg (pnd, REG_CIU_TX_MODE, SYMBOL_TX_FRAMING, 0x00)) { + if (!pn53x_write_register (pnd, REG_CIU_TX_MODE, SYMBOL_TX_FRAMING, 0x00)) { return false; } - if (!pn53x_set_reg (pnd, REG_CIU_RX_MODE, SYMBOL_RX_FRAMING, 0x00)) { + if (!pn53x_write_register (pnd, REG_CIU_RX_MODE, SYMBOL_RX_FRAMING, 0x00)) { return false; } return true; @@ -932,7 +890,7 @@ pn53x_initiator_select_dep_target(nfc_device_t * pnd, const nfc_dep_info_t * pndiInitiator, nfc_target_t * pnt) { - const byte_t abtPassiveInitiatorData[5] = { 0x00, 0xff, 0xff, 0x00, 0x00 }; // Only for 212/424 kpbs: First 4 bytes shall be set like this according to NFCIP-1, last byte is TSN (Time Slot Number) + const byte_t abtPassiveInitiatorData[] = { 0x00, 0xff, 0xff, 0x00, 0x00 }; // Only for 212/424 kpbs: First 4 bytes shall be set like this according to NFCIP-1, last byte is TSN (Time Slot Number) const byte_t * pbtPassiveInitiatorData = NULL; switch (nbr) { @@ -973,25 +931,19 @@ pn53x_InJumpForDEP (nfc_device_t * pnd, const byte_t * pbtGBi, const size_t szGBi, nfc_target_t * pnt) { - byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN]; - size_t szRx; - size_t offset; - byte_t abtCmd[sizeof (pncmd_initiator_jump_for_dep)]; + byte_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { InJumpForDEP, (ndm == NDM_ACTIVE) ? 0x01 : 0x00 }; - memcpy (abtCmd, pncmd_initiator_jump_for_dep, sizeof (pncmd_initiator_jump_for_dep)); - - offset = 5; // 2 bytes for command, 1 byte for DEP mode (Active/Passive), 1 byte for baud rate, 1 byte for following parameters flag - abtCmd[2] = (ndm == NDM_ACTIVE) ? 0x01 : 0x00; + size_t offset = 4; // 1 byte for command, 1 byte for DEP mode (Active/Passive), 1 byte for baud rate, 1 byte for following parameters flag switch (nbr) { case NBR_106: - abtCmd[3] = 0x00; // baud rate is 106 kbps + abtCmd[2] = 0x00; // baud rate is 106 kbps break; case NBR_212: - abtCmd[3] = 0x01; // baud rate is 212 kbps + abtCmd[2] = 0x01; // baud rate is 212 kbps break; case NBR_424: - abtCmd[3] = 0x02; // baud rate is 424 kbps + abtCmd[2] = 0x02; // baud rate is 424 kbps break; case NBR_847: case NBR_UNDEFINED: @@ -1004,13 +956,13 @@ pn53x_InJumpForDEP (nfc_device_t * pnd, if (pbtPassiveInitiatorData && (ndm == NDM_PASSIVE)) { /* can't have passive initiator data when using active mode */ switch (nbr) { case NBR_106: - abtCmd[4] |= 0x01; + abtCmd[3] |= 0x01; memcpy (abtCmd + offset, pbtPassiveInitiatorData, 4); offset += 4; break; case NBR_212: case NBR_424: - abtCmd[4] |= 0x01; + abtCmd[3] |= 0x01; memcpy (abtCmd + offset, pbtPassiveInitiatorData, 5); offset += 5; break; @@ -1024,18 +976,21 @@ pn53x_InJumpForDEP (nfc_device_t * pnd, } if (pbtNFCID3i) { - abtCmd[4] |= 0x02; + abtCmd[3] |= 0x02; memcpy (abtCmd + offset, pbtNFCID3i, 10); offset += 10; } if (szGBi && pbtGBi) { - abtCmd[4] |= 0x04; + abtCmd[3] |= 0x04; memcpy (abtCmd + offset, pbtGBi, szGBi); offset += szGBi; } + + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof (abtRx); // Try to find a target, call the transceive callback function of the current device - if (!pn53x_transceive (pnd, abtCmd, offset, abtRx, &szRx)) + if (!pn53x_transceive (pnd, abtCmd, offset, abtRx, &szRx, false)) return false; // Make sure one target has been found, the PN53X returns 0x00 if none was available @@ -1066,20 +1021,16 @@ bool pn53x_initiator_transceive_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxBits, const byte_t * pbtTxPar, byte_t * pbtRx, size_t * pszRxBits, byte_t * pbtRxPar) { - byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN]; - size_t szRx = PN53x_EXTENDED_FRAME_MAX_LEN; size_t szFrameBits = 0; size_t szFrameBytes = 0; uint8_t ui8rcc; uint8_t ui8Bits = 0; - byte_t abtCmd[sizeof (pncmd_initiator_exchange_raw_data)]; - - memcpy (abtCmd, pncmd_initiator_exchange_raw_data, sizeof (pncmd_initiator_exchange_raw_data)); + byte_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { InCommunicateThru }; // Check if we should prepare the parity bits ourself if (!pnd->bPar) { // Convert data with parity to a frame - pn53x_wrap_frame (pbtTx, szTxBits, pbtTxPar, abtCmd + 2, &szFrameBits); + pn53x_wrap_frame (pbtTx, szTxBits, pbtTxPar, abtCmd + 1, &szFrameBits); } else { szFrameBits = szTxBits; } @@ -1092,19 +1043,21 @@ pn53x_initiator_transceive_bits (nfc_device_t * pnd, const byte_t * pbtTx, const // When the parity is handled before us, we just copy the data if (pnd->bPar) - memcpy (abtCmd + 2, pbtTx, szFrameBytes); + memcpy (abtCmd + 1, pbtTx, szFrameBytes); // Set the amount of transmission bits in the PN53X chip register if (!pn53x_set_tx_bits (pnd, ui8Bits)) return false; // Send the frame to the PN53X chip and get the answer - // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42) - if (!pn53x_transceive (pnd, abtCmd, szFrameBytes + 2, abtRx, &szRx)) + // We have to give the amount of bytes + (the command byte 0x42) + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof(abtRx); + if (!pn53x_transceive (pnd, abtCmd, szFrameBytes + 1, abtRx, &szRx, false)) return false; // Get the last bit-count that is stored in the received byte - if (!pn53x_get_reg (pnd, REG_CIU_CONTROL, &ui8rcc)) + if (!pn53x_read_register (pnd, REG_CIU_CONTROL, &ui8rcc)) return false; ui8Bits = ui8rcc & SYMBOL_RX_LAST_BITS; @@ -1131,10 +1084,8 @@ bool pn53x_initiator_transceive_bytes (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx, byte_t * pbtRx, size_t * pszRx) { - byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN]; - size_t szRx = PN53x_EXTENDED_FRAME_MAX_LEN; size_t szExtraTxLen; - byte_t abtCmd[sizeof (pncmd_initiator_exchange_raw_data)]; + byte_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; // We can not just send bytes without parity if while the PN53X expects we handled them if (!pnd->bPar) @@ -1142,14 +1093,14 @@ pn53x_initiator_transceive_bytes (nfc_device_t * pnd, const byte_t * pbtTx, cons // Copy the data into the command frame if (pnd->bEasyFraming) { - memcpy (abtCmd, pncmd_initiator_exchange_data, sizeof (pncmd_initiator_exchange_data)); - abtCmd[2] = 1; /* target number */ - memcpy (abtCmd + 3, pbtTx, szTx); - szExtraTxLen = 3; - } else { - memcpy (abtCmd, pncmd_initiator_exchange_raw_data, sizeof (pncmd_initiator_exchange_raw_data)); + abtCmd[0] = InDataExchange; + abtCmd[1] = 1; /* target number */ memcpy (abtCmd + 2, pbtTx, szTx); szExtraTxLen = 2; + } else { + abtCmd[0] = InCommunicateThru; + memcpy (abtCmd + 1, pbtTx, szTx); + szExtraTxLen = 1; } // To transfer command frames bytes we can not have any leading bits, reset this to zero @@ -1158,7 +1109,9 @@ pn53x_initiator_transceive_bytes (nfc_device_t * pnd, const byte_t * pbtTx, cons // Send the frame to the PN53X chip and get the answer // We have to give the amount of bytes + (the two command bytes 0xD4, 0x42) - if (!pn53x_transceive (pnd, abtCmd, szTx + szExtraTxLen, abtRx, &szRx)) + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof(abtRx); + if (!pn53x_transceive (pnd, abtCmd, szTx + szExtraTxLen, abtRx, &szRx, false)) return false; // Save the received byte count @@ -1187,14 +1140,14 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_ pnd->iLastError = ETGUIDNOTSUP; return false; } - pn53x_set_parameter(pnd, PARAM_AUTO_ATR_RES, false); - if (pnd->nc == NC_PN532) { // We have a PN532 + pn53x_set_parameters (pnd, PARAM_AUTO_ATR_RES, false); + if (((struct pn53x_data*)(pnd->chip_data))->type == PN532) { // We have a PN532 if ((pnt->nti.nai.btSak & SAK_ISO14443_4_COMPLIANT) && (pnd->bAutoIso14443_4)) { // We have a ISO14443-4 tag to emulate and NDO_AUTO_14443_4A option is enabled ptm |= PTM_ISO14443_4_PICC_ONLY; // We add ISO14443-4 restriction - pn53x_set_parameter(pnd, PARAM_14443_4_PICC, true); + pn53x_set_parameters (pnd, PARAM_14443_4_PICC, true); } else { - pn53x_set_parameter(pnd, PARAM_14443_4_PICC, false); + pn53x_set_parameters (pnd, PARAM_14443_4_PICC, false); } } break; @@ -1202,7 +1155,7 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_ ptm = PTM_PASSIVE_ONLY; break; case NMT_DEP: - pn53x_set_parameter(pnd, PARAM_AUTO_ATR_RES, true); + pn53x_set_parameters (pnd, PARAM_AUTO_ATR_RES, true); ptm = PTM_DEP_ONLY; if (pnt->nti.ndi.ndm == NDM_PASSIVE) { ptm |= PTM_PASSIVE_ONLY; // We add passive mode restriction @@ -1217,12 +1170,12 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_ // Make sure the CRC & parity are handled by the device, this is needed for target_init to work properly if (!bCrc) - pn53x_configure ((nfc_device_t *) pnd, NDO_HANDLE_CRC, true); + pn53x_configure (pnd, NDO_HANDLE_CRC, true); if (!bPar) - pn53x_configure ((nfc_device_t *) pnd, NDO_HANDLE_PARITY, true); + pn53x_configure (pnd, NDO_HANDLE_PARITY, true); // Let the PN53X be activated by the RF level detector from power down mode - if (!pn53x_set_reg (pnd, REG_CIU_TX_AUTO, SYMBOL_INITIAL_RF_ON, 0x04)) + if (!pn53x_write_register (pnd, REG_CIU_TX_AUTO, SYMBOL_INITIAL_RF_ON, 0x04)) return false; byte_t abtMifareParams[6]; @@ -1283,16 +1236,17 @@ pn53x_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_ bool targetActivated = false; while (!targetActivated) { - nfc_modulation_t nm; - nfc_dep_mode_t ndm = NDM_UNDEFINED; byte_t btActivatedMode; - nm.nbr = NBR_UNDEFINED; - if(!pn53x_TgInitAsTarget(pnd, ptm, pbtMifareParams, pbtTkt, szTkt, pbtFeliCaParams, pbtNFCID3t, pbtGBt, szGBt, pbtRx, pszRx, &btActivatedMode)) { return false; } + nfc_modulation_t nm = { + .nmt = NMT_DEP, // Silent compilation warnings + .nbr = NBR_UNDEFINED + }; + nfc_dep_mode_t ndm = NDM_UNDEFINED; // Decode activated "mode" switch(btActivatedMode & 0x70) { // Baud rate case 0x00: // 106kbps @@ -1354,57 +1308,53 @@ pn53x_TgInitAsTarget (nfc_device_t * pnd, pn53x_target_mode_t ptm, const byte_t * pbtNFCID3t, const byte_t * pbtGBt, const size_t szGBt, byte_t * pbtRx, size_t * pszRx, byte_t * pbtModeByte) { - byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN]; - size_t szRx; - byte_t abtCmd[39 + 47 + 48]; // Worst case: 39-byte base, 47 bytes max. for General Bytes, 48 bytes max. for Historical Bytes + byte_t abtCmd[39 + 47 + 48] = { TgInitAsTarget }; // Worst case: 39-byte base, 47 bytes max. for General Bytes, 48 bytes max. for Historical Bytes size_t szOptionalBytes = 0; - memcpy (abtCmd, pncmd_target_init, sizeof (pncmd_target_init)); - // Clear the target init struct, reset to all zeros - memset (abtCmd + sizeof (pncmd_target_init), 0x00, sizeof (abtCmd) - sizeof (pncmd_target_init)); + memset (abtCmd + 1, 0x00, sizeof (abtCmd) - 1); // Store the target mode in the initialization params - abtCmd[2] = ptm; + abtCmd[1] = ptm; // MIFARE part if (pbtMifareParams) { - memcpy (abtCmd+3, pbtMifareParams, 6); + memcpy (abtCmd+2, pbtMifareParams, 6); } // FeliCa part if (pbtFeliCaParams) { - memcpy (abtCmd+9, pbtFeliCaParams, 18); + memcpy (abtCmd+8, pbtFeliCaParams, 18); } // DEP part if (pbtNFCID3t) { - memcpy(abtCmd+27, pbtNFCID3t, 10); + memcpy(abtCmd+26, pbtNFCID3t, 10); } // General Bytes (ISO/IEC 18092) - if (pnd->nc == NC_PN531) { + if (((struct pn53x_data*)(pnd->chip_data))->type == PN531) { if (szGBt) { - memcpy (abtCmd+37, pbtGBt, szGBt); + memcpy (abtCmd+36, pbtGBt, szGBt); szOptionalBytes = szGBt; } } else { - abtCmd[37] = (byte_t)(szGBt); + abtCmd[36] = (byte_t)(szGBt); if (szGBt) { - memcpy (abtCmd+38, pbtGBt, szGBt); + memcpy (abtCmd+37, pbtGBt, szGBt); } szOptionalBytes = szGBt + 1; } // Historical bytes (ISO/IEC 14443-4) - if (pnd->nc != NC_PN531) { // PN531 does not handle Historical Bytes - abtCmd[37+szOptionalBytes] = (byte_t)(szTkt); + if (((struct pn53x_data*)(pnd->chip_data))->type != PN531) { // PN531 does not handle Historical Bytes + abtCmd[36+szOptionalBytes] = (byte_t)(szTkt); if (szTkt) { - memcpy (abtCmd+38+szOptionalBytes, pbtTkt, szTkt); + memcpy (abtCmd+37+szOptionalBytes, pbtTkt, szTkt); } szOptionalBytes += szTkt + 1; } // Request the initialization as a target - szRx = PN53x_EXTENDED_FRAME_MAX_LEN; - - if (!pn53x_transceive (pnd, abtCmd, 37 + szOptionalBytes, abtRx, &szRx)) + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof (abtRx); + if (!pn53x_transceive (pnd, abtCmd, 36 + szOptionalBytes, abtRx, &szRx, false)) return false; // Note: the first byte is skip: @@ -1424,23 +1374,22 @@ pn53x_TgInitAsTarget (nfc_device_t * pnd, pn53x_target_mode_t ptm, bool pn53x_target_receive_bits (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxBits, byte_t * pbtRxPar) { - byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN]; - size_t szRx; - size_t szFrameBits; - uint8_t ui8rcc; - uint8_t ui8Bits; + byte_t abtCmd[] = { TgGetInitiatorCommand }; + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof (abtRx); // Try to gather a received frame from the reader - if (!pn53x_transceive (pnd, pncmd_target_get_initiator_command, 2, abtRx, &szRx)) + if (!pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), abtRx, &szRx, false)) return false; // Get the last bit-count that is stored in the received byte - if (!pn53x_get_reg (pnd, REG_CIU_CONTROL, &ui8rcc)) + uint8_t ui8rcc; + if (!pn53x_read_register (pnd, REG_CIU_CONTROL, &ui8rcc)) return false; - ui8Bits = ui8rcc & SYMBOL_RX_LAST_BITS; + uint8_t ui8Bits = ui8rcc & SYMBOL_RX_LAST_BITS; // Recover the real frame length in bits - szFrameBits = ((szRx - 1 - ((ui8Bits == 0) ? 0 : 1)) * 8) + ui8Bits; + size_t szFrameBits = ((szRx - 1 - ((ui8Bits == 0) ? 0 : 1)) * 8) + ui8Bits; // Ignore the status byte from the PN53X here, it was checked earlier in pn53x_transceive() // Check if we should recover the parity bits ourself @@ -1460,18 +1409,18 @@ pn53x_target_receive_bits (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRxBit bool pn53x_target_receive_bytes (nfc_device_t * pnd, byte_t * pbtRx, size_t * pszRx) { - byte_t const *pbtTx; - byte_t abtRx[PN53x_EXTENDED_FRAME_MAX_LEN]; - size_t szRx; + byte_t abtCmd[1]; if (pnd->bEasyFraming) { - pbtTx = pncmd_target_get_data; + abtCmd[0] = TgGetData; } else { - pbtTx = pncmd_target_get_initiator_command; + abtCmd[0] = TgGetInitiatorCommand; } // Try to gather a received frame from the reader - if (!pn53x_transceive (pnd, pbtTx, 2, abtRx, &szRx)) + byte_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; + size_t szRx = sizeof (abtRx); + if (!pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), abtRx, &szRx, false)) return false; // Save the received byte count @@ -1490,14 +1439,12 @@ pn53x_target_send_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t s size_t szFrameBits = 0; size_t szFrameBytes = 0; uint8_t ui8Bits = 0; - byte_t abtCmd[sizeof (pncmd_target_response_to_initiator)]; - - memcpy (abtCmd, pncmd_target_response_to_initiator, sizeof (pncmd_target_response_to_initiator)); + byte_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { TgResponseToInitiator }; // Check if we should prepare the parity bits ourself if (!pnd->bPar) { // Convert data with parity to a frame - pn53x_wrap_frame (pbtTx, szTxBits, pbtTxPar, abtCmd + 2, &szFrameBits); + pn53x_wrap_frame (pbtTx, szTxBits, pbtTxPar, abtCmd + 1, &szFrameBits); } else { szFrameBits = szTxBits; } @@ -1510,14 +1457,14 @@ pn53x_target_send_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t s // When the parity is handled before us, we just copy the data if (pnd->bPar) - memcpy (abtCmd + 2, pbtTx, szFrameBytes); + memcpy (abtCmd + 1, pbtTx, szFrameBytes); // Set the amount of transmission bits in the PN53X chip register if (!pn53x_set_tx_bits (pnd, ui8Bits)) return false; // Try to send the bits to the reader - if (!pn53x_transceive (pnd, abtCmd, szFrameBytes + 2, NULL, NULL)) + if (!pn53x_transceive (pnd, abtCmd, szFrameBytes + 1, NULL, NULL, false)) return false; // Everyting seems ok, return true @@ -1527,31 +1474,30 @@ pn53x_target_send_bits (nfc_device_t * pnd, const byte_t * pbtTx, const size_t s bool pn53x_target_send_bytes (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTx) { - byte_t abtCmd[MAX (sizeof (pncmd_target_response_to_initiator), sizeof (pncmd_target_set_data))]; - + byte_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; // We can not just send bytes without parity if while the PN53X expects we handled them if (!pnd->bPar) return false; if (pnd->bEasyFraming) { - memcpy (abtCmd, pncmd_target_set_data, sizeof (pncmd_target_set_data)); + abtCmd[0] = TgSetData; } else { - memcpy (abtCmd, pncmd_target_response_to_initiator, sizeof (pncmd_target_response_to_initiator)); + abtCmd[0] = TgResponseToInitiator; } // Copy the data into the command frame - memcpy (abtCmd + 2, pbtTx, szTx); + memcpy (abtCmd + 1, pbtTx, szTx); // Try to send the bits to the reader - if (!pn53x_transceive (pnd, abtCmd, szTx + 2, NULL, NULL)) + if (!pn53x_transceive (pnd, abtCmd, szTx + 1, NULL, NULL, false)) return false; // Everyting seems ok, return true return true; } -const pn53x_modulation_t +pn53x_modulation_t pn53x_nm_to_pm(const nfc_modulation_t nm) { switch(nm.nmt) { @@ -1605,7 +1551,7 @@ pn53x_nm_to_pm(const nfc_modulation_t nm) return PM_UNDEFINED; } -const nfc_modulation_t +nfc_modulation_t pn53x_ptt_to_nm( const pn53x_target_type_t ptt ) { switch (ptt) { @@ -1654,7 +1600,7 @@ pn53x_ptt_to_nm( const pn53x_target_type_t ptt ) return (const nfc_modulation_t){ .nmt = NMT_ISO14443A, .nbr = NBR_106 }; } -const pn53x_target_type_t +pn53x_target_type_t pn53x_nm_to_ptt(const nfc_modulation_t nm) { switch(nm.nmt) { diff --git a/libnfc/chips/pn53x.h b/libnfc/chips/pn53x.h index 822c4bc..7352ad9 100644 --- a/libnfc/chips/pn53x.h +++ b/libnfc/chips/pn53x.h @@ -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 -# 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); diff --git a/libnfc/drivers.h b/libnfc/drivers.h index 14c5891..7dccd74 100644 --- a/libnfc/drivers.h +++ b/libnfc/drivers.h @@ -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 -# 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__ diff --git a/libnfc/drivers/arygon.c b/libnfc/drivers/arygon.c index 7bdc974..eb868df 100644 --- a/libnfc/drivers/arygon.c +++ b/libnfc/drivers/arygon.c @@ -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; } diff --git a/libnfc/drivers/pn532_uart.c b/libnfc/drivers/pn532_uart.c index 73190cd..21cdebe 100644 --- a/libnfc/drivers/pn532_uart.c +++ b/libnfc/drivers/pn532_uart.c @@ -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 #include @@ -36,44 +39,26 @@ #include #include -// 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, +}; diff --git a/libnfc/drivers/pn532_uart.h b/libnfc/drivers/pn532_uart.h index aa912f1..36d684f 100644 --- a/libnfc/drivers/pn532_uart.h +++ b/libnfc/drivers/pn532_uart.h @@ -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__ diff --git a/libnfc/nfc-internal.h b/libnfc/nfc-internal.h new file mode 100644 index 0000000..d0c08ac --- /dev/null +++ b/libnfc/nfc-internal.h @@ -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 + */ + +/** + * @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__ diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 0cc85a2..5fa3f81 100644 --- a/libnfc/nfc.c +++ b/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_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); } /** diff --git a/test/test_register_access.c b/test/test_register_access.c index b2b5941..90aafb9 100644 --- a/test/test_register_access.c +++ b/test/test_register_access.c @@ -1,13 +1,11 @@ #include #include -#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); diff --git a/test/test_register_endianness.c b/test/test_register_endianness.c index 6cae3e5..d227825 100644 --- a/test/test_register_endianness.c +++ b/test/test_register_endianness.c @@ -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);