diff --git a/examples/nfc-poll.c b/examples/nfc-poll.c index fabadc5..c90e8ee 100644 --- a/examples/nfc-poll.c +++ b/examples/nfc-poll.c @@ -2,6 +2,7 @@ * Public platform independent Near Field Communication (NFC) library examples * * Copyright (C) 2010, Romuald Conty + * Copyright (C) 2011, Romain Tartiere, Romuald Conty * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -37,6 +38,7 @@ #endif // HAVE_CONFIG_H #include +#include #include #include #include @@ -49,7 +51,16 @@ #define MAX_DEVICE_COUNT 16 -static nfc_device_t *pnd; +static nfc_device_t *pnd = NULL; + +void stop_polling (int sig) +{ + (void) sig; + if (pnd) + nfc_abort_command (pnd); + else + exit (EXIT_FAILURE); +} int main (int argc, const char *argv[]) @@ -59,6 +70,8 @@ main (int argc, const char *argv[]) bool verbose = false; nfc_device_desc_t *pnddDevices; + signal (SIGINT, stop_polling); + pnddDevices = parse_args (argc, argv, &szFound, &verbose); // Display libnfc version diff --git a/include/nfc/nfc-types.h b/include/nfc/nfc-types.h index 1663c06..76d484d 100644 --- a/include/nfc/nfc-types.h +++ b/include/nfc/nfc-types.h @@ -72,6 +72,7 @@ typedef struct { int iLastError; /** Last sent command */ int iLastCommand; + int iAbortFds[2]; } nfc_device_t; // TODO: Move chip's specifics in a chips structure (e.g. iLastCommand, ui8Parameters, ui8TxBits) diff --git a/include/nfc/nfc.h b/include/nfc/nfc.h index b814b1a..b203cc0 100644 --- a/include/nfc/nfc.h +++ b/include/nfc/nfc.h @@ -63,6 +63,7 @@ extern "C" { /* NFC Device/Hardware manipulation */ NFC_EXPORT nfc_device_t *nfc_connect (nfc_device_desc_t * pndd); NFC_EXPORT void nfc_disconnect (nfc_device_t * pnd); + NFC_EXPORT void nfc_abort_command (nfc_device_t * pnd); NFC_EXPORT void nfc_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound); NFC_EXPORT bool nfc_configure (nfc_device_t * pnd, const nfc_device_option_t ndo, const bool bEnable); @@ -147,6 +148,7 @@ extern "C" { #define DEIO 0x1000 /* Input/output error */ #define DEINVAL 0x2000 /* Invalid argument */ #define DETIMEOUT 0x3000 /* Operation timeout */ +#define DEABORT 0x4000 /* Operation aborted */ # ifdef __cplusplus } diff --git a/libnfc/buses/uart.h b/libnfc/buses/uart.h index 9745477..e88ceb4 100644 --- a/libnfc/buses/uart.h +++ b/libnfc/buses/uart.h @@ -69,7 +69,7 @@ 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, const size_t szRx); +int uart_receive (serial_port sp, byte_t * pbtRx, const size_t szRx, int iAbortFd); int uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx); char **uart_list_ports (void); diff --git a/libnfc/buses/uart_posix.c b/libnfc/buses/uart_posix.c index 877f54c..0d40d54 100644 --- a/libnfc/buses/uart_posix.c +++ b/libnfc/buses/uart_posix.c @@ -31,9 +31,10 @@ # include # include # include -# include -# include # include +# include +# include +# include # include "nfc-internal.h" @@ -215,19 +216,33 @@ static const struct timeval tvTimeout = { * @return 0 on success, otherwise driver error code */ int -uart_receive (serial_port sp, byte_t * pbtRx, const size_t szRx) +uart_receive (serial_port sp, byte_t * pbtRx, const size_t szRx, int iAbortFd) { struct timeval tv = tvTimeout; + struct timeval *ptv = &tv; int received_bytes_count = 0; int available_bytes_count = 0; const int expected_bytes_count = (int)szRx; int res; fd_set rfds; do { +select: // Reset file descriptor FD_ZERO (&rfds); FD_SET (((serial_port_unix *) sp)->fd, &rfds); - res = select (((serial_port_unix *) sp)->fd + 1, &rfds, NULL, NULL, &tv); + + if (iAbortFd) { + FD_SET (iAbortFd, &rfds); + ptv = NULL; + } + + res = select (MAX(((serial_port_unix *) sp)->fd, iAbortFd) + 1, &rfds, NULL, NULL, ptv); + + if ((res < 0) && (EINTR == errno)) { + // The system call was interupted by a signal and a signal handler was + // run. Restart the interupted system call. + goto select; + } // Read error if (res < 0) { @@ -239,6 +254,14 @@ uart_receive (serial_port sp, byte_t * pbtRx, const size_t szRx) DBG ("Timeout!"); return DETIMEOUT; } + + if (FD_ISSET (iAbortFd, &rfds)) { + // Abort requested + DBG ("Abort!"); + close (iAbortFd); + return DEABORT; + } + // Retrieve the count of the incoming bytes res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &available_bytes_count); if (res != 0) { diff --git a/libnfc/chips/pn53x.c b/libnfc/chips/pn53x.c index 1dfd10e..2c10242 100644 --- a/libnfc/chips/pn53x.c +++ b/libnfc/chips/pn53x.c @@ -755,6 +755,7 @@ static struct sErrorMessage { { DEINVAL, "Invalid argument" }, { DEIO, "Input/output error" }, { DETIMEOUT, "Operation timed-out" }, + { DEABORT, "Operation aborted" }, { DENOTSUP, "Operation not supported" } }; @@ -1686,3 +1687,16 @@ pn53x_nm_to_ptt(const nfc_modulation_t nm) return PTT_UNDEFINED; } +bool +pn53x_check_communication (nfc_device_t *pnd) +{ + const byte_t abtCmd[] = { Diagnose, 0x00, 'l', 'i', 'b', 'n', 'f', 'c' }; + const byte_t abtExpectedRx[] = { 0x00, 'l', 'i', 'b', 'n', 'f', 'c' }; + byte_t abtRx[sizeof(abtExpectedRx)]; + size_t szRx = sizeof (abtRx); + + if (!pn53x_transceive (pnd, abtCmd, sizeof (abtCmd), abtRx, &szRx)) + return false; + + return ((sizeof(abtExpectedRx) == szRx) && (0 == memcmp (abtRx, abtExpectedRx, sizeof(abtExpectedRx)))); +} diff --git a/libnfc/chips/pn53x.h b/libnfc/chips/pn53x.h index aff2be9..af88dc2 100644 --- a/libnfc/chips/pn53x.h +++ b/libnfc/chips/pn53x.h @@ -210,6 +210,7 @@ bool pn53x_decode_target_data (const byte_t * pbtRawData, size_t szRawData, 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); +bool pn53x_check_communication (nfc_device_t *pnd); // NFC device as Initiator functions bool pn53x_initiator_select_passive_target (nfc_device_t * pnd, diff --git a/libnfc/drivers/arygon.c b/libnfc/drivers/arygon.c index e7df3ea..b149cb4 100644 --- a/libnfc/drivers/arygon.c +++ b/libnfc/drivers/arygon.c @@ -79,7 +79,6 @@ static const byte_t arygon_error_unknown_mode[] = "FF060000\x0d\x0a"; // void arygon_ack (const nfc_device_spec_t nds); bool arygon_reset_tama (nfc_device_t * pnd); void arygon_firmware (nfc_device_t * pnd, char * str); -bool arygon_check_communication (nfc_device_t * pnd); bool arygon_probe (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound) @@ -217,7 +216,7 @@ arygon_tama_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szDat } byte_t abtRxBuf[6]; - res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 6); + res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, sizeof (abtRxBuf), 0); if (res != 0) { ERR ("%s", "Unable to read ACK"); pnd->iLastError = res; @@ -235,13 +234,38 @@ arygon_tama_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szDat return true; } +int +arygon_abort (nfc_device_t *pnd) +{ + ((struct pn53x_data*)(pnd->chip_data))->state = NORMAL; + + // Using Arygon device we can't send ACK frame to abort the running command + return (pn53x_check_communication (pnd)) ? 0 : -1; +} + int arygon_tama_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen) { byte_t abtRxBuf[5]; size_t len; + int abort_fd = 0; + + switch (pnd->iLastCommand) { + case InAutoPoll: + case TgInitAsTarget: + case TgGetData: + abort_fd = pnd->iAbortFds[1]; + break; + default: + break; + } + + int res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 5, abort_fd); + + if (abort_fd && (DEABORT == res)) { + return arygon_abort (pnd); + } - int res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 5); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -257,7 +281,7 @@ arygon_tama_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLe if ((0x01 == abtRxBuf[3]) && (0xff == abtRxBuf[4])) { // Error frame - uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 3); + uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 3, 0); ERR ("%s", "Application level error detected"); pnd->iLastError = DEISERRFRAME; return -1; @@ -285,7 +309,7 @@ arygon_tama_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLe } // TFI + PD0 (CC+1) - res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 2); + res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 2, 0); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -305,7 +329,7 @@ arygon_tama_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLe } if (len) { - res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, pbtData, len); + res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, pbtData, len, 0); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -313,7 +337,7 @@ arygon_tama_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLe } } - res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 2); + res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRxBuf, 2, 0); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -354,7 +378,7 @@ arygon_firmware (nfc_device_t * pnd, char * str) DBG ("Unable to send ARYGON firmware command."); return; } - res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRx, szRx); + res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRx, szRx, 0); if (res != 0) { DBG ("Unable to retrieve ARYGON firmware version."); return; @@ -381,7 +405,7 @@ arygon_reset_tama (nfc_device_t * pnd) // Two reply are possible from ARYGON device: arygon_error_none (ie. in case the byte is well-sent) // or arygon_error_unknown_mode (ie. in case of the first byte was bad-transmitted) - res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRx, szRx); + res = uart_receive (((struct arygon_data*)(pnd->driver_data))->port, abtRx, szRx, 0); if (res != 0) { DBG ("No reply to 'reset TAMA' command."); return false; @@ -390,7 +414,7 @@ arygon_reset_tama (nfc_device_t * pnd) if ( 0 == memcmp (abtRx, arygon_error_unknown_mode, sizeof (arygon_error_unknown_mode))) { // HACK Here we are... the first byte wasn't sent as expected, so we resend the same command uart_send ((serial_port) nds, arygon_reset_tama_cmd, sizeof (arygon_reset_tama_cmd)); - res = uart_receive ((serial_port) nds, abtRx, &szRx); + res = uart_receive ((serial_port) nds, abtRx, &szRx, 0); if (res != 0) { return false; } @@ -413,7 +437,7 @@ arygon_ack (const nfc_device_spec_t nds) PRINT_HEX ("TX", arygon_ack_frame, sizeof (arygon_ack_frame)); #endif uart_send ((serial_port) nds, arygon_ack_frame, sizeof (arygon_ack_frame)); - uart_receive ((serial_port) nds, abtRx, &szRx); + uart_receive ((serial_port) nds, abtRx, &szRx, 0); #ifdef DEBUG PRINT_HEX ("RX", abtRx, szRx); #endif diff --git a/libnfc/drivers/pn532_uart.c b/libnfc/drivers/pn532_uart.c index f23dfec..9b53d0b 100644 --- a/libnfc/drivers/pn532_uart.c +++ b/libnfc/drivers/pn532_uart.c @@ -50,7 +50,6 @@ static const byte_t ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 }; 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; @@ -95,7 +94,7 @@ pn532_uart_probe (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * ps // PN532 could be powered down, we need to wake it up before line testing. // TODO pn532_uart_wakeup ((nfc_device_spec_t) sp); // Check communication using "Diagnose" command, with "Communication test" (0x00) - bool res = pn532_uart_check_communication (&nd); + bool res = pn53x_check_communication (&nd); free(nd.driver_data); free(nd.chip_data); uart_close (sp); @@ -156,7 +155,7 @@ pn532_uart_connect (const nfc_device_desc_t * pndd) pnd->driver = &pn532_uart_driver; // Check communication using "Diagnose" command, with "Communication test" (0x00) - if (!pn532_uart_check_communication (pnd)) { + if (!pn53x_check_communication (pnd)) { pn532_uart_disconnect(pnd); return NULL; } @@ -204,7 +203,7 @@ pn532_uart_send (nfc_device_t * pnd, const byte_t * pbtData, const size_t szData } byte_t abtRxBuf[6]; - res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 6); + res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 6, 0); if (res != 0) { ERR ("%s", "Unable to read ACK"); pnd->iLastError = res; @@ -225,7 +224,7 @@ 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); + int res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 5, 0); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -241,7 +240,7 @@ pn532_uart_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen if ((0x01 == abtRxBuf[3]) && (0xff == abtRxBuf[4])) { // Error frame - uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 3); + uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 3, 0); ERR ("%s", "Application level error detected"); pnd->iLastError = DEISERRFRAME; return -1; @@ -269,7 +268,7 @@ pn532_uart_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen } // TFI + PD0 (CC+1) - res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 2); + res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 2, 0); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -289,7 +288,7 @@ pn532_uart_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen } if (len) { - res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, pbtData, len); + res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, pbtData, len, 0); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -297,7 +296,7 @@ pn532_uart_receive (nfc_device_t * pnd, byte_t * pbtData, const size_t szDataLen } } - res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 2); + res = uart_receive (((struct pn532_uart_data*)(pnd->driver_data))->port, abtRxBuf, 2, 0); if (res != 0) { ERR ("%s", "Unable to receive data. (RX)"); pnd->iLastError = res; @@ -331,23 +330,6 @@ 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, diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 1fe2c57..e22c83f 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -30,10 +30,12 @@ # include "config.h" #endif // HAVE_CONFIG_H +#include #include #include #include #include +#include #include @@ -136,6 +138,8 @@ nfc_connect (nfc_device_desc_t * pndd) if (!nfc_configure (pnd, NDO_ACCEPT_MULTIPLE_FRAMES, false)) return NULL; + pipe (pnd->iAbortFds); + return pnd; } else { DBG ("No device found using driver: %s", ndr->name); @@ -160,6 +164,8 @@ nfc_disconnect (nfc_device_t * pnd) nfc_initiator_deselect_target (pnd); // Disable RF field to avoid heating nfc_configure (pnd, NDO_ACTIVATE_FIELD, false); + close (pnd->iAbortFds[0]); + close (pnd->iAbortFds[1]); // Disconnect, clean up and release the device pnd->driver->disconnect (pnd); } @@ -584,6 +590,15 @@ nfc_target_init (nfc_device_t * pnd, nfc_target_t * pnt, byte_t * pbtRx, size_t return pn53x_target_init (pnd, pnt, pbtRx, pszRx); } +void +nfc_abort_command (nfc_device_t * pnd) +{ + if (pnd) { + close (pnd->iAbortFds[0]); + pipe (pnd->iAbortFds); + } +} + /** * @brief Send bytes and APDU frames * @return Returns \c true if action was successfully performed; otherwise returns \c false.