Attempt fix some UART timeouts, should also allow lower devices to be detected.

This commit is contained in:
Romuald Conty 2010-12-30 10:01:06 +00:00
parent ba37313cb8
commit 53c8917353

View file

@ -32,11 +32,11 @@ typedef struct {
term_info tiNew; // Terminal info during the transaction term_info tiNew; // Terminal info during the transaction
} serial_port_unix; } serial_port_unix;
// timeval struct that define timeout delay for serial port // timeval struct that define timeout delay for serial port:
static struct timeval default_timeout = { // first is constant and currently related to PN53x response delay
.tv_sec = 0, // 0 second static const unsigned long int uiTimeoutStatic = 15000; // 15 ms to allow device to respond
.tv_usec = 60000 // 60 ms // 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 // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
# define CCLAIMED 0x80000000 # define CCLAIMED 0x80000000
@ -84,15 +84,25 @@ uart_open (const char *pcPortName)
return sp; return sp;
} }
// TODO Remove PN53x related timeout /**
#define UART_TIMEOUT(X) ((X * 7) + 15000) // where X is 1-byte duration (µs): X * 6+1 bytes (PN53x's ACK + 1 other chance) + 15 ms (PN532 Tmax to reply ACK) * @note This define convert a Baud rate in a per-byte duration (in µs)
// UART_SPEED_T0_TIME(X) convert baud rate to interval between 2 bytes (in us) * Bauds are "symbols per second", so each symbol is bit here.
#define UART_SPEED_T0_TIME(X) ((1000000 * 9)/ X) // 8,n,1 => 9 bits => data rate ~= bauds/9 (bytes/s); ex: 8N1@9600 ~= 1066 bytes/s * 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 void
uart_set_speed (serial_port sp, const uint32_t uiPortSpeed) uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
{ {
long int iTimeout = UART_TIMEOUT(UART_SPEED_T0_TIME(uiPortSpeed)); // Set per-byte timeout
DBG ("Serial port speed requested to be set to %d bauds (%ld µs).", uiPortSpeed, iTimeout); uiTimeoutPerByte = UART_BAUDRATE_T0_BYTE_DURATION(uiPortSpeed);
DBG ("Serial port speed requested to be set to %d bauds (%lu µs).", uiPortSpeed, uiTimeoutPerByte);
const serial_port_unix *spu = (serial_port_unix *) sp; const serial_port_unix *spu = (serial_port_unix *) sp;
// Portability note: on some systems, B9600 != 9600 so we have to do // Portability note: on some systems, B9600 != 9600 so we have to do
@ -133,8 +143,6 @@ uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
uiPortSpeed); uiPortSpeed);
return; return;
}; };
// Set default timeout
default_timeout.tv_usec = iTimeout;
// Set port speed (Input and Output) // Set port speed (Input and Output)
cfsetispeed ((struct termios *) &(spu->tiNew), stPortSpeed); cfsetispeed ((struct termios *) &(spu->tiNew), stPortSpeed);
@ -205,16 +213,21 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
int res; int res;
int byteCount; int byteCount;
fd_set rfds; fd_set rfds;
struct timeval tv;
int iExpectedByteCount = (int)*pszRx;
struct timeval tvTimeout = {
.tv_sec = 0,
.tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * iExpectedByteCount),
};
struct timeval tv = tvTimeout;
// Reset the output count // Reset the output count
*pszRx = 0; *pszRx = 0;
do { do {
DBG( "Expecting %d bytes (in %lu µs)", iExpectedByteCount, tv.tv_usec );
// Reset file descriptor // Reset file descriptor
FD_ZERO (&rfds); FD_ZERO (&rfds);
FD_SET (((serial_port_unix *) sp)->fd, &rfds); FD_SET (((serial_port_unix *) sp)->fd, &rfds);
tv = default_timeout;
res = select (((serial_port_unix *) sp)->fd + 1, &rfds, NULL, NULL, &tv); res = select (((serial_port_unix *) sp)->fd + 1, &rfds, NULL, NULL, &tv);
// Read error // Read error
@ -226,7 +239,7 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
if (res == 0) { if (res == 0) {
if (*pszRx == 0) { if (*pszRx == 0) {
// Error, we received no data // Error, we received no data
DBG ("RX time-out (%ld µs), buffer empty.", default_timeout.tv_usec); DBG ("RX time-out (%lu µs), buffer empty.", tvTimeout.tv_usec);
return DETIMEOUT; return DETIMEOUT;
} else { } else {
// We received some data, but nothing more is available // We received some data, but nothing more is available
@ -240,6 +253,7 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
} }
// There is something available, read the data // There is something available, read the data
res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRx), byteCount); res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRx), byteCount);
iExpectedByteCount -= byteCount;
// Stop if the OS has some troubles reading the data // Stop if the OS has some troubles reading the data
if (res <= 0) { if (res <= 0) {
@ -247,8 +261,9 @@ uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
} }
*pszRx += res; *pszRx += res;
DBG( "Remaining %d bytes (%lu µs remains in tv)", iExpectedByteCount, tv.tv_usec );
} while (byteCount); tv.tv_usec = uiTimeoutPerByte * (iExpectedByteCount>16?16:iExpectedByteCount) ;
} while (byteCount && (iExpectedByteCount > 0));
return 0; return 0;
} }
@ -265,12 +280,13 @@ uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
size_t szPos = 0; size_t szPos = 0;
fd_set rfds; fd_set rfds;
struct timeval tv; struct timeval tv;
const struct timeval tvDefault = { .tv_sec = 0, .tv_usec = 20000 };
while (szPos < szTx) { while (szPos < szTx) {
// Reset file descriptor // Reset file descriptor
FD_ZERO (&rfds); FD_ZERO (&rfds);
FD_SET (((serial_port_unix *) sp)->fd, &rfds); FD_SET (((serial_port_unix *) sp)->fd, &rfds);
tv = default_timeout; tv = tvDefault;
res = select (((serial_port_unix *) sp)->fd + 1, NULL, &rfds, NULL, &tv); res = select (((serial_port_unix *) sp)->fd + 1, NULL, &rfds, NULL, &tv);
// Write error // Write error