diff --git a/CMakeLists.txt b/CMakeLists.txt index cd8183f..9a88c5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -234,7 +234,14 @@ ENDIF(WIN32) SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Near Field Communication (NFC) library") SET(CPACK_PACKAGE_VENDOR "Roel Verdult") SET(CPACK_PACKAGE_CONTACT "Roel Verdul ") -SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") + +#Readme file +IF(WIN32) + SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README-Windows.md") +ELSE(WIN32) + SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") +ENDIF(WIN32) + SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") SET(CPACK_PACKAGE_INSTALL_DIRECTORY "libnfc") SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) diff --git a/Makefile.am b/Makefile.am index a1604a3..413b6de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,7 @@ pkgconfig_DATA = libnfc.pc EXTRA_DIST = \ CMakeLists.txt \ Doxyfile \ - README-Windows.txt \ + README-Windows.md \ libnfc.conf.sample CLEANFILES = Doxygen.log coverage.info libnfc.pc diff --git a/README.md b/README.md index b03551f..d68508f 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ The official forum site is: The official development site is: https://github.com/nfc-tools/libnfc -Important note: this file covers POSIX systems, for Windows please read README-Windows.txt +Important note: this file covers POSIX systems, for Windows please read README-Windows.md Requirements ============ diff --git a/contrib/linux/blacklist-libnfc.conf b/contrib/linux/blacklist-libnfc.conf index e9382b1..40f406f 100644 --- a/contrib/linux/blacklist-libnfc.conf +++ b/contrib/linux/blacklist-libnfc.conf @@ -1,2 +1,3 @@ blacklist nfc blacklist pn533 +blacklist pm533_usb diff --git a/contrib/win32/nfc.def b/contrib/win32/nfc.def index 085b2f7..5ed4097 100644 --- a/contrib/win32/nfc.def +++ b/contrib/win32/nfc.def @@ -4,6 +4,7 @@ VERSION 1.7 EXPORTS nfc_init nfc_exit + nfc_register_driver nfc_open nfc_close nfc_abort_command @@ -17,7 +18,6 @@ EXPORTS nfc_initiator_select_dep_target nfc_initiator_poll_dep_target nfc_initiator_deselect_target - nfc_initiator_poll_targets nfc_initiator_transceive_bytes nfc_initiator_transceive_bits nfc_initiator_transceive_bytes_timed @@ -36,11 +36,15 @@ EXPORTS nfc_device_get_connstring nfc_device_get_supported_modulation nfc_device_get_supported_baud_rate + nfc_device_get_supported_baud_rate_target_mode nfc_device_set_property_int nfc_device_set_property_bool iso14443a_crc iso14443a_crc_append + iso14443b_crc + iso14443b_crc_append iso14443a_locate_historical_bytes + nfc_free nfc_version nfc_device_get_information_about str_nfc_modulation_type diff --git a/include/nfc/nfc.h b/include/nfc/nfc.h index 4ebc6ff..bbbde94 100644 --- a/include/nfc/nfc.h +++ b/include/nfc/nfc.h @@ -28,7 +28,7 @@ * @file nfc.h * @brief libnfc interface * - * Provide all usefull functions (API) to handle NFC devices. + * Provide all useful functions (API) to handle NFC devices. */ #ifndef _LIBNFC_H_ diff --git a/libnfc/buses/uart.c b/libnfc/buses/uart.c index 7f14532..b9b6121 100644 --- a/libnfc/buses/uart.c +++ b/libnfc/buses/uart.c @@ -77,6 +77,8 @@ const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial", "tty.usbmodem", NULL }; # elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__FreeBSD_kernel__) const char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL }; +# elif defined (__NetBSD__) +const char *serial_ports_device_radix[] = { "tty0", "ttyC", "ttyS", "ttyU", "ttyY" , NULL }; # elif defined (__linux__) || defined (__CYGWIN__) const char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", "ttyACM", "ttyAMA", "ttyO", NULL }; # else diff --git a/libnfc/chips/pn53x-internal.h b/libnfc/chips/pn53x-internal.h index c43934a..e4869cd 100644 --- a/libnfc/chips/pn53x-internal.h +++ b/libnfc/chips/pn53x-internal.h @@ -81,32 +81,38 @@ #define TgGetTargetStatus 0x8A /** @note PN53x's normal frame: + * See the PN532 (firmware) user manual, section 6.2.1.1: Normal information + * frame, figure 13. Normal information frame, page 28 rev. 02 - 2007-11-07. * - * .-- Start - * | .-- Packet length - * | | .-- Length checksum - * | | | .-- Direction (D4 Host to PN, D5 PN to Host) - * | | | | .-- Code - * | | | | | .-- Packet checksum - * | | | | | | .-- Postamble - * V | | | | | | - * ----- V V V V V V - * 00 FF 02 FE D4 02 2A 00 + * .-- Preamble + * | .-- Start + * | | .-- Packet length + * | | | .-- Length checksum + * | | | | .-- Direction (D4 Host to PN, D5 PN to Host) + * | | | | | .-- Code + * | | | | | | .-- Packet checksum + * | | | | | | | .-- Postamble + * | V | | | | | | + * V ----- V V V V V V + * 00 00 FF 02 FE D4 02 2A 00 */ /** @note PN53x's extended frame: + * See the PN532 (firmware) user manual, section 6.2.1.2: Extended information + * frame, figure 14. Normal information frame, page 29 rev. 02 - 2007-11-07. * - * .-- Start - * | .-- Fixed to FF to enable extended frame - * | | .-- Packet length - * | | | .-- Length checksum - * | | | | .-- Direction (D4 Host to PN, D5 PN to Host) - * | | | | | .-- Code - * | | | | | | .-- Packet checksum - * | | | | | | | .-- Postamble - * V V V | | | | | - * ----- ----- ----- V V V V V - * 00 FF FF FF 00 02 FE D4 02 2A 00 + * .-- Preamble + * | .-- Start + * | | .-- Fixed to FF to enable extended frame + * | | | .-- Packet length + * | | | | .-- Length checksum + * | | | | | .-- Direction (D4 Host to PN, D5 PN to Host) + * | | | | | | .-- Code + * | | | | | | | .-- Packet checksum + * | | | | | | | | .-- Postamble + * | V V V | | | | | + * V ----- ----- ----- V V V V V + * 00 00 FF FF FF 00 02 FE D4 02 2A 00 */ /** diff --git a/libnfc/drivers/acr122_pcsc.c b/libnfc/drivers/acr122_pcsc.c index 6d7c9e6..93af3aa 100644 --- a/libnfc/drivers/acr122_pcsc.c +++ b/libnfc/drivers/acr122_pcsc.c @@ -59,7 +59,7 @@ # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500) #elif defined(__APPLE__) # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2)) -#elif defined (__FreeBSD__) || defined (__OpenBSD__) +#elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2)) #elif defined (__linux__) # include diff --git a/libnfc/drivers/pn532_i2c.c b/libnfc/drivers/pn532_i2c.c index b62c7de..d242df9 100644 --- a/libnfc/drivers/pn532_i2c.c +++ b/libnfc/drivers/pn532_i2c.c @@ -59,6 +59,13 @@ // I2C address of the PN532 chip. #define PN532_I2C_ADDR 0x24 +/* + * When sending lots of data, the pn532 occasionally fails to respond in time. + * Since it happens so rarely, lets try to fix it by re-sending the data. This + * define allows for fine tuning the number of retries. + */ +#define PN532_SEND_RETRIES 3 + // Internal data structs const struct pn53x_io pn532_i2c_io; @@ -67,13 +74,9 @@ struct pn532_i2c_data { volatile bool abort_flag; }; -/* Delay for the loop waiting for READY frame (in ms) */ -#define PN532_RDY_LOOP_DELAY 90 - -const struct timespec rdyDelay = { - .tv_sec = 0, - .tv_nsec = PN532_RDY_LOOP_DELAY * 1000 * 1000 -}; +/* preamble and start bytes, see pn532-internal.h for details */ +const uint8_t pn53x_preamble_and_start[] = { 0x00, 0x00, 0xff }; +#define PN53X_PREAMBLE_AND_START_LEN (sizeof(pn53x_preamble_and_start) / sizeof(pn53x_preamble_and_start[0])) /* Private Functions Prototypes */ @@ -96,6 +99,70 @@ static size_t pn532_i2c_scan(const nfc_context *context, nfc_connstring connstri #define DRIVER_DATA(pnd) ((struct pn532_i2c_data*)(pnd->driver_data)) +/* + * Bus free time (in ms) between a STOP condition and START condition. See + * tBuf in the PN532 data sheet, section 12.25: Timing for the I2C interface, + * table 320. I2C timing specification, page 211, rev. 3.2 - 2007-12-07. + */ +#define PN532_BUS_FREE_TIME 5 +static struct timespec __transaction_stop; + +/** + * @brief Wrapper around i2c_read to ensure proper timing by respecting the + * minimal free bus time between a STOP condition and a START condition. + * + * @note This is not thread safe, but since libnfc is single threaded + * this should be okay. + * + * @param id I2C device + * @param buf pointer on buffer used to store data + * @param len length of the buffer + * @return length (in bytes) of read data, or driver error code (negative value) + */ +static ssize_t pn532_i2c_read(const i2c_device id, + uint8_t *buf, const size_t len) +{ + struct timespec transaction_start, bus_free_time = { 0 }; + ssize_t ret; + + clock_gettime(CLOCK_MONOTONIC, &transaction_start); + bus_free_time.tv_nsec = (PN532_BUS_FREE_TIME * 1000 * 1000) - + (transaction_start.tv_nsec - __transaction_stop.tv_nsec); + nanosleep(&bus_free_time, NULL); + + ret = i2c_read(id, buf, len); + clock_gettime(CLOCK_MONOTONIC, &__transaction_stop); + return ret; +} + +/** + * @brief Wrapper around i2c_write to ensure proper timing by respecting the + * minimal free bus time between a STOP condition and a START condition. + * + * @note This is not thread safe, but since libnfc is single threaded + * this should be okay. + * + * @param id I2C device + * @param buf pointer on buffer containing data + * @param len length of the buffer + * @return NFC_SUCCESS on success, otherwise driver error code + */ +static ssize_t pn532_i2c_write(const i2c_device id, + const uint8_t *buf, const size_t len) +{ + struct timespec transaction_start, bus_free_time = { 0 }; + ssize_t ret; + + clock_gettime(CLOCK_MONOTONIC, &transaction_start); + bus_free_time.tv_nsec = (PN532_BUS_FREE_TIME * 1000 * 1000) - + (transaction_start.tv_nsec - __transaction_stop.tv_nsec); + nanosleep(&bus_free_time, NULL); + + ret = i2c_write(id, buf, len); + clock_gettime(CLOCK_MONOTONIC, &__transaction_stop); + return ret; +} + /** * @brief Scan all available I2C buses to find PN532 devices. * @@ -308,6 +375,7 @@ static int pn532_i2c_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout) { int res = 0; + uint8_t retries; // Discard any existing data ? @@ -334,15 +402,22 @@ pn532_i2c_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int break; }; - uint8_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" + uint8_t abtFrame[PN532_BUFFER_LEN]; size_t szFrame = 0; + memcpy(abtFrame, pn53x_preamble_and_start, PN53X_PREAMBLE_AND_START_LEN); // Every packet must start with the preamble and start bytes. if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) { pnd->last_error = res; return pnd->last_error; } - res = i2c_write(DRIVER_DATA(pnd)->dev, abtFrame, szFrame); + for (retries = PN532_SEND_RETRIES; retries > 0; retries--) { + res = pn532_i2c_write(DRIVER_DATA(pnd)->dev, abtFrame, szFrame); + if (res >= 0) + break; + + log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Failed to transmit data. Retries left: %d.", retries - 1); + } if (res < 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); @@ -400,10 +475,7 @@ pn532_i2c_wait_rdyframe(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLe } do { - // Wait a little bit before reading - nanosleep(&rdyDelay, (struct timespec *) NULL); - - int recCount = i2c_read(DRIVER_DATA(pnd)->dev, i2cRx, szDataLen + 1); + int recCount = pn532_i2c_read(DRIVER_DATA(pnd)->dev, i2cRx, szDataLen + 1); if (DRIVER_DATA(pnd)->abort_flag) { // Reset abort flag @@ -477,9 +549,7 @@ pn532_i2c_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int goto error; } - const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; - - if (0 != (memcmp(frameBuf, pn53x_preamble, 3))) { + if (0 != (memcmp(frameBuf, pn53x_preamble_and_start, PN53X_PREAMBLE_AND_START_LEN))) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); pnd->last_error = NFC_EIO; goto error; @@ -572,7 +642,7 @@ error: int pn532_i2c_ack(nfc_device *pnd) { - return i2c_write(DRIVER_DATA(pnd)->dev, pn53x_ack_frame, sizeof(pn53x_ack_frame)); + return pn532_i2c_write(DRIVER_DATA(pnd)->dev, pn53x_ack_frame, sizeof(pn53x_ack_frame)); } /** diff --git a/libnfc/mirror-subr.h b/libnfc/mirror-subr.h index 2f53bc9..4410bde 100644 --- a/libnfc/mirror-subr.h +++ b/libnfc/mirror-subr.h @@ -39,6 +39,5 @@ uint8_t mirror(uint8_t bt); uint32_t mirror32(uint32_t ui32Bits); uint64_t mirror64(uint64_t ui64Bits); -void mirror_uint8_ts(uint8_t *pbts, size_t szLen); #endif // _LIBNFC_MIRROR_SUBR_H_ diff --git a/libnfc/nfc-internal.c b/libnfc/nfc-internal.c index b0beae1..68ecd34 100644 --- a/libnfc/nfc-internal.c +++ b/libnfc/nfc-internal.c @@ -242,7 +242,6 @@ connstring_decode(const nfc_connstring connstring, const char *driver_name, cons int res = sscanf(connstring, format, param0, param1, param2); if (res < 1 || ((0 != strcmp(param0, driver_name)) && - (bus_name != NULL) && (0 != strcmp(param0, bus_name)))) { // Driver name does not match. res = 0; diff --git a/libnfc/nfc.c b/libnfc/nfc.c index 404786a..42d4ab7 100644 --- a/libnfc/nfc.c +++ b/libnfc/nfc.c @@ -645,7 +645,7 @@ nfc_initiator_poll_target(nfc_device *pnd, * @param pnd \a nfc_device struct pointer that represent currently used device * @param ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode) * @param nbr desired baud rate - * @param ndiInitiator pointer \a nfc_dep_info struct that contains \e NFCID3 and \e General \e Bytes to set to the initiator device (optionnal, can be \e NULL) + * @param pndiInitiator pointer \a nfc_dep_info struct that contains \e NFCID3 and \e General \e Bytes to set to the initiator device (optionnal, can be \e NULL) * @param[out] pnt is a \a nfc_target struct pointer where target information will be put. * @param timeout in milliseconds * @@ -673,7 +673,7 @@ nfc_initiator_select_dep_target(nfc_device *pnd, * @param pnd \a nfc_device struct pointer that represent currently used device * @param ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode) * @param nbr desired baud rate - * @param ndiInitiator pointer \a nfc_dep_info struct that contains \e NFCID3 and \e General \e Bytes to set to the initiator device (optionnal, can be \e NULL) + * @param pndiInitiator pointer \a nfc_dep_info struct that contains \e NFCID3 and \e General \e Bytes to set to the initiator device (optionnal, can be \e NULL) * @param[out] pnt is a \a nfc_target struct pointer where target information will be put. * @param timeout in milliseconds * @@ -972,7 +972,7 @@ nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t s * @param pnd \a nfc_device struct pointer that represent currently used device * * This function switch the device in idle mode. - * In initiator mode, the RF field is turned off and the device is set to low power mode (if avaible); + * In initiator mode, the RF field is turned off and the device is set to low power mode (if available); * In target mode, the emulation is stoped (no target available from external initiator) and the device is set to low power mode (if avaible). */ int diff --git a/utils/nfc-mfclassic.c b/utils/nfc-mfclassic.c index 56d5717..9a8f8b6 100644 --- a/utils/nfc-mfclassic.c +++ b/utils/nfc-mfclassic.c @@ -671,7 +671,7 @@ main(int argc, const char *argv[]) if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02) // 4K uiBlocks = 0xff; - else if ((nt.nti.nai.btSak & 0x01) == 0x01) + else if (nt.nti.nai.btSak == 0x09) // 320b uiBlocks = 0x13; else diff --git a/utils/nfc-mfultralight.c b/utils/nfc-mfultralight.c index 4b9f39d..63ea215 100644 --- a/utils/nfc-mfultralight.c +++ b/utils/nfc-mfultralight.c @@ -98,7 +98,7 @@ read_card(void) { uint32_t page; bool bFailure = false; - uint32_t uiReadedPages = 0; + uint32_t uiReadPages = 0; printf("Reading %d pages |", uiBlocks + 1); @@ -111,13 +111,13 @@ read_card(void) break; } - print_success_or_failure(bFailure, &uiReadedPages); - print_success_or_failure(bFailure, &uiReadedPages); - print_success_or_failure(bFailure, &uiReadedPages); - print_success_or_failure(bFailure, &uiReadedPages); + print_success_or_failure(bFailure, &uiReadPages); + print_success_or_failure(bFailure, &uiReadPages); + print_success_or_failure(bFailure, &uiReadPages); + print_success_or_failure(bFailure, &uiReadPages); } printf("|\n"); - printf("Done, %d of %d pages read.\n", uiReadedPages, uiBlocks + 1); + printf("Done, %d of %d pages read.\n", uiReadPages, uiBlocks + 1); fflush(stdout); return (!bFailure); @@ -234,7 +234,7 @@ write_card(bool write_otp, bool write_lock, bool write_uid) { uint32_t uiBlock = 0; bool bFailure = false; - uint32_t uiWritenPages = 0; + uint32_t uiWrittenPages = 0; uint32_t uiSkippedPages = 0; char buffer[BUFSIZ]; @@ -276,7 +276,7 @@ write_card(bool write_otp, bool write_lock, bool write_uid) } } - for (uint32_t page = uiSkippedPages; page <= ((uiBlocks / 4) * 4); page++) { + for (uint32_t page = uiSkippedPages; page <= uiBlocks; page++) { if ((page == 0x2) && (!write_lock)) { printf("s"); uiSkippedPages++; @@ -306,10 +306,10 @@ write_card(bool write_otp, bool write_lock, bool write_uid) if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp)) bFailure = true; - print_success_or_failure(bFailure, &uiWritenPages); + print_success_or_failure(bFailure, &uiWrittenPages); } printf("|\n"); - printf("Done, %d of %d pages written (%d pages skipped).\n", uiWritenPages, uiBlocks + 1, uiSkippedPages); + printf("Done, %d of %d pages written (%d pages skipped).\n", uiWrittenPages, uiBlocks + 1, uiSkippedPages); return true; }