Enable aborting blocking commands (e.g. TgInitAsTarget) and refactor

*_check_communication() as pn53x_check_communication().
This commit is contained in:
Romain Tartiere 2011-03-04 19:59:49 +00:00
parent 7ed71a1501
commit 4b6060aeeb
10 changed files with 118 additions and 43 deletions

View file

@ -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 <err.h>
#include <signal.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
@ -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

View file

@ -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)

View file

@ -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
}

View file

@ -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);

View file

@ -31,9 +31,10 @@
# include <sys/select.h>
# include <sys/param.h>
# include <ctype.h>
# include <termios.h>
# include <stdio.h>
# include <dirent.h>
# include <errno.h>
# include <stdio.h>
# include <termios.h>
# 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) {

View file

@ -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))));
}

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -30,10 +30,12 @@
# include "config.h"
#endif // HAVE_CONFIG_H
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <nfc/nfc.h>
@ -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.