From 20b3fddc89e29afd4d0517a4876feb851ec5ec3f Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sat, 16 Jan 2021 11:43:58 -0800 Subject: [PATCH 1/9] Add note on getting macOS working via PN532 UART --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a9bb447..51b82724 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,13 @@ them in a modprobe conf file. This file is provided within libnfc archive: sudo cp contrib/linux/blacklist-libnfc.conf /etc/modprobe.d/blacklist-libnfc.conf +PN532 UART on macOS: +-------------------- + +- Receiving error: "Unable to set serial port speed to 115200 baud. Speed value must be one of those defined in termios(3)." + - The PN532 High Speed UART (HSU) requires a baud rate of 115200, however macOS may use the incorrect `termios.h` (valid path: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/termios.h) preventing the detection of the `B115200` definition producing the error above. + - Solution: Either add `-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/termios.h` as an include path before the rest of your includes or manually add `#define B115200 115200`. + FEITIAN bR500 and R502: ----------------------- @@ -214,7 +221,7 @@ Readers known to work: These readers are support by CCID since v1.4.25, make sure your CCID driver version higher or equal to 1.4.25. -On MacOS, you can check your CCID version with the following command, and if required, you can install latest CCID driver from [https://github.com/martinpaljak/osx-ccid-installer/releases](https://github.com/martinpaljak/osx-ccid-installer/releases) +On macOS, you can check your CCID version with the following command, and if required, you can install latest CCID driver from [https://github.com/martinpaljak/osx-ccid-installer/releases](https://github.com/martinpaljak/osx-ccid-installer/releases) ``` grep -A 1 CFBundleShortVersionString /usr/local/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist From 9f3c859c3bfe00923b1f139e9673facf3f60bf39 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sat, 16 Jan 2021 11:50:41 -0800 Subject: [PATCH 2/9] Fix PN532 UART support (8 data bits per HSU TX) --- libnfc/buses/uart.c | 16 ++++++++++++++++ libnfc/drivers/pn532_uart.c | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index ffe64aa5..8008037c 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -367,6 +367,22 @@ uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, i return NFC_SUCCESS; } +/** + * @brief Send \a pbtTx content to UART one byte at a time + * + * @return 0 on success, otherwise a driver error is returned + */ +int +uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) +{ + (void) timeout; + int error = 0; + for (int i = 0; i < szTx; i++) + error |= uart_send(sp, pbtTx+i, 1, timeout); + + return error ? NFC_EIO : NFC_SUCCESS; +} + /** * @brief Send \a pbtTx content to UART * diff --git a/libnfc/drivers/pn532_uart.c b/libnfc/drivers/pn532_uart.c index d82051d7..dae0242c 100644 --- a/libnfc/drivers/pn532_uart.c +++ b/libnfc/drivers/pn532_uart.c @@ -304,7 +304,7 @@ pn532_uart_wakeup(nfc_device *pnd) { /* High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for PN532 being wakeup. */ const uint8_t pn532_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - int res = uart_send(DRIVER_DATA(pnd)->port, pn532_wakeup_preamble, sizeof(pn532_wakeup_preamble), 0); + int res = uart_send_single(DRIVER_DATA(pnd)->port, pn532_wakeup_preamble, sizeof(pn532_wakeup_preamble), 0); CHIP_DATA(pnd)->power_mode = NORMAL; // PN532 should now be awake return res; } @@ -348,7 +348,7 @@ pn532_uart_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, in return pnd->last_error; } - res = uart_send(DRIVER_DATA(pnd)->port, abtFrame, szFrame, timeout); + res = uart_send_single(DRIVER_DATA(pnd)->port, abtFrame, szFrame, timeout); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); pnd->last_error = res; @@ -507,7 +507,7 @@ pn532_uart_ack(nfc_device *pnd) return res; } } - return (uart_send(DRIVER_DATA(pnd)->port, pn53x_ack_frame, sizeof(pn53x_ack_frame), 0)); + return (uart_send_single(DRIVER_DATA(pnd)->port, pn53x_ack_frame, sizeof(pn53x_ack_frame), 0)); } static int From 8c1bf6f56fa304ef4e2dfe6da87b4c57fb5875d5 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sat, 16 Jan 2021 11:59:46 -0800 Subject: [PATCH 3/9] Complete macOS + PN532 UART support --- README.md | 7 ------- libnfc/buses/i2c.c | 4 ++++ libnfc/buses/spi.c | 4 ++++ libnfc/buses/uart.c | 17 +++++++++++++++++ 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 51b82724..ec7d62f9 100644 --- a/README.md +++ b/README.md @@ -201,13 +201,6 @@ them in a modprobe conf file. This file is provided within libnfc archive: sudo cp contrib/linux/blacklist-libnfc.conf /etc/modprobe.d/blacklist-libnfc.conf -PN532 UART on macOS: --------------------- - -- Receiving error: "Unable to set serial port speed to 115200 baud. Speed value must be one of those defined in termios(3)." - - The PN532 High Speed UART (HSU) requires a baud rate of 115200, however macOS may use the incorrect `termios.h` (valid path: /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/termios.h) preventing the detection of the `B115200` definition producing the error above. - - Solution: Either add `-I/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/sys/termios.h` as an include path before the rest of your includes or manually add `#define B115200 115200`. - FEITIAN bR500 and R502: ----------------------- diff --git a/libnfc/buses/i2c.c b/libnfc/buses/i2c.c index dc1ad1f0..52180e64 100644 --- a/libnfc/buses/i2c.c +++ b/libnfc/buses/i2c.c @@ -47,7 +47,11 @@ #include #include #include +#ifdef __APPLE__ +#include +#else #include +#endif #include #include #include diff --git a/libnfc/buses/spi.c b/libnfc/buses/spi.c index 0e68f9b4..774d17d3 100644 --- a/libnfc/buses/spi.c +++ b/libnfc/buses/spi.c @@ -49,7 +49,11 @@ #include #include #include +#ifdef __APPLE__ +#include +#else #include +#endif #include #include diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index 8008037c..0cff3f20 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -47,7 +47,11 @@ #include #include #include +#ifdef __APPLE__ +#include +#else #include +#endif #include #include @@ -95,6 +99,19 @@ const char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", "ttyACM", "ttyAMA" // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct # define CCLAIMED 0x80000000 +// If macOS and still haven't detected required baud rates, set them as we do have support for some +#ifdef __APPLE__ +#ifndef B57600 +#define B57600 57600 +#endif +#ifndef B115200 +#define B115200 115200 +#endif +#ifndef B230400 +#define B230400 230400 +#endif +#endif + struct serial_port_unix { int fd; // Serial port file descriptor struct termios termios_backup; // Terminal info before using the port From 62216df450ab8fd0d2e23d3020a694fa1e4f0566 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sat, 16 Jan 2021 12:07:52 -0800 Subject: [PATCH 4/9] Improve reliability of PN532 HSU --- libnfc/buses/uart.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index 0cff3f20..62f0f012 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -395,7 +395,11 @@ uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int ti (void) timeout; int error = 0; for (int i = 0; i < szTx; i++) + { error |= uart_send(sp, pbtTx+i, 1, timeout); + usleep(9); + } + return error ? NFC_EIO : NFC_SUCCESS; } From f1b6ee4c0627b72c003424781357d1f6730d43b9 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sat, 16 Jan 2021 16:20:34 -0800 Subject: [PATCH 5/9] Add header declaration --- libnfc/buses/uart.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libnfc/buses/uart.h b/libnfc/buses/uart.h index 39d8d2f0..485ccf31 100644 --- a/libnfc/buses/uart.h +++ b/libnfc/buses/uart.h @@ -58,6 +58,7 @@ uint32_t uart_get_speed(const serial_port sp); int uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, int timeout); int uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout); +int uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout); char **uart_list_ports(void); From 27836d78106d56fed04c89b1e7d63a65224d8ef2 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 17 Jan 2021 11:02:12 -0800 Subject: [PATCH 6/9] Add Windows support for single byte UART TX --- contrib/win32/libnfc/buses/uart.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/contrib/win32/libnfc/buses/uart.c b/contrib/win32/libnfc/buses/uart.c index ba7ddfe8..6a5ff1f9 100644 --- a/contrib/win32/libnfc/buses/uart.c +++ b/contrib/win32/libnfc/buses/uart.c @@ -240,6 +240,26 @@ uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) return 0; } +/** + * @brief Send \a pbtTx content to UART one byte at a time + * + * @return 0 on success, otherwise a driver error is returned + */ +int +uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) +{ + (void) timeout; + int error = 0; + for (int i = 0; i < szTx; i++) + { + error |= uart_send(sp, pbtTx+i, 1, timeout); + usleep(9); // ceil(1_000_000us / 115200baud) + } + + return error ? NFC_EIO : 0; +} + + BOOL is_port_available(int nPort) { TCHAR szPort[15]; From c8cf4b924eb017866fcb4373b3b345611216a076 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Sun, 17 Jan 2021 12:31:39 -0800 Subject: [PATCH 7/9] Fix UART sleep on windows --- contrib/win32/libnfc/buses/uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/win32/libnfc/buses/uart.c b/contrib/win32/libnfc/buses/uart.c index 6a5ff1f9..2a68be04 100644 --- a/contrib/win32/libnfc/buses/uart.c +++ b/contrib/win32/libnfc/buses/uart.c @@ -253,7 +253,7 @@ uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int ti for (int i = 0; i < szTx; i++) { error |= uart_send(sp, pbtTx+i, 1, timeout); - usleep(9); // ceil(1_000_000us / 115200baud) + delay_ms(1); // ceil(1_000_000us / 115200baud) = 9us but no usleep on windows } return error ? NFC_EIO : 0; From 4c50adc0eb6c5da486799a5ee972974c21b35403 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Mon, 18 Jan 2021 11:41:48 -0800 Subject: [PATCH 8/9] Error out on uart_send_single if any byte fails tx --- contrib/win32/libnfc/buses/uart.c | 14 +++++++---- libnfc/buses/uart.c | 40 +++++++++++++++++-------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/contrib/win32/libnfc/buses/uart.c b/contrib/win32/libnfc/buses/uart.c index 2a68be04..f0bbe784 100644 --- a/contrib/win32/libnfc/buses/uart.c +++ b/contrib/win32/libnfc/buses/uart.c @@ -237,7 +237,7 @@ uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) } if (!dwTxLen) return NFC_EIO; - return 0; + return NFC_SUCCESS; } /** @@ -249,17 +249,21 @@ int uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) { (void) timeout; - int error = 0; + int ret; for (int i = 0; i < szTx; i++) { - error |= uart_send(sp, pbtTx+i, 1, timeout); + ret = uart_send(sp, pbtTx+i, 1, timeout); + + // if we didn't transmit byte, bail out + if (ret != NFC_SUCCESS) + return ret; + delay_ms(1); // ceil(1_000_000us / 115200baud) = 9us but no usleep on windows } - return error ? NFC_EIO : 0; + return NFC_SUCCESS; } - BOOL is_port_available(int nPort) { TCHAR szPort[15]; diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index 62f0f012..e4d34c0b 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -385,39 +385,43 @@ uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, i } /** - * @brief Send \a pbtTx content to UART one byte at a time + * @brief Send \a pbtTx content to UART * * @return 0 on success, otherwise a driver error is returned */ int -uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) +uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) { (void) timeout; - int error = 0; - for (int i = 0; i < szTx; i++) - { - error |= uart_send(sp, pbtTx+i, 1, timeout); - usleep(9); - } - - - return error ? NFC_EIO : NFC_SUCCESS; + LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx); + if ((int) szTx == write(UART_DATA(sp)->fd, pbtTx, szTx)) + return NFC_SUCCESS; + else + return NFC_EIO; } /** - * @brief Send \a pbtTx content to UART + * @brief Send \a pbtTx content to UART one byte at a time * * @return 0 on success, otherwise a driver error is returned */ int -uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) +uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) { (void) timeout; - LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx); - if ((int) szTx == write(UART_DATA(sp)->fd, pbtTx, szTx)) - return NFC_SUCCESS; - else - return NFC_EIO; + int ret; + for (int i = 0; i < szTx; i++) + { + ret = uart_send(sp, pbtTx+i, 1, timeout); + + // if we didn't transmit byte, bail out + if (ret != NFC_SUCCESS) + return ret; + + usleep(9); // sleep for ceil(1_000_000us / 115200baud) = 9us + } + + return NFC_SUCCESS; } char ** From 27f7537430779deb64018fed1c0f6d4cfaede3b4 Mon Sep 17 00:00:00 2001 From: Samy Kamkar Date: Thu, 21 Jan 2021 20:36:24 -0800 Subject: [PATCH 9/9] Revert changes except for macOS where we still delay --- contrib/win32/libnfc/buses/uart.c | 24 ------------------------ libnfc/buses/uart.c | 19 ++++++++++++------- libnfc/drivers/pn532_uart.c | 6 +++--- 3 files changed, 15 insertions(+), 34 deletions(-) diff --git a/contrib/win32/libnfc/buses/uart.c b/contrib/win32/libnfc/buses/uart.c index f0bbe784..982e18c8 100644 --- a/contrib/win32/libnfc/buses/uart.c +++ b/contrib/win32/libnfc/buses/uart.c @@ -240,30 +240,6 @@ uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) return NFC_SUCCESS; } -/** - * @brief Send \a pbtTx content to UART one byte at a time - * - * @return 0 on success, otherwise a driver error is returned - */ -int -uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) -{ - (void) timeout; - int ret; - for (int i = 0; i < szTx; i++) - { - ret = uart_send(sp, pbtTx+i, 1, timeout); - - // if we didn't transmit byte, bail out - if (ret != NFC_SUCCESS) - return ret; - - delay_ms(1); // ceil(1_000_000us / 115200baud) = 9us but no usleep on windows - } - - return NFC_SUCCESS; -} - BOOL is_port_available(int nPort) { TCHAR szPort[15]; diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index e4d34c0b..08ff9cea 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -394,14 +394,22 @@ uart_send(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) { (void) timeout; LOG_HEX(LOG_GROUP, "TX", pbtTx, szTx); + +#ifndef __APPLE__ if ((int) szTx == write(UART_DATA(sp)->fd, pbtTx, szTx)) return NFC_SUCCESS; else return NFC_EIO; +#else + // macOS's termios write() to a uart is async so we need to determine how to make it sync + // see https://github.com/nfc-tools/libnfc/pull/633 + // there is probably a proper way to do this, if so, please share! + return uart_send_single(sp, pbtTx, szTx, timeout); +#endif } /** - * @brief Send \a pbtTx content to UART one byte at a time + * @brief Send \a pbtTx content to UART one byte at a time with a delay (to support macOS' async write) * * @return 0 on success, otherwise a driver error is returned */ @@ -409,14 +417,11 @@ int uart_send_single(serial_port sp, const uint8_t *pbtTx, const size_t szTx, int timeout) { (void) timeout; - int ret; + for (int i = 0; i < szTx; i++) { - ret = uart_send(sp, pbtTx+i, 1, timeout); - - // if we didn't transmit byte, bail out - if (ret != NFC_SUCCESS) - return ret; + if (write(UART_DATA(sp)->fd, pbtTx+i, 1) != 1) + return NFC_EIO; usleep(9); // sleep for ceil(1_000_000us / 115200baud) = 9us } diff --git a/libnfc/drivers/pn532_uart.c b/libnfc/drivers/pn532_uart.c index dae0242c..d82051d7 100644 --- a/libnfc/drivers/pn532_uart.c +++ b/libnfc/drivers/pn532_uart.c @@ -304,7 +304,7 @@ pn532_uart_wakeup(nfc_device *pnd) { /* High Speed Unit (HSU) wake up consist to send 0x55 and wait a "long" delay for PN532 being wakeup. */ const uint8_t pn532_wakeup_preamble[] = { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - int res = uart_send_single(DRIVER_DATA(pnd)->port, pn532_wakeup_preamble, sizeof(pn532_wakeup_preamble), 0); + int res = uart_send(DRIVER_DATA(pnd)->port, pn532_wakeup_preamble, sizeof(pn532_wakeup_preamble), 0); CHIP_DATA(pnd)->power_mode = NORMAL; // PN532 should now be awake return res; } @@ -348,7 +348,7 @@ pn532_uart_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, in return pnd->last_error; } - res = uart_send_single(DRIVER_DATA(pnd)->port, abtFrame, szFrame, timeout); + res = uart_send(DRIVER_DATA(pnd)->port, abtFrame, szFrame, timeout); if (res != 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); pnd->last_error = res; @@ -507,7 +507,7 @@ pn532_uart_ack(nfc_device *pnd) return res; } } - return (uart_send_single(DRIVER_DATA(pnd)->port, pn53x_ack_frame, sizeof(pn53x_ack_frame), 0)); + return (uart_send(DRIVER_DATA(pnd)->port, pn53x_ack_frame, sizeof(pn53x_ack_frame), 0)); } static int