Broke whole the libnfc :-)

use a new way to handle drivers
use absolute include path instead of relative ones
move some nfc_device_t members in a better place
nfc_device_t now embeddeds driver data and chip data pointers (useful to be more generic)
use more readable variables instead of strange coding convention
move PRINT_HEX macro into nfc-internal.h
silent warnings with more strict CFLAGS
chips/pn53x: use the powerful C99 writing to construct PN53x commands
chips/pn53x: remove almost all memcpy()
chips/pn53x: WriteRegister, ReadRegister and SetParameters command wrappers are correctly named
chips/pn53x: introduce chip state (SLEEP, NORMAL or EXECUTE)
chips/pn53x: add SAMConfiguration command wrapper (need to be improved)
chips/pn53x: remove almost all const arrays
chips/pn53x: use human readable defines for commands instead of hex values
chips/pn53x: in debug mode, the PN53x command is shown in human-readable string, awesome isn't it? ;-)
drivers: split transceive() into send() and receive() to be able to handle more cases (differed replies, abort commands, etc) later
drivers: use a const structure of functions instead of -dirty- callbacks array
drivers/pn532_uart: major improvement of UART handling
drivers/pn532_uart: check PN53x frames when received
buses/uart: receive() is now based on expected bytes instead of calculated timeouts..
buses/uart: use a smart way to determine available ports on POSIX systems (tested on Linux and FreeBSD)
This commit is contained in:
Romuald Conty 2011-03-02 15:00:44 +00:00
parent f1d909ae74
commit 5af845cdfc
20 changed files with 937 additions and 775 deletions

View file

@ -2,6 +2,8 @@
* Public platform independent Near Field Communication (NFC) library
*
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
* Copyright (C) 2010, Roel Verdult, Romuald Conty
* Copyright (C) 2011, Romuald Conty, Romain Tartière
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by the
@ -23,9 +25,29 @@
* @brief POSIX UART driver
*/
/* vim: set ts=2 sw=2 et: */
# include <sys/types.h>
# include <sys/select.h>
# include <sys/param.h>
# include <ctype.h>
# include <termios.h>
# include <stdio.h>
# include <dirent.h>
# include "nfc-internal.h"
# if defined(__APPLE__)
// FIXME: find UART connection string for PN53X device on Mac OS X when multiples devices are used
char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", NULL };
# elif defined (__FreeBSD__) || defined (__OpenBSD__)
char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL };
# elif defined (__linux__)
char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", NULL };
# else
# error "Can't determine serial string for your system"
# endif
typedef struct termios term_info;
typedef struct {
int fd; // Serial port file descriptor
@ -33,12 +55,6 @@ typedef struct {
term_info tiNew; // Terminal info during the transaction
} serial_port_unix;
// timeval struct that define timeout delay for serial port:
// first is constant and currently related to PN53x response delay
static const unsigned long int uiTimeoutStatic = 15000; // 15 ms to allow device to respond
// second is a per-byte timeout (sets when setting baudrate)
static unsigned long int uiTimeoutPerByte = 0;
// Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
# define CCLAIMED 0x80000000
@ -85,25 +101,10 @@ uart_open (const char *pcPortName)
return sp;
}
/**
* @note This define convert a Baud rate in a per-byte duration (in µs)
* Bauds are "symbols per second", so each symbol is bit here.
* We want to convert Bd to bytes/s in first time,
* 1 serial-transmitted byte is (in 8N1):
* - 1 start bit,
* - 8 data bits,
* - 1 stop bit.
*
* In 8N1 mode, byte-rate = baud-rate / 10
*/
#define UART_BAUDRATE_T0_BYTE_DURATION(X) ((1000000 * 10)/ X)
void
uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
{
// Set per-byte timeout
uiTimeoutPerByte = UART_BAUDRATE_T0_BYTE_DURATION(uiPortSpeed);
DBG ("Serial port speed requested to be set to %d bauds (%lu µs).", uiPortSpeed, uiTimeoutPerByte);
DBG ("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
const serial_port_unix *spu = (serial_port_unix *) sp;
// Portability note: on some systems, B9600 != 9600 so we have to do
@ -203,28 +204,26 @@ uart_close (const serial_port sp)
free (sp);
}
static const struct timeval tvTimeout = {
.tv_sec = 1,
.tv_usec = 0
};
/**
* @brief Receive data from UART and copy data to \a pbtRx
*
* @return 0 on success, otherwise driver error code
*/
int
uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
uart_receive (serial_port sp, byte_t * pbtRx, const size_t szRx)
{
int res;
int byteCount;
fd_set rfds;
int iExpectedByteCount = (int)*pszRx;
DBG ("iExpectedByteCount == %d", iExpectedByteCount);
struct timeval tvTimeout = {
.tv_sec = 0,
.tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * iExpectedByteCount),
};
struct timeval tv = tvTimeout;
// Reset the output count
*pszRx = 0;
int received_bytes_count = 0;
int available_bytes_count = 0;
const int expected_bytes_count = (int)szRx;
int res;
fd_set rfds;
do {
// Reset file descriptor
FD_ZERO (&rfds);
@ -238,35 +237,25 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
}
// Read time-out
if (res == 0) {
if (*pszRx == 0) {
// Error, we received no data
// DBG ("RX time-out (%lu µs), buffer empty.", tvTimeout.tv_usec);
return DETIMEOUT;
} else {
// We received some data, but nothing more is available
return 0;
}
DBG ("Timeout!");
return DETIMEOUT;
}
// Retrieve the count of the incoming bytes
res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &byteCount);
if (res < 0) {
res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &available_bytes_count);
if (res != 0) {
return DEIO;
}
// There is something available, read the data
res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRx), MIN(byteCount, iExpectedByteCount));
iExpectedByteCount -= MIN (byteCount, iExpectedByteCount);
// DBG ("expected bytes: %zu, received bytes: %d, available bytes: %d", szRx, received_bytes_count, available_bytes_count);
res = read (((serial_port_unix *) sp)->fd, pbtRx + received_bytes_count, MIN(available_bytes_count, (expected_bytes_count - received_bytes_count)));
// Stop if the OS has some troubles reading the data
if (res <= 0) {
return DEIO;
}
received_bytes_count += res;
*pszRx += res;
// Reload timeout with a low value to prevent from waiting too long on slow devices (16x is enought to took at least 1 byte)
tv.tv_usec = uiTimeoutPerByte * MIN( iExpectedByteCount, 16 );
// DBG("Timeout reloaded at: %d µs", tv.tv_usec);
} while (byteCount && (iExpectedByteCount > 0));
DBG ("byteCount == %d, iExpectedByteCount == %d", byteCount, iExpectedByteCount);
} while (expected_bytes_count > received_bytes_count);
PRINT_HEX ("RX", pbtRx, szRx);
return 0;
}
@ -278,13 +267,16 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
int
uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
{
PRINT_HEX ("TX", pbtTx, szTx);
#if 0
if ((int) szTx == write (((serial_port_unix *) sp)->fd, pbtTx, szTx))
return 0;
else
return DEIO;
#endif
int32_t res;
size_t szPos = 0;
fd_set rfds;
struct timeval tvTimeout = {
.tv_sec = 0,
.tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * szTx),
};
struct timeval tv = tvTimeout;
while (szPos < szTx) {
@ -312,10 +304,45 @@ uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
}
szPos += res;
// Reload timeout with a low value to prevent from waiting too long on slow devices (16x is enought to took at least 1 byte)
tv.tv_usec = uiTimeoutStatic + uiTimeoutPerByte * MIN( szTx - szPos, 16 );
}
return 0;
}
char **
uart_list_ports (void)
{
char **res = malloc (sizeof (char *));
size_t szRes = 1;
res[0] = NULL;
DIR *pdDir = opendir("/dev");
struct dirent *pdDirEnt;
while ((pdDirEnt = readdir(pdDir)) != NULL) {
if (!isdigit (pdDirEnt->d_name[strlen (pdDirEnt->d_name) - 1]))
continue;
char **p = serial_ports_device_radix;
while (*p) {
if (!strncmp(pdDirEnt->d_name, *p, strlen (*p))) {
char **res2 = realloc (res, (szRes+1) * sizeof (char *));
if (!res2)
goto oom;
res = res2;
if (!(res[szRes-1] = malloc (6 + strlen (pdDirEnt->d_name))))
goto oom;
sprintf (res[szRes-1], "/dev/%s", pdDirEnt->d_name);
szRes++;
res[szRes-1] = NULL;
}
p++;
}
}
oom:
closedir (pdDir);
return res;
}