summaryrefslogtreecommitdiffstats
path: root/Linux_x86
diff options
context:
space:
mode:
Diffstat (limited to 'Linux_x86')
-rw-r--r--Linux_x86/phDal4Nfc.c16
-rw-r--r--Linux_x86/phDal4Nfc_uart.c101
-rw-r--r--Linux_x86/phOsalNfc.c44
3 files changed, 146 insertions, 15 deletions
diff --git a/Linux_x86/phDal4Nfc.c b/Linux_x86/phDal4Nfc.c
index 9bedaf9..8b4f687 100644
--- a/Linux_x86/phDal4Nfc.c
+++ b/Linux_x86/phDal4Nfc.c
@@ -135,9 +135,9 @@ static void refresh_low_level_traces() {
return;
}
- property_get("debug.nfc.LOW_LEVEL_TRACES", value, "");
+ property_get("debug.nfc.LOW_LEVEL_TRACES", value, "0");
if (value[0]) {
- low_level_traces = atoi(value) ? 1 : 0;
+ low_level_traces = atoi(value);
return;
}
#endif
@@ -752,7 +752,8 @@ retry:
if (low_level_traces)
{
- phOsalNfc_PrintData("RECV", (uint16_t)gReadWriteContext.nNbOfBytesRead, gReadWriteContext.pReadBuffer);
+ phOsalNfc_PrintData("RECV", (uint16_t)gReadWriteContext.nNbOfBytesRead,
+ gReadWriteContext.pReadBuffer, low_level_traces);
}
DAL_DEBUG("RX Thread Read ok. nbToRead=%d\n", gReadWriteContext.nNbOfBytesToRead);
DAL_DEBUG("RX Thread NbReallyRead=%d\n", gReadWriteContext.nNbOfBytesRead);
@@ -882,7 +883,11 @@ void phDal4Nfc_DeferredCb (void *params)
DAL_PRINT(" Dal deferred read called \n");
TransactionInfo.buffer=gReadWriteContext.pReadBuffer;
TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesRead;
- TransactionInfo.status=NFCSTATUS_SUCCESS;
+ if (gReadWriteContext.nNbOfBytesRead == gReadWriteContext.nNbOfBytesToRead) {
+ TransactionInfo.status=NFCSTATUS_SUCCESS;
+ } else {
+ TransactionInfo.status=NFCSTATUS_READ_FAILED;
+ }
gReadWriteContext.nReadBusy = FALSE;
@@ -900,7 +905,8 @@ void phDal4Nfc_DeferredCb (void *params)
if(low_level_traces)
{
- phOsalNfc_PrintData("SEND", (uint16_t)gReadWriteContext.nNbOfBytesToWrite, gReadWriteContext.pWriteBuffer);
+ phOsalNfc_PrintData("SEND", (uint16_t)gReadWriteContext.nNbOfBytesToWrite,
+ gReadWriteContext.pWriteBuffer, low_level_traces);
}
/* DAL_DEBUG("dalMsg->transactInfo.length : %d\n", dalMsg->transactInfo.length); */
diff --git a/Linux_x86/phDal4Nfc_uart.c b/Linux_x86/phDal4Nfc_uart.c
index bb891e3..7ff9c4c 100644
--- a/Linux_x86/phDal4Nfc_uart.c
+++ b/Linux_x86/phDal4Nfc_uart.c
@@ -29,6 +29,7 @@
#define LOG_TAG "NFC_uart"
#include <cutils/log.h>
+#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
@@ -44,6 +45,7 @@
#include <phNfcStatus.h>
#if defined(ANDROID)
#include <string.h>
+#include <cutils/properties.h> // for property_get
#endif
typedef struct
@@ -164,6 +166,8 @@ NFCSTATUS phDal4Nfc_uart_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void *
DAL_ASSERT_STR(gComPortContext.nOpened==0, "Trying to open but already done!");
+ srand(time(NULL));
+
switch(pConfig->nLinkType)
{
case ENUM_DAL_LINK_TYPE_COM1:
@@ -260,6 +264,60 @@ NFCSTATUS phDal4Nfc_uart_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void *
return nfcret;
}
+/*
+ adb shell setprop debug.nfc.UART_ERROR_RATE X
+ will corrupt and drop bytes in uart_read(), to test the error handling
+ of DAL & LLC errors.
+ */
+int property_error_rate = 0;
+static void read_property() {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("debug.nfc.UART_ERROR_RATE", value, "0");
+ property_error_rate = atoi(value);
+}
+
+/* returns length of buffer after errors */
+static int apply_errors(uint8_t *buffer, int length) {
+ int i;
+ if (!property_error_rate) return length;
+
+ for (i = 0; i < length; i++) {
+ if (rand() % 1000 < property_error_rate) {
+ if (rand() % 2) {
+ // 50% chance of dropping byte
+ length--;
+ memcpy(&buffer[i], &buffer[i+1], length-i);
+ LOGW("dropped byte %d", i);
+ } else {
+ // 50% chance of corruption
+ buffer[i] = (uint8_t)rand();
+ LOGW("corrupted byte %d", i);
+ }
+ }
+ }
+ return length;
+}
+
+static struct timeval timeval_remaining(struct timespec timeout) {
+ struct timespec now;
+ struct timeval delta;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+
+ delta.tv_sec = timeout.tv_sec - now.tv_sec;
+ delta.tv_usec = (timeout.tv_nsec - now.tv_nsec) / (long)1000;
+
+ if (delta.tv_usec < 0) {
+ delta.tv_usec += 1000000;
+ delta.tv_sec--;
+ }
+ if (delta.tv_sec < 0) {
+ delta.tv_sec = 0;
+ delta.tv_usec = 0;
+ }
+ return delta;
+}
+
+static int libnfc_firmware_mode = 0;
/*-----------------------------------------------------------------------------
@@ -274,20 +332,41 @@ int phDal4Nfc_uart_read(uint8_t * pBuffer, int nNbBytesToRead)
int ret;
int numRead = 0;
struct timeval tv;
+ struct timeval *ptv;
+ struct timespec timeout;
fd_set rfds;
DAL_ASSERT_STR(gComPortContext.nOpened == 1, "read called but not opened!");
DAL_DEBUG("_uart_read() called to read %d bytes", nNbBytesToRead);
- // Read with 2 second timeout, so that the read thread can be aborted
- // when the pn544 does not respond and we need to switch to FW download
- // mode. This should be done via a control socket instead.
+ read_property();
+
+ // Read timeout:
+ // FW mode: no timeout
+ // 1 byte read: steady-state LLC length read, allowed to block forever
+ // >1 byte read: LLC payload, 100ms timeout (before pn544 re-transmit)
+ if (nNbBytesToRead > 1 && !libnfc_firmware_mode) {
+ clock_gettime(CLOCK_MONOTONIC, &timeout);
+ timeout.tv_nsec += 100000000;
+ if (timeout.tv_nsec > 1000000000) {
+ timeout.tv_sec++;
+ timeout.tv_nsec -= 1000000000;
+ }
+ ptv = &tv;
+ } else {
+ ptv = NULL;
+ }
+
while (numRead < nNbBytesToRead) {
FD_ZERO(&rfds);
FD_SET(gComPortContext.nHandle, &rfds);
- tv.tv_sec = 2;
- tv.tv_usec = 0;
- ret = select(gComPortContext.nHandle + 1, &rfds, NULL, NULL, NULL);
+
+ if (ptv) {
+ tv = timeval_remaining(timeout);
+ ptv = &tv;
+ }
+
+ ret = select(gComPortContext.nHandle + 1, &rfds, NULL, NULL, ptv);
if (ret < 0) {
DAL_DEBUG("select() errno=%d", errno);
if (errno == EINTR || errno == EAGAIN) {
@@ -295,11 +374,13 @@ int phDal4Nfc_uart_read(uint8_t * pBuffer, int nNbBytesToRead)
}
return -1;
} else if (ret == 0) {
- DAL_PRINT("timeout!");
+ LOGW("timeout!");
break; // return partial response
}
ret = read(gComPortContext.nHandle, pBuffer + numRead, nNbBytesToRead - numRead);
if (ret > 0) {
+ ret = apply_errors(pBuffer + numRead, ret);
+
DAL_DEBUG("read %d bytes", ret);
numRead += ret;
} else if (ret == 0) {
@@ -313,6 +394,7 @@ int phDal4Nfc_uart_read(uint8_t * pBuffer, int nNbBytesToRead)
return -1;
}
}
+
return numRead;
}
@@ -388,6 +470,11 @@ int phDal4Nfc_uart_reset(long level)
goto out;
}
ret = NFCSTATUS_SUCCESS;
+ if (level == 2) {
+ libnfc_firmware_mode = 1;
+ } else {
+ libnfc_firmware_mode = 0;
+ }
out:
if (fd >= 0) {
diff --git a/Linux_x86/phOsalNfc.c b/Linux_x86/phOsalNfc.c
index 0544309..cbca1ac 100644
--- a/Linux_x86/phOsalNfc.c
+++ b/Linux_x86/phOsalNfc.c
@@ -158,10 +158,11 @@ void phOsalNfc_RaiseException(phOsalNfc_ExceptionType_t eExceptionType, uint16_t
* \param[in] pBuffer pointer to data bytes to be displayed.
*
*/
-void phOsalNfc_PrintData(const char *pString, uint32_t length, uint8_t *pBuffer)
+void phOsalNfc_PrintData(const char *pString, uint32_t length, uint8_t *pBuffer,
+ int verbosity)
{
char print_buffer[length * 3 + 1];
- int i;
+ unsigned int i;
if (pString == NULL) {
pString = "";
@@ -170,5 +171,42 @@ void phOsalNfc_PrintData(const char *pString, uint32_t length, uint8_t *pBuffer)
for (i = 0; i < length; i++) {
snprintf(&print_buffer[i*3], 4, " %02X", pBuffer[i]);
}
- LOGD("> %s:%s", pString, print_buffer);
+
+ char llc[40] = "";
+
+ if (verbosity >= 2) {
+ uint8_t llc_header = 0;
+ if (!strcmp(pString, "SEND") && length >= 2) {
+ llc_header = pBuffer[1];
+ } else if (!strcmp(pString, "RECV") && length >= 2) {
+ llc_header = pBuffer[0];
+ }
+
+ if ((llc_header & 0xC0) == 0x80) {
+ // I
+ uint8_t ns = (llc_header & 0x38) >> 3;
+ uint8_t nr = llc_header & 0x07;
+ snprintf(&llc[0], sizeof(llc), "I %d (%d)", ns, nr);
+ } else if ((llc_header & 0xE0) == 0xC0) {
+ // S
+ uint8_t t = (llc_header & 0x18) >> 3;
+ uint8_t nr = llc_header & 0x07;
+ char *type;
+ switch (t) {
+ case 0x00: type = "RR "; break;
+ case 0x01: type = "REJ"; break;
+ case 0x02: type = "RNR"; break;
+ case 0x03: type = "SREJ"; break;
+ default: type = "???"; break;
+ }
+ snprintf(&llc[0], sizeof(llc), "S %s (%d)", type, nr);
+ } else if ((llc_header & 0xE0) == 0xE0) {
+ // U
+ snprintf(&llc[0], sizeof(llc), "U");
+ } else if (length > 1) {
+ snprintf(&llc[0], sizeof(llc), "???");
+ }
+ }
+
+ LOGD("> %s:%s\t%s", pString, print_buffer, llc);
}