/*- * Free/Libre Near Field Communication (NFC) library * * Libnfc historical contributors: * Copyright (C) 2009 Roel Verdult * Copyright (C) 2009-2013 Romuald Conty * Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2012-2013 Ludovic Rousseau * See AUTHORS file for a more comprehensive list of contributors. * Additional contributors of this file: * Copyright (C) 2020 Adam Laurie * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ /** * @file nfc.c * @brief NFC library implementation */ /** * @defgroup lib Library initialization/deinitialization * This page details how to initialize and deinitialize libnfc. Initialization * must be performed before using any libnfc functionality, and similarly you * must not call any libnfc functions after deinitialization. */ /** * @defgroup dev NFC Device/Hardware manipulation * The functionality documented below is designed to help with the following * operations: * - Enumerating the NFC devices currently attached to the system * - Opening and closing the chosen device */ /** * @defgroup initiator NFC initiator * This page details how to act as "reader". */ /** * @defgroup target NFC target * This page details how to act as tag (i.e. MIFARE Classic) or NFC target device. */ /** * @defgroup error Error reporting * Most libnfc functions return 0 on success or one of error codes defined on failure. */ /** * @defgroup data Special data accessors * The functionnality documented below allow to access to special data as device name or device connstring. */ /** * @defgroup properties Properties accessors * The functionnality documented below allow to configure parameters and registers. */ /** * @defgroup misc Miscellaneous * */ /** * @defgroup string-converter To-string converters * The functionnality documented below allow to retreive some information in text format. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif // HAVE_CONFIG_H #include #include #include #include #include #include #include #include "nfc-internal.h" #include "target-subr.h" #include "drivers.h" #if defined (DRIVER_PCSC_ENABLED) # include "drivers/pcsc.h" #endif /* DRIVER_PCSC_ENABLED */ #if defined (DRIVER_ACR122_PCSC_ENABLED) # include "drivers/acr122_pcsc.h" #endif /* DRIVER_ACR122_PCSC_ENABLED */ #if defined (DRIVER_ACR122_USB_ENABLED) # include "drivers/acr122_usb.h" #endif /* DRIVER_ACR122_USB_ENABLED */ #if defined (DRIVER_ACR122S_ENABLED) # include "drivers/acr122s.h" #endif /* DRIVER_ACR122S_ENABLED */ #if defined (DRIVER_PN53X_USB_ENABLED) # include "drivers/pn53x_usb.h" #endif /* DRIVER_PN53X_USB_ENABLED */ #if defined (DRIVER_ARYGON_ENABLED) # include "drivers/arygon.h" #endif /* DRIVER_ARYGON_ENABLED */ #if defined (DRIVER_PN532_UART_ENABLED) # include "drivers/pn532_uart.h" #endif /* DRIVER_PN532_UART_ENABLED */ #if defined (DRIVER_PN532_SPI_ENABLED) # include "drivers/pn532_spi.h" #endif /* DRIVER_PN532_SPI_ENABLED */ #if defined (DRIVER_PN532_I2C_ENABLED) # include "drivers/pn532_i2c.h" #endif /* DRIVER_PN532_I2C_ENABLED */ #if defined (DRIVER_PN71XX_ENABLED) # include "drivers/pn71xx.h" #endif /* DRIVER_PN71XX_ENABLED */ #define LOG_CATEGORY "libnfc.general" #define LOG_GROUP NFC_LOG_GROUP_GENERAL struct nfc_driver_list { const struct nfc_driver_list *next; const struct nfc_driver *driver; }; const struct nfc_driver_list *nfc_drivers = NULL; // descritions for debugging const char *nfc_property_name[] = { "NP_TIMEOUT_COMMAND", "NP_TIMEOUT_ATR", "NP_TIMEOUT_COM", "NP_HANDLE_CRC", "NP_HANDLE_PARITY", "NP_ACTIVATE_FIELD", "NP_ACTIVATE_CRYPTO1", "NP_INFINITE_SELECT", "NP_ACCEPT_INVALID_FRAMES", "NP_ACCEPT_MULTIPLE_FRAMES", "NP_AUTO_ISO14443_4", "NP_EASY_FRAMING", "NP_FORCE_ISO14443_A", "NP_FORCE_ISO14443_B", "NP_FORCE_SPEED_106" }; static void nfc_drivers_init(void) { #if defined (DRIVER_PN53X_USB_ENABLED) nfc_register_driver(&pn53x_usb_driver); #endif /* DRIVER_PN53X_USB_ENABLED */ #if defined (DRIVER_PCSC_ENABLED) nfc_register_driver(&pcsc_driver); #endif /* DRIVER_ACR122_PCSC_ENABLED */ #if defined (DRIVER_ACR122_PCSC_ENABLED) nfc_register_driver(&acr122_pcsc_driver); #endif /* DRIVER_ACR122_PCSC_ENABLED */ #if defined (DRIVER_ACR122_USB_ENABLED) nfc_register_driver(&acr122_usb_driver); #endif /* DRIVER_ACR122_USB_ENABLED */ #if defined (DRIVER_ACR122S_ENABLED) nfc_register_driver(&acr122s_driver); #endif /* DRIVER_ACR122S_ENABLED */ #if defined (DRIVER_PN532_UART_ENABLED) nfc_register_driver(&pn532_uart_driver); #endif /* DRIVER_PN532_UART_ENABLED */ #if defined (DRIVER_PN532_SPI_ENABLED) nfc_register_driver(&pn532_spi_driver); #endif /* DRIVER_PN532_SPI_ENABLED */ #if defined (DRIVER_PN532_I2C_ENABLED) nfc_register_driver(&pn532_i2c_driver); #endif /* DRIVER_PN532_I2C_ENABLED */ #if defined (DRIVER_ARYGON_ENABLED) nfc_register_driver(&arygon_driver); #endif /* DRIVER_ARYGON_ENABLED */ #if defined (DRIVER_PN71XX_ENABLED) nfc_register_driver(&pn71xx_driver); #endif /* DRIVER_PN71XX_ENABLED */ } static int nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation *nm); /** @ingroup lib * @brief Register an NFC device driver with libnfc. * This function registers a driver with libnfc, the caller is responsible of managing the lifetime of the * driver and make sure that any resources associated with the driver are available after registration. * @param pnd Pointer to an NFC device driver to be registered. * @retval NFC_SUCCESS If the driver registration succeeds. */ int nfc_register_driver(const struct nfc_driver *ndr) { if (!ndr) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_register_driver returning NFC_EINVARG"); return NFC_EINVARG; } struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list)); if (!pndl) return NFC_ESOFT; pndl->driver = ndr; pndl->next = nfc_drivers; nfc_drivers = pndl; return NFC_SUCCESS; } /** @ingroup lib * @brief Initialize libnfc. * This function must be called before calling any other libnfc function * @param context Output location for nfc_context */ void nfc_init(nfc_context **context) { *context = nfc_context_new(); if (!*context) { perror("malloc"); return; } if (!nfc_drivers) nfc_drivers_init(); } /** @ingroup lib * @brief Deinitialize libnfc. * Should be called after closing all open devices and before your application terminates. * @param context The context to deinitialize */ void nfc_exit(nfc_context *context) { while (nfc_drivers) { struct nfc_driver_list *pndl = (struct nfc_driver_list *) nfc_drivers; nfc_drivers = pndl->next; free(pndl); } nfc_context_free(context); } /** @ingroup dev * @brief Open a NFC device * @param context The context to operate on. * @param connstring The device connection string if specific device is wanted, \c NULL otherwise * @return Returns pointer to a \a nfc_device struct if successfull; otherwise returns \c NULL value. * * If \e connstring is \c NULL, the first available device from \a nfc_list_devices function is used. * * If \e connstring is set, this function will try to claim the right device using information provided by \e connstring. * * When it has successfully claimed a NFC device, memory is allocated to save the device information. * It will return a pointer to a \a nfc_device struct. * This pointer should be supplied by every next functions of libnfc that should perform an action with this device. * * @note Depending on the desired operation mode, the device needs to be configured by using nfc_initiator_init() or nfc_target_init(), * optionally followed by manual tuning of the parameters if the default parameters are not suiting your goals. */ nfc_device * nfc_open(nfc_context *context, const nfc_connstring connstring) { nfc_device *pnd = NULL; nfc_connstring ncs; if (connstring == NULL) { if (!nfc_list_devices(context, &ncs, 1)) { return NULL; } } else { strncpy(ncs, connstring, sizeof(nfc_connstring)); ncs[sizeof(nfc_connstring) - 1] = '\0'; } // Search through the device list for an available device const struct nfc_driver_list *pndl = nfc_drivers; while (pndl) { const struct nfc_driver *ndr = pndl->driver; // Specific device is requested: using device description if (0 != strncmp(ndr->name, ncs, strlen(ndr->name))) { // Check if connstring driver is usb -> accept any driver *_usb if ((0 != strncmp("usb", ncs, strlen("usb"))) || 0 != strncmp("_usb", ndr->name + (strlen(ndr->name) - 4), 4)) { pndl = pndl->next; continue; } } pnd = ndr->open(context, ncs); // Test if the opening was successful if (pnd == NULL) { if (0 == strncmp("usb", ncs, strlen("usb"))) { // We've to test the other usb drivers before giving up pndl = pndl->next; continue; } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open \"%s\".", ncs); return NULL; } for (uint32_t i = 0; i < context->user_defined_device_count; i++) { if (strcmp(ncs, context->user_defined_devices[i].connstring) == 0) { // This is a device sets by user, we use the device name given by user strcpy(pnd->name, context->user_defined_devices[i].name); break; } } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "\"%s\" (%s) has been claimed.", pnd->name, pnd->connstring); return pnd; } // Too bad, no driver can decode connstring log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "No driver available to handle \"%s\".", ncs); return NULL; } /** @ingroup dev * @brief Close from a NFC device * @param pnd \a nfc_device struct pointer that represent currently used device * * Initiator's selected tag is closed and the device, including allocated \a nfc_device struct, is released. */ void nfc_close(nfc_device *pnd) { if (pnd) { // Close, clean up and release the device pnd->driver->close(pnd); } } /** @ingroup dev * @brief Scan for discoverable supported devices (ie. only available for some drivers) * @return Returns the number of devices found. * @param context The context to operate on, or NULL for the default context. * @param connstrings array of \a nfc_connstring. * @param connstrings_len size of the \a connstrings array. * */ size_t nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) { size_t device_found = 0; #ifdef CONFFILES // Load manually configured devices (from config file and env variables) // TODO From env var... for (uint32_t i = 0; i < context->user_defined_device_count; i++) { if (context->user_defined_devices[i].optional) { // let's make sure the device exists nfc_device *pnd = NULL; #ifdef ENVVARS char *env_log_level = getenv("LIBNFC_LOG_LEVEL"); char *old_env_log_level = NULL; // do it silently if (env_log_level) { if ((old_env_log_level = malloc(strlen(env_log_level) + 1)) == NULL) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to malloc()"); return 0; } strcpy(old_env_log_level, env_log_level); } setenv("LIBNFC_LOG_LEVEL", "0", 1); #endif // ENVVARS pnd = nfc_open(context, context->user_defined_devices[i].connstring); #ifdef ENVVARS if (old_env_log_level) { setenv("LIBNFC_LOG_LEVEL", old_env_log_level, 1); free(old_env_log_level); } else { unsetenv("LIBNFC_LOG_LEVEL"); } #endif // ENVVARS if (pnd) { nfc_close(pnd); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "User device %s found", context->user_defined_devices[i].name); strcpy((char *)(connstrings + device_found), context->user_defined_devices[i].connstring); device_found ++; if (device_found == connstrings_len) break; } } else { // manual choice is not marked as optional so let's take it blindly strcpy((char *)(connstrings + device_found), context->user_defined_devices[i].connstring); device_found++; if (device_found >= connstrings_len) return device_found; } } #endif // CONFFILES // Device auto-detection if (context->allow_autoscan) { const struct nfc_driver_list *pndl = nfc_drivers; while (pndl) { const struct nfc_driver *ndr = pndl->driver; if ((ndr->scan_type == NOT_INTRUSIVE) || ((context->allow_intrusive_scan) && (ndr->scan_type == INTRUSIVE))) { size_t _device_found = ndr->scan(context, connstrings + (device_found), connstrings_len - (device_found)); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%ld device(s) found using %s driver", (unsigned long) _device_found, ndr->name); if (_device_found > 0) { device_found += _device_found; if (device_found == connstrings_len) break; } } // scan_type is INTRUSIVE but not allowed or NOT_AVAILABLE pndl = pndl->next; } } else if (context->user_defined_device_count == 0) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: %s", "user must specify device(s) manually when autoscan is disabled"); } return device_found; } /** @ingroup properties * @brief Set a device's integer-property value * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param property \a nfc_property which will be set * @param value integer value * * Sets integer property. * * @see nfc_property enum values */ int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_int %s %s", nfc_property_name[property], value ? "True" : "False"); HAL(device_set_property_int, pnd, property, value); } /** @ingroup properties * @brief Set a device's boolean-property value * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param property \a nfc_property which will be set * @param bEnable boolean to activate/disactivate the property * * Configures parameters and registers that control for example timing, * modulation, frame and error handling. There are different categories for * configuring the \e PN53X chip features (handle, activate, infinite and * accept). */ int nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) { log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_bool %s %s", nfc_property_name[property], bEnable ? "True" : "False"); HAL(device_set_property_bool, pnd, property, bEnable); } /** @ingroup initiator * @brief Initialize NFC device as initiator (reader) * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * * The NFC device is configured to function as RFID reader. * After initialization it can be used to communicate to passive RFID tags and active NFC devices. * The reader will act as initiator to communicate peer 2 peer (NFCIP) to other active NFC devices. * - Crc is handled by the device (NP_HANDLE_CRC = true) * - Parity is handled the device (NP_HANDLE_PARITY = true) * - Cryto1 cipher is disabled (NP_ACTIVATE_CRYPTO1 = false) * - Easy framing is enabled (NP_EASY_FRAMING = true) * - Auto-switching in ISO14443-4 mode is enabled (NP_AUTO_ISO14443_4 = true) * - Invalid frames are not accepted (NP_ACCEPT_INVALID_FRAMES = false) * - Multiple frames are not accepted (NP_ACCEPT_MULTIPLE_FRAMES = false) * - 14443-A mode is activated (NP_FORCE_ISO14443_A = true) * - speed is set to 106 kbps (NP_FORCE_SPEED_106 = true) * - Let the device try forever to find a target (NP_INFINITE_SELECT = true) * - RF field is shortly dropped (if it was enabled) then activated again */ int nfc_initiator_init(nfc_device *pnd) { int res = 0; // Drop the field for a while if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) return res; // Enable field so more power consuming cards can power themselves up if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, true)) < 0) return res; // Let the device try forever to find a target/tag if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return res; // Activate auto ISO14443-4 switching by default if ((res = nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true)) < 0) return res; // Force 14443-A mode if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_ISO14443_A, true)) < 0) return res; // Force speed at 106kbps if ((res = nfc_device_set_property_bool(pnd, NP_FORCE_SPEED_106, true)) < 0) return res; // Disallow invalid frame if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_INVALID_FRAMES, false)) < 0) return res; // Disallow multiple frames if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_MULTIPLE_FRAMES, false)) < 0) return res; HAL(initiator_init, pnd); } /** @ingroup initiator * @brief Initialize NFC device as initiator with its secure element as target (reader) * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * * The NFC device is configured to function as secure element reader. * After initialization it can be used to communicate with the secure element. * @note RF field is deactivated in order to save some power */ int nfc_initiator_init_secure_element(nfc_device *pnd) { HAL(initiator_init_secure_element, pnd); } /** @ingroup initiator * @brief Select a passive or emulated tag * @return Returns selected passive target count on success, otherwise returns libnfc's error code (negative value) * * @param pnd \a nfc_device struct pointer that represent currently used device * @param nm desired modulation * @param pbtInitData optional initiator data, NULL for using the default values. * @param szInitData length of initiator data \a pbtInitData. * @note pbtInitData is used with different kind of data depending on modulation type: * - for an ISO/IEC 14443 type A modulation, pbbInitData contains the UID you want to select; * - for an ISO/IEC 14443 type B modulation, pbbInitData contains Application Family Identifier (AFI) (see ISO/IEC 14443-3) and optionally a second byte = 0x01 if you want to use probabilistic approach instead of timeslot approach; * - for a FeliCa modulation, pbbInitData contains a 5-byte polling payload (see ISO/IEC 18092 11.2.2.5). * - for ISO14443B', ASK CTx and ST SRx, see corresponding standards * - if NULL, default values adequate for the chosen modulation will be used. * * @param[out] pnt \a nfc_target struct pointer which will filled if available * * The NFC device will try to find one available passive tag or emulated tag. * * The chip needs to know with what kind of tag it is dealing with, therefore * the initial modulation and speed (106, 212 or 424 kbps) should be supplied. */ int nfc_initiator_select_passive_target(nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt) { uint8_t *abtInit = NULL; uint8_t maxAbt = MAX(12, szInitData); uint8_t *abtTmpInit = malloc(sizeof(uint8_t) * maxAbt); size_t szInit = 0; int res; if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) { free(abtTmpInit); return res; } if (szInitData == 0) { // Provide default values, if any prepare_initiator_data(nm, &abtInit, &szInit); free(abtTmpInit); } else if (nm.nmt == NMT_ISO14443A) { abtInit = abtTmpInit; iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit); } else { abtInit = abtTmpInit; memcpy(abtInit, pbtInitData, szInitData); free(abtTmpInit); szInit = szInitData; } HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt); free(abtTmpInit); } /** @ingroup initiator * @brief List passive or emulated tags * @return Returns the number of targets found on success, otherwise returns libnfc's error code (negative value) * * @param pnd \a nfc_device struct pointer that represent currently used device * @param nm desired modulation * @param[out] ant array of \a nfc_target that will be filled with targets info * @param szTargets size of \a ant (will be the max targets listed) * * The NFC device will try to find the available passive tags. Some NFC devices * are capable to emulate passive tags. The standards (ISO18092 and ECMA-340) * describe the modulation that can be used for reader to passive * communications. The chip needs to know with what kind of tag it is dealing * with, therefore the initial modulation and speed (106, 212 or 424 kbps) * should be supplied. */ int nfc_initiator_list_passive_targets(nfc_device *pnd, const nfc_modulation nm, nfc_target ant[], const size_t szTargets) { nfc_target nt; size_t szTargetFound = 0; uint8_t *pbtInitData = NULL; size_t szInitDataLen = 0; int res = 0; pnd->last_error = 0; // Let the reader only try once to find a tag bool bInfiniteSelect = pnd->bInfiniteSelect; if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) { return res; } prepare_initiator_data(nm, &pbtInitData, &szInitDataLen); while (nfc_initiator_select_passive_target(pnd, nm, pbtInitData, szInitDataLen, &nt) > 0) { size_t i; bool seen = false; // Check if we've already seen this tag for (i = 0; i < szTargetFound; i++) { if (memcmp(&(ant[i]), &nt, sizeof(nfc_target)) == 0) { seen = true; } } if (seen) { break; } memcpy(&(ant[szTargetFound]), &nt, sizeof(nfc_target)); szTargetFound++; if (szTargets == szTargetFound) { break; } nfc_initiator_deselect_target(pnd); // deselect has no effect on FeliCa, Jewel and Thinfilm cards so we'll stop after one... // ISO/IEC 14443 B' cards are polled at 100% probability so it's not possible to detect correctly two cards at the same time if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_BARCODE) || (nm.nmt == NMT_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) { break; } } if (bInfiniteSelect) { if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) { return res; } } return szTargetFound; } /** @ingroup initiator * @brief Polling for NFC targets * @return Returns polled targets count, otherwise returns libnfc's error code (negative value). * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pnmModulations desired modulations * @param szModulations size of \a pnmModulations * @param uiPollNr specifies the number of polling (0x01 – 0xFE: 1 up to 254 polling, 0xFF: Endless polling) * @note one polling is a polling for each desired target type * @param uiPeriod indicates the polling period in units of 150 ms (0x01 – 0x0F: 150ms – 2.25s) * @note e.g. if uiPeriod=10, it will poll each desired target type during 1.5s * @param[out] pnt pointer on \a nfc_target (over)writable struct */ int nfc_initiator_poll_target(nfc_device *pnd, const nfc_modulation *pnmModulations, const size_t szModulations, const uint8_t uiPollNr, const uint8_t uiPeriod, nfc_target *pnt) { HAL(initiator_poll_target, pnd, pnmModulations, szModulations, uiPollNr, uiPeriod, pnt); } /** @ingroup initiator * @brief Select a target and request active or passive mode for D.E.P. (Data Exchange Protocol) * @return Returns selected D.E.P targets count on success, otherwise returns libnfc's error code (negative value). * * @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 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 * * The NFC device will try to find an available D.E.P. target. The standards * (ISO18092 and ECMA-340) describe the modulation that can be used for reader * to passive communications. * * @note \a nfc_dep_info will be returned when the target was acquired successfully. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_initiator_select_dep_target(nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout) { HAL(initiator_select_dep_target, pnd, ndm, nbr, pndiInitiator, pnt, timeout); } /** @ingroup initiator * @brief Poll a target and request active or passive mode for D.E.P. (Data Exchange Protocol) * @return Returns selected D.E.P targets count on success, otherwise returns libnfc's error code (negative value). * * @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 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 * * The NFC device will try to find an available D.E.P. target. The standards * (ISO18092 and ECMA-340) describe the modulation that can be used for reader * to passive communications. * * @note \a nfc_dep_info will be returned when the target was acquired successfully. */ int nfc_initiator_poll_dep_target(struct nfc_device *pnd, const nfc_dep_mode ndm, const nfc_baud_rate nbr, const nfc_dep_info *pndiInitiator, nfc_target *pnt, const int timeout) { const int period = 300; int remaining_time = timeout; int res; int result = 0; bool bInfiniteSelect = pnd->bInfiniteSelect; if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) return res; while (remaining_time > 0) { if ((res = nfc_initiator_select_dep_target(pnd, ndm, nbr, pndiInitiator, pnt, period)) < 0) { if (res != NFC_ETIMEOUT) { result = res; goto end; } } if (res == 1) { result = res; goto end; } remaining_time -= period; } end: if (! bInfiniteSelect) { if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) { return res; } } return result; } /** @ingroup initiator * @brief Deselect a selected passive or emulated tag * @return Returns 0 on success, otherwise returns libnfc's error code (negative value). * @param pnd \a nfc_device struct pointer that represents currently used device * * After selecting and communicating with a passive tag, this function could be * used to deactivate and release the tag. This is very useful when there are * multiple tags available in the field. It is possible to use the \fn * nfc_initiator_select_passive_target() function to select the first available * tag, test it for the available features and support, deselect it and skip to * the next tag until the correct tag is found. */ int nfc_initiator_deselect_target(nfc_device *pnd) { HAL(initiator_deselect_target, pnd); } /** @ingroup initiator * @brief Send data to target then retrieve data from target * @return Returns received bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represents currently used device * @param pbtTx contains a byte array of the frame that needs to be transmitted. * @param szTx contains the length in bytes. * @param[out] pbtRx response from the target * @param szRx size of \a pbtRx (Will return NFC_EOVFLOW if RX exceeds this size) * @param timeout in milliseconds * * The NFC device (configured as initiator) will transmit the supplied bytes (\a pbtTx) to the target. * It waits for the response and stores the received bytes in the \a pbtRx byte array. * * If \a NP_EASY_FRAMING option is disabled the frames will sent and received in raw mode: \e PN53x will not handle input neither output data. * * The parity bits are handled by the \e PN53x chip. The CRC can be generated automatically or handled manually. * Using this function, frames can be communicated very fast via the NFC initiator to the tag. * * Tests show that on average this way of communicating is much faster than using the regular driver/middle-ware (often supplied by manufacturers). * * @warning The configuration option \a NP_HANDLE_PARITY must be set to \c true (the default value). * * @note When used with MIFARE Classic, NFC_EMFCAUTHFAIL error is returned if authentication command failed. You need to re-select the tag to operate with. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_initiator_transceive_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout) { HAL(initiator_transceive_bytes, pnd, pbtTx, szTx, pbtRx, szRx, timeout) } /** @ingroup initiator * @brief Transceive raw bit-frames to a target * @return Returns received bits count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represents currently used device * @param pbtTx contains a byte array of the frame that needs to be transmitted. * @param szTxBits contains the length in bits. * * @note For example the REQA (0x26) command (first anti-collision command of * ISO14443-A) must be precise 7 bits long. This is not possible by using * nfc_initiator_transceive_bytes(). With that function you can only * communicate frames that consist of full bytes. When you send a full byte (8 * bits + 1 parity) with the value of REQA (0x26), a tag will simply not * respond. More information about this can be found in the anti-collision * example (\e nfc-anticol). * * @param pbtTxPar parameter contains a byte array of the corresponding parity bits needed to send per byte. * * @note For example if you send the SELECT_ALL (0x93, 0x20) = [ 10010011, * 00100000 ] command, you have to supply the following parity bytes (0x01, * 0x00) to define the correct odd parity bits. This is only an example to * explain how it works, if you just are sending two bytes with ISO14443-A * compliant parity bits you better can use the * nfc_initiator_transceive_bytes() function. * * @param[out] pbtRx response from the target * @param szRx size of \a pbtRx (Will return NFC_EOVFLOW if RX exceeds this size) * @param[out] pbtRxPar parameter contains a byte array of the corresponding parity bits * * The NFC device (configured as \e initiator) will transmit low-level messages * where only the modulation is handled by the \e PN53x chip. Construction of * the frame (data, CRC and parity) is completely done by libnfc. This can be * very useful for testing purposes. Some protocols (e.g. MIFARE Classic) * require to violate the ISO14443-A standard by sending incorrect parity and * CRC bytes. Using this feature you are able to simulate these frames. */ int nfc_initiator_transceive_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar) { (void)szRx; HAL(initiator_transceive_bits, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar); } /** @ingroup initiator * @brief Send data to target then retrieve data from target * @return Returns received bytes count on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represents currently used device * @param pbtTx contains a byte array of the frame that needs to be transmitted. * @param szTx contains the length in bytes. * @param[out] pbtRx response from the target * @param szRx size of \a pbtRx (Will return NFC_EOVFLOW if RX exceeds this size) * * This function is similar to nfc_initiator_transceive_bytes() with the following differences: * - A precise cycles counter will indicate the number of cycles between emission & reception of frames. * - It only supports mode with \a NP_EASY_FRAMING option disabled. * - Overall communication with the host is heavier and slower. * * Timer control: * By default timer configuration tries to maximize the precision, which also limits the maximum * cycles count before saturation/timeout. * E.g. with PN53x it can count up to 65535 cycles, so about 4.8ms, with a precision of about 73ns. * - If you're ok with the defaults, set *cycles = 0 before calling this function. * - If you need to count more cycles, set *cycles to the maximum you expect but don't forget * you'll loose in precision and it'll take more time before timeout, so don't abuse! * * @warning The configuration option \a NP_EASY_FRAMING must be set to \c false. * @warning The configuration option \a NP_HANDLE_PARITY must be set to \c true (the default value). */ int nfc_initiator_transceive_bytes_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, uint32_t *cycles) { HAL(initiator_transceive_bytes_timed, pnd, pbtTx, szTx, pbtRx, szRx, cycles); } /** @ingroup initiator * @brief Check target presence * @return Returns 0 on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pnt a \a nfc_target struct pointer where desired target information was stored (optionnal, can be \e NULL). * This function tests if \a nfc_target (or last selected tag if \e NULL) is currently present on NFC device. * @warning The target have to be selected before check its presence * @warning To run the test, one or more commands will be sent to target */ int nfc_initiator_target_is_present(nfc_device *pnd, const nfc_target *pnt) { HAL(initiator_target_is_present, pnd, pnt); } /** @ingroup initiator * @brief Transceive raw bit-frames to a target * @return Returns received bits count on success, otherwise returns libnfc's error code * * This function is similar to nfc_initiator_transceive_bits() with the following differences: * - A precise cycles counter will indicate the number of cycles between emission & reception of frames. * - It only supports mode with \a NP_EASY_FRAMING option disabled and CRC must be handled manually. * - Overall communication with the host is heavier and slower. * * Timer control: * By default timer configuration tries to maximize the precision, which also limits the maximum * cycles count before saturation/timeout. * E.g. with PN53x it can count up to 65535 cycles, so about 4.8ms, with a precision of about 73ns. * - If you're ok with the defaults, set *cycles = 0 before calling this function. * - If you need to count more cycles, set *cycles to the maximum you expect but don't forget * you'll loose in precision and it'll take more time before timeout, so don't abuse! * * @warning The configuration option \a NP_EASY_FRAMING must be set to \c false. * @warning The configuration option \a NP_HANDLE_CRC must be set to \c false. * @warning The configuration option \a NP_HANDLE_PARITY must be set to \c true (the default value). */ int nfc_initiator_transceive_bits_timed(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar, uint32_t *cycles) { (void)szRx; HAL(initiator_transceive_bits_timed, pnd, pbtTx, szTxBits, pbtTxPar, pbtRx, pbtRxPar, cycles); } /** @ingroup target * @brief Initialize NFC device as an emulated tag * @return Returns received bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pnt pointer to \a nfc_target struct that represents the wanted emulated target * * @note \a pnt can be updated by this function: if you set NBR_UNDEFINED * and/or NDM_UNDEFINED (ie. for DEP mode), these fields will be updated. * * @param[out] pbtRx Rx buffer pointer * @param[out] szRx received bytes count * @param timeout in milliseconds * * This function initializes NFC device in \e target mode in order to emulate a * tag using the specified \a nfc_target_mode_t. * - Crc is handled by the device (NP_HANDLE_CRC = true) * - Parity is handled the device (NP_HANDLE_PARITY = true) * - Cryto1 cipher is disabled (NP_ACTIVATE_CRYPTO1 = false) * - Auto-switching in ISO14443-4 mode is enabled (NP_AUTO_ISO14443_4 = true) * - Easy framing is disabled (NP_EASY_FRAMING = false) * - Invalid frames are not accepted (NP_ACCEPT_INVALID_FRAMES = false) * - Multiple frames are not accepted (NP_ACCEPT_MULTIPLE_FRAMES = false) * - RF field is dropped * * @warning Be aware that this function will wait (hang) until a command is * received that is not part of the anti-collision. The RATS command for * example would wake up the emulator. After this is received, the send and * receive functions can be used. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_target_init(nfc_device *pnd, nfc_target *pnt, uint8_t *pbtRx, const size_t szRx, int timeout) { int res = 0; // Disallow invalid frame if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_INVALID_FRAMES, false)) < 0) return res; // Disallow multiple frames if ((res = nfc_device_set_property_bool(pnd, NP_ACCEPT_MULTIPLE_FRAMES, false)) < 0) return res; // Make sure we reset the CRC and parity to chip handling. if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true)) < 0) return res; if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true)) < 0) return res; // Activate auto ISO14443-4 switching by default if ((res = nfc_device_set_property_bool(pnd, NP_AUTO_ISO14443_4, true)) < 0) return res; // Activate "easy framing" feature by default if ((res = nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true)) < 0) return res; // Deactivate the CRYPTO1 cipher, it may could cause problems when still active if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_CRYPTO1, false)) < 0) return res; // Drop explicitely the field if ((res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) return res; HAL(target_init, pnd, pnt, pbtRx, szRx, timeout); } /** @ingroup dev * @brief Turn NFC device in idle mode * @return Returns 0 on success, otherwise returns libnfc's error code. * * @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 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 nfc_idle(nfc_device *pnd) { HAL(idle, pnd); } /** @ingroup dev * @brief Abort current running command * @return Returns 0 on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device * * Some commands (ie. nfc_target_init()) are blocking functions and will return only in particular conditions (ie. external initiator request). * This function attempt to abort the current running command. * * @note The blocking function (ie. nfc_target_init()) will failed with DEABORT error. */ int nfc_abort_command(nfc_device *pnd) { HAL(abort_command, pnd); } /** @ingroup target * @brief Send bytes and APDU frames * @return Returns sent bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtTx pointer to Tx buffer * @param szTx size of Tx buffer * @param timeout in milliseconds * * This function make the NFC device (configured as \e target) send byte frames * (e.g. APDU responses) to the \e initiator. * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_target_send_bytes(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, int timeout) { HAL(target_send_bytes, pnd, pbtTx, szTx, timeout); } /** @ingroup target * @brief Receive bytes and APDU frames * @return Returns received bytes count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtRx pointer to Rx buffer * @param szRx size of Rx buffer * @param timeout in milliseconds * * This function retrieves bytes frames (e.g. ADPU) sent by the \e initiator to the NFC device (configured as \e target). * * If timeout equals to 0, the function blocks indefinitely (until an error is raised or function is completed) * If timeout equals to -1, the default timeout will be used */ int nfc_target_receive_bytes(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, int timeout) { HAL(target_receive_bytes, pnd, pbtRx, szRx, timeout); } /** @ingroup target * @brief Send raw bit-frames * @return Returns sent bits count on success, otherwise returns libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtTx pointer to Tx buffer * @param szTxBits size of Tx buffer * @param pbtTxPar parameter contains a byte array of the corresponding parity bits needed to send per byte. * This function can be used to transmit (raw) bit-frames to the \e initiator * using the specified NFC device (configured as \e target). */ int nfc_target_send_bits(nfc_device *pnd, const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar) { HAL(target_send_bits, pnd, pbtTx, szTxBits, pbtTxPar); } /** @ingroup target * @brief Receive bit-frames * @return Returns received bits count on success, otherwise returns libnfc's error code * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pbtRx pointer to Rx buffer * @param szRx size of Rx buffer * @param[out] pbtRxPar parameter contains a byte array of the corresponding parity bits * * This function makes it possible to receive (raw) bit-frames. It returns all * the messages that are stored in the FIFO buffer of the \e PN53x chip. It * does not require to send any frame and thereby could be used to snoop frames * that are transmitted by a nearby \e initiator. @note Check out the * NP_ACCEPT_MULTIPLE_FRAMES configuration option to avoid losing transmitted * frames. */ int nfc_target_receive_bits(nfc_device *pnd, uint8_t *pbtRx, const size_t szRx, uint8_t *pbtRxPar) { HAL(target_receive_bits, pnd, pbtRx, szRx, pbtRxPar); } static struct sErrorMessage { int iErrorCode; const char *pcErrorMsg; } sErrorMessages[] = { /* Chip-level errors (internal errors, RF errors, etc.) */ { NFC_SUCCESS, "Success" }, { NFC_EIO, "Input / Output Error" }, { NFC_EINVARG, "Invalid argument(s)" }, { NFC_EDEVNOTSUPP, "Not Supported by Device" }, { NFC_ENOTSUCHDEV, "No Such Device" }, { NFC_EOVFLOW, "Buffer Overflow" }, { NFC_ETIMEOUT, "Timeout" }, { NFC_EOPABORTED, "Operation Aborted" }, { NFC_ENOTIMPL, "Not (yet) Implemented" }, { NFC_ETGRELEASED, "Target Released" }, { NFC_EMFCAUTHFAIL, "Mifare Authentication Failed" }, { NFC_ERFTRANS, "RF Transmission Error" }, { NFC_ECHIP, "Device's Internal Chip Error" }, }; /** @ingroup error * @brief Return the last error string * @return Returns a string * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_strerror(const nfc_device *pnd) { const char *pcRes = "Unknown error"; size_t i; for (i = 0; i < (sizeof(sErrorMessages) / sizeof(struct sErrorMessage)); i++) { if (sErrorMessages[i].iErrorCode == pnd->last_error) { pcRes = sErrorMessages[i].pcErrorMsg; break; } } return pcRes; } /** @ingroup error * @brief Renders the last error in pcStrErrBuf for a maximum size of szBufLen chars * @return Returns 0 upon success * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pcStrErrBuf a string that contains the last error. * @param szBufLen size of buffer */ int nfc_strerror_r(const nfc_device *pnd, char *pcStrErrBuf, size_t szBufLen) { return (snprintf(pcStrErrBuf, szBufLen, "%s", nfc_strerror(pnd)) < 0) ? -1 : 0; } /** @ingroup error * @brief Display the last error occured on a nfc_device * * @param pnd \a nfc_device struct pointer that represent currently used device * @param pcString a string */ void nfc_perror(const nfc_device *pnd, const char *pcString) { fprintf(stderr, "%s: %s\n", pcString, nfc_strerror(pnd)); } /** @ingroup error * @brief Returns last error occured on a nfc_device * @return Returns an integer that represents to libnfc's error code. * * @param pnd \a nfc_device struct pointer that represent currently used device */ int nfc_device_get_last_error(const nfc_device *pnd) { return pnd->last_error; } /* Special data accessors */ /** @ingroup data * @brief Returns the device name * @return Returns a string with the device name * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_device_get_name(nfc_device *pnd) { return pnd->name; } /** @ingroup data * @brief Returns the device connection string * @return Returns a string with the device connstring * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_device_get_connstring(nfc_device *pnd) { return pnd->connstring; } /** @ingroup data * @brief Get supported modulations. * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param mode \a nfc_mode. * @param supported_mt pointer of \a nfc_modulation_type array. * */ int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) { HAL(get_supported_modulation, pnd, mode, supported_mt); } /** @ingroup data * @brief Get supported baud rates (initiator mode). * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param nmt \a nfc_modulation_type. * @param supported_br pointer of \a nfc_baud_rate array. * */ int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) { HAL(get_supported_baud_rate, pnd, N_INITIATOR, nmt, supported_br); } /** @ingroup data * @brief Get supported baud rates for target mode. * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param nmt \a nfc_modulation_type. * @param supported_br pointer of \a nfc_baud_rate array. * */ int nfc_device_get_supported_baud_rate_target_mode(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) { HAL(get_supported_baud_rate, pnd, N_TARGET, nmt, supported_br); } /** @ingroup data * @brief Validate combination of modulation and baud rate on the currently used device. * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param mode \a nfc_mode. * @param nm \a nfc_modulation. * */ static int nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation *nm) { int res; const nfc_modulation_type *nmt = NULL; if ((res = nfc_device_get_supported_modulation(pnd, mode, &nmt)) < 0) { return res; } assert(nmt != NULL); for (int i = 0; nmt[i]; i++) { if (nmt[i] == nm->nmt) { const nfc_baud_rate *nbr = NULL; if (mode == N_INITIATOR) { if ((res = nfc_device_get_supported_baud_rate(pnd, nmt[i], &nbr)) < 0) { return res; } } else { if ((res = nfc_device_get_supported_baud_rate_target_mode(pnd, nmt[i], &nbr)) < 0) { return res; } } assert(nbr != NULL); for (int j = 0; nbr[j]; j++) { if (nbr[j] == nm->nbr) return NFC_SUCCESS; } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG"); return NFC_EINVARG; } } log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG"); return NFC_EINVARG; } /* Misc. functions */ /** @ingroup misc * @brief Returns the library version * @return Returns a string with the library version * * @param pnd \a nfc_device struct pointer that represent currently used device */ const char * nfc_version(void) { #ifdef GIT_REVISION return GIT_REVISION; #else return PACKAGE_VERSION; #endif // GIT_REVISION } /** @ingroup misc * @brief Free buffer allocated by libnfc * * @param pointer on buffer that needs to be freed */ void nfc_free(void *p) { free(p); } /** @ingroup misc * @brief Print information about NFC device * @return Upon successful return, this function returns the number of characters printed (excluding the null byte used to end output to strings), otherwise returns libnfc's error code (negative value) * @param pnd \a nfc_device struct pointer that represent currently used device * @param buf pointer where string will be allocated, then information printed * * @warning *buf must be freed using nfc_free() */ int nfc_device_get_information_about(nfc_device *pnd, char **buf) { HAL(device_get_information_about, pnd, buf); } /** @ingroup string-converter * @brief Convert \a nfc_baud_rate value to string * @return Returns nfc baud rate * @param nbr \a nfc_baud_rate to convert */ const char * str_nfc_baud_rate(const nfc_baud_rate nbr) { switch (nbr) { case NBR_UNDEFINED: return "undefined baud rate"; case NBR_106: return "106 kbps"; case NBR_212: return "212 kbps"; case NBR_424: return "424 kbps"; case NBR_847: return "847 kbps"; } return "???"; } /** @ingroup string-converter * @brief Convert \a nfc_modulation_type value to string * @return Returns nfc modulation type * @param nmt \a nfc_modulation_type to convert */ const char * str_nfc_modulation_type(const nfc_modulation_type nmt) { switch (nmt) { case NMT_ISO14443A: return "ISO/IEC 14443A"; case NMT_ISO14443B: return "ISO/IEC 14443-4B"; case NMT_ISO14443BI: return "ISO/IEC 14443-4B'"; case NMT_ISO14443BICLASS: return "ISO/IEC 14443-2B-3B iClass (Picopass)"; case NMT_ISO14443B2CT: return "ISO/IEC 14443-2B ASK CTx"; case NMT_ISO14443B2SR: return "ISO/IEC 14443-2B ST SRx"; case NMT_FELICA: return "FeliCa"; case NMT_JEWEL: return "Innovision Jewel"; case NMT_BARCODE: return "Thinfilm NFC Barcode"; case NMT_DEP: return "D.E.P."; } return "???"; } /** @ingroup string-converter * @brief Convert \a nfc_target content to string * @return Upon successful return, this function returns the number of characters printed (excluding the null byte used to end output to strings), otherwise returns libnfc's error code (negative value) * @param pnt \a nfc_target struct pointer to print * @param buf pointer where string will be allocated, then nfc target information printed * @param verbose false for essential, true for detailed, human-readable, information * * @warning *buf must be freed using nfc_free() */ int str_nfc_target(char **buf, const nfc_target *pnt, bool verbose) { *buf = malloc(4096); if (! *buf) return NFC_ESOFT; (*buf)[0] = '\0'; snprint_nfc_target(*buf, 4096, pnt, verbose); return strlen(*buf); }