Fix pn532_uart driver.

This commit is contained in:
Romuald Conty 2010-08-19 09:01:39 +00:00
parent eb90b92c12
commit edba53c5da
4 changed files with 61 additions and 51 deletions

View file

@ -107,11 +107,10 @@ serial_port uart_open(const char* pcPortName)
return sp; return sp;
} }
void uart_set_speed(nfc_device_t* pnd, const uint32_t uiPortSpeed) void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
{ {
serial_port sp = (serial_port)pnd->nds;
DBG("Serial port speed requested to be set to %d bauds.", uiPortSpeed); DBG("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
// Set port speed (Input and Output) 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
// uint32_t <=> speed_t associations by hand. // uint32_t <=> speed_t associations by hand.
@ -142,18 +141,18 @@ void uart_set_speed(nfc_device_t* pnd, const uint32_t uiPortSpeed)
default: default:
ERR("Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).", uiPortSpeed); ERR("Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).", uiPortSpeed);
}; };
const serial_port_unix* spu = (serial_port_unix*)sp;
cfsetispeed((struct termios*)&spu->tiNew, stPortSpeed); // Set port speed (Input and Output)
cfsetospeed((struct termios*)&spu->tiNew, stPortSpeed); cfsetispeed((struct termios*)&(spu->tiNew), stPortSpeed);
if( tcsetattr(spu->fd, TCSADRAIN, &spu->tiNew) == -1) cfsetospeed((struct termios*)&(spu->tiNew), stPortSpeed);
if( tcsetattr(spu->fd, TCSADRAIN, &(spu->tiNew)) == -1)
{ {
ERR("%s", "Unable to apply new speed settings."); ERR("%s", "Unable to apply new speed settings.");
} }
} }
uint32_t uart_get_speed(const nfc_device_t* pnd) uint32_t uart_get_speed(serial_port sp)
{ {
serial_port sp = (serial_port)pnd->nds;
uint32_t uiPortSpeed = 0; uint32_t uiPortSpeed = 0;
const serial_port_unix* spu = (serial_port_unix*)sp; const serial_port_unix* spu = (serial_port_unix*)sp;
switch (cfgetispeed(&spu->tiNew)) switch (cfgetispeed(&spu->tiNew))
@ -194,13 +193,18 @@ void uart_close(const serial_port sp)
free(sp); free(sp);
} }
bool uart_receive(nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxLen) /**
* @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* pszRxLen)
{ {
int res; int res;
int byteCount; int byteCount;
fd_set rfds; fd_set rfds;
struct timeval tv; struct timeval tv;
serial_port sp = (serial_port)pnd->nds;
// Reset the output count // Reset the output count
*pszRxLen = 0; *pszRxLen = 0;
@ -215,8 +219,7 @@ bool uart_receive(nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxLen)
// Read error // Read error
if (res < 0) { if (res < 0) {
DBG("%s", "RX error."); DBG("%s", "RX error.");
pnd->iLastError = DEIO; return DEIO;
return false;
} }
// Read time-out // Read time-out
@ -224,19 +227,17 @@ bool uart_receive(nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxLen)
if (*pszRxLen == 0) { if (*pszRxLen == 0) {
// Error, we received no data // Error, we received no data
DBG("%s", "RX time-out, buffer empty."); DBG("%s", "RX time-out, buffer empty.");
pnd->iLastError = DETIMEOUT; return DETIMEOUT;
return false;
} else { } else {
// We received some data, but nothing more is available // We received some data, but nothing more is available
return true; return 0;
} }
} }
// Retrieve the count of the incoming bytes // Retrieve the count of the incoming bytes
res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount); res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
if (res < 0) { if (res < 0) {
pnd->iLastError = DEIO; return DEIO;
return false;
} }
// There is something available, read the data // There is something available, read the data
@ -244,24 +245,28 @@ bool uart_receive(nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxLen)
// 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) {
pnd->iLastError = DEIO; return DEIO;
return false;
} }
*pszRxLen += res; *pszRxLen += res;
} while (byteCount); } while (byteCount);
return true; return 0;
} }
bool uart_send(nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen) /**
* @brief Send \a pbtTx content to UART
*
* @return 0 on success, otherwise a driver error is returned
*/
int
uart_send(serial_port sp, const byte_t* pbtTx, const size_t szTxLen)
{ {
int32_t res; int32_t res;
size_t szPos = 0; size_t szPos = 0;
fd_set rfds; fd_set rfds;
struct timeval tv; struct timeval tv;
serial_port sp = (serial_port)pnd->nds;
while (szPos < szTxLen) while (szPos < szTxLen)
{ {
@ -274,15 +279,13 @@ bool uart_send(nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen)
// Write error // Write error
if (res < 0) { if (res < 0) {
DBG("%s", "TX error."); DBG("%s", "TX error.");
pnd->iLastError = DEIO; return DEIO;
return false;
} }
// Write time-out // Write time-out
if (res == 0) { if (res == 0) {
DBG("%s", "TX time-out."); DBG("%s", "TX time-out.");
pnd->iLastError = DETIMEOUT; return DETIMEOUT;
return false;
} }
// Send away the bytes // Send away the bytes
@ -290,13 +293,12 @@ bool uart_send(nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen)
// Stop if the OS has some troubles sending the data // Stop if the OS has some troubles sending the data
if (res <= 0) { if (res <= 0) {
pnd->iLastError = DEIO; return DEIO;
return false;
} }
szPos += res; szPos += res;
} }
return true; return 0;
} }
#else #else

View file

@ -81,12 +81,11 @@ typedef void* serial_port;
serial_port uart_open(const char* pcPortName); serial_port uart_open(const char* pcPortName);
void uart_close(const serial_port sp); void uart_close(const serial_port sp);
void uart_set_speed(nfc_device_t* pnd, const uint32_t uiPortSpeed); void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed);
uint32_t uart_get_speed(const nfc_device_t* pnd); uint32_t uart_get_speed(const serial_port sp);
bool uart_receive(nfc_device_t* pnd, byte_t* pbtRx, size_t* pszRxLen); int uart_receive(serial_port sp, byte_t* pbtRx, size_t* pszRxLen);
bool uart_send(nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen); int uart_send(serial_port sp, const byte_t* pbtTx, const size_t szTxLen);
#endif // __NFC_BUS_UART_H__ #endif // __NFC_BUS_UART_H__

View file

@ -69,9 +69,10 @@ 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_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_nack_frame[] = { 0x00,0x00,0xff,0xff,0x00,0x00 };
// XXX: Is this function correctly named ?
bool pn53x_transceive_callback(nfc_device_t* pnd, const byte_t *pbtRxFrame, const size_t szRxFrameLen) bool pn53x_transceive_callback(nfc_device_t* pnd, const byte_t *pbtRxFrame, const size_t szRxFrameLen)
{ {
if (szRxFrameLen == sizeof (pn53x_ack_frame)) { if (szRxFrameLen >= sizeof (pn53x_ack_frame)) {
if (0 == memcmp (pbtRxFrame, pn53x_ack_frame, sizeof (pn53x_ack_frame))) { if (0 == memcmp (pbtRxFrame, pn53x_ack_frame, sizeof (pn53x_ack_frame))) {
DBG("%s", "PN53x ACKed"); DBG("%s", "PN53x ACKed");
return true; return true;

View file

@ -100,7 +100,7 @@ pn532_uart_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_
// PN532 could be powered down, we need to wake it up before line testing. // PN532 could be powered down, we need to wake it up before line testing.
pn532_uart_wakeup((nfc_device_spec_t)sp); pn532_uart_wakeup((nfc_device_spec_t)sp);
// Check communication using "Diagnose" command, with "Comunication test" (0x00) // Check communication using "Diagnose" command, with "Comunication test" (0x00)
if(!pn532_uart_check_communication((nfc_device_spec_t)sp), &bComOk) if(!pn532_uart_check_communication((nfc_device_spec_t)sp, &bComOk))
return false; return false;
if (!bComOk) if (!bComOk)
continue; continue;
@ -200,16 +200,19 @@ bool pn532_uart_transceive(nfc_device_t* pnd, const byte_t* pbtTx, const size_t
#ifdef DEBUG #ifdef DEBUG
PRINT_HEX("TX", abtTxBuf,szTxLen+7); PRINT_HEX("TX", abtTxBuf,szTxLen+7);
#endif #endif
if (!uart_send((serial_port)pnd->nds,abtTxBuf,szTxLen+7)) { int res;
res = uart_send((serial_port)pnd->nds,abtTxBuf,szTxLen+7);
if(res != 0) {
ERR("%s", "Unable to transmit data. (TX)"); ERR("%s", "Unable to transmit data. (TX)");
pnd->iLastError = DEIO; pnd->iLastError = res;
return false; return false;
} }
szRxBufLen = 6; szRxBufLen = 6;
if (!uart_receive((serial_port)pnd->nds,abtRxBuf,&szRxBufLen)) { res = uart_receive((serial_port)pnd->nds,abtRxBuf,&szRxBufLen);
if (res != 0) {
ERR("%s", "Unable to receive data. (RX)"); ERR("%s", "Unable to receive data. (RX)");
pnd->iLastError = DEIO; pnd->iLastError = res;
return false; return false;
} }
@ -217,18 +220,22 @@ bool pn532_uart_transceive(nfc_device_t* pnd, const byte_t* pbtTx, const size_t
PRINT_HEX("RX", abtRxBuf,szRxBufLen); PRINT_HEX("RX", abtRxBuf,szRxBufLen);
#endif #endif
// WARN: UART is a per byte reception, so you usually receive ACK and next frame the same time
if (!pn53x_transceive_callback(pnd, abtRxBuf, szRxBufLen)) if (!pn53x_transceive_callback(pnd, abtRxBuf, szRxBufLen))
return false; return false;
szRxBufLen -= sizeof(ack_frame);
memmove(abtRxBuf, abtRxBuf+sizeof(ack_frame), szRxBufLen);
szRxBufLen = BUFFER_LENGTH; if (szRxBufLen == 0) {
szRxBufLen = BUFFER_LENGTH;
while (!uart_receive((serial_port)pnd->nds,abtRxBuf,&szRxBufLen)) { do {
delay_ms(10); delay_ms(10);
} res = uart_receive((serial_port)pnd->nds,abtRxBuf,&szRxBufLen);
} while (res != 0 );
#ifdef DEBUG #ifdef DEBUG
PRINT_HEX("RX", abtRxBuf,szRxBufLen); PRINT_HEX("RX", abtRxBuf,szRxBufLen);
#endif #endif
}
// When the answer should be ignored, just return a successful result // When the answer should be ignored, just return a successful result
if(pbtRx == NULL || pszRxLen == NULL) return true; if(pbtRx == NULL || pszRxLen == NULL) return true;
@ -242,9 +249,10 @@ bool pn532_uart_transceive(nfc_device_t* pnd, const byte_t* pbtTx, const size_t
#ifdef DEBUG #ifdef DEBUG
PRINT_HEX("TX", ack_frame,6); PRINT_HEX("TX", ack_frame,6);
#endif #endif
if (!uart_send((serial_port)pnd->nds,ack_frame,6)) { res = uart_send((serial_port)pnd->nds,ack_frame,6);
if (res != 0) {
ERR("%s", "Unable to transmit data. (TX)"); ERR("%s", "Unable to transmit data. (TX)");
pnd->iLastError = DEIO; pnd->iLastError = res;
return false; return false;
} }
@ -268,7 +276,7 @@ pn532_uart_wakeup(const nfc_device_spec_t nds)
PRINT_HEX("TX", pncmd_pn532c106_wakeup_preamble,sizeof(pncmd_pn532c106_wakeup_preamble)); PRINT_HEX("TX", pncmd_pn532c106_wakeup_preamble,sizeof(pncmd_pn532c106_wakeup_preamble));
#endif #endif
uart_send((serial_port)nds, pncmd_pn532c106_wakeup_preamble, sizeof(pncmd_pn532c106_wakeup_preamble)); uart_send((serial_port)nds, pncmd_pn532c106_wakeup_preamble, sizeof(pncmd_pn532c106_wakeup_preamble));
if(uart_receive((serial_port)nds,abtRx,&szRxLen)) { if(0 == uart_receive((serial_port)nds,abtRx,&szRxLen)) {
#ifdef DEBUG #ifdef DEBUG
PRINT_HEX("RX", abtRx,szRxLen); PRINT_HEX("RX", abtRx,szRxLen);
#endif #endif
@ -290,10 +298,10 @@ pn532_uart_check_communication(const nfc_device_spec_t nds, bool* success)
#ifdef DEBUG #ifdef DEBUG
PRINT_HEX("TX", pncmd_communication_test,sizeof(pncmd_communication_test)); PRINT_HEX("TX", pncmd_communication_test,sizeof(pncmd_communication_test));
#endif #endif
if (!uart_send((serial_port)nds, pncmd_communication_test, sizeof(pncmd_communication_test))) if (0 != uart_send((serial_port)nds, pncmd_communication_test, sizeof(pncmd_communication_test)))
return false; return false;
if(!uart_receive((serial_port)nds,abtRx,&szRxLen)) { if (0 != uart_receive((serial_port)nds,abtRx,&szRxLen)) {
return false; return false;
} }
#ifdef DEBUG #ifdef DEBUG