added mfcuk + fix compil on Visaul studio 2022 (via Cmake)

mfcuk  added to utils
cmakelist modified
acr122_usb.C et pn53x_usb.c modified to remove errors when compiling on Visual Studio 2022 on Windows
This commit is contained in:
Xavier AVERBOUCH 2022-11-01 21:07:44 +01:00
parent 5f71a79b56
commit d5bbda3d67
137 changed files with 17707 additions and 2958 deletions

85
.gitignore vendored
View File

@ -1,16 +1,21 @@
**/.deps/
**/.libs/
**/Makefile
**/Makefile.in
*.exe
*.la
*.lo
*.o
*~ *~
.vs/
CMakeSettings.json
Doxyfile Doxyfile
INSTALL INSTALL
Makefile
Makefile.in
aclocal.m4 aclocal.m4
ar-lib ar-lib
autom4te.cache/ autom4te.cache/
build build
cmake/Makefile compile
cmake/Makefile.in
cmake/modules/Makefile
cmake/modules/Makefile.in
config.guess config.guess
config.h config.h
config.h.in config.h.in
@ -18,23 +23,8 @@ config.log
config.status config.status
config.sub config.sub
configure configure
contrib/Makefile
contrib/Makefile.in
contrib/devd/Makefile
contrib/devd/Makefile.in
contrib/udev/Makefile
contrib/udev/Makefile.in
contrib/win32/Makefile
contrib/win32/Makefile.in
contrib/win32/sys/Makefile
contrib/win32/sys/Makefile.in
debian/ debian/
depcomp depcomp
examples/*.o
examples/.deps/
examples/.libs/
examples/Makefile
examples/Makefile.in
examples/nfc-anticol examples/nfc-anticol
examples/nfc-dep-initiator examples/nfc-dep-initiator
examples/nfc-dep-target examples/nfc-dep-target
@ -47,44 +37,10 @@ examples/nfc-relay
examples/pn53x-diagnose examples/pn53x-diagnose
examples/pn53x-sam examples/pn53x-sam
examples/pn53x-tamashell examples/pn53x-tamashell
examples/pn53x-tamashell-scripts/Makefile
examples/pn53x-tamashell-scripts/Makefile.in
examples/quick_start_example1 examples/quick_start_example1
examples/quick_start_example2 examples/quick_start_example2
include/Makefile
include/Makefile.in
include/nfc/Makefile
include/nfc/Makefile.in
install-sh install-sh
libnfc.pc libnfc.pc
libnfc/*.lo
libnfc/*.o
libnfc/.deps/
libnfc/.libs/
libnfc/Makefile
libnfc/Makefile.in
libnfc/buses/*.la
libnfc/buses/*.lo
libnfc/buses/*.o
libnfc/buses/.deps/
libnfc/buses/.libs/
libnfc/buses/Makefile
libnfc/buses/Makefile.in
libnfc/chips/*.la
libnfc/chips/*.lo
libnfc/chips/*.o
libnfc/chips/.deps/
libnfc/chips/.libs/
libnfc/chips/Makefile
libnfc/chips/Makefile.in
libnfc/drivers/*.la
libnfc/drivers/*.lo
libnfc/drivers/*.o
libnfc/drivers/.deps/
libnfc/drivers/.libs/
libnfc/drivers/Makefile
libnfc/drivers/Makefile.in
libnfc/libnfc.la
libtool libtool
ltmain.sh ltmain.sh
m4/libtool.m4 m4/libtool.m4
@ -94,21 +50,12 @@ m4/ltversion.m4
m4/lt~obsolete.m4 m4/lt~obsolete.m4
missing missing
stamp-h1 stamp-h1
test/*.la test-driver
test/*.lo test/run-test.sh.log
test/*.o test/run-test.sh.trs
test/.deps/ test/test-suite.log
test/.libs/
test/Makefile
test/Makefile.in
utils/*.la
utils/*.lo
utils/*.o
utils/.deps/
utils/.libs/
utils/Makefile
utils/Makefile.in
utils/nfc-emulate-forum-tag4 utils/nfc-emulate-forum-tag4
utils/nfc-jewel
utils/nfc-list utils/nfc-list
utils/nfc-mfclassic utils/nfc-mfclassic
utils/nfc-mfultralight utils/nfc-mfultralight

81
.travis.yml Normal file
View File

@ -0,0 +1,81 @@
language: c
matrix:
include:
- os: windows
compiler:
- clang
before_install:
- mkdir build && cd build && wget "https://sourceforge.net/projects/libusb-win32/files/libusb-win32-releases/1.2.6.0/libusb-win32-bin-1.2.6.0.zip" && 7z x libusb-win32-bin-1.2.6.0.zip -o"$PROGRAMFILES" && mv "$PROGRAMFILES/libusb-win32-bin-1.2.6.0" "$PROGRAMFILES/libusb-win32"
install:
choco install doxygen.install ninja
script:
cmake -GNinja .. && cmake --build .
- os: linux
dist: bionic
compiler:
- clang
addons:
apt:
packages:
- libusb-dev
- doxygen
- cmake
script:
- mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install
- os: linux
dist: bionic
compiler:
- clang
addons:
apt:
packages:
- libusb-dev
- doxygen
script:
- autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install
- os: linux
dist: bionic
compiler:
- gcc
addons:
apt:
packages:
- libusb-dev
- doxygen
- cmake
script:
- mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install
- os: linux
dist: bionic
compiler:
- gcc
addons:
apt:
packages:
- libusb-dev
- doxygen
script:
- autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install
- os: osx
osx_image: xcode12
compiler:
- clang
before_install:
- brew install doxygen libusb-compat
script:
- mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install
- os: osx
osx_image: xcode12
compiler:
- clang
before_install:
- brew install doxygen libusb-compat m4
script:
- autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install

32
AUTHORS
View File

@ -2,16 +2,48 @@
Adam Laurie <adam@algroup.co.uk> Adam Laurie <adam@algroup.co.uk>
Ahti Legonkov <ahti.legonkov@gmail.com> Ahti Legonkov <ahti.legonkov@gmail.com>
Alex Lian <alian@alum.mit.edu> Alex Lian <alian@alum.mit.edu>
Alexander Inyukhin <shurick@sectorb.msk.ru>
Anugrah Redja Kusuma <anugrah.redja@gmail.com> Anugrah Redja Kusuma <anugrah.redja@gmail.com>
Audrey Diacre <adiacre@il4p.fr> Audrey Diacre <adiacre@il4p.fr>
Boris Moiseev <cyberbobs@gmail.com>
Christoph Gritschenberger <christoph.gritschenberger@gmail.com>
Dario Carluccio <dario.carluccio@gmail.com>
David Kreitschmann <david@kreitschmann.de>
Emanuele Bertoldi <emanuele.bertoldi@gmail.com> Emanuele Bertoldi <emanuele.bertoldi@gmail.com>
Emmanuel Dreyfus <manu@netbsd.org>
Eugeny Boger <eugenyboger@gmail.com> Eugeny Boger <eugenyboger@gmail.com>
Francois Kooman <fkooman@tuxed.net> Francois Kooman <fkooman@tuxed.net>
Frank Morgner <frankmorgner@gmail.com>
Frédéric Bourgeois <bourgeoislab@gmail.com>
Hidde Wieringa <hidde@hiddewieringa.nl>
Jairo Andres Suarez <andres4005@gmail.com>
Jiapeng Li <gapleehit@gmail.com>
Jim Anastassiou <jim.anastassiou@gmail.com>
John Galt <centromere@users.noreply.github.com>
Julien Ehrhart <julien.ehrhart@live.com>
Julien Schueller <julien.schueller@gmail.com> Julien Schueller <julien.schueller@gmail.com>
Laurent Latil <laurent@latil.nom.fr> Laurent Latil <laurent@latil.nom.fr>
Ludovic Rousseau <ludovic.rousseau@gmail.com> Ludovic Rousseau <ludovic.rousseau@gmail.com>
Marcello Morena <marcello.morena@gmail.com>
Marcos Vives Del Sol <socram8888@gmail.com>
Mati Vait <mativait@gmail.com>
Maxim Martyanov <llorephie@gmail.com>
Mike Auty <mike.auty@gmail.com>
Nobuhiro Iwamatsu <iwamatsu@nigauri.org> Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
Olliver Schinagl <oliver@schinagl.nl>
Paul Menzel <paul.menzel@giantmonkey.de>
Peter Meerwald <pmeerw@pmeerw.net>
Philippe Teuwen <yobibe@gmail.com> Philippe Teuwen <yobibe@gmail.com>
Pim 't Hart <pimmeyproductions@gmail.com>
Ray Lee <rayleesky@outlook.com>
Roel Verdult <roel@libnfc.org> Roel Verdult <roel@libnfc.org>
Romain Tartiere <romain.tartiere@gmail.com> Romain Tartiere <romain.tartiere@gmail.com>
Romuald Conty <romuald@libnfc.org> Romuald Conty <romuald@libnfc.org>
Simon Yorkston <simon.yorkston@gmail.com>
bhack <s.fabri@email.it>
lego <lego@debian-fresh.prx>
quantum-x <simon.yorkston@gmail.com>
timzi <developers@make-gadget.ru>
xantares <xantares09@hotmail.com>
xaqq <kapp.arno@gmail.com>
yerzhanm <yerzhan.mukhamejan@gmail.com>

View File

@ -1,7 +1,13 @@
PROJECT(libnfc C) cmake_minimum_required (VERSION 2.6)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
if (NOT DEFINED CMAKE_BUILD_TYPE)
set (CMAKE_BUILD_TYPE Release CACHE STRING "Build type")
endif ()
project (libnfc C)
SET(VERSION_MAJOR "1") SET(VERSION_MAJOR "1")
SET(VERSION_MINOR "7") SET(VERSION_MINOR "8")
SET(VERSION_PATCH "0") SET(VERSION_PATCH "0")
SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
@ -12,29 +18,33 @@ SET(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
# config.h # config.h
IF(WIN32) IF(WIN32)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) SET(LIBNFC_SYSCONFDIR "./config" CACHE PATH "libnfc configuration directory")
SET(LIBNFC_SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/config" CACHE PATH "libnfc configuration directory") CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32)
IF(NOT MINGW)
SET(CMAKE_C_FLAGS "-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE ${CMAKE_C_FLAGS}")
ENDIF(NOT MINGW)
ELSE(WIN32) ELSE(WIN32)
SET(_XOPEN_SOURCE 600) SET(_XOPEN_SOURCE 600)
SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory") SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
ENDIF(WIN32) ENDIF(WIN32)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
ADD_DEFINITIONS("-DHAVE_CONFIG_H") ADD_DEFINITIONS("-DHAVE_CONFIG_H")
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include)
# make it easy to locate CMake modules for finding libraries # make it easy to locate CMake modules for finding libraries
SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules/")
# Options # Options
SET(LIBNFC_LOG ON CACHE BOOL "Enable log facility (errors, warning, info and debug messages)") option (LIBNFC_LOG "Enable log facility (errors, warning, info and debug messages)" ON)
IF(LIBNFC_LOG) IF(LIBNFC_LOG)
ADD_DEFINITIONS(-DLOG) ADD_DEFINITIONS(-DLOG)
ENDIF(LIBNFC_LOG) ENDIF(LIBNFC_LOG)
SET(LIBNFC_ENVVARS ON CACHE BOOL "Enable envvars facility") option (LIBNFC_ENVVARS "Enable envvars facility" ON)
IF(LIBNFC_ENVVARS) IF(LIBNFC_ENVVARS)
ADD_DEFINITIONS(-DENVVARS) ADD_DEFINITIONS(-DENVVARS)
ENDIF(LIBNFC_ENVVARS) ENDIF(LIBNFC_ENVVARS)
@ -49,6 +59,17 @@ ELSE(LIBNFC_DEBUG_MODE)
SET(WIN32_MODE "release") SET(WIN32_MODE "release")
ENDIF(LIBNFC_DEBUG_MODE) ENDIF(LIBNFC_DEBUG_MODE)
option (LIBNFC_CONFFILES_MODE "Enable configuration files" ON)
IF(LIBNFC_CONFFILES_MODE)
ADD_DEFINITIONS(-DCONFFILES)
ENDIF(LIBNFC_CONFFILES_MODE)
option (BUILD_EXAMPLES "build examples ON/OFF" ON)
option (BUILD_UTILS "build utils ON/OFF" ON)
option (BUILD_DEBPKG "build debian package ON/OFF" OFF)
# Doxygen # Doxygen
SET(builddir "${CMAKE_BINARY_DIR}") SET(builddir "${CMAKE_BINARY_DIR}")
SET(top_srcdir "${CMAKE_SOURCE_DIR}") SET(top_srcdir "${CMAKE_SOURCE_DIR}")
@ -82,12 +103,34 @@ ENDIF(CMAKE_COMPILER_IS_GNUCC)
ADD_DEFINITIONS(-Du_int8_t=uint8_t -Du_int16_t=uint16_t) ADD_DEFINITIONS(-Du_int8_t=uint8_t -Du_int16_t=uint16_t)
IF(MINGW) IF(MINGW)
# force MinGW-w64 in 32bit mode IF (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}") # force MinGW-w64 in 32bit mode
SET(CMAKE_MODULE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}")
SET(CMAKE_SHARED_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") SET(CMAKE_MODULE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}")
SET(CMAKE_EXE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}") SET(CMAKE_SHARED_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}")
SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}") SET(CMAKE_EXE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}")
SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}")
ELSE(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
# force MinGW-w64 in 32bit mode
MESSAGE("Building 32-bit Windows DLL")
#SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}")
#SET(CMAKE_MODULE_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}")
#SET(CMAKE_SHARED_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}")
#SET(CMAKE_EXE_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}")
SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}")
ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
MESSAGE("Building 64-bit Windows DLL")
SET(CMAKE_RC_FLAGS "--target=pe-x86-64 --output-format=coff ${CMAKE_RC_FLAGS}")
ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
MESSAGE(FATAL_ERROR "Unknown Processor: ${CMAKE_SYSTEM_PROCESSOR}")
ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86")
ENDIF(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
FIND_PROGRAM(DLLTOOL dlltool CMAKE_FIND_ROOT_PATH_BOTH)
IF (NOT DLLTOOL)
MESSAGE(FATAL_ERROR "Could not find dlltool command")
ENDIF (NOT DLLTOOL)
ENDIF(MINGW) ENDIF(MINGW)
IF(NOT WIN32) IF(NOT WIN32)
@ -98,26 +141,39 @@ IF(NOT WIN32)
IF(LIBNFC_DRIVER_PN53X_USB) IF(LIBNFC_DRIVER_PN53X_USB)
SET(PKG_REQ ${PKG_REQ} "libusb") SET(PKG_REQ ${PKG_REQ} "libusb")
ENDIF(LIBNFC_DRIVER_PN53X_USB) ENDIF(LIBNFC_DRIVER_PN53X_USB)
IF(LIBNFC_DRIVER_ACR122) IF(LIBNFC_DRIVER_ACR122_USB)
SET(PKG_REQ ${PKG_REQ} "libusb")
ENDIF(LIBNFC_DRIVER_ACR122_USB)
IF(LIBNFC_DRIVER_PCSC)
SET(PKG_REQ ${PKG_REQ} "libpcsclite") SET(PKG_REQ ${PKG_REQ} "libpcsclite")
ENDIF(LIBNFC_DRIVER_ACR122) ENDIF(LIBNFC_DRIVER_PCSC)
IF(LIBNFC_DRIVER_ACR122_PCSC)
SET(PKG_REQ ${PKG_REQ} "libpcsclite")
ENDIF(LIBNFC_DRIVER_ACR122_PCSC)
# CMake lists are separated by a semi colon, replace with colon # CMake lists are separated by a semi colon, replace with colon
STRING(REPLACE ";" "," PKG_CONFIG_REQUIRES "${PKG_REQ}") STRING(REPLACE ";" "," PKG_CONFIG_REQUIRES "${PKG_REQ}")
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libnfc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libnfc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc @ONLY)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
ENDIF(NOT WIN32) ENDIF(NOT WIN32)
# Require PCRE for Win32
IF (WIN32)
FIND_PACKAGE(PCRE REQUIRED)
IF(PCRE_INCLUDE_DIRS)
INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIRS})
LINK_DIRECTORIES(${PCRE_LIBRARY_DIRS})
ENDIF(PCRE_INCLUDE_DIRS)
ENDIF(WIN32)
INCLUDE(LibnfcDrivers) INCLUDE(LibnfcDrivers)
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(I2C_REQUIRED)
# Inspired from http://cmake.3232098.n2.nabble.com/RFC-cmake-analog-to-AC-SEARCH-LIBS-td7585423.html
INCLUDE (CheckFunctionExists)
INCLUDE (CheckLibraryExists)
CHECK_FUNCTION_EXISTS (clock_gettime HAVE_CLOCK_GETTIME)
IF (NOT HAVE_CLOCK_GETTIME)
CHECK_LIBRARY_EXISTS (rt clock_gettime "" HAVE_CLOCK_GETTIME_IN_RT)
IF (HAVE_CLOCK_GETTIME_IN_RT)
SET(LIBRT_FOUND TRUE)
SET(LIBRT_LIBRARIES "rt")
ENDIF (HAVE_CLOCK_GETTIME_IN_RT)
ENDIF (NOT HAVE_CLOCK_GETTIME)
ENDIF(I2C_REQUIRED)
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
IF(PCSC_INCLUDE_DIRS) IF(PCSC_INCLUDE_DIRS)
INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS})
LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS}) LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS})
@ -131,39 +187,118 @@ ENDIF(LIBUSB_INCLUDE_DIRS)
# version.rc for Windows # version.rc for Windows
IF(WIN32) IF(WIN32)
# Date for filling in rc file information
IF(NOT MINGW) IF (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
# Date for filling in rc file information
MACRO (GET_CURRENT_YEAR RESULT) MACRO (GET_CURRENT_YEAR RESULT)
EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT}) EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT})
STRING(REGEX REPLACE ".*(..)/(..)/(....).*" "\\3" ${RESULT} ${${RESULT}}) STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}})
STRING(REGEX REPLACE ".*(..)/(..)/(....).*" "\\3" ${RESULT} ${${RESULT}})
ENDMACRO (GET_CURRENT_YEAR) ENDMACRO (GET_CURRENT_YEAR)
GET_CURRENT_YEAR(CURRENT_YEAR) ELSE(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
MESSAGE("Year for copyright is " ${CURRENT_YEAR}) MACRO (GET_CURRENT_YEAR RESULT)
ENDIF() EXECUTE_PROCESS(COMMAND "date" "+%Y" OUTPUT_VARIABLE ${RESULT})
STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}})
ENDMACRO (GET_CURRENT_YEAR)
ENDIF(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
GET_CURRENT_YEAR(CURRENT_YEAR)
MESSAGE("Year for copyright is " ${CURRENT_YEAR})
SET(prefix ${CMAKE_INSTALL_PREFIX})
SET(RC_COMMENT "${PACKAGE_NAME} library") SET(RC_COMMENT "${PACKAGE_NAME} library")
SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}") SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}")
SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll) SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll)
SET(RC_FILE_TYPE VFT_DLL) # RC_FILE_TYPE: VFT_DLL
SET(RC_FILE_TYPE 0x00000002L)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/windows/libnfc.rc @ONLY)
ENDIF(WIN32) ENDIF(WIN32)
ADD_SUBDIRECTORY(libnfc) ADD_SUBDIRECTORY(libnfc)
ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(include)
ADD_SUBDIRECTORY(utils)
ADD_SUBDIRECTORY(examples) if (BUILD_UTILS)
add_subdirectory (utils)
endif ()
if (BUILD_EXAMPLES)
add_subdirectory (examples)
endif ()
if (NOT MSVC)
# config script install path
if ( NOT DEFINED LIBNFC_CMAKE_CONFIG_DIR )
set ( LIBNFC_CMAKE_CONFIG_DIR lib${LIB_SUFFIX}/cmake/libnfc )
endif ()
set ( LIBNFC_INCLUDE_DIR ${includedir} )
set ( LIBNFC_INCLUDE_DIRS ${LIBNFC_INCLUDE_DIR} )
list ( APPEND LIBNFC_INCLUDE_DIRS ${LIBUSB_INCLUDE_DIRS} )
set ( LIBNFC_LIBRARY nfc )
set ( LIBNFC_LIBRARIES ${LIBNFC_LIBRARY} )
list ( APPEND LIBNFC_LIBRARIES ${LIBUSB_LIBRARIES} )
set ( LIBNFC_LIBRARY_DIRS ${libdir} )
set ( LIBNFC_ROOT_DIR ${prefix} )
set ( LIBNFC_VERSION_STRING ${VERSION} )
set ( LIBNFC_VERSION_MAJOR ${VERSION_MAJOR} )
set ( LIBNFC_VERSION_MINOR ${VERSION_MINOR} )
set ( LIBNFC_VERSION_PATCH ${VERSION_PATCH} )
set ( LIBNFC_USE_FILE ${CMAKE_INSTALL_PREFIX}/${LIBNFC_CMAKE_CONFIG_DIR}/UseLibNFC.cmake )
if(CMAKE_VERSION VERSION_LESS 2.8.8)
configure_file ( cmake/LibNFCConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfig.cmake @ONLY )
configure_file ( cmake/LibNFCConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfigVersion.cmake @ONLY )
else ()
include(CMakePackageConfigHelpers)
configure_package_config_file (
cmake/LibNFCConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfig.cmake
INSTALL_DESTINATION ${LIBNFC_CMAKE_CONFIG_DIR}
PATH_VARS
LIBNFC_USE_FILE
LIBNFC_ROOT_DIR
LIBNFC_INCLUDE_DIR
LIBNFC_INCLUDE_DIRS
LIBNFC_LIBRARY_DIRS
NO_CHECK_REQUIRED_COMPONENTS_MACRO
)
write_basic_package_version_file (
LibNFCConfigVersion.cmake
VERSION ${LIBNFC_VERSION_STRING}
COMPATIBILITY AnyNewerVersion
)
endif ()
install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfigVersion.cmake
cmake/UseLibNFC.cmake
DESTINATION ${LIBNFC_CMAKE_CONFIG_DIR}
)
endif ()
# Binary Package # Binary Package
IF(WIN32) IF(WIN32)
SET(CPACK_GENERATOR "ZIP") SET(CPACK_GENERATOR "ZIP")
ELSE(WIN32) ELSE(WIN32)
SET(CPACK_GENERATOR "TBZ2") SET(CPACK_GENERATOR "TBZ2")
IF(BUILD_DEBPKG)
SET(CPACK_GENERATOR "DEB")
ENDIF(BUILD_DEBPKG)
ENDIF(WIN32) ENDIF(WIN32)
SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Near Field Communication (NFC) library") SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Near Field Communication (NFC) library")
SET(CPACK_PACKAGE_VENDOR "Roel Verdult") SET(CPACK_PACKAGE_VENDOR "Roel Verdult")
SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") SET(CPACK_PACKAGE_CONTACT "Roel Verdult <roel@libnfc.org>")
#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_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
SET(CPACK_PACKAGE_INSTALL_DIRECTORY "libnfc") SET(CPACK_PACKAGE_INSTALL_DIRECTORY "libnfc")
SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})

112
ChangeLog
View File

@ -1,5 +1,88 @@
TBD - 1.7.0.99~rc1 May 22, 2020 - 1.8.0
------------------ --------------------
Fixes:
- Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1
Changes:
- Bump revision due to changes in API introduced in v1.7.2
- Bump library version to 6.0.0
May 21, 2020 - 1.7.2 (avoid using it, incompatible with 1.7.1)
--------------------
Fixes:
- Remove unreachable code
- nfc_emulate_uid: cleaner exit on interrupt
- Fix reporting of modulations and baud rates by nfc-scan-device -v
- Fix out-of-bounds access in nfc-mfultralight
- Several Cygwin compilation fixes
- Fix comparison when nfc_initiator_target_is_present() with a specified target
- Fix nfc_initiator_poll_target without tag on PN532
- Export iso14443b* symbols
- Fix udev rule which was executed too early
- Fix improper device name initialization
- Fix setenv()/unsetenv() for Windows
- Fix win32/nfc.def according to nfc.h
- Fix missing timeout in pn53x_initiator_select_passive_target()
- nfc-mfclassic: fix option to tolerate write errors
- nfc-poll: fix card removing check
- nfc-relay-picc: fix wrong open mode for file descriptor
Improvements:
- Allow ISO14443A to be used at higher baud rates
- nfc_initiator_select_passive_target() now checks against
reported modulations and baud rates for current device
- More serial devices on MAC OS X
- Add section to README to help to configure libnfc
- Various cmake improvements
- Drop PCRE dependency on Windows
- Remove deprecated readdir_r
- Markdown conversion of the text files
- Use hardcoded PN533 descriptors to be more robust on Windows
- Add support for SCL3712
- Add support for ACR1222U-C1
- Add support for NetBSD
- Add support for PN532 on RPi3 UART
- Add support for cross-compilation of 32b & 64b versions of the library for Windows
- Add pn533_usb to the kernel modules blacklist
- Add support for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested)
- Add support for contactless PC/SC readers (only as initiator)
- Add support for Feitian R502 and bR500 into pcsc driver
- Add support for HID iClass (Picopass) support (nfc-iclass tool in external nfc-tools repo)
- Allows for sending empty data in nfc_initiator_transceive_bits
- driver i2c: respect proper timing specifications
- driver i2c: add retry on error mechanism
- nfc-mfclassic: improvements fo magic cards
- nfc-mfclassic: add option to specify UID
- nfc-mfclassic/nfc-mfsetuid: add support for new gen (1b) of magic 4K cards
- nfc-mfclassic: Add RATS support indicator
- nfc-mfsetuid: allow to write complete Block0, instead of only UID
- nfc-mfultralight: add automatic modes and --check-magic
- nfc-mfultralight: add support for magic gen2 cards
- nfc-mfultralight: add option to specify UID
- nfc-mfultralight: add support for Ultralight NTAG213/215/216
- nfc-barcode: new command to read and decode NFC Barcodes (Tag-Talks-First)
Changes:
- nfc_device_get_supported_baud_rate() takes now a "mode" parameter
- New nfc_device_get_supported_baud_rate_target_mode()
- New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol
- New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass)
- pn53x_transceive() is now part of public API
Special thanks to:
- Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus,
Julien Ehrhart, S. Fabri, John Galt, Christoph Gritschenberger,
Alexander Inyukhin, Arnaud Kapp, David Kreitschmann, Adam Laurie, Ray Lee,
Maxim Martyanov, Paul Menzel, Boris Moiseev, Yerzhan Mukhamejan,
Olliver Shinagl, Jairo Andres Suarez, Mati Vait, Marcos Vives Del Sol,
Hidde Wieringa, Simon Yorkston, timzi, usk-johnny-s, xantares, Hanno
Heinrichs, jgeslin, Mikolaj Stawiski, rstular, Khem Raj, Frank Morgner, jpwidera,
Feitian Technologies
Feb 24, 2014 - 1.7.1
--------------------
Fixes: Fixes:
- Fix several issues reported by Coverity Scan - Fix several issues reported by Coverity Scan
@ -7,6 +90,10 @@ Fixes:
- More robust when several conflicting uart drivers are in the config - More robust when several conflicting uart drivers are in the config
- Fix racing condition with uart_flush_input() - Fix racing condition with uart_flush_input()
- Silent pn53x_check_communication error messages when scanning - Silent pn53x_check_communication error messages when scanning
- Fix nfc_target_init(), was returning success in case of timeout
- Windows: fix several compilation issues
- On tag selection, save current target info also for ISO14443B*
- nfc-read-forum-tag3: fix incomplete NDEF retrieval and size of output file
Improvements: Improvements:
- nfc-list: New option to choose which technologies to poll for - nfc-list: New option to choose which technologies to poll for
@ -14,6 +101,27 @@ Improvements:
- New LIBNFC_DEVICE env var to use one reader and exclude all other readers - New LIBNFC_DEVICE env var to use one reader and exclude all other readers
while LIBNFC_DEFAULT_DEVICE only prepends it to the configured devices list while LIBNFC_DEFAULT_DEVICE only prepends it to the configured devices list
- New LIBNFC_AUTO_SCAN env var to enable(default)/disable auto scan - New LIBNFC_AUTO_SCAN env var to enable(default)/disable auto scan
- On tag selection, save current target info even if pnt=NULL
- On tag selection, grant NP_INFINITE_SELECT also for ISO14443B*
- Save & restore NP_INFINITE_SELECT status when changing it internally
- nfc-mfclassic: add format/wipe command (thanks to Adam Laurie)
- nfc-jewel: new utility to read/write Topaz/Jewel tags (thanks to Pim 't Hart)
- nfc_initiator_select_passive_target() provides defaults if pbtInitData=NULL
- nfc-read-forum-tag3: add -q option, add full parsing of NDEF Attribute Block
Fixes & improvements specific to nfc_initiator_target_is_present():
- Supports fully PN532 & PN533, not tested on other chips
- Fix usage after nfc_initiator_poll_target()
- Set correctly last_error
- Fix issue when there was no saved target
- Allow NULL pointer to tag
- Fix issues in case of tear off conditions
- Now works with:
* MFUL, MFC, MFC Mini, MFC 7-byte (re-selection: you'll need to auth again)
* ISO14443-4A, ISO14443-4B
* ISO14443-4B', ASK CTx, ST SRx
* Jewel
* FeliCa
Sep 03, 2013 - 1.7.0 Sep 03, 2013 - 1.7.0
-------------------- --------------------

File diff suppressed because it is too large Load Diff

68
HACKING.md Normal file
View File

@ -0,0 +1,68 @@
Hello hackers!
General remarks about contributing
----------------------------------
Contributions to the libnfc are welcome!
Here are some directions to get you started:
1. Follow style conventions
The source code of the library trend to follow some conventions so that it
is consistent in style and thus easier to read.
Look around and respect the same style.
Don't use tabs. Increment unit is two spaces.
Don't leave dandling spaces or tabs at EOL.
Helper script to get some uniformity in the style:
$ make style
If you use vim see the [Vim: How to prevent trailing whitespaces](http://www.carbon-project.org/Vim__How_to_prevent_trailing_whitespaces.html).
2. Chase warnings: no warning should be introduced by your changes
Depending what you touch, you can check with:
2.1 When using autotools
$ autoreconf -Wall -vis
2.2 When compiling
2.2.1 Using extra flags:
$ export CFLAGS="-Wall -g -O2 -Wextra -pipe -funsigned-char -fstrict-aliasing \
-Wchar-subscripts -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wunused \
-Wuninitialized -Wpointer-arith -Wredundant-decls -Winline -Wformat \
-Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs \
-Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition \
-Wbad-function-cast -Wnested-externs -Wmissing-declarations"
$ ./configure
$ make clean
$ make
2.2.2 Using clang:
You can use same CFLAGS but also `-Wunreachable-code`
$ scan-build ./configure
$ make clean
$ scan-build make
2.2.3 Using `cppcheck` (v1.58 or higher):
$ make cppcheck
2.3 When Debianizing
$ lintian --info --display-info --display-experimental *deb
or (shorter version)
$ lintian -iIE *deb
3. Preserve cross-platform compatibility
The source code should remain compilable across various platforms,
including some you probably cannot test alone so keep it in mind.
Supported platforms:
- Linux
- FreeBSD
- Mac OS X
- Windows with MinGW

View File

@ -2,7 +2,13 @@ ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = $(LIBNFC_CFLAGS) AM_CFLAGS = $(LIBNFC_CFLAGS)
SUBDIRS = libnfc utils examples include contrib cmake test SUBDIRS = libnfc utils
if EXAMPLE_ENABLED
SUBDIRS += examples
endif
SUBDIRS += include contrib cmake test
pkgconfigdir = $(libdir)/pkgconfig pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnfc.pc pkgconfig_DATA = libnfc.pc
@ -10,8 +16,12 @@ pkgconfig_DATA = libnfc.pc
EXTRA_DIST = \ EXTRA_DIST = \
CMakeLists.txt \ CMakeLists.txt \
Doxyfile \ Doxyfile \
README-Windows.txt \ HACKING.md \
libnfc.conf.sample NEWS.md \
README.md \
README-Windows.md \
libnfc.conf.sample \
mingw-cross-compile.sh
CLEANFILES = Doxygen.log coverage.info libnfc.pc CLEANFILES = Doxygen.log coverage.info libnfc.pc
@ -34,7 +44,7 @@ style:
find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \
--indent=spaces=2 --indent-switches --indent-preprocessor \ --indent=spaces=2 --indent-switches --indent-preprocessor \
--keep-one-line-blocks --max-instatement-indent=60 \ --keep-one-line-blocks --max-instatement-indent=60 \
--brackets=linux --pad-oper --unpad-paren --pad-header \ --style=linux --pad-oper --unpad-paren --pad-header \
--align-pointer=name {} \; --align-pointer=name {} \;
cppcheck: cppcheck:

394
NEWS.md Normal file
View File

@ -0,0 +1,394 @@
New in 1.8.0:
API Changes:
- Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1
- Bump library version to 6.0.0
New in 1.7.2:
Drivers:
* New driver for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested)
* New driver for contactless PC/SC readers (only as initiator)
API Changes:
* nfc_device_get_supported_baud_rate() now takes also "mode" as argument
* New nfc_device_get_supported_baud_rate_target_mode()
* New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol
* New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass)
* pn53x_transceive() is now part of public API
New in 1.7.1:
API Changes:
* nfc_initiator_select_passive_target() provides defaults if pbtInitData=NULL
* nfc_initiator_target_is_present() allow NULL pointer to tag
New in 1.7.0:
Drivers:
* New PN532 over I2C driver, see contrib/libnfc/pn532_i2c_on_rpi.conf.sample
API Changes:
* New function iso14443b_crc_append()
New in 1.7.0-rc7:
Drivers:
* New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample
API Changes:
* Functions
- nfc_initiator_target_is_present() & str_nfc_target():
now take a pointer to nfc_target as argument
- nfc_init(): upon malloc error, doesn't force exit() anymore
so now you should test if context != NULL after nfc_init() call
New in 1.7.0-rc5:
API Changes:
* Functions
- New nfc_register_driver() function allowing to hook custom drivers.
New in 1.7.0-rc3:
API Changes:
* Functions
- Add timeout param to nfc_emulate_target()
New in 1.7.0-rc2:
Configuration:
libnfc can now use a configuration file for special setups, or features
activation. This file (/etc/nfc/libnfc.conf under GNU/Linux systems)
supports already some keywords:
- "allow_autoscan" to enable/disable device auto-detection feature;
- "allow_intrusive_scan" to enable/disable intrusive auto-detection
(ie. serial port probing);
- "log_level" to select library verbosity;
- "device.name" and "device.connstring" to define a user device,
this is the recommended method if user has a not easily detectable
device (ie. a serial one).
It is also possible to define devices using dedicated configuration files and
put them into device search directory (/etc/nfc/devices.d under GNU/Linux).
Example for the OpenPCD2: create /etc/nfc/devices.d/openpcd2.conf with:
name = "OpenPCD2"
connstring = "pn532_uart:/dev/ttyACM0"
optional = true
The keyword "optional" does not mandate the device to be present always
(it detects if the reader is indeed present before using it)
API Changes:
* Types
- New NFC_ESOFT error to handle software errors (allocations, pipe
creation, etc.)
* Functions
- Remove nfc_get_default_device() function: the default device is now the
first in nfc_list_devices() or could be open using NULL connstring with
nfc_open() function.
- New enum-to-string converter functions str_nfc_modulation_type() and
str_nfc_baud_rate()
- New str_nfc_target() to convert nfc_target struct into allocated string
- New nfc_device_get_information_about() function to retreive some device's
information
- No more in/out function parameter: nfc_initiator_transceive_*() now
take a constant size for Rx buffer
- New nfc_initiator_target_is_present() to test is the previously selected
target is available in the field
- nfc_initiator_transceive_bytes() returns NFC_EMFCAUTHFAIL when AUTH
command failed on a Mifare Classic
- New nfc_initiator_init_secure_element() to initiate a connection with
secure element (Only supported with a PN532 with SAM equipped)
New in 1.6.0-rc1:
API Changes:
* Types
- '_t' suffix removed from all types (e.g. nfc_device_t is now nfc_device)
- All errors removed in flavour of NFC_EIO, NFC_EINVARG, NFC_EDEVNOTSUPP,
NFC_ENOTSUCHDEV, NFC_EOVFLOW, NFC_ETIMEOUT, NFC_EOPABORTED, NFC_ENOTIMPL,
NFC_ETGRELEASED, NFC_ERFTRANS, NFC_ECHIP and NFC_SUCCESS
- nfc_device_desc_t replaced by nfc_connstring: libnfc now uses connection
strings to describe a device
- byte_t typedef removed, libnfc now uses uint8_t from C99
- nfc_device is now an opaque type
- nfc_properties replaces nfc_options
* Functions
- New nfc_get_default_device() function that allows to grab the connstring
stored in LIBNFC_DEFAULT_DEVICE environnement variable or returns the
first available device if not set
- New nfc_device_get_connstring() accessor function to know the device
connstring
- New nfc_device_set_property_bool() function that replace nfc_configure()
- New nfc_device_set_property_int() function to set integer property
- nfc_device_name() renamed to nfc_device_get_name() for the sake of
consistency
- New nfc_device_get_last_error() function, an accessor to last error occured
- Whole libnfc's functions now return 0 (NFC_SUCCESS) or positive value if
appropriated on success and libnfc's error code on failure
- nfc_connect(), nfc_disconnect() renamed to nfc_open(), nfc_close()
respectively
- Add 2 new functions: initialization and deinitialization functions:
nfc_init() and nfc_exit()
- New nfc_device_get_supported_modulation() and
nfc_device_get_supported_baud_rate() functions
* Dependencies
- log4c is not anymore used for debugging facility. It was a bad choice,
sorry for inconvenience.
New in 1.5.1:
API Changes
* Types
- Communication-level errors DEIO and DETIMEOUT are now know as ECOMIO,
ECOMTIMEOUT respectively
- Common device-level errors DEINVAL and DEABORT are now know as EINVALARG,
EOPABORT respectively
- New errors: EFRAACKMISMATCH, EFRAISERRFRAME, EDEVNOTSUP and ENOTIMPL
* Functions
- nfc_abort_command() returns a boolean
- timeout (struct timeval) pointer added to
nfc_initiator_transceive_bytes(), nfc_target_send_bytes() and
nfc_target_receive_bytes()
- timed functions nfc_initiator_transceive_bytes_timed() and
nfc_initiator_transceive_bits_timed() now takes uint32_t as cycles
pointer
- nfc_initiator_poll_targets() renamed to nfc_initiator_poll_target() and
only return one target
New in 1.5.0:
Installed files
- nfc-message.h have been removed, internal macros are not part of API.
- New nfc-emulation.h file offers a middle level API to handle emulation (see
nfc-emulate-forum-tag4 example)
API Changes
* Types
- New error: DEABORT raised when operation is aborted by user (using
nfc_abort_command())
- nfc_chip_t type removed from public API (have been renamed to pn53x_type
in chips/pn53x)
- nfc_device_spec_t removed, each driver can use his own way to keep a
connection pointer
* Structures
- nfc_device_t now have a nfc_driver_t struct pointer (named .driver) and
void pointer (.driver_data) to handle device specific wrapping
- nfc_device_t now have a void pointer (.chip_data) to keep some chip
specific data
- nfc_device_t now have an file descriptor array to manage to abort request
- nfc_device_t does have .nc member (nfc_chip_t) anymore (different chips
handling in now in chip level)
- nfc_device_t does have .nds member (nfc_device_spec_t) anymore, each
driver handle its communication using driver_data pointer
- nfc_device_t does have .bActive member (bool) anymore, this variable was
almost not used and was not efficient
- nfc_device_t does have chip's register caches anymore, this is handle in
chip level (using chip_data pointer)
- driver_callbacks structure have been removed from public API
- New nfc_emulator structure used by the new emulation API (see
nfc_emulate_target())
- New nfc_emulation_state_machine structure used by the new emulation API,
it handles an I/O function and data pointer to create a software based
state-machine.
* Functions
- New nfc_abort_command() function to abort current running command.
- New nfc_initiator_transceive_bits_timed() and
nfc_initiator_transceive_bytes_timed() to transceive bits/bytes and
measure the time to have a reply
- New nfc_emulate_target() function to start a target emulation using an
nfc_emulator structure (it contains a custom state-machine
(nfc_emulation_state_machine struct) and a custom target (nfc_target_t)
(see nfc-emulate-forum-tag4 to have a look on how-to use it)
New in 1.4.1:
API Changes
* Types
- New error: ETGUIDNOTSUP raised when UID is not 4 bytes long or does not
start with 0x08 (Security restriction present in the NXP PN53x chips)
New in 1.4.0:
API Changes
* Types
- New nfc_device_option value (enum): NDO_FORCE_ISO14443_A to force the
chip to switch in ISO14443-A
- New nfc_dep_mode_t (enum) for DEP mode:
NDM_UNDEFINED, NDM_PASSIVE, NDM_ACTIVE
- New nfc_modulation_type_t (enum) that lists modulation types:
NMT_ISO14443A, NMT_ISO14443B, NMT_FELICA, NMT_JEWEL, NMT_DEP
- New nfc_baud_rate_t (enum): list of baud rates:
NBR_UNDEFINED, NBR_106, NBR_212, NBR_424, NBR_847
- nfc_target_type_t have been removed from API (use nfc_modulation_t
instead)
* Structures
- nfc_device_t now have a boolean bAutoIso14443_4 to keep the locally the
state of NDO_AUTO_ISO14443_4 (should not be directly set, use
nfc_configure() with NDO_AUTO_ISO14443_4)
- nfc_device_t now have an uint8_t ui8Parameters to cache PN53x parameters
- nfc_device_t now have a byte_t btSupportByte to cache supported
modulations
- nfc_dep_info_t have completely changed, please see API documentation
- nfc_iso14443b_info_t have completely changed, please see API
documentation
- nfc_modulation_t have completely changed: it now contains a
nfc_modulation_type_t and nfc_baud_rate_t couple. Initialization example:
nfc_modulation_t nm = {
.nmt = NMT_ISO14443A,
.nbr = NBR_106,
};
- nfc_target_t now contains new nfc_modulation_t instead of
nfc_target_type_t. Initialization example:
nfc_target_t nt = {
.nm.nmt = NMT_ISO14443A,
.nm.nbr = NBR_UNDEFINED,
.nti.nai.abtAtqa = { 0x03, 0x44 },
.nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef },
.nti.nai.btSak = 0x20,
.nti.nai.szUidLen = 4,
.nti.nai.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 },
.nti.nai.szAtsLen = 5,
};
* Functions
- nfc_initiator_select_passive_target() now use new nfc_modulation_t and
nfc_target_t instead of nfc_target_info_t
- nfc_initiator_list_passive_targets() now use new nfc_modulation_t and
nfc_target_t instead of nfc_target_info_t
- nfc_initiator_poll_targets() use new nfc_modulation_t instead of
nfc_target_type_t
- nfc_initiator_select_dep_target() completely changed, use now
nfc_dep_mode_t, nfc_baudrate_t, nfc_dep_info_t and nfc_target_t, please
see API documentation
- nfc_target_init() have an additional argument: nfc_target_t to describe
the wanted target
- append_iso14443a_crc() was renamed to iso14443a_crc_append()
- New iso14443a_locate_historical_bytes() to locate historical bytes in ATS
New in 1.3.9 (since 1.3.4):
Installed files
- mifaretag.h and mifareultag.h are removed, Mifare features are not a part
of libnfc API anymore (these features are always available in examples/)
API Changes
* Types
- New nfc_device_option_t value (enum): NDO_AUTO_14443_4, an option to
enable/disable auto-switching to ISO/IEC 14443-4 if device is compliliant
- New nfc_device_option_t value (enum): NDO_EASY_FRAMING, an option to
enable/disable automatic frames encapsulation and chaining
- New nfc_target_type_t (enum), with values like NTT_MIFARE,
NTT_ISO14443B_106, NTT_DEP_ACTIVE_424, etc.
- Mifare related types have been removed from API: mifare_cmd,
mifare_param_auth, mifare_param_data, mifare_param_value, mifare_param
* Structures
- nfc_device_t now have boolean bEasyFraming to enable/disable "easy
framing" feature (should not be directly set, use nfc_configure() with
NDO_EASY_FRAMING)
- nfc_device_t now have integer iLastError to handle last error
- New chip_callbacks to handle error lookup per chip
- driver_callbacks now have a pointer to chip_callbacks
- New nfc_target_t that contains nfc_target_info_t and nfc_target_type_t
* Functions
- nfc_initiator_select_tag() became nfc_initiator_select_passive_target()
- New nfc_initiator_list_passive_targets() returns a list of detected
target on desired modulation
- (experimental) New nfc_initiator_poll_targets() returns targets that are
detected during hardware polling (available only with PN532)
- nfc_initiator_transceive_dep_bytes(), nfc_target_receive_dep_bytes() and
nfc_target_send_dep_bytes() have been removed from API, use
NDO_EASY_FRAMING option to switch from raw mode to "easy framing"
- nfc_initiator_mifare_cmd() have been removed: no more Mifare related
stuff in libnfc's API
- New nfc_strerror(), nfc_strerror_r() and nfc_perror() to report errors
- New append_iso14443a_crc() to append iso14443a_crc() to a string
New in 1.3.4 (since 1.2.1):
Installed files
- Headers are now installed in include/nfc instead of include/libnfc
- libnfc.h have been renamed to nfc.h
- defines.h and types.h have been merge into nfc-types.h
- bitutils.h is not installed anymore, some functions are now in
examples/nfc-utils.c
- devices.h, dev_acr122.h, dev_arygon.h, dev_pn531.h, dev_pn533.h and rs232.h
are not installed anymore
- New header mifareultag.h, like mifaretag.h for Mifare UltraLight
- New header nfc-messages.h with messages macros (DBG, ERR, INFO)
API Changes
* Types
- uint32_t which was used as size now are size_t
- chip_type became nfc_chip_t (enum)
- init_modulation became nfc_modulation_t (enum), and now have
NM_ACTIVE_DEP and NM_PASSIVE_DEP modulation values added
* Structures
- dev_info became nfc_device_t
- dev_config_option became nfc_device_option_t
- New nfc_device_desc_t to describe the way to access to a NFC device.
Initialisation example:
nfc_device_desc_t ndd = {
ndd.pcDriver = "ARYGON";
ndd.pcPort = "/dev/ttyUSB0";
ndd.uiSpeed = 115200;
};
- dev_callbacks became driver_callbacks and now have two function pointers
more: pick_device() and list_devices()
- New nfc_dep_info_t to handle DEP targets info
- tag_info_iso14443a became nfc_iso14443a_info_t
- tag_info_iso14443b became nfc_iso14443b_info_t
- tag_info_felica became nfc_felica_info_t
- tag_info_jewel became nfc_jewel_info_t
- tag_info became nfc_target_info_t, and now have extended union to
nfc_dep_info_t
* Functions
- nfc_connect() now takes 1 nfc_devive_desc_t argument (can be NULL)
- New nfc_list_devices(), it find available NFC devices using all know
drivers
- (experimental) New nfc_initiator_select_dep(), it looks for DEP targets
- (experimental) New nfc_initiator_transceive_dep_bytes(), like
nfc_initiator_transceive_bytes() for DEP targets
- (experimental) New nfc_target_receive_dep_bytes() and
nfc_target_send_dep_bytes(), to receive/send bytes to DEP target
(configured as initiator) while local NFC device is configured as target
- New nfc_device_name() returns the device's name
- New iso14443a_crc() computes CRC as described in ISO/IEC 14443
- New nfc_version() returns the actual version of libnfc (with SVN
revision, if available)

70
README-Windows.md Normal file
View File

@ -0,0 +1,70 @@
*-
* 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
* Additional contributors of Windows-specific parts:
* Copyright (C) 2010 Glenn Ergeerts
* Copyright (C) 2013 Alex Lian
-*
Requirements
============
- MinGW-w64 compiler toolchain [1]
- LibUsb-Win32 1.2.5.0 (or greater) [2]
- CMake 2.8 [3]
This was tested on Windows 7 64 bit, but should work on Windows Vista and
Windows XP and 32 bit as well.
Only the ACS ACR122 and the ASK Logo readers are tested at the moment, so any feedback about other devices is very welcome.
Community forum: http://www.libnfc.org/community/
Building
========
To build the distribution the MinGW Makefiles generator of CMake was used. Here
is an example of how to generate a distribution with the above mentioned
requirements fulfilled (it is assumed the CMake binaries are in the system
path, this is optional during installation of CMake):
- Add the following directories to your PATH:
c:\MinGW64\bin;c:\MinGW64\x86_64-w64-mingw32\lib32;c:\MinGW64\x86_64-w64-mingw32\include
- Now it is possible to run CMake and mingw32-make:
C:\dev\libnfc-read-only> mkdir ..\libnfc-build
C:\dev\libnfc-read-only> cd ..\libnfc-build
C:\dev\libnfc-build> cmake-gui .
Now you can configure the build. Press "Configure", specify "MinGW32 Makefiles"
and then you have the opportunity to set some configuration variables. If you
don't want a Debug build change the variable CMAKE_BUILD_TYPE to "Release".
If a non-GUI solution is preferred one can use:
C:\dev\libnfc-build> cmake -G "MinGW Makefiles"
-DCMAKE_BUILD_TYPE=Release ..\libnfc-read-only
Now run mingw32-make to build:
C:\dev\libnfc-read-only\bin> mingw32-make
The build will create a shared library for Windows (nfc.dll) to link your applications against. It will compile
the tools against this shared library.
References
==========
[1] the easiest way is to use the TDM-GCC installer.
Make sure to select MinGW-w64 in the installer, the regular MinGW does not contain headers for PCSC.
http://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/tdm64-gcc-4.5.1.exe/download
[2] http://sourceforge.net/projects/libusb-win32/files/
[3] http://www.cmake.org

239
README.md Normal file
View File

@ -0,0 +1,239 @@
```
*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2015 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau
* Additional contributors:
* See AUTHORS file
-*
```
General Information
===================
libnfc is a library which allows userspace application access to NFC devices.
The official web site is:
http://www.nfc-tools.org/
The official forum site is:
http://www.libnfc.org/community/
The official development site is:
https://github.com/nfc-tools/libnfc
Important note: this file covers POSIX systems, for Windows please read README-Windows.md
Requirements
============
Some NFC drivers depend on third party software:
* pn53x_usb & acr122_usb:
- libusb-0.1 http://libusb.sf.net
* acr122_pcsc:
- pcsc-lite https://pcsclite.apdu.fr/
- pcsc:
- Support build with pcsc driver, which can be using all compatible readers, Feitian R502 and bR500 already passed the test.
The regression test suite depends on the cutter framework:
http://cutter.sf.net
Building
========
Note: If working directly from a git clone of the repository, some of the files need to be generated first. To do this run
`autoreconf -vis`
Alternatively use a .tar.bz2 version of a packaged release (which already contains ./configure):
https://github.com/nfc-tools/libnfc/releases/
The build should be as simple as running these commands:
./configure
make
To build with specific driver(s), see option `--with-drivers=...` detailed in `./configure --help`.
Installation
============
make install
You may need to grant permissions to your user to drive your device.
Under GNU/Linux systems, if you use udev, you could use the provided udev rules.
e.g. under Debian, Ubuntu, etc.
sudo cp contrib/udev/93-pn53x.rules /lib/udev/rules.d/
Under FreeBSD, if you use devd, there is also a rules file: contrib/devd/pn53x.conf.
Configuration
=============
In order to change the default behavior of the library, the libnfc uses a
configuration file located in sysconfdir (as provided to ./configure).
A sample commented file is available in sources: libnfc.conf.sample
If you have compiled using:
./configure --prefix=/usr --sysconfdir=/etc
you can make configuration directory and copy the sample file:
sudo mkdir /etc/nfc
sudo cp libnfc.conf.sample /etc/nfc/libnfc.conf
To configure multiple devices, you can either modify libnfc.conf or create a
file per device in a nfc/devices.d directory:
sudo mkdir -p /etc/nfc/devices.d
printf 'name = "My first device"\nconnstring = "pn532_uart:/dev/ttyACM0"\n' | sudo tee /etc/nfc/devices.d/first.conf
printf 'name = "My second device"\nconnstring = "pn532_uart:/dev/ttyACM1"\n' | sudo tee /etc/nfc/devices.d/second.conf
How to report bugs
==================
To report a bug, visit https://github.com/nfc-tools/libnfc/issues and fill
out a bug report form.
If you have questions, remarks, we encourage you to post this in the developers
community:
http://www.libnfc.org/community
Please make sure to include:
* The version of libnfc
* Information about your system. For instance:
- What operating system and version
- For Linux, what version of the C library
And anything else you think is relevant.
* A trace with debug activated.
Reproduce the bug with debug, e.g. if it was:
$ nfc-list -v
run it as:
$ LIBNFC_LOG_LEVEL=3 nfc-list -v
* How to reproduce the bug.
Please include a short test program that exhibits the behavior.
As a last resort, you can also provide a pointer to a larger piece
of software that can be downloaded.
* If the bug was a crash, the exact text that was printed out
when the crash occured.
* Further information such as stack traces may be useful, but
is not necessary.
Patches
=======
Patches can be posted to https://github.com/nfc-tools/libnfc/issues
If the patch fixes a bug, it is usually a good idea to include
all the information described in "How to Report Bugs".
Troubleshooting
===============
Touchatag/ACR122:
-----------------
If your Touchatag or ACR122 device fails being detected by libnfc, make sure
that PCSC-lite daemon (`pcscd`) is installed and is running.
If your Touchatag or ACR122 device fails being detected by PCSC-lite daemon
(`pcsc_scan` doesn't see anything) then try removing the bogus firmware detection
of libccid: edit libccid_Info.plist configuration file (usually
`/etc/libccid_Info.plist`) and locate `<key>ifdDriverOptions</key>`, turn
`<string>0x0000</string>` value into `0x0004` to allow bogus devices and restart
pcscd daemon.
ACR122:
-------
Using an ACR122 device with libnfc and without tag (e.g. to use NFCIP modes or
card emulation) needs yet another PCSC-lite tweak: You need to allow usage of
CCID Exchange command. To do this, edit `libccid_Info.plist` configuration file
(usually `/etc/libccid_Info.plist`) and locate `<key>ifdDriverOptions</key>`,
turn `<string>0x0000</string>` value into `0x0001` to allow CCID exchange or
`0x0005` to allow CCID exchange and bogus devices (cf previous remark) and
restart pcscd daemon.
Warning: if you use ACS CCID drivers (acsccid), configuration file is located
in something like: `/usr/lib/pcsc/drivers/ifd-acsccid.bundle/Contents/Info.plist`
SCL3711:
--------
Libnfc cannot be used concurrently with the PCSC proprietary driver of SCL3711.
Two possible solutions:
* Either you don't install SCL3711 driver at all
* Or you stop the PCSC daemon when you want to use libnfc-based tools
PN533 USB device on Linux >= 3.1:
---------------------------------
Since Linux kernel version 3.1, a few kernel-modules must not be loaded in order
to use libnfc : "nfc", "pn533" and "pn533_usb".
To prevent kernel from loading automatically these modules, you can blacklist
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
FEITIAN bR500 and R502:
-----------------------
Libnfc can work with PCSC proprietary driver of bR500 and R502, which is already available on most Linux setups.
To activate the PCSC support: `./configure --with-drivers=pcsc`.
Readers known to work:
- Feitian bR500
- Feitian R502 Dual interface reader
- Feitian R502 CL(Contactless) reader
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)
```
grep -A 1 CFBundleShortVersionString /usr/local/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
```
On Linux, you can check your CCID version with the following command, and if required, you can install latest CCID driver from [https://ccid.apdu.fr/](https://ccid.apdu.fr/)
```
grep -A 1 CFBundleShortVersionString /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist
```
Proprietary Notes
=================
FeliCa is a registered trademark of the Sony Corporation.
MIFARE is a trademark of NXP Semiconductors.
Jewel Topaz is a trademark of Innovision Research & Technology.
All other trademarks are the property of their respective owners.

View File

@ -0,0 +1,34 @@
# -*- cmake -*-
# Use the following variables to compile and link against LibNFC:
# LIBNFC_FOUND - True if LibNFC was found on your system
# LIBNFC_USE_FILE - The file making LibNFC usable
# LIBNFC_DEFINITIONS - Definitions needed to build with LibNFC
# LIBNFC_INCLUDE_DIR - Directory where nfc/nfc.h can be found
# LIBNFC_INCLUDE_DIRS - List of directories of LibNFC and it's dependencies
# LIBNFC_LIBRARY - LibNFC library location
# LIBNFC_LIBRARIES - List of libraries to link against LibNFC library
# LIBNFC_LIBRARY_DIRS - List of directories containing LibNFC' libraries
# LIBNFC_ROOT_DIR - The base directory of LibNFC
# LIBNFC_VERSION_STRING - A human-readable string containing the version
# LIBNFC_VERSION_MAJOR - The major version of LibNFC
# LIBNFC_VERSION_MINOR - The minor version of LibNFC
# LIBNFC_VERSION_PATCH - The patch version of LibNFC
set ( LIBNFC_FOUND 1 )
set ( LIBNFC_USE_FILE "@LIBNFC_USE_FILE@" )
set ( LIBNFC_DEFINITIONS "@LIBNFC_DEFINITIONS@" )
set ( LIBNFC_INCLUDE_DIR "@LIBNFC_INCLUDE_DIR@" )
set ( LIBNFC_INCLUDE_DIRS "@LIBNFC_INCLUDE_DIRS@" )
set ( LIBNFC_LIBRARY "@LIBNFC_LIBRARY@" )
set ( LIBNFC_LIBRARIES "@LIBNFC_LIBRARIES@" )
set ( LIBNFC_LIBRARY_DIRS "@LIBNFC_LIBRARY_DIRS@" )
set ( LIBNFC_ROOT_DIR "@LIBNFC_ROOT_DIR@" )
set ( LIBNFC_VERSION_STRING "@LIBNFC_VERSION_STRING@" )
set ( LIBNFC_VERSION_MAJOR "@LIBNFC_VERSION_MAJOR@" )
set ( LIBNFC_VERSION_MINOR "@LIBNFC_VERSION_MINOR@" )
set ( LIBNFC_VERSION_PATCH "@LIBNFC_VERSION_PATCH@" )

View File

@ -0,0 +1,31 @@
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "@LIBNFC_VERSION_STRING@")
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" )
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()

View File

@ -3,4 +3,7 @@ SUBDIRS = modules
EXTRA_DIST = \ EXTRA_DIST = \
FixBundle.cmake.in \ FixBundle.cmake.in \
config_posix.h.cmake \ config_posix.h.cmake \
config_windows.h.cmake config_windows.h.cmake \
LibNFCConfig.cmake.in \
LibNFCConfigVersion.cmake.in \
UseLibNFC.cmake

5
cmake/UseLibNFC.cmake Normal file
View File

@ -0,0 +1,5 @@
# -*- cmake -*-
add_definitions ( ${LIBNFC_DEFINITIONS} )
include_directories ( ${LIBNFC_INCLUDE_DIRS} )
link_directories ( ${LIBNFC_LIBRARY_DIRS} )

View File

@ -17,6 +17,7 @@ IF(CMAKE_SYSTEM_NAME MATCHES FreeBSD)
EXEC_PROGRAM(sysctl ARGS -n kern.osreldate OUTPUT_VARIABLE FREEBSD_VERSION) EXEC_PROGRAM(sysctl ARGS -n kern.osreldate OUTPUT_VARIABLE FREEBSD_VERSION)
SET(MIN_FREEBSD_VERSION 800068) SET(MIN_FREEBSD_VERSION 800068)
IF(FREEBSD_VERSION GREATER ${MIN_FREEBSD_VERSION}) IF(FREEBSD_VERSION GREATER ${MIN_FREEBSD_VERSION})
SET(LIBUSB_FOUND TRUE)
SET(LIBUSB_INCLUDE_DIRS "/usr/include") SET(LIBUSB_INCLUDE_DIRS "/usr/include")
SET(LIBUSB_LIBRARIES "usb") SET(LIBUSB_LIBRARIES "usb")
SET(LIBUSB_LIBRARY_DIRS "/usr/lib/") SET(LIBUSB_LIBRARY_DIRS "/usr/lib/")
@ -24,27 +25,39 @@ IF(CMAKE_SYSTEM_NAME MATCHES FreeBSD)
ENDIF(CMAKE_SYSTEM_NAME MATCHES FreeBSD) ENDIF(CMAKE_SYSTEM_NAME MATCHES FreeBSD)
IF(NOT LIBUSB_FOUND) IF(NOT LIBUSB_FOUND)
FIND_PACKAGE (PkgConfig) IF(WIN32)
IF(MINGW)
FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/include" NO_SYSTEM_ENVIRONMENT_PATH)
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES libusb PATHS "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/lib/gcc")
SET(LIBUSB_LIBRARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/LibUSB-Win32/bin/x86/")
ELSE(MINGW)
FIND_PATH(LIBUSB_INCLUDE_DIRS lusb0_usb.h "$ENV{ProgramW6432}/libusb-win32/include" NO_SYSTEM_ENVIRONMENT_PATH)
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0 libusb-1.0 libusb PATHS "$ENV{ProgramW6432}/libusb-win32/lib/msvc_x64")
SET(LIBUSB_LIBRARY_DIR "$ENV{ProgramW6432}/libusb-win32/bin/amd64/")
ENDIF(MINGW)
# Must fix up variable to avoid backslashes during packaging
STRING(REGEX REPLACE "\\\\" "/" LIBUSB_LIBRARY_DIR ${LIBUSB_LIBRARY_DIR})
ELSE(WIN32)
# If not under Windows we use PkgConfig
FIND_PACKAGE (PkgConfig)
IF(PKG_CONFIG_FOUND)
PKG_CHECK_MODULES(LIBUSB REQUIRED libusb-1.0)
ELSE(PKG_CONFIG_FOUND)
MESSAGE(FATAL_ERROR "Could not find PkgConfig")
ENDIF(PKG_CONFIG_FOUND)
ENDIF(WIN32)
IF(PKG_CONFIG_FOUND) IF(LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES)
PKG_CHECK_MODULES(LIBUSB REQUIRED libusb-1.0) SET(LIBUSB_FOUND TRUE)
ENDIF() ENDIF(LIBUSB_INCLUDE_DIRS AND LIBUSB_LIBRARIES)
ENDIF(NOT LIBUSB_FOUND)
FIND_PATH(LIBUSB_INCLUDE_DIRS libusb.h lusb0_usb.h IF(LIBUSB_FOUND)
PATHS IF(NOT LIBUSB_FIND_QUIETLY)
${PC_LIBUSB_INCLUDEDIR} ${PC_LIBUSB_INCLUDE_DIRS} MESSAGE(STATUS "Found LIBUSB: ${LIBUSB_LIBRARIES} ${LIBUSB_INCLUDE_DIRS}")
"$ENV{ProgramFiles}/LibUSB-Win32/include" ENDIF (NOT LIBUSB_FIND_QUIETLY)
PATH_SUFFIXES libusb-1.0 ELSE(LIBUSB_FOUND)
) IF(LIBUSB_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find LIBUSB")
FIND_LIBRARY(LIBUSB_LIBRARIES NAMES usb-1.0 libusb ENDIF(LIBUSB_FIND_REQUIRED)
PATHS ${PC_LIBUSB_LIBDIR} ${PC_LIBUSB_LIBRARY_DIRS} ENDIF(LIBUSB_FOUND)
"$ENV{ProgramFiles}/LibUSB-Win32/lib/gcc"
)
ENDIF()
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LIBUSB DEFAULT_MSG LIBUSB_LIBRARIES LIBUSB_INCLUDE_DIRS)
MARK_AS_ADVANCED(LIBUSB_INCLUDE_DIRS LIBUSB_LIBRARIES)

View File

@ -1,30 +0,0 @@
# This CMake script wants to use pcre functionality needed for windows
# compilation. However, since PCRE isn't really a default install location
# there isn't much to search.
#
# Operating Systems Supported:
# - Windows (requires MinGW)
# Tested with Windows XP/Windows 7
#
# This should work for both 32 bit and 64 bit systems.
#
# Author: A. Lian <alex.lian@gmail.com>
#
IF(WIN32)
IF(NOT PCRE_FOUND)
FIND_PATH(PCRE_INCLUDE_DIRS regex.h)
FIND_LIBRARY(PCRE_LIBRARIES NAMES PCRE pcre)
IF(PCRE_INCLUDE_DIRS AND PCRE_LIBRARIES)
SET(PCRE_FOUND TRUE)
ENDIF(PCRE_INCLUDE_DIRS AND PCRE_LIBRARIES)
ENDIF(NOT PCRE_FOUND)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG
PCRE_LIBRARIES
PCRE_INCLUDE_DIRS
)
ENDIF(WIN32)

View File

@ -1,17 +1,24 @@
SET(LIBNFC_DRIVER_PCSC OFF CACHE BOOL "Enable PC/SC reader support (Depends on PC/SC)")
SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on PC/SC)") SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on PC/SC)")
SET(LIBNFC_DRIVER_ACR122_USB ON CACHE BOOL "Enable ACR122 support (Direct USB connection)") SET(LIBNFC_DRIVER_ACR122_USB ON CACHE BOOL "Enable ACR122 support (Direct USB connection)")
SET(LIBNFC_DRIVER_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)") SET(LIBNFC_DRIVER_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)")
SET(LIBNFC_DRIVER_ARYGON ON CACHE BOOL "Enable ARYGON support (Use serial port)") SET(LIBNFC_DRIVER_ARYGON ON CACHE BOOL "Enable ARYGON support (Use serial port)")
IF(WIN32) IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(LIBNFC_DRIVER_PN532_I2C OFF CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI OFF CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ELSE(WIN32)
SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)") SET(LIBNFC_DRIVER_PN532_I2C ON CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)") SET(LIBNFC_DRIVER_PN532_SPI ON CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ENDIF(WIN32) ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(LIBNFC_DRIVER_PN532_I2C OFF CACHE BOOL "Enable PN532 I2C support (Use I2C bus)")
SET(LIBNFC_DRIVER_PN532_SPI OFF CACHE BOOL "Enable PN532 SPI support (Use SPI bus)")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)") SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)")
SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)") SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)")
IF(LIBNFC_DRIVER_PCSC)
FIND_PACKAGE(PCSC REQUIRED)
ADD_DEFINITIONS("-DDRIVER_PCSC_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pcsc")
ENDIF(LIBNFC_DRIVER_PCSC)
IF(LIBNFC_DRIVER_ACR122_PCSC) IF(LIBNFC_DRIVER_ACR122_PCSC)
FIND_PACKAGE(PCSC REQUIRED) FIND_PACKAGE(PCSC REQUIRED)
ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED") ADD_DEFINITIONS("-DDRIVER_ACR122_PCSC_ENABLED")
@ -61,4 +68,11 @@ IF(LIBNFC_DRIVER_PN53X_USB)
SET(USB_REQUIRED TRUE) SET(USB_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_PN53X_USB) ENDIF(LIBNFC_DRIVER_PN53X_USB)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/drivers) IF(LIBNFC_DRIVER_ACR122_USB)
FIND_PACKAGE(LIBUSB REQUIRED)
ADD_DEFINITIONS("-DDRIVER_ACR122_USB_ENABLED")
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122_usb")
SET(USB_REQUIRED TRUE)
ENDIF(LIBNFC_DRIVER_ACR122_USB)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers)

View File

@ -2,6 +2,5 @@ EXTRA_DIST = \
COPYING-CMAKE-SCRIPTS \ COPYING-CMAKE-SCRIPTS \
FindLIBUSB.cmake \ FindLIBUSB.cmake \
FindPCSC.cmake \ FindPCSC.cmake \
FindPCRE.cmake \
UseDoxygen.cmake \ UseDoxygen.cmake \
LibnfcDrivers.cmake LibnfcDrivers.cmake

View File

@ -91,8 +91,7 @@ if(DOXYGEN_FOUND AND DOXYFILE_IN)
configure_file(${DOXYFILE_IN} Doxyfile ESCAPE_QUOTES IMMEDIATE @ONLY) configure_file(${DOXYFILE_IN} Doxyfile ESCAPE_QUOTES IMMEDIATE @ONLY)
get_target_property(DOC_TARGET doc TYPE) if(NOT TARGET doc)
if(NOT DOC_TARGET)
add_custom_target(doc) add_custom_target(doc)
endif() endif()

View File

@ -1,7 +1,7 @@
# General init # General init
# /!\ Don't forget to update 'CMakeLists.txt' too /!\ # /!\ Don't forget to update 'CMakeLists.txt' too /!\
AC_INIT([libnfc],[1.7.0],[nfc-tools@googlegroups.com]) AC_INIT([libnfc],[1.8.0],[nfc-tools@googlegroups.com])
AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_MACRO_DIR([m4])
@ -13,7 +13,7 @@ if test x"$GIT_REVISION" != x""; then
AC_DEFINE_UNQUOTED([GIT_REVISION], ["$GIT_REVISION"], [GIT revision]) AC_DEFINE_UNQUOTED([GIT_REVISION], ["$GIT_REVISION"], [GIT revision])
fi fi
AM_INIT_AUTOMAKE(subdir-objects dist-bzip2 no-dist-gzip) AM_INIT_AUTOMAKE(subdir-objects dist-bzip2 no-dist-gzip foreign)
m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
@ -47,6 +47,7 @@ AC_HEADER_STDBOOL
AC_CHECK_HEADERS([fcntl.h limits.h stdio.h stdlib.h stdint.h stddef.h stdbool.h sys/ioctl.h sys/param.h sys/time.h termios.h]) AC_CHECK_HEADERS([fcntl.h limits.h stdio.h stdlib.h stdint.h stddef.h stdbool.h sys/ioctl.h sys/param.h sys/time.h termios.h])
AC_CHECK_HEADERS([linux/spi/spidev.h], [spi_available="yes"]) AC_CHECK_HEADERS([linux/spi/spidev.h], [spi_available="yes"])
AC_CHECK_HEADERS([linux/i2c-dev.h], [i2c_available="yes"]) AC_CHECK_HEADERS([linux/i2c-dev.h], [i2c_available="yes"])
AC_CHECK_HEADERS([linux_nfc_api.h], [nfc_nci_available="yes"])
AC_CHECK_FUNCS([memmove memset select strdup strerror strstr strtol usleep], AC_CHECK_FUNCS([memmove memset select strdup strerror strstr strtol usleep],
[AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])]) [AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])])
@ -125,6 +126,20 @@ AM_CONDITIONAL(SPI_ENABLED, [test x"$spi_required" = x"yes"])
# Enable I2C if # Enable I2C if
AM_CONDITIONAL(I2C_ENABLED, [test x"$i2c_required" = x"yes"]) AM_CONDITIONAL(I2C_ENABLED, [test x"$i2c_required" = x"yes"])
if test x"$i2c_required" = x"yes"
then
AC_SEARCH_LIBS([clock_gettime], [rt])
fi
# Enable Libnfc-NCI if required
if test x"$nfc_nci_required" = x"yes"
then
PKG_CHECK_MODULES([LIBNFC_NCI], [libnfc-nci],
[AC_MSG_NOTICE([libnfc-nci present])],
[AC_MSG_ERROR([libnfc-nci not present but required for some drivers configuration])]
)
CFLAGS="$CFLAGS $LIBNFC_NCI_CFLAGS"
fi
# Documentation (default: no) # Documentation (default: no)
AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"]) AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"])
@ -142,6 +157,14 @@ then
fi fi
AM_CONDITIONAL(DOC_ENABLED, [test x"$enable_doc" = xyes]) AM_CONDITIONAL(DOC_ENABLED, [test x"$enable_doc" = xyes])
# Example build (default: yes)
AC_ARG_ENABLE([example],AS_HELP_STRING([--enable-example],[Enable example build.]),[enable_example=$enableval],[enable_example="yes"])
AC_MSG_CHECKING(for example build)
AC_MSG_RESULT($enable_example)
AM_CONDITIONAL(EXAMPLE_ENABLED, [test x"$enable_example" = xyes])
# Dependencies # Dependencies
PKG_CONFIG_REQUIRES="" PKG_CONFIG_REQUIRES=""
@ -160,7 +183,10 @@ if test x$ac_cv_with_cutter = xyes -a x$ac_cv_use_cutter = xno; then
fi fi
AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"]) AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"])
if test x"$enable_example" = "xyes"
then
AC_CHECK_READLINE AC_CHECK_READLINE
fi
# Help us to write great code ;-) # Help us to write great code ;-)
CFLAGS="$CFLAGS -Wall -pedantic -Wextra" CFLAGS="$CFLAGS -Wall -pedantic -Wextra"

View File

@ -1,4 +1,7 @@
EXTRA_DIST = \ EXTRA_DIST = \
pn532_via_uart2usb.conf.sample \ arygon.conf.sample \
arygon.conf.sample \ pn532_i2c_on_rpi.conf.sample \
pn532_uart_on_rpi.conf.sample pn532_spi_on_rpi.conf.sample \
pn532_uart_on_rpi_3.conf.sample \
pn532_uart_on_rpi.conf.sample \
pn532_via_uart2usb.conf.sample

View File

@ -0,0 +1,22 @@
## Typical configuration file for PN532 device on R-Pi 3 connected using miniUART
## Note: Changes have been made to R-Pi 3 with the addition of Bluetooth LE
## The UART is now being used by the BLE module. Instead of disabling it, you can
## use the PN532 device with the "mini UART", which is still hijacked by the linux kernel
## as a serial console
##
## Tested recipe with PN532 breakout from Adafruit
##
## To enable uart on GPIO, add this line to bottom of /boot/config.txt
## enable_uart=1
##
## Stop and disable serial console:
## $ sudo systemctl stop serial-getty@ttyS0.service
## $ sudo systemctl disable serial-getty@ttyS0.service
##
## Remove console from /boot/cmdline.txt by removing:
## console=serial0,115200 Save and reboot for changes to take effect.
##
name = "PN532 board via UART"
connstring = pn532_uart:/dev/ttyS0
allow_intrusive_scan = true

View File

@ -1,2 +1,3 @@
blacklist nfc blacklist nfc
blacklist pn533 blacklist pn533
blacklist pn533_usb

View File

@ -0,0 +1,22 @@
# udev rules file for PN531 and PN533 devices (for udev 0.98 version)
# to be installed in /etc/udev/rules.d
SUBSYSTEM!="usb|usb_device", GOTO="pn53x_rules_end"
ACTION!="add", GOTO="pn53x_rules_end"
# PN531
ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="0531", MODE="0664", GROUP="plugdev"
ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0193", MODE="0664", GROUP="plugdev"
# PN533
ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="2533", MODE="0664", GROUP="plugdev"
ATTRS{idVendor}=="04e6", ATTRS{idProduct}=="5591", MODE="0664", GROUP="plugdev"
ATTRS{idVendor}=="04e6", ATTRS{idProduct}=="5594", MODE="0664", GROUP="plugdev"
ATTRS{idVendor}=="1fd3", ATTRS{idProduct}=="0608", MODE="0664", GROUP="plugdev"
ATTRS{idVendor}=="054c", ATTRS{idProduct}=="02e1", MODE="0664", GROUP="plugdev"
# ACR122 / Touchatag
ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2200", MODE="0664", GROUP="plugdev"
ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90cc", MODE="0664", GROUP="plugdev"
LABEL="pn53x_rules_end"

View File

@ -1,2 +1,2 @@
EXTRA_DIST = \ EXTRA_DIST = \
42-pn53x.rules 93-pn53x.rules

870
contrib/win32/dirent.h Normal file
View File

@ -0,0 +1,870 @@
/*
* Dirent interface for Microsoft Visual Studio
*
* Copyright (C) 2006-2012 Toni Ronkko
* This file is part of dirent. Dirent may be freely distributed
* under the MIT license. For all details and documentation, see
* https://github.com/tronkko/dirent
*/
#ifndef DIRENT_H
#define DIRENT_H
/*
* Include windows.h without Windows Sockets 1.1 to prevent conflicts with
* Windows Sockets 2.0.
*/
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
/* Indicates that d_type field is available in dirent structure */
#define _DIRENT_HAVE_D_TYPE
/* Indicates that d_namlen field is available in dirent structure */
#define _DIRENT_HAVE_D_NAMLEN
/* Entries missing from MSVC 6.0 */
#if !defined(FILE_ATTRIBUTE_DEVICE)
# define FILE_ATTRIBUTE_DEVICE 0x40
#endif
/* File type and permission flags for stat(), general mask */
#if !defined(S_IFMT)
# define S_IFMT _S_IFMT
#endif
/* Directory bit */
#if !defined(S_IFDIR)
# define S_IFDIR _S_IFDIR
#endif
/* Character device bit */
#if !defined(S_IFCHR)
# define S_IFCHR _S_IFCHR
#endif
/* Pipe bit */
#if !defined(S_IFFIFO)
# define S_IFFIFO _S_IFFIFO
#endif
/* Regular file bit */
#if !defined(S_IFREG)
# define S_IFREG _S_IFREG
#endif
/* Read permission */
#if !defined(S_IREAD)
# define S_IREAD _S_IREAD
#endif
/* Write permission */
#if !defined(S_IWRITE)
# define S_IWRITE _S_IWRITE
#endif
/* Execute permission */
#if !defined(S_IEXEC)
# define S_IEXEC _S_IEXEC
#endif
/* Pipe */
#if !defined(S_IFIFO)
# define S_IFIFO _S_IFIFO
#endif
/* Block device */
#if !defined(S_IFBLK)
# define S_IFBLK 0
#endif
/* Link */
#if !defined(S_IFLNK)
# define S_IFLNK 0
#endif
/* Socket */
#if !defined(S_IFSOCK)
# define S_IFSOCK 0
#endif
/* Read user permission */
#if !defined(S_IRUSR)
# define S_IRUSR S_IREAD
#endif
/* Write user permission */
#if !defined(S_IWUSR)
# define S_IWUSR S_IWRITE
#endif
/* Execute user permission */
#if !defined(S_IXUSR)
# define S_IXUSR 0
#endif
/* Read group permission */
#if !defined(S_IRGRP)
# define S_IRGRP 0
#endif
/* Write group permission */
#if !defined(S_IWGRP)
# define S_IWGRP 0
#endif
/* Execute group permission */
#if !defined(S_IXGRP)
# define S_IXGRP 0
#endif
/* Read others permission */
#if !defined(S_IROTH)
# define S_IROTH 0
#endif
/* Write others permission */
#if !defined(S_IWOTH)
# define S_IWOTH 0
#endif
/* Execute others permission */
#if !defined(S_IXOTH)
# define S_IXOTH 0
#endif
/* Maximum length of file name */
#if !defined(PATH_MAX)
# define PATH_MAX MAX_PATH
#endif
#if !defined(FILENAME_MAX)
# define FILENAME_MAX MAX_PATH
#endif
#if !defined(NAME_MAX)
# define NAME_MAX FILENAME_MAX
#endif
/* File type flags for d_type */
#define DT_UNKNOWN 0
#define DT_REG S_IFREG
#define DT_DIR S_IFDIR
#define DT_FIFO S_IFIFO
#define DT_SOCK S_IFSOCK
#define DT_CHR S_IFCHR
#define DT_BLK S_IFBLK
#define DT_LNK S_IFLNK
/* Macros for converting between st_mode and d_type */
#define IFTODT(mode) ((mode) & S_IFMT)
#define DTTOIF(type) (type)
/*
* File type macros. Note that block devices, sockets and links cannot be
* distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
* only defined for compatibility. These macros should always return false
* on Windows.
*/
#if !defined(S_ISFIFO)
# define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
#endif
#if !defined(S_ISDIR)
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
#if !defined(S_ISREG)
# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#endif
#if !defined(S_ISLNK)
# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
#endif
#if !defined(S_ISSOCK)
# define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
#endif
#if !defined(S_ISCHR)
# define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
#endif
#if !defined(S_ISBLK)
# define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
#endif
/* Return the exact length of the file name without zero terminator */
#define _D_EXACT_NAMLEN(p) ((p)->d_namlen)
/* Return the maximum size of a file name */
#define _D_ALLOC_NAMLEN(p) ((PATH_MAX)+1)
#ifdef __cplusplus
extern "C" {
#endif
/* Wide-character version */
struct _wdirent {
/* Always zero */
long d_ino;
/* File position within stream */
long d_off;
/* Structure size */
unsigned short d_reclen;
/* Length of name without \0 */
size_t d_namlen;
/* File type */
int d_type;
/* File name */
wchar_t d_name[PATH_MAX+1];
};
typedef struct _wdirent _wdirent;
struct _WDIR {
/* Current directory entry */
struct _wdirent ent;
/* Private file data */
WIN32_FIND_DATAW data;
/* True if data is valid */
int cached;
/* Win32 search handle */
HANDLE handle;
/* Initial directory name */
wchar_t *patt;
};
typedef struct _WDIR _WDIR;
/* Multi-byte character version */
struct dirent {
/* Always zero */
long d_ino;
/* File position within stream */
long d_off;
/* Structure size */
unsigned short d_reclen;
/* Length of name without \0 */
size_t d_namlen;
/* File type */
int d_type;
/* File name */
char d_name[PATH_MAX+1];
};
typedef struct dirent dirent;
struct DIR {
struct dirent ent;
struct _WDIR *wdirp;
};
typedef struct DIR DIR;
/* Dirent functions */
static DIR *opendir (const char *dirname);
static _WDIR *_wopendir (const wchar_t *dirname);
static struct dirent *readdir (DIR *dirp);
static int readdir_r(
DIR *dirp, struct dirent *entry, struct dirent **result);
static int closedir (DIR *dirp);
static int _wclosedir (_WDIR *dirp);
/* For compatibility with Symbian */
#define wdirent _wdirent
#define WDIR _WDIR
#define wopendir _wopendir
#define wreaddir _wreaddir
#define wclosedir _wclosedir
#define wrewinddir _wrewinddir
/* Internal utility functions */
static WIN32_FIND_DATAW *dirent_first (_WDIR *dirp);
static WIN32_FIND_DATAW *dirent_next (_WDIR *dirp);
static int dirent_mbstowcs_s(
size_t *pReturnValue,
wchar_t *wcstr,
size_t sizeInWords,
const char *mbstr,
size_t count);
static int dirent_wcstombs_s(
size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes,
const wchar_t *wcstr,
size_t count);
static void dirent_set_errno (int error);
/*
* Open directory stream DIRNAME for read and return a pointer to the
* internal working area that is used to retrieve individual directory
* entries.
*/
static _WDIR*
_wopendir(
const wchar_t *dirname)
{
_WDIR *dirp = NULL;
int error;
/* Must have directory name */
if (dirname == NULL || dirname[0] == '\0') {
dirent_set_errno (ENOENT);
return NULL;
}
/* Allocate new _WDIR structure */
dirp = (_WDIR*) malloc (sizeof (struct _WDIR));
if (dirp != NULL) {
DWORD n;
/* Reset _WDIR structure */
dirp->handle = INVALID_HANDLE_VALUE;
dirp->patt = NULL;
dirp->cached = 0;
/* Compute the length of full path plus zero terminator
*
* Note that on WinRT there's no way to convert relative paths
* into absolute paths, so just assume it is an absolute path.
*/
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
n = wcslen(dirname);
# else
n = GetFullPathNameW (dirname, 0, NULL, NULL);
# endif
/* Allocate room for absolute directory name and search pattern */
dirp->patt = (wchar_t*) malloc (sizeof (wchar_t) * n + 16);
if (dirp->patt) {
/*
* Convert relative directory name to an absolute one. This
* allows rewinddir() to function correctly even when current
* working directory is changed between opendir() and rewinddir().
*
* Note that on WinRT there's no way to convert relative paths
* into absolute paths, so just assume it is an absolute path.
*/
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
wcsncpy_s(dirp->patt, n+1, dirname, n);
# else
n = GetFullPathNameW (dirname, n, dirp->patt, NULL);
# endif
if (n > 0) {
wchar_t *p;
/* Append search pattern \* to the directory name */
p = dirp->patt + n;
if (dirp->patt < p) {
switch (p[-1]) {
case '\\':
case '/':
case ':':
/* Directory ends in path separator, e.g. c:\temp\ */
/*NOP*/;
break;
default:
/* Directory name doesn't end in path separator */
*p++ = '\\';
}
}
*p++ = '*';
*p = '\0';
/* Open directory stream and retrieve the first entry */
if (dirent_first (dirp)) {
/* Directory stream opened successfully */
error = 0;
} else {
/* Cannot retrieve first entry */
error = 1;
dirent_set_errno (ENOENT);
}
} else {
/* Cannot retrieve full path name */
dirent_set_errno (ENOENT);
error = 1;
}
} else {
/* Cannot allocate memory for search pattern */
error = 1;
}
} else {
/* Cannot allocate _WDIR structure */
error = 1;
}
/* Clean up in case of error */
if (error && dirp) {
_wclosedir (dirp);
dirp = NULL;
}
return dirp;
}
/*
* Close directory stream opened by opendir() function. This invalidates the
* DIR structure as well as any directory entry read previously by
* _wreaddir().
*/
static int
_wclosedir(
_WDIR *dirp)
{
int ok;
if (dirp) {
/* Release search handle */
if (dirp->handle != INVALID_HANDLE_VALUE) {
FindClose (dirp->handle);
dirp->handle = INVALID_HANDLE_VALUE;
}
/* Release search pattern */
if (dirp->patt) {
free (dirp->patt);
dirp->patt = NULL;
}
/* Release directory structure */
free (dirp);
ok = /*success*/0;
} else {
/* Invalid directory stream */
dirent_set_errno (EBADF);
ok = /*failure*/-1;
}
return ok;
}
/* Get first directory entry (internal) */
static WIN32_FIND_DATAW*
dirent_first(
_WDIR *dirp)
{
WIN32_FIND_DATAW *datap;
/* Open directory and retrieve the first entry */
dirp->handle = FindFirstFileExW(
dirp->patt, FindExInfoStandard, &dirp->data,
FindExSearchNameMatch, NULL, 0);
if (dirp->handle != INVALID_HANDLE_VALUE) {
/* a directory entry is now waiting in memory */
datap = &dirp->data;
dirp->cached = 1;
} else {
/* Failed to re-open directory: no directory entry in memory */
dirp->cached = 0;
datap = NULL;
}
return datap;
}
/*
* Get next directory entry (internal).
*
* Returns
*/
static WIN32_FIND_DATAW*
dirent_next(
_WDIR *dirp)
{
WIN32_FIND_DATAW *p;
/* Get next directory entry */
if (dirp->cached != 0) {
/* A valid directory entry already in memory */
p = &dirp->data;
dirp->cached = 0;
} else if (dirp->handle != INVALID_HANDLE_VALUE) {
/* Get the next directory entry from stream */
if (FindNextFileW (dirp->handle, &dirp->data) != FALSE) {
/* Got a file */
p = &dirp->data;
} else {
/* The very last entry has been processed or an error occurred */
FindClose (dirp->handle);
dirp->handle = INVALID_HANDLE_VALUE;
p = NULL;
}
} else {
/* End of directory stream reached */
p = NULL;
}
return p;
}
/*
* Open directory stream using plain old C-string.
*/
static DIR*
opendir(
const char *dirname)
{
struct DIR *dirp;
int error;
/* Must have directory name */
if (dirname == NULL || dirname[0] == '\0') {
dirent_set_errno (ENOENT);
return NULL;
}
/* Allocate memory for DIR structure */
dirp = (DIR*) malloc (sizeof (struct DIR));
if (dirp) {
wchar_t wname[PATH_MAX + 1];
size_t n;
/* Convert directory name to wide-character string */
error = dirent_mbstowcs_s(
&n, wname, PATH_MAX + 1, dirname, PATH_MAX + 1);
if (!error) {
/* Open directory stream using wide-character name */
dirp->wdirp = _wopendir (wname);
if (dirp->wdirp) {
/* Directory stream opened */
error = 0;
} else {
/* Failed to open directory stream */
error = 1;
}
} else {
/*
* Cannot convert file name to wide-character string. This
* occurs if the string contains invalid multi-byte sequences or
* the output buffer is too small to contain the resulting
* string.
*/
error = 1;
}
} else {
/* Cannot allocate DIR structure */
error = 1;
}
/* Clean up in case of error */
if (error && dirp) {
free (dirp);
dirp = NULL;
}
return dirp;
}
/*
* Read next directory entry.
*/
static struct dirent*
readdir(
DIR *dirp)
{
struct dirent *entry;
/*
* Read directory entry to buffer. We can safely ignore the return value
* as entry will be set to NULL in case of error.
*/
(void) readdir_r (dirp, &dirp->ent, &entry);
/* Return pointer to statically allocated directory entry */
return entry;
}
/*
* Read next directory entry into called-allocated buffer.
*
* Returns zero on success. If the end of directory stream is reached, then
* sets result to NULL and returns zero.
*/
static int
readdir_r(
DIR *dirp,
struct dirent *entry,
struct dirent **result)
{
WIN32_FIND_DATAW *datap;
/* Read next directory entry */
datap = dirent_next (dirp->wdirp);
if (datap) {
size_t n;
int error;
/* Attempt to convert file name to multi-byte string */
error = dirent_wcstombs_s(
&n, entry->d_name, PATH_MAX + 1, datap->cFileName, PATH_MAX + 1);
/*
* If the file name cannot be represented by a multi-byte string,
* then attempt to use old 8+3 file name. This allows traditional
* Unix-code to access some file names despite of unicode
* characters, although file names may seem unfamiliar to the user.
*
* Be ware that the code below cannot come up with a short file
* name unless the file system provides one. At least
* VirtualBox shared folders fail to do this.
*/
if (error && datap->cAlternateFileName[0] != '\0') {
error = dirent_wcstombs_s(
&n, entry->d_name, PATH_MAX + 1,
datap->cAlternateFileName, PATH_MAX + 1);
}
if (!error) {
DWORD attr;
/* Length of file name excluding zero terminator */
entry->d_namlen = n - 1;
/* File attributes */
attr = datap->dwFileAttributes;
if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
entry->d_type = DT_CHR;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
entry->d_type = DT_DIR;
} else {
entry->d_type = DT_REG;
}
/* Reset dummy fields */
entry->d_ino = 0;
entry->d_off = 0;
entry->d_reclen = sizeof (struct dirent);
} else {
/*
* Cannot convert file name to multi-byte string so construct
* an erroneous directory entry and return that. Note that
* we cannot return NULL as that would stop the processing
* of directory entries completely.
*/
entry->d_name[0] = '?';
entry->d_name[1] = '\0';
entry->d_namlen = 1;
entry->d_type = DT_UNKNOWN;
entry->d_ino = 0;
entry->d_off = -1;
entry->d_reclen = 0;
}
/* Return pointer to directory entry */
*result = entry;
} else {
/* No more directory entries */
*result = NULL;
}
return /*OK*/0;
}
/*
* Close directory stream.
*/
static int
closedir(
DIR *dirp)
{
int ok;
if (dirp) {
/* Close wide-character directory stream */
ok = _wclosedir (dirp->wdirp);
dirp->wdirp = NULL;
/* Release multi-byte character version */
free (dirp);
} else {
/* Invalid directory stream */
dirent_set_errno (EBADF);
ok = /*failure*/-1;
}
return ok;
}
/* Convert multi-byte string to wide character string */
static int
dirent_mbstowcs_s(
size_t *pReturnValue,
wchar_t *wcstr,
size_t sizeInWords,
const char *mbstr,
size_t count)
{
int error;
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 or later */
error = mbstowcs_s (pReturnValue, wcstr, sizeInWords, mbstr, count);
#else
/* Older Visual Studio or non-Microsoft compiler */
size_t n;
/* Convert to wide-character string (or count characters) */
n = mbstowcs (wcstr, mbstr, sizeInWords);
if (!wcstr || n < count) {
/* Zero-terminate output buffer */
if (wcstr && sizeInWords) {
if (n >= sizeInWords) {
n = sizeInWords - 1;
}
wcstr[n] = 0;
}
/* Length of resulting multi-byte string WITH zero terminator */
if (pReturnValue) {
*pReturnValue = n + 1;
}
/* Success */
error = 0;
} else {
/* Could not convert string */
error = 1;
}
#endif
return error;
}
/* Convert wide-character string to multi-byte string */
static int
dirent_wcstombs_s(
size_t *pReturnValue,
char *mbstr,
size_t sizeInBytes, /* max size of mbstr */
const wchar_t *wcstr,
size_t count)
{
int error;
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 or later */
error = wcstombs_s (pReturnValue, mbstr, sizeInBytes, wcstr, count);
#else
/* Older Visual Studio or non-Microsoft compiler */
size_t n;
/* Convert to multi-byte string (or count the number of bytes needed) */
n = wcstombs (mbstr, wcstr, sizeInBytes);
if (!mbstr || n < count) {
/* Zero-terminate output buffer */
if (mbstr && sizeInBytes) {
if (n >= sizeInBytes) {
n = sizeInBytes - 1;
}
mbstr[n] = '\0';
}
/* Length of resulting multi-bytes string WITH zero-terminator */
if (pReturnValue) {
*pReturnValue = n + 1;
}
/* Success */
error = 0;
} else {
/* Cannot convert string */
error = 1;
}
#endif
return error;
}
/* Set errno variable */
static void
dirent_set_errno(
int error)
{
#if defined(_MSC_VER) && _MSC_VER >= 1400
/* Microsoft Visual Studio 2005 and later */
_set_errno (error);
#else
/* Non-Microsoft compiler or older Microsoft compiler */
errno = error;
#endif
}
#ifdef __cplusplus
}
#endif
#endif /*DIRENT_H*/

106
contrib/win32/getopt.c Normal file
View File

@ -0,0 +1,106 @@
#include "getopt.h" // make sure you construct the header file as dictated above
/*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <string.h>
#include <stdio.h>
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
/*
* getopt --
* Parse argc/argv argument vector.
*/
int getopt(int nargc, char * const nargv[], const char *ostr)
{
static char *place = EMSG; /* option letter processing */
const char *oli; /* option letter list index */
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc || *(place = nargv[optind]) != '-') {
place = EMSG;
return (-1);
}
if (place[1] && *++place == '-') { /* found "--" */
++optind;
place = EMSG;
return (-1);
}
} /* option letter okay? */
if ((optopt = (int)*place++) == (int)':' ||
!(oli = strchr(ostr, optopt))) {
/*
* if the user didn't specify '-' as an option,
* assume it means -1.
*/
if (optopt == (int)'-')
return (-1);
if (!*place)
++optind;
if (opterr && *ostr != ':')
(void)printf("illegal option -- %c\n", optopt);
return (BADCH);
}
if (*++oli != ':') { /* don't need argument */
optarg = NULL;
if (!*place)
++optind;
}
else { /* need an argument */
if (*place) /* no white space */
optarg = place;
else if (nargc <= ++optind) { /* no arg */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)printf("option requires an argument -- %c\n", optopt);
return (BADCH);
}
else /* white space */
optarg = nargv[optind];
place = EMSG;
++optind;
}
return (optopt); /* dump back option letter */
}

13
contrib/win32/getopt.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef GETOPT_H
#define GETOPT_H
extern int opterr; /* if error message should be printed */
extern int optind; /* index into parent argv vector */
extern int optopt; /* character checked for validity */
extern int optreset; /* reset getopt */
extern char *optarg; /* argument associated with option */
int getopt(int nargc, char * const nargv[], const char *ostr);
#endif

View File

@ -123,7 +123,7 @@ uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
{ {
struct serial_port_windows *spw; struct serial_port_windows *spw;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d baud.", uiPortSpeed);
// Set port speed (Input and Output) // Set port speed (Input and Output)
switch (uiPortSpeed) { switch (uiPortSpeed) {
case 9600: case 9600:
@ -135,7 +135,7 @@ uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
case 460800: case 460800:
break; break;
default: default:
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d bauds. Speed value must be one of these constants: 9600 (default), 19200, 38400, 57600, 115200, 230400 or 460800.", uiPortSpeed); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d baud. Speed value must be one of these constants: 9600 (default), 19200, 38400, 57600, 115200, 230400 or 460800.", uiPortSpeed);
return; return;
}; };
spw = (struct serial_port_windows *) sp; spw = (struct serial_port_windows *) sp;
@ -183,7 +183,7 @@ uart_receive(serial_port sp, uint8_t *pbtRx, const size_t szRx, void *abort_p, i
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Timeouts are set to %lu ms", timeout_ms); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Timeouts are set to %lu ms", timeout_ms);
// TODO Enhance the reception method // TODO Enhance the reception method
// - According to MSDN, it could be better to implement nfc_abort_command() mecanism using Cancello() // - According to MSDN, it could be better to implement nfc_abort_command() mechanism using Cancello()
volatile bool *abort_flag_p = (volatile bool *)abort_p; volatile bool *abort_flag_p = (volatile bool *)abort_p;
do { do {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ReadFile"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ReadFile");

View File

@ -4,9 +4,10 @@ VERSION 1.7
EXPORTS EXPORTS
nfc_init nfc_init
nfc_exit nfc_exit
nfc_register_driver
nfc_open nfc_open
nfc_close nfc_close
nfc_abbort_command nfc_abort_command
nfc_list_devices nfc_list_devices
nfc_idle nfc_idle
nfc_initiator_init nfc_initiator_init
@ -17,7 +18,6 @@ EXPORTS
nfc_initiator_select_dep_target nfc_initiator_select_dep_target
nfc_initiator_poll_dep_target nfc_initiator_poll_dep_target
nfc_initiator_deselect_target nfc_initiator_deselect_target
nfc_initiator_poll_targets
nfc_initiator_transceive_bytes nfc_initiator_transceive_bytes
nfc_initiator_transceive_bits nfc_initiator_transceive_bits
nfc_initiator_transceive_bytes_timed nfc_initiator_transceive_bytes_timed
@ -36,13 +36,22 @@ EXPORTS
nfc_device_get_connstring nfc_device_get_connstring
nfc_device_get_supported_modulation nfc_device_get_supported_modulation
nfc_device_get_supported_baud_rate nfc_device_get_supported_baud_rate
nfc_device_get_supported_baud_rate_target_mode
nfc_device_set_property_int nfc_device_set_property_int
nfc_device_set_property_bool nfc_device_set_property_bool
nfc_emulate_target
iso14443a_crc iso14443a_crc
iso14443a_crc_append iso14443a_crc_append
iso14443b_crc
iso14443b_crc_append
iso14443a_locate_historical_bytes iso14443a_locate_historical_bytes
nfc_free
nfc_version nfc_version
nfc_device_get_information_about nfc_device_get_information_about
str_nfc_modulation_type str_nfc_modulation_type
str_nfc_baud_rate str_nfc_baud_rate
str_nfc_target str_nfc_target
pn53x_transceive
pn532_SAMConfiguration
pn53x_read_register
pn53x_write_register

View File

@ -0,0 +1,57 @@
LIBRARY nfc
VERSION 1.7
EXPORTS
nfc_init
nfc_exit
nfc_register_driver
nfc_open
nfc_close
nfc_abort_command
nfc_list_devices
nfc_idle
nfc_initiator_init
nfc_initiator_init_secure_element
nfc_initiator_select_passive_target
nfc_initiator_list_passive_targets
nfc_initiator_poll_target
nfc_initiator_select_dep_target
nfc_initiator_poll_dep_target
nfc_initiator_deselect_target
nfc_initiator_transceive_bytes
nfc_initiator_transceive_bits
nfc_initiator_transceive_bytes_timed
nfc_initiator_transceive_bits_timed
nfc_initiator_target_is_present
nfc_target_init
nfc_target_send_bytes
nfc_target_receive_bytes
nfc_target_send_bits
nfc_target_receive_bits
nfc_strerror
nfc_strerror_r
nfc_perror
nfc_device_get_last_error
nfc_device_get_name
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
nfc_emulate_target
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
str_nfc_baud_rate
str_nfc_target
pn53x_transceive
pn532_SAMConfiguration
pn53x_read_register
pn53x_write_register

View File

@ -34,21 +34,24 @@
// Handle platform specific includes // Handle platform specific includes
#include "contrib/windows.h" #include "contrib/windows.h"
//There is no setenv()and unsetenv() in windows,but we can use putenv() instead.
int setenv(const char *name, const char *value, int overwrite) int setenv(const char *name, const char *value, int overwrite)
{ {
int exists = GetEnvironmentVariableA(name, NULL, 0); char *env = getenv(name);
if ((exists && overwrite) || (!exists)) { if ((env && overwrite) || (!env)) {
if (!SetEnvironmentVariableA(name, value)) { char *str[32];
// Set errno here correctly strcpy(str, name);
return -1; strcat(str, "=");
} strcat(str, value);
return 0; return putenv(str);
} }
// Exists and overwrite is 0.
return -1; return -1;
} }
void unsetenv(const char *name) void unsetenv(const char *name)
{ {
SetEnvironmentVariableA(name, NULL); char *str[32];
strcpy(str, name);
strcat(str, "=");
putenv(str);
} }

View File

@ -1,15 +1,9 @@
#include "windows.h"
1 VERSIONINFO 1 VERSIONINFO
FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0 FILEVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0 PRODUCTVERSION @VERSION_MAJOR@,@VERSION_MINOR@,@VERSION_PATCH@,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG FILEFLAGS 0x0L
FILEFLAGS VS_FF_DEBUG|VS_FF_PRERELEASE FILEOS 0x00040004L
#else
FILEFLAGS 0L
#endif
FILEOS VOS_NT_WINDOWS32
FILETYPE @RC_FILE_TYPE@ FILETYPE @RC_FILE_TYPE@
FILESUBTYPE 0x0L FILESUBTYPE 0x0L
BEGIN BEGIN

View File

@ -49,7 +49,9 @@
# define ENOTSUP WSAEOPNOTSUPP # define ENOTSUP WSAEOPNOTSUPP
# define ECONNABORTED WSAECONNABORTED # define ECONNABORTED WSAECONNABORTED
# else # else
#ifndef _MSC_VER
# define snprintf sprintf_s # define snprintf sprintf_s
#endif
# define strdup _strdup # define strdup _strdup
# endif # endif

View File

@ -8,6 +8,11 @@ SET(EXAMPLES-SOURCES
nfc-mfsetuid nfc-mfsetuid
nfc-poll nfc-poll
nfc-relay nfc-relay
nfc-st25tb
pn53x-diagnose
pn53x-sam
pn53x-tamashell
) )
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libnfc) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libnfc)
@ -20,9 +25,15 @@ FOREACH(source ${EXAMPLES-SOURCES})
SET(RC_COMMENT "${PACKAGE_NAME} example") SET(RC_COMMENT "${PACKAGE_NAME} example")
SET(RC_INTERNAL_NAME ${source}) SET(RC_INTERNAL_NAME ${source})
SET(RC_ORIGINAL_NAME ${source}.exe) SET(RC_ORIGINAL_NAME ${source}.exe)
SET(RC_FILE_TYPE VFT_APP) # RC_FILE_TYPE: VFT_APP
SET(RC_FILE_TYPE 0x00000001L)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY)
LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc) LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc)
IF(${source} MATCHES "nfc-st25tb")
LIST(APPEND TARGETS ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/getopt.c)
ENDIF()
ENDIF(WIN32) ENDIF(WIN32)
ADD_EXECUTABLE(${source} ${TARGETS}) ADD_EXECUTABLE(${source} ${TARGETS})

View File

@ -10,6 +10,7 @@ bin_PROGRAMS = \
nfc-mfsetuid \ nfc-mfsetuid \
nfc-poll \ nfc-poll \
nfc-relay \ nfc-relay \
nfc-st25tb \
pn53x-diagnose \ pn53x-diagnose \
pn53x-sam pn53x-sam
@ -63,6 +64,9 @@ nfc_mfsetuid_SOURCES = nfc-mfsetuid.c
nfc_mfsetuid_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_mfsetuid_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la $(top_builddir)/utils/libnfcutils.la
nfc_st25tb_SOURCES = nfc-st25tb.c
nfc_st25tb_LDADD = $(top_builddir)/libnfc/libnfc.la
pn53x_diagnose_SOURCES = pn53x-diagnose.c pn53x_diagnose_SOURCES = pn53x-diagnose.c
pn53x_diagnose_LDADD = $(top_builddir)/libnfc/libnfc.la \ pn53x_diagnose_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la $(top_builddir)/utils/libnfcutils.la
@ -74,6 +78,7 @@ pn53x_sam_LDADD = $(top_builddir)/libnfc/libnfc.la \
pn53x_tamashell_SOURCES = pn53x-tamashell.c pn53x_tamashell_SOURCES = pn53x-tamashell.c
pn53x_tamashell_LDADD = $(top_builddir)/libnfc/libnfc.la \ pn53x_tamashell_LDADD = $(top_builddir)/libnfc/libnfc.la \
$(top_builddir)/utils/libnfcutils.la $(top_builddir)/utils/libnfcutils.la
pn53x_tamashell_CFLAGS = @READLINE_INCLUDES@ -I$(top_srcdir)
pn53x_tamashell_LDFLAGS = @READLINE_LIBS@ pn53x_tamashell_LDFLAGS = @READLINE_LIBS@
quick_start_example1_SOURCES = doc/quick_start_example1.c quick_start_example1_SOURCES = doc/quick_start_example1.c

View File

@ -23,7 +23,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -18,7 +18,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -18,7 +18,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -35,7 +35,7 @@ bug, this problem is due to ACR122's internal MCU in front of NFC chip (PN532).
Please report any bugs on the Please report any bugs on the
.Em libnfc .Em libnfc
issue tracker at: issue tracker at:
.Em http://code.google.com/p/libnfc/issues .Em https://github.com/nfc-tools/libnfc/issues
.Sh LICENCE .Sh LICENCE
.Em libnfc .Em libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -39,7 +39,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -266,9 +266,9 @@ main(int argc, char *argv[])
}, },
.nti = { .nti = {
.nai = { .nai = {
abtAtqa = { 0x03, 0x44 }, .abtAtqa = { 0x03, 0x44 },
abtUid = { 0x08, 0xab, 0xcd, 0xef }, .abtUid = { 0x08, 0xab, 0xcd, 0xef },
btSak = 0x20, .btSak = 0x20,
.szUidLen = 4, .szUidLen = 4,
.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, .abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 },
.szAtsLen = 5, .szAtsLen = 5,

View File

@ -14,7 +14,7 @@ fully customized UID but only of "random" UIDs, which always start with 0x08.
The nfc-emulate-uid tool demonstrates that this can still be done using The nfc-emulate-uid tool demonstrates that this can still be done using
transmission of raw frames, and the desired UID can be optionally specified. transmission of raw frames, and the desired UID can be optionally specified.
This makes it a serious thread for security systems that rely only on the This makes it a serious threat for security systems that rely only on the
uniqueness of the UID. uniqueness of the UID.
Unfortunately, this example can't directly start in fully customisable Unfortunately, this example can't directly start in fully customisable
@ -54,7 +54,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -79,7 +79,10 @@ intr_hdlr(int sig)
if (pnd != NULL) { if (pnd != NULL) {
printf("\nAborting current command...\n"); printf("\nAborting current command...\n");
nfc_abort_command(pnd); nfc_abort_command(pnd);
nfc_close(pnd);
} }
nfc_exit(context);
exit(EXIT_SUCCESS);
} }
static void static void
@ -237,7 +240,4 @@ main(int argc, char *argv[])
} }
} }
} }
nfc_close(pnd);
nfc_exit(context);
exit(EXIT_SUCCESS);
} }

View File

@ -24,7 +24,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -10,6 +10,7 @@
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2011 Adam Laurie * Copyright (C) 2011 Adam Laurie
* Copyright (C) 2014 Dario Carluccio
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -140,12 +141,13 @@ transmit_bytes(const uint8_t *pbtTx, const size_t szTx)
static void static void
print_usage(char *argv[]) print_usage(char *argv[])
{ {
printf("Usage: %s [OPTIONS] [UID]\n", argv[0]); printf("Usage: %s [OPTIONS] [UID|BLOCK0]\n", argv[0]);
printf("Options:\n"); printf("Options:\n");
printf("\t-h\tHelp. Print this message.\n"); printf("\t-h\tHelp. Print this message.\n");
printf("\t-f\tFormat. Delete all data (set to 0xFF) and reset ACLs to default.\n"); printf("\t-f\tFormat. Delete all data (set to 0xFF) and reset ACLs to default.\n");
printf("\t-q\tQuiet mode. Suppress output of READER and CARD data (improves timing).\n"); printf("\t-q\tQuiet mode. Suppress output of READER and CARD data (improves timing).\n");
printf("\n\tSpecify UID (4 HEX bytes) to set UID, or leave blank for default '01234567'.\n"); printf("\n\tSpecify UID (4 HEX bytes) to set UID, or leave blank for default '01234567'.\n");
printf("\n\tSpecify BLOCK0 (16 HEX bytes) to set content of Block0. CRC (Byte 4) is recalculated an overwritten'.\n");
printf("\tThis utility can be used to recover cards that have been damaged by writing bad\n"); printf("\tThis utility can be used to recover cards that have been damaged by writing bad\n");
printf("\tdata (e.g. wrong BCC), thus making them non-selectable by most tools/readers.\n"); printf("\tdata (e.g. wrong BCC), thus making them non-selectable by most tools/readers.\n");
printf("\n\t*** Note: this utility only works with special Mifare 1K cards (Chinese clones).\n\n"); printf("\n\t*** Note: this utility only works with special Mifare 1K cards (Chinese clones).\n\n");
@ -177,6 +179,14 @@ main(int argc, char *argv[])
} }
abtData[4] = abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3]; abtData[4] = abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3];
iso14443a_crc_append(abtData, 16); iso14443a_crc_append(abtData, 16);
} else if (strlen(argv[arg]) == 32) {
for (i = 0 ; i < 16 ; ++i) {
memcpy(tmp, argv[arg] + i * 2, 2);
sscanf(tmp, "%02x", &c);
abtData[i] = (char) c;
}
abtData[4] = abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3];
iso14443a_crc_append(abtData, 16);
} else { } else {
ERR("%s is not supported option.", argv[arg]); ERR("%s is not supported option.", argv[arg]);
print_usage(argv); print_usage(argv);
@ -355,13 +365,23 @@ main(int argc, char *argv[])
// now reset UID // now reset UID
iso14443a_crc_append(abtHalt, 2); iso14443a_crc_append(abtHalt, 2);
transmit_bytes(abtHalt, 4); transmit_bytes(abtHalt, 4);
transmit_bits(abtUnlock1, 7);
if (format) { if (!transmit_bits(abtUnlock1, 7)) {
transmit_bytes(abtWipe, 1); printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n");
transmit_bytes(abtHalt, 4); } else {
transmit_bits(abtUnlock1, 7); if (format) {
transmit_bytes(abtWipe, 1);
transmit_bytes(abtHalt, 4);
transmit_bits(abtUnlock1, 7);
}
if (transmit_bytes(abtUnlock2, 1)) {
printf("Card unlocked\n");
} else {
printf("Warning: Unlock command [2/2]: failed / not acknowledged.\n");
}
} }
transmit_bytes(abtUnlock2, 1);
transmit_bytes(abtWrite, 4); transmit_bytes(abtWrite, 4);
transmit_bytes(abtData, 18); transmit_bytes(abtData, 18);
if (format) { if (format) {

View File

@ -42,7 +42,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@ -101,14 +102,15 @@ main(int argc, const char *argv[])
const uint8_t uiPollNr = 20; const uint8_t uiPollNr = 20;
const uint8_t uiPeriod = 2; const uint8_t uiPeriod = 2;
const nfc_modulation nmModulations[5] = { const nfc_modulation nmModulations[6] = {
{ .nmt = NMT_ISO14443A, .nbr = NBR_106 }, { .nmt = NMT_ISO14443A, .nbr = NBR_106 },
{ .nmt = NMT_ISO14443B, .nbr = NBR_106 }, { .nmt = NMT_ISO14443B, .nbr = NBR_106 },
{ .nmt = NMT_FELICA, .nbr = NBR_212 }, { .nmt = NMT_FELICA, .nbr = NBR_212 },
{ .nmt = NMT_FELICA, .nbr = NBR_424 }, { .nmt = NMT_FELICA, .nbr = NBR_424 },
{ .nmt = NMT_JEWEL, .nbr = NBR_106 }, { .nmt = NMT_JEWEL, .nbr = NBR_106 },
{ .nmt = NMT_ISO14443BICLASS, .nbr = NBR_106 },
}; };
const size_t szModulations = 5; const size_t szModulations = 6;
nfc_target nt; nfc_target nt;
int res = 0; int res = 0;
@ -145,9 +147,15 @@ main(int argc, const char *argv[])
if (res > 0) { if (res > 0) {
print_nfc_target(&nt, verbose); print_nfc_target(&nt, verbose);
printf("Waiting for card removing...");
fflush(stdout);
while (0 == nfc_initiator_target_is_present(pnd, NULL)) {}
nfc_perror(pnd, "nfc_initiator_target_is_present");
printf("done.\n");
} else { } else {
printf("No target found.\n"); printf("No target found.\n");
} }
nfc_close(pnd); nfc_close(pnd);
nfc_exit(context); nfc_exit(context);
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);

View File

@ -22,7 +22,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

609
examples/nfc-st25tb.c Normal file
View File

@ -0,0 +1,609 @@
/*-
* 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:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2 )Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Note that this license only applies on the examples, NFC library itself is under LGPL
*
*/
/**
* @file nfc-st25tb.c
* @brief Tool to operate on ISO-14443-B ST25TB* and legacy SR* cards
*/
/* Benjamin DELPY `gentilkiwi`
* https://blog.gentilkiwi.com
* benjamin@gentilkiwi.com
* Licence : https://creativecommons.org/licenses/by/4.0/
* Rely on : libnfc - https://github.com/nfc-tools/libnfc
*
* $ gcc -Wall -lnfc -o nfc-st25tb nfc-st25tb.c
* $ ./nfc-st25tb -h
*
* Tested with
* - ST25TB512-AC - (BE/Brussels/STIB ; AliExpress ones)
* - ST25TB512-AT - (FR/Lille/Ilevia ; FR/Reims/Citura)
* - SRT512 - legacy - (FR/Bordeaux/TBM)
* - SRI512 - legacy - (anonymous vending machine)
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <nfc/nfc.h>
#if defined(WIN32) /* mingw compiler */
#include <getopt.h>
#endif
#define ST25TB_SR_BLOCK_MAX_SIZE ((uint8_t) 4) // for static arrays
typedef void(*get_info_specific) (uint8_t * systemArea);
typedef struct _st_data {
uint8_t chipId;
bool bIsLegacy;
const char *szName;
const char *szDatasheetUrl;
uint8_t blockSize;
uint8_t nbNormalBlock;
uint8_t bnSystem;
get_info_specific pfnGetInfo;
} st_data;
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt);
const st_data * get_info(const nfc_target *pnt, bool bPrintIt);
void display_system_info(nfc_device *pnd, const st_data * stdata);
void print_hex(const uint8_t *pbtData, const size_t szBytes);
int main(int argc, char *argv[])
{
nfc_context *context = NULL;
nfc_device *pnd = NULL;
nfc_target nt = {0};
nfc_modulation nm = {NMT_ISO14443B, NBR_106};
const st_data * stcurrent;
int opt, res;
bool bIsBlock = false, bIsRead = false, bIsWrite = false, bIsBadCli = false;
uint8_t i, blockNumber = 0, data[ST25TB_SR_BLOCK_MAX_SIZE] = {0xff, 0xff, 0xff, 0xff}; // just in case...
size_t cbData = 0;
while(!bIsBadCli && ((opt = getopt(argc, argv, ":hib:rw:")) != -1))
{
switch(opt)
{
case 'i':
break;
case 'b':
if(optarg)
{
bIsBlock = true;
blockNumber = strtoul(optarg, NULL, 0);
}
else bIsBadCli = true;
break;
case 'r':
bIsRead = true;
break;
case 'w':
if(optarg)
{
cbData = strlen(optarg);
if((cbData == (2*2)) || ((cbData == (4*2))))
{
cbData >>= 1;
if(cbData == 2) // sr176
{
res = sscanf(optarg, "%02hhx%02hhx", data, data + 1);
}
else // all others
{
res = sscanf(optarg, "%02hhx%02hhx%02hhx%02hhx", data, data + 1, data + 2, data + 3);
}
if(res == (int) cbData)
{
bIsWrite = true;
}
}
if(!bIsWrite)
{
bIsBadCli = true;
}
}
break;
default: // includes -h
bIsBadCli = true;
}
}
if(!bIsBadCli)
{
if(bIsBlock && (bIsRead || bIsWrite))
{
if(bIsRead && bIsWrite)
{
printf("|mode : read then write\n");
}
else if(bIsRead)
{
printf("|mode : read\n");
}
else if(bIsWrite)
{
printf("|mode : write\n");
}
printf("|blk num: 0x%02hhx\n", blockNumber);
if(bIsWrite)
{
printf("|data : ");
print_hex(data, cbData);
printf("\n");
}
}
else if(!bIsRead && !bIsWrite && !bIsBlock)
{
printf("|mode : info\n");
}
else bIsBadCli = true;
}
if(!bIsBadCli)
{
nfc_init(&context);
if(context)
{
pnd = nfc_open(context, NULL);
if(pnd)
{
res = nfc_initiator_init(pnd);
if(res == NFC_SUCCESS)
{
printf("Reader : %s - via %s\n ...wait for card...\n", nfc_device_get_name(pnd), nfc_device_get_connstring(pnd));
res = nfc_initiator_list_passive_targets(pnd, nm, &nt, 1);
if(res == 0) // we don't really wanted a NMT_ISO14443B
{
nm.nmt = NMT_ISO14443B2SR; // we want a NMT_ISO14443B2SR, but needed to ask for NMT_ISO14443B before
if (nfc_initiator_select_passive_target(pnd, nm, NULL, 0, &nt) > 0)
{
stcurrent = get_info(&nt, true);
if(stcurrent)
{
printf("\n");
if(bIsBlock && (bIsRead || bIsWrite))
{
if(bIsRead)
{
get_block_at(pnd, blockNumber, NULL, 0, true);
}
if(bIsWrite)
{
set_block_at_confirmed(pnd, blockNumber, data, cbData, true);
}
}
else if(!bIsRead && !bIsWrite && !bIsBlock)
{
for(i = 0; i < stcurrent->nbNormalBlock; i++)
{
get_block_at(pnd, i, NULL, 0, true);
}
display_system_info(pnd, stcurrent);
}
}
}
}
else if(res > 0)
{
printf("ERROR - We got a NMT_ISO14443B ?\n");
}
else printf("ERROR - nfc_initiator_list_passive_targets: %i\n", res);
}
else printf("ERROR - nfc_initiator_init: %i\n", res);
nfc_close(pnd);
}
else printf("ERROR - nfc_open\n");
nfc_exit(context);
}
else printf("ERROR - nfc_init\n");
}
else
{
printf(
"Usage:\n"
" %s [-i]\n"
" %s -b N -r\n"
" %s -b N [-r] -w ABCD[EF01]\n %s -h\n"
"Options:\n"
" -i (default) information mode - will try to dump the tag content and display informations\n"
" -b N specify block number to operate on (tag dependent), needed for read (-r) and write (-w) modes\n"
" -r read mode - will try to read block (specified with -b N parameter)\n"
" -w ABCD[EF01] write mode - will try to write specicied data (2 or 4 bytes depending on tag) to block (specified with -b N parameter)\n"
" -h this help\n"
"Examples:\n"
" %s -i\n"
" Display all tag informations\n"
" %s -b 0x0e -r\n"
" Read block 0x0e (14) of the tag\n"
" %s -b 0x0d -w 0123abcd\n"
" Write block 0x0d (13) of the tag with hexadecimal value '01 23 ab cd'\n"
" %s -b 0x0c -r -w 0123abcd\n"
" Read, then write block 0x0c (12) of the tag with hexadecimal value '01 23 ab cd'\n"
"Warnings:\n"
" Be careful with: system area, counters & otp, bytes order.\n"
, argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0], argv[0]);
}
return 0;
}
bool get_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t tx[2] = {0x08, block}, rx[ST25TB_SR_BLOCK_MAX_SIZE]; // 4 is the maximum, SR176 (only 2) will fit
int res;
res = nfc_initiator_transceive_bytes(pnd, tx, sizeof(tx), rx, sizeof(rx), 0);
if((res == 2) || (res == 4))
{
if(data)
{
if(cbData == res)
{
memcpy(data, rx, res);
bRet = true;
}
else printf("ERROR - We got %i bytes for a %hhu buffer size?\n", res, cbData);
}
else bRet = true;
if(bPrintIt)
{
printf("[0x%02hhx] ", block);
print_hex(rx, res);
printf("\n");
}
}
else if(res > 0)
{
printf("ERROR - We got %i bytes?\n", res);
}
else printf("ERROR - nfc_initiator_transceive_bytes(get): %i\n", res);
return bRet;
}
bool set_block_at(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t tx[2 + ST25TB_SR_BLOCK_MAX_SIZE] = {0x09, block}; // 4 is the maximum, SR176 (only 2) will fit
int res;
if(cbData <= ST25TB_SR_BLOCK_MAX_SIZE)
{
memcpy(tx + 2, data, cbData);
if(bPrintIt)
{
printf(">0x%02hhx> ", block);
print_hex(data, cbData);
printf("\n");
}
res = nfc_initiator_transceive_bytes(pnd, tx, 2 + cbData, NULL, 0, 0);
if(res == NFC_ERFTRANS) // ? :')
{
bRet = true;
}
else printf("ERROR - nfc_initiator_transceive_bytes(set): %i\n", res);
}
else printf("ERROR - Wanted to write %hhu bytes, but maximum is %hhu\n", cbData, ST25TB_SR_BLOCK_MAX_SIZE);
return bRet;
}
bool set_block_at_confirmed(nfc_device *pnd, uint8_t block, uint8_t *data, uint8_t cbData, bool bPrintIt)
{
bool bRet = false;
uint8_t buffer[ST25TB_SR_BLOCK_MAX_SIZE]; // maximum size will be checked in set_block_at
if(set_block_at(pnd, block, data, cbData, bPrintIt))
{
if(get_block_at(pnd, block, buffer, cbData, bPrintIt))
{
if(memcmp(data, buffer, cbData) == 0)
{
bRet = true;
}
else if(bPrintIt)
{
printf("WARNING - not same value readed after write\n");
}
}
}
return bRet;
}
void get_info_st25tb512(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | ST reserved : ");
for(i = 0; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
for(i = 16; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 16; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
}
}
}
void get_info_st25tb2k_4k(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | ST reserved : ");
for(i = 0; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_RegU: ", b, b ? "not " : "");
for(i = 16; i < 24; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 24; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
{
printf(" blocks 0x07 and 0x08 are write protected\n");
}
for(i = 25; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", ((uint8_t) (i - 16)));
}
}
}
void get_info_sr176_legacy(uint8_t * systemArea)
{
uint8_t i;
printf(" | Fixed Chip_ID: 0x%1x\n | ST reserved : ", systemArea[0] & 0x0f);
for(i = 4; i < 8; i++)
{
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 8; i < 16; i++)
{
printf("%hhu", (uint8_t) (((*(uint16_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 8; i < 16; i++)
{
if(((*(uint16_t *) systemArea) >> i) & 1)
{
printf(" blocks 0x%02hhx and 0x%02hhx are write protected\n", (uint8_t) ((i - 8) * 2), (uint8_t) (((i - 8) * 2) + 1));
}
}
}
void get_info_sri_srt_512_legacy(uint8_t * systemArea)
{
uint8_t b, i;
b = ((*(uint32_t *) systemArea) >> 15) & 1;
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
for(i = 8; i < 15; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | b15 : %hhu - %sOTP (?)\n | OTP_Lock_Reg : ", b, b ? "not " : "");
for(i = 16; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
for(i = 16; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
}
}
}
void get_info_sri2k_4k_srix4k_srix512_legacy(uint8_t * systemArea)
{
uint8_t i;
printf(" | Fixed Chip_ID: 0x%02hhx\n | ST reserved : ", systemArea[0]);
for(i = 8; i < 24; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n | OTP_Lock_Reg : ");
for(i = 24; i < 32; i++)
{
printf("%hhu", (uint8_t) (((*(uint32_t *) systemArea) >> i) & 1));
}
printf("\n");
if(!(((*(uint32_t *) systemArea) >> 24) & 1))
{
printf(" blocks 0x07 and 0x08 are write protected\n");
}
for(i = 25; i < 32; i++)
{
if(!(((*(uint32_t *) systemArea) >> i) & 1))
{
printf(" block 0x%02hhx is write protected\n", (uint8_t) (i - 16));
}
}
}
const st_data STRefs[] = {
{0x1b, false, "ST25TB512-AC", "https://www.st.com/resource/en/datasheet/st25tb512-ac.pdf", 4, 16, 255, get_info_st25tb512},
{0x33, false, "ST25TB512-AT", "https://www.st.com/resource/en/datasheet/st25tb512-at.pdf", 4, 16, 255, get_info_st25tb512},
{0x3f, false, "ST25TB02K", "https://www.st.com/resource/en/datasheet/st25tb02k.pdf", 4, 64, 255, get_info_st25tb2k_4k},
{0x1f, false, "ST25TB04K", "https://www.st.com/resource/en/datasheet/st25tb04k.pdf", 4, 128, 255, get_info_st25tb2k_4k},
};
const st_data STRefs_legacy[] = {
{ 0, true, "SRI4K(s)", NULL, 4, 128, 255, NULL},
{ 2, true, "SR176", "https://www.st.com/resource/en/datasheet/sr176.pdf", 2, 15, 15, get_info_sr176_legacy},
{ 3, true, "SRIX4K", NULL, 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{ 4, true, "SRIX512", "https://www.st.com/resource/en/datasheet/srix512.pdf", 4, 16, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{ 6, true, "SRI512", "https://www.st.com/resource/en/datasheet/sri512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
{ 7, true, "SRI4K", "https://www.st.com/resource/en/datasheet/sri4k.pdf", 4, 128, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
{12, true, "SRT512", "https://www.st.com/resource/en/datasheet/srt512.pdf", 4, 16, 255, get_info_sri_srt_512_legacy},
{15, true, "SRI2K", "https://www.st.com/resource/en/datasheet/sri2k.pdf", 4, 64, 255, get_info_sri2k_4k_srix4k_srix512_legacy},
};
const st_data * get_info(const nfc_target *pnt, bool bPrintIt)
{
const st_data *currentData = NULL;
const uint8_t *p;
uint8_t chipId, i;
if(pnt->nm.nmt == NMT_ISO14443B2SR)
{
printf("Target : %s (%s)\nUID : ", str_nfc_modulation_type(pnt->nm.nmt), str_nfc_baud_rate(pnt->nm.nbr));
print_hex(pnt->nti.nsi.abtUID, sizeof(pnt->nti.nsi.abtUID));
printf("\n");
p = pnt->nti.nsi.abtUID;
if(p[7] == 0xd0) // ST25TB* / SR*
{
chipId = p[5];
printf("Manuf : 0x%02hhx - %s\n", p[6], (p[6] == 0x02) ? "STMicroelectronics" : "other");
for(i = 0; i < (sizeof(STRefs) / sizeof(STRefs[0])); i++)
{
if(chipId == STRefs[i].chipId)
{
currentData = &STRefs[i];
break;
}
}
if(!currentData)
{
chipId >>= 2;
for(i = 0; i < (sizeof(STRefs_legacy) / sizeof(STRefs_legacy[0])); i++)
{
if(chipId == STRefs_legacy[i].chipId)
{
currentData = &STRefs_legacy[i];
break;
}
}
}
if(bPrintIt && currentData)
{
printf("ChipId : 0x%02hhx - %s%s\nSerial : 0x", currentData->chipId, currentData->szName, currentData->bIsLegacy ? " (legacy)" : "");
if(currentData->bIsLegacy)
{
printf("%1hhx", (uint8_t) (p[5] & 0x03));
}
printf("%02hhx%02hhx%02hhx%02hhx%02hhx\n|blk sz : %hhu bits\n|nb blks: %hhu\n|sys idx: %hhu\n", p[4], p[3], p[2], p[1], p[0], (uint8_t) (currentData->blockSize * 8), currentData->nbNormalBlock, currentData->bnSystem);
}
}
else printf("WARNI - Last byte of UID isn\'t 0xd0, but 0x%02hhx (not ST25TB / SR series?)\n", p[7]);
}
else printf("ERROR - not a NMT_ISO14443B2SR ?\n");
return currentData;
}
void display_system_info(nfc_device *pnd, const st_data * stdata)
{
uint8_t systemArea[ST25TB_SR_BLOCK_MAX_SIZE];
if(get_block_at(pnd, stdata->bnSystem, systemArea, stdata->blockSize, true))
{
if(stdata->pfnGetInfo)
{
stdata->pfnGetInfo(systemArea);
}
}
}
void print_hex(const uint8_t *pbtData, const size_t szBytes)
{
size_t szPos;
for (szPos = 0; szPos < szBytes; szPos++)
{
printf("%02hhx ", pbtData[szPos]);
}
}

View File

@ -13,7 +13,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -19,7 +19,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

View File

@ -1,8 +1,10 @@
#!/bin/sh #!/bin/sh
#DEBUG='//;'
cat << EOF | \ cat << EOF | \
pn53x-tamashell |\ pn53x-tamashell |\
awk '\ awk $DEBUG'\
/^> #.*:/{ /^> #.*:/{
sub(/^> #/,"") sub(/^> #/,"")
n=$0 n=$0
@ -21,27 +23,33 @@ cat << EOF | \
# Select one typeB target # Select one typeB target
4A010300 4A010300
# SELECT AID "1TIC.ICA"
4001 00a4 0400 08 315449432e494341
# Select ICC file # Select ICC file
4001 80a4 0800 04 3f00 0002 4001 00a4 0000 02 3f00
4001 00a4 0000 02 0002
#ICC: #ICC:
4001 80b2 0104 1d 4001 00b2 0104 1d
# Select Holder file # Select Holder file
4001 80a4 0800 04 3f00 3f1c 4001 00a4 0000 02 3f1c
#Holder1: #Holder1:
4001 80b2 0104 1d 4001 00b2 0104 1d
#Holder2: #Holder2:
4001 80b2 0204 1d 4001 00b2 0204 1d
# Select EnvHol file # Select EnvHol file
4001 00a4 0800 04 2000 2001 4001 00a4 0000 00
4001 00a4 0000 02 2000
4001 00a4 0000 02 2001
#EnvHol1: #EnvHol1:
4001 00b2 0104 1d 4001 00b2 0104 1d
#EnvHol2: #EnvHol2:
4001 00b2 0204 1d 4001 00b2 0204 1d
# Select EvLog file # Select EvLog file
4001 00a4 0800 04 2000 2010 4001 00a4 0000 02 2010
#EvLog1: #EvLog1:
4001 00b2 0104 1d 4001 00b2 0104 1d
#EvLog2: #EvLog2:
@ -50,12 +58,12 @@ cat << EOF | \
4001 00b2 0304 1d 4001 00b2 0304 1d
# Select ConList file # Select ConList file
4001 00a4 0800 04 2000 2050 4001 00a4 0000 02 2050
#ConList: #ConList:
4001 00b2 0104 1d 4001 00b2 0104 1d
# Select Contra file # Select Contra file
4001 00a4 0800 04 2000 2020 4001 00a4 0000 02 2020
#Contra1: #Contra1:
4001 00b2 0104 1d 4001 00b2 0104 1d
#Contra2: #Contra2:
@ -82,17 +90,19 @@ cat << EOF | \
4001 00b2 0c04 1d 4001 00b2 0c04 1d
# Select Counter file # Select Counter file
4001 00a4 0800 04 2000 2069 4001 00a4 0000 02 2069
#Counter: #Counter:
4001 00b2 0104 1d 4001 00b2 0104 1d
# Select LoadLog file # Select LoadLog file
4001 00a4 0800 04 1000 1014 4001 00a4 0000 00
4001 00a4 0000 02 1000
4001 00a4 0000 02 1014
#LoadLog: #LoadLog:
4001 00b2 0104 1d 4001 00b2 0104 1d
# Select Purcha file # Select Purcha file
4001 00a4 08 0004 1000 1015 4001 00a4 0000 02 1015
#Purcha1: #Purcha1:
4001 00b2 0104 1d 4001 00b2 0104 1d
#Purcha2: #Purcha2:
@ -101,7 +111,9 @@ cat << EOF | \
4001 00b2 0304 1d 4001 00b2 0304 1d
# Select SpecEv file # Select SpecEv file
4001 00a4 08 0004 2000 2040 4001 00a4 0000 00
4001 00a4 0000 02 2000
4001 00a4 0000 02 2040
#SpecEv1: #SpecEv1:
4001 00b2 0104 1d 4001 00b2 0104 1d
#SpecEv2: #SpecEv2:

View File

@ -68,7 +68,7 @@ Please report any bugs on the
.B libnfc .B libnfc
issue tracker at: issue tracker at:
.br .br
.BR http://code.google.com/p/libnfc/issues .BR https://github.com/nfc-tools/libnfc/issues
.SH LICENCE .SH LICENCE
.B libnfc .B libnfc
is licensed under the GNU Lesser General Public License (LGPL), version 3. is licensed under the GNU Lesser General Public License (LGPL), version 3.

2142
include/libusb-1.0/libusb.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -234,6 +235,14 @@ typedef struct {
uint8_t abtAtr[33]; uint8_t abtAtr[33];
} nfc_iso14443bi_info; } nfc_iso14443bi_info;
/**
* @struct nfc_iso14443biclass_info
* @brief NFC ISO14443BiClass tag information
*/
typedef struct {
uint8_t abtUID[8];
} nfc_iso14443biclass_info;
/** /**
* @struct nfc_iso14443b2sr_info * @struct nfc_iso14443b2sr_info
* @brief NFC ISO14443-2B ST SRx tag information * @brief NFC ISO14443-2B ST SRx tag information
@ -261,6 +270,15 @@ typedef struct {
uint8_t btId[4]; uint8_t btId[4];
} nfc_jewel_info; } nfc_jewel_info;
/**
* @struct nfc_barcode_info
* @brief Thinfilm NFC Barcode information
*/
typedef struct {
size_t szDataLen;
uint8_t abtData[32];
} nfc_barcode_info;
/** /**
* @union nfc_target_info * @union nfc_target_info
* @brief Union between all kind of tags information structures. * @brief Union between all kind of tags information structures.
@ -274,6 +292,8 @@ typedef union {
nfc_iso14443b2ct_info nci; nfc_iso14443b2ct_info nci;
nfc_jewel_info nji; nfc_jewel_info nji;
nfc_dep_info ndi; nfc_dep_info ndi;
nfc_barcode_info nti; // "t" for Thinfilm, "b" already used
nfc_iso14443biclass_info nhi; // hid iclass / picopass - nii already used
} nfc_target_info; } nfc_target_info;
/** /**
@ -301,6 +321,9 @@ typedef enum {
NMT_ISO14443B2CT, // ISO14443-2B ASK CTx NMT_ISO14443B2CT, // ISO14443-2B ASK CTx
NMT_FELICA, NMT_FELICA,
NMT_DEP, NMT_DEP,
NMT_BARCODE, // Thinfilm NFC Barcode
NMT_ISO14443BICLASS, // HID iClass 14443B mode
NMT_END_ENUM = NMT_ISO14443BICLASS, // dummy for sizing - always should alias last
} nfc_modulation_type; } nfc_modulation_type;
/** /**

View File

@ -28,14 +28,12 @@
* @file nfc.h * @file nfc.h
* @brief libnfc interface * @brief libnfc interface
* *
* Provide all usefull functions (API) to handle NFC devices. * Provide all useful functions (API) to handle NFC devices.
*/ */
#ifndef _LIBNFC_H_ #ifndef _LIBNFC_H_
# define _LIBNFC_H_ # define _LIBNFC_H_
# include <sys/time.h>
# include <stdint.h> # include <stdint.h>
# include <stdbool.h> # include <stdbool.h>
@ -127,6 +125,7 @@ NFC_EXPORT const char *nfc_device_get_name(nfc_device *pnd);
NFC_EXPORT const char *nfc_device_get_connstring(nfc_device *pnd); NFC_EXPORT const char *nfc_device_get_connstring(nfc_device *pnd);
NFC_EXPORT int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); NFC_EXPORT int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt);
NFC_EXPORT int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); NFC_EXPORT int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
NFC_EXPORT int nfc_device_get_supported_baud_rate_target_mode(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
/* Properties accessors */ /* Properties accessors */
NFC_EXPORT int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value); NFC_EXPORT int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value);

View File

@ -5,6 +5,9 @@ IF(WIN32)
# Add in the rc for version information in the dll # Add in the rc for version information in the dll
LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../windows/libnfc.rc) LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../windows/libnfc.rc)
IF (NOT MINGW)
LIST(APPEND WINDOWS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc_msvc.def)
ENDIF()
ENDIF(WIN32) ENDIF(WIN32)
# Library's chips # Library's chips
@ -26,37 +29,27 @@ IF(UART_REQUIRED)
ENDIF(UART_REQUIRED) ENDIF(UART_REQUIRED)
IF(I2C_REQUIRED) IF(I2C_REQUIRED)
IF(WIN32) IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Windows is not supported at the moment
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c)
MESSAGE( FATAL_ERROR "I2C not (yet) supported under Windows!" )
ELSE(WIN32)
LIST(APPEND BUSES_SOURCES buses/i2c) LIST(APPEND BUSES_SOURCES buses/i2c)
ENDIF(WIN32) ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Only Linux is supported at the moment
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/i2c)
MESSAGE( FATAL_ERROR "I2C is only (yet) supported in Linux!" )
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
ENDIF(I2C_REQUIRED) ENDIF(I2C_REQUIRED)
IF(SPI_REQUIRED) IF(SPI_REQUIRED)
IF(WIN32) IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Windows is not supported at the moment
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi)
MESSAGE( FATAL_ERROR "SPI not (yet) supported under Windows!" )
ELSE(WIN32)
LIST(APPEND BUSES_SOURCES buses/spi) LIST(APPEND BUSES_SOURCES buses/spi)
ENDIF(WIN32) ELSE(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Only Linux is supported at the moment
#LIST(APPEND BUSES_SOURCES ../contrib/win32/libnfc/buses/spi)
MESSAGE( FATAL_ERROR "SPI is only (yet) supported in Linux!" )
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
ENDIF(SPI_REQUIRED) ENDIF(SPI_REQUIRED)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
IF(WIN32)
# Windows now requires regex, so we utilize PCRE
# since Windows doesn't get the benefit of finding in CMake
# it has to be added manually
IF(PCRE_FOUND)
INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIRS})
LINK_DIRECTORIES(${PCRE_LIBRARY_DIRS})
ENDIF(PCRE_FOUND)
ENDIF(WIN32)
IF(PCSC_FOUND) IF(PCSC_FOUND)
INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS})
LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS}) LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS})
@ -73,13 +66,15 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
IF(LIBNFC_LOG) IF(LIBNFC_LOG)
IF(WIN32) IF(WIN32)
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}") IF(MINGW)
SET(CMAKE_C_FLAGS "-fgnu89-inline ${CMAKE_C_FLAGS}")
ENDIF(MINGW)
LIST(APPEND LIBRARY_SOURCES log ../contrib/win32/libnfc/log-internal) LIST(APPEND LIBRARY_SOURCES log ../contrib/win32/libnfc/log-internal)
ELSE(WIN32) ELSE(WIN32)
LIST(APPEND LIBRARY_SOURCES log log-internal) LIST(APPEND LIBRARY_SOURCES log log-internal)
ENDIF(WIN32) ENDIF(WIN32)
ENDIF(LIBNFC_LOG) ENDIF(LIBNFC_LOG)
ADD_LIBRARY(nfc ${LIBRARY_SOURCES}) ADD_LIBRARY(nfc SHARED ${LIBRARY_SOURCES})
IF(PCSC_FOUND) IF(PCSC_FOUND)
TARGET_LINK_LIBRARIES(nfc ${PCSC_LIBRARIES}) TARGET_LINK_LIBRARIES(nfc ${PCSC_LIBRARIES})
@ -89,33 +84,33 @@ IF(LIBUSB_FOUND)
TARGET_LINK_LIBRARIES(nfc ${LIBUSB_LIBRARIES}) TARGET_LINK_LIBRARIES(nfc ${LIBUSB_LIBRARIES})
ENDIF(LIBUSB_FOUND) ENDIF(LIBUSB_FOUND)
SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 0) IF(LIBRT_FOUND)
TARGET_LINK_LIBRARIES(nfc ${LIBRT_LIBRARIES})
ENDIF(LIBRT_FOUND)
SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 6 VERSION 6.0.0)
IF(WIN32) IF(WIN32)
# Libraries that are windows specific # Libraries that are windows specific
TARGET_LINK_LIBRARIES(nfc wsock32) TARGET_LINK_LIBRARIES(nfc wsock32)
IF(PCRE_FOUND) IF(MINGW)
TARGET_LINK_LIBRARIES(nfc ${PCRE_LIBRARIES})
ENDIF(PCRE_FOUND)
IF(NOT MINGW)
ADD_CUSTOM_COMMAND( ADD_CUSTOM_COMMAND(
OUTPUT libnfc.lib OUTPUT libnfc.lib
COMMAND dlltool -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll COMMAND ${DLLTOOL} -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll
DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def
) )
ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib) ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib)
ELSE()
# At compile time we need the .LIB file, we place it in the lib directory ADD_LIBRARY(win32lib ALIAS nfc)
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
ENDIF() ENDIF()
# On Windows the shared (runtime) library should be either in the same
# directory as the excutables or in the path, we add it to same directory
INSTALL(TARGETS nfc RUNTIME DESTINATION bin COMPONENT libraries)
# At compile time we need the .LIB file, we place it in the lib directory
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
ELSE(WIN32)
INSTALL(TARGETS nfc LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
ENDIF(WIN32) ENDIF(WIN32)
# On Windows the shared (runtime) library should be either in the same
# directory as the excutables or in the path, we add it to same directory
INSTALL(TARGETS nfc
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION bin
COMPONENT libraries)

View File

@ -22,7 +22,7 @@ libnfc_la_SOURCES = \
nfc-internal.h \ nfc-internal.h \
target-subr.h target-subr.h
libnfc_la_LDFLAGS = -no-undefined -version-info 5:0:0 -export-symbols-regex '^nfc_|^iso14443a_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register' libnfc_la_LDFLAGS = -no-undefined -version-info 6:0:0 -export-symbols-regex '^nfc_|^iso14443a_|^iso14443b_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register'
libnfc_la_CFLAGS = @DRIVERS_CFLAGS@ libnfc_la_CFLAGS = @DRIVERS_CFLAGS@
libnfc_la_LIBADD = \ libnfc_la_LIBADD = \
$(top_builddir)/libnfc/chips/libnfcchips.la \ $(top_builddir)/libnfc/chips/libnfcchips.la \
@ -44,4 +44,5 @@ if WITH_LOG
endif endif
EXTRA_DIST = \ EXTRA_DIST = \
CMakeLists.txt CMakeLists.txt \
additional-pages.dox

View File

@ -135,6 +135,8 @@ i2c_read(i2c_device id, uint8_t *pbtRx, const size_t szRx)
if (recCount < 0) { if (recCount < 0) {
res = NFC_EIO; res = NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR,
"Error: read only %d bytes (%d expected) (%s).", (int)recCount, (int) szRx, strerror(errno));
} else { } else {
if (recCount < (ssize_t)szRx) { if (recCount < (ssize_t)szRx) {
res = NFC_EINVARG; res = NFC_EINVARG;
@ -167,7 +169,7 @@ i2c_write(i2c_device id, const uint8_t *pbtTx, const size_t szTx)
return NFC_SUCCESS; return NFC_SUCCESS;
} else { } else {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR,
"Error: wrote only %d bytes (%d expected).", (int)writeCount, (int) szTx); "Error: wrote only %d bytes (%d expected) (%s).", (int)writeCount, (int) szTx, strerror(errno));
return NFC_EIO; return NFC_EIO;
} }
} }
@ -189,29 +191,27 @@ i2c_list_ports(void)
size_t szRes = 1; size_t szRes = 1;
res[0] = NULL; res[0] = NULL;
DIR *dir; DIR *pdDir;
if ((dir = opendir("/dev")) == NULL) { if ((pdDir = opendir("/dev")) == NULL) {
perror("opendir error: /dev"); perror("opendir error: /dev");
return res; return res;
} }
struct dirent entry; struct dirent *pdDirEnt;
struct dirent *result; while ((pdDirEnt = readdir(pdDir)) != NULL) {
while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) {
const char **p = i2c_ports_device_radix; const char **p = i2c_ports_device_radix;
while (*p) { while (*p) {
if (!strncmp(entry.d_name, *p, strlen(*p))) { if (!strncmp(pdDirEnt->d_name, *p, strlen(*p))) {
char **res2 = realloc(res, (szRes + 1) * sizeof(char *)); char **res2 = realloc(res, (szRes + 1) * sizeof(char *));
if (!res2) { if (!res2) {
perror("malloc"); perror("malloc");
goto oom; goto oom;
} }
res = res2; res = res2;
if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) { if (!(res[szRes - 1] = malloc(6 + strlen(pdDirEnt->d_name)))) {
perror("malloc"); perror("malloc");
goto oom; goto oom;
} }
sprintf(res[szRes - 1], "/dev/%s", entry.d_name); sprintf(res[szRes - 1], "/dev/%s", pdDirEnt->d_name);
szRes++; szRes++;
res[szRes - 1] = NULL; res[szRes - 1] = NULL;
@ -220,7 +220,7 @@ i2c_list_ports(void)
} }
} }
oom: oom:
closedir(dir); closedir(pdDir);
return res; return res;
} }

View File

@ -196,7 +196,7 @@ spi_send_receive(spi_port sp, const uint8_t *pbtTx, const size_t szTx, uint8_t *
struct spi_ioc_transfer tr_send = { struct spi_ioc_transfer tr_send = {
.tx_buf = (unsigned long) pbtTx, .tx_buf = (unsigned long) pbtTx,
.rx_buf = 0, .rx_buf = 0,
.len = szTx , .len = szTx,
.delay_usecs = 0, .delay_usecs = 0,
.speed_hz = 0, .speed_hz = 0,
.bits_per_word = 0, .bits_per_word = 0,
@ -283,10 +283,7 @@ spi_list_ports(void)
DIR *pdDir = opendir("/dev"); DIR *pdDir = opendir("/dev");
struct dirent *pdDirEnt; struct dirent *pdDirEnt;
struct dirent entry; while ((pdDirEnt = readdir(pdDir)) != NULL) {
struct dirent *result;
while ((readdir_r(pdDir, &entry, &result) == 0) && (result != NULL)) {
pdDirEnt = &entry;
#if !defined(__APPLE__) #if !defined(__APPLE__)
if (!isdigit(pdDirEnt->d_name[strlen(pdDirEnt->d_name) - 1])) if (!isdigit(pdDirEnt->d_name[strlen(pdDirEnt->d_name) - 1]))
continue; continue;

View File

@ -74,15 +74,24 @@
#endif #endif
# if defined(__APPLE__) # if defined(__APPLE__)
const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial-", NULL }; const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial", "tty.usbmodem", NULL };
# elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__FreeBSD_kernel__) # elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__FreeBSD_kernel__)
const char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL }; const char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL };
# elif defined (__linux__) # 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 }; const char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", "ttyACM", "ttyAMA", "ttyO", NULL };
# else # else
# error "Can't determine serial string for your system" # error "Can't determine serial string for your system"
# endif # endif
// As of 2015/Feb/22, Cygwin does not handle FIONREAD on physical serial devices.
// We'll use TIOCINQ instead which is pretty much the same.
#ifdef __CYGWIN__
# include <sys/termios.h>
# define FIONREAD TIOCINQ
#endif
// Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
# define CCLAIMED 0x80000000 # define CCLAIMED 0x80000000
@ -179,7 +188,7 @@ uart_flush_input(serial_port sp, bool wait)
void void
uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
{ {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d baud.", uiPortSpeed);
// Portability note: on some systems, B9600 != 9600 so we have to do // Portability note: on some systems, B9600 != 9600 so we have to do
// uint32_t <=> speed_t associations by hand. // uint32_t <=> speed_t associations by hand.
@ -215,7 +224,7 @@ uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
break; break;
# endif # endif
default: default:
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).", log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set serial port speed to %d baud. Speed value must be one of those defined in termios(3).",
uiPortSpeed); uiPortSpeed);
return; return;
}; };
@ -385,32 +394,31 @@ uart_list_ports(void)
size_t szRes = 1; size_t szRes = 1;
res[0] = NULL; res[0] = NULL;
DIR *dir; DIR *pdDir;
if ((dir = opendir("/dev")) == NULL) { if ((pdDir = opendir("/dev")) == NULL) {
perror("opendir error: /dev"); perror("opendir error: /dev");
return res; return res;
} }
struct dirent entry; struct dirent *pdDirEnt;
struct dirent *result; while ((pdDirEnt = readdir(pdDir)) != NULL) {
while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) {
#if !defined(__APPLE__) #if !defined(__APPLE__)
if (!isdigit(entry.d_name[strlen(entry.d_name) - 1])) if (!isdigit(pdDirEnt->d_name[strlen(pdDirEnt->d_name) - 1]))
continue; continue;
#endif #endif
const char **p = serial_ports_device_radix; const char **p = serial_ports_device_radix;
while (*p) { while (*p) {
if (!strncmp(entry.d_name, *p, strlen(*p))) { if (!strncmp(pdDirEnt->d_name, *p, strlen(*p))) {
char **res2 = realloc(res, (szRes + 1) * sizeof(char *)); char **res2 = realloc(res, (szRes + 1) * sizeof(char *));
if (!res2) { if (!res2) {
perror("malloc"); perror("malloc");
goto oom; goto oom;
} }
res = res2; res = res2;
if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) { if (!(res[szRes - 1] = malloc(6 + strlen(pdDirEnt->d_name)))) {
perror("malloc"); perror("malloc");
goto oom; goto oom;
} }
sprintf(res[szRes - 1], "/dev/%s", entry.d_name); sprintf(res[szRes - 1], "/dev/%s", pdDirEnt->d_name);
szRes++; szRes++;
res[szRes - 1] = NULL; res[szRes - 1] = NULL;
@ -419,7 +427,7 @@ uart_list_ports(void)
} }
} }
oom: oom:
closedir(dir); closedir(pdDir);
return res; return res;
} }

View File

@ -33,7 +33,9 @@
#ifndef __NFC_BUS_UART_H__ #ifndef __NFC_BUS_UART_H__
# define __NFC_BUS_UART_H__ # define __NFC_BUS_UART_H__
#if !defined(_MSC_VER)
# include <sys/time.h> # include <sys/time.h>
#endif
# include <stdio.h> # include <stdio.h>
# include <string.h> # include <string.h>

View File

@ -7,6 +7,7 @@
* Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* Copyright (C) 2022 Kenspeckle
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* *
@ -24,634 +25,326 @@
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
* *
*/ */
#include <stdbool.h>
/** #include <string.h>
* @file usbbus.c
* @brief libusb 0.1 driver wrapper
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include <stdlib.h> #include <stdlib.h>
#include <libusb.h>
#include <stdint.h>
#include "usbbus.h" #include "usbbus.h"
#include "log.h" #include "log.h"
#define LOG_CATEGORY "libnfc.buses.usbbus"
#define LOG_CATEGORY "libnfc.bus.usbbus"
#define LOG_GROUP NFC_LOG_GROUP_DRIVER #define LOG_GROUP NFC_LOG_GROUP_DRIVER
/*
* This file embeds partially libusb-compat-0.1 by:
* Copyright (C) 2008 Daniel Drake <dsd@gentoo.org>
* Copyright (c) 2000-2003 Johannes Erdfelt <johannes@erdfelt.com>
* This layer will be removed ASAP before integration in the main trunk
*/
#define LIST_ADD(begin, ent) \
do { \
if (begin) { \
ent->next = begin; \
ent->next->prev = ent; \
} else \
ent->next = NULL; \
ent->prev = NULL; \
begin = ent; \
} while(0)
#define LIST_DEL(begin, ent) \
do { \
if (ent->prev) \
ent->prev->next = ent->next; \
else \
begin = ent->next; \
if (ent->next) \
ent->next->prev = ent->prev; \
ent->prev = NULL; \
ent->next = NULL; \
} while (0)
#define USBBUS_DT_CONFIG_SIZE 9
#define USBBUS_DT_INTERFACE_SIZE 9
#define USBBUS_DT_ENDPOINT_AUDIO_SIZE 9
static libusb_context *ctx = NULL; static libusb_context *ctx = NULL;
struct usbbus_bus *usb_busses = NULL; uint8_t get_usb_num_configs(struct libusb_device *dev);
static void _usb_finalize(void) int usbbus_prepare()
{
if (ctx) {
libusb_exit(ctx);
ctx = NULL;
}
}
static void usb_init(void)
{
if (!ctx) {
int r;
r = libusb_init(&ctx);
if (r < 0) {
return;
}
atexit(_usb_finalize);
}
}
static int find_busses(struct usbbus_bus **ret)
{
libusb_device **dev_list = NULL;
struct usbbus_bus *busses = NULL;
struct usbbus_bus *bus;
int dev_list_len = 0;
int i;
int r;
r = libusb_get_device_list(ctx, &dev_list);
if (r < 0) {
return r;
}
if (r == 0) {
libusb_free_device_list(dev_list, 1);
/* no buses */
return 0;
}
/* iterate over the device list, identifying the individual busses.
* we use the location field of the usbbus_bus structure to store the
* bus number. */
dev_list_len = r;
for (i = 0; i < dev_list_len; i++) {
libusb_device *dev = dev_list[i];
uint8_t bus_num = libusb_get_bus_number(dev);
/* if we already know about it, continue */
if (busses) {
bus = busses;
int found = 0;
do {
if (bus_num == bus->location) {
found = 1;
break;
}
} while ((bus = bus->next) != NULL);
if (found)
continue;
}
/* add it to the list of busses */
bus = malloc(sizeof(*bus));
if (!bus)
goto err;
memset(bus, 0, sizeof(*bus));
bus->location = bus_num;
snprintf(bus->dirname, USBBUS_PATH_MAX, "%03d", bus_num);
LIST_ADD(busses, bus);
}
libusb_free_device_list(dev_list, 1);
*ret = busses;
return 0;
err:
bus = busses;
while (bus) {
struct usbbus_bus *tbus = bus->next;
free(bus);
bus = tbus;
}
return LIBUSB_ERROR_NO_MEM;
}
static int usb_find_busses(void)
{
struct usbbus_bus *new_busses = NULL;
struct usbbus_bus *bus;
int changes = 0;
int r;
/* libusb-1.0 initialization might have failed, but we can't indicate
* this with libusb-0.1, so trap that situation here */
if (!ctx)
return 0;
r = find_busses(&new_busses);
if (r < 0) {
return r;
}
/* walk through all busses we already know about, removing duplicates
* from the new list. if we do not find it in the new list, the bus
* has been removed. */
bus = usb_busses;
while (bus) {
struct usbbus_bus *tbus = bus->next;
struct usbbus_bus *nbus = new_busses;
int found = 0;
while (nbus) {
struct usbbus_bus *tnbus = nbus->next;
if (bus->location == nbus->location) {
LIST_DEL(new_busses, nbus);
free(nbus);
found = 1;
break;
}
nbus = tnbus;
}
if (!found) {
/* bus removed */
changes++;
LIST_DEL(usb_busses, bus);
free(bus);
}
bus = tbus;
}
/* anything remaining in new_busses is a new bus */
bus = new_busses;
while (bus) {
struct usbbus_bus *tbus = bus->next;
LIST_DEL(new_busses, bus);
LIST_ADD(usb_busses, bus);
changes++;
bus = tbus;
}
return changes;
}
static int find_devices(libusb_device **dev_list, int dev_list_len,
struct usbbus_bus *bus, struct usbbus_device **ret)
{
struct usbbus_device *devices = NULL;
struct usbbus_device *dev;
int i;
for (i = 0; i < dev_list_len; i++) {
libusb_device *newlib_dev = dev_list[i];
uint8_t bus_num = libusb_get_bus_number(newlib_dev);
if (bus_num != bus->location)
continue;
dev = malloc(sizeof(*dev));
if (!dev)
goto err;
/* No need to reference the device now, just take the pointer. We
* increase the reference count later if we keep the device. */
dev->dev = newlib_dev;
dev->bus = bus;
dev->devnum = libusb_get_device_address(newlib_dev);
snprintf(dev->filename, USBBUS_PATH_MAX, "%03d", dev->devnum);
LIST_ADD(devices, dev);
}
*ret = devices;
return 0;
err:
dev = devices;
while (dev) {
struct usbbus_device *tdev = dev->next;
free(dev);
dev = tdev;
}
return LIBUSB_ERROR_NO_MEM;
}
static void clear_endpoint_descriptor(struct usbbus_endpoint_descriptor *ep)
{
if (ep->extra)
free(ep->extra);
}
static void clear_interface_descriptor(struct usbbus_interface_descriptor *iface)
{
if (iface->extra)
free(iface->extra);
if (iface->endpoint) {
int i;
for (i = 0; i < iface->bNumEndpoints; i++)
clear_endpoint_descriptor(iface->endpoint + i);
free(iface->endpoint);
}
}
static void clear_interface(struct usbbus_interface *iface)
{
if (iface->altsetting) {
int i;
for (i = 0; i < iface->num_altsetting; i++)
clear_interface_descriptor(iface->altsetting + i);
free(iface->altsetting);
}
}
static void clear_config_descriptor(struct usbbus_config_descriptor *config)
{
if (config->extra)
free(config->extra);
if (config->interface) {
int i;
for (i = 0; i < config->bNumInterfaces; i++)
clear_interface(config->interface + i);
free(config->interface);
}
}
static void clear_device(struct usbbus_device *dev)
{
int i;
for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
clear_config_descriptor(dev->config + i);
}
static int copy_endpoint_descriptor(struct usbbus_endpoint_descriptor *dest,
const struct libusb_endpoint_descriptor *src)
{
memcpy(dest, src, USBBUS_DT_ENDPOINT_AUDIO_SIZE);
dest->extralen = src->extra_length;
if (src->extra_length) {
dest->extra = malloc(src->extra_length);
if (!dest->extra)
return LIBUSB_ERROR_NO_MEM;
memcpy(dest->extra, src->extra, src->extra_length);
}
return 0;
}
static int copy_interface_descriptor(struct usbbus_interface_descriptor *dest,
const struct libusb_interface_descriptor *src)
{
int i;
int num_endpoints = src->bNumEndpoints;
size_t alloc_size = sizeof(struct usbbus_endpoint_descriptor) * num_endpoints;
memcpy(dest, src, USBBUS_DT_INTERFACE_SIZE);
dest->endpoint = malloc(alloc_size);
if (!dest->endpoint)
return LIBUSB_ERROR_NO_MEM;
memset(dest->endpoint, 0, alloc_size);
for (i = 0; i < num_endpoints; i++) {
int r = copy_endpoint_descriptor(dest->endpoint + i, &src->endpoint[i]);
if (r < 0) {
clear_interface_descriptor(dest);
return r;
}
}
dest->extralen = src->extra_length;
if (src->extra_length) {
dest->extra = malloc(src->extra_length);
if (!dest->extra) {
clear_interface_descriptor(dest);
return LIBUSB_ERROR_NO_MEM;
}
memcpy(dest->extra, src->extra, src->extra_length);
}
return 0;
}
static int copy_interface(struct usbbus_interface *dest,
const struct libusb_interface *src)
{
int i;
int num_altsetting = src->num_altsetting;
size_t alloc_size = sizeof(struct usbbus_interface_descriptor)
* num_altsetting;
dest->num_altsetting = num_altsetting;
dest->altsetting = malloc(alloc_size);
if (!dest->altsetting)
return LIBUSB_ERROR_NO_MEM;
memset(dest->altsetting, 0, alloc_size);
for (i = 0; i < num_altsetting; i++) {
int r = copy_interface_descriptor(dest->altsetting + i,
&src->altsetting[i]);
if (r < 0) {
clear_interface(dest);
return r;
}
}
return 0;
}
static int copy_config_descriptor(struct usbbus_config_descriptor *dest,
const struct libusb_config_descriptor *src)
{
int i;
int num_interfaces = src->bNumInterfaces;
size_t alloc_size = sizeof(struct usbbus_interface) * num_interfaces;
memcpy(dest, src, USBBUS_DT_CONFIG_SIZE);
dest->interface = malloc(alloc_size);
if (!dest->interface)
return LIBUSB_ERROR_NO_MEM;
memset(dest->interface, 0, alloc_size);
for (i = 0; i < num_interfaces; i++) {
int r = copy_interface(dest->interface + i, &src->interface[i]);
if (r < 0) {
clear_config_descriptor(dest);
return r;
}
}
dest->extralen = src->extra_length;
if (src->extra_length) {
dest->extra = malloc(src->extra_length);
if (!dest->extra) {
clear_config_descriptor(dest);
return LIBUSB_ERROR_NO_MEM;
}
memcpy(dest->extra, src->extra, src->extra_length);
}
return 0;
}
static int initialize_device(struct usbbus_device *dev)
{
libusb_device *newlib_dev = dev->dev;
int num_configurations;
size_t alloc_size;
int r;
int i;
/* device descriptor is identical in both libs */
r = libusb_get_device_descriptor(newlib_dev,
(struct libusb_device_descriptor *) &dev->descriptor);
if (r < 0) {
return r;
}
num_configurations = dev->descriptor.bNumConfigurations;
alloc_size = sizeof(struct usbbus_config_descriptor) * num_configurations;
dev->config = malloc(alloc_size);
if (!dev->config)
return LIBUSB_ERROR_NO_MEM;
memset(dev->config, 0, alloc_size);
for (i = 0; i < num_configurations; i++) {
struct libusb_config_descriptor *newlib_config;
r = libusb_get_config_descriptor(newlib_dev, i, &newlib_config);
if (r < 0) {
clear_device(dev);
free(dev->config);
return r;
}
r = copy_config_descriptor(dev->config + i, newlib_config);
libusb_free_config_descriptor(newlib_config);
if (r < 0) {
clear_device(dev);
free(dev->config);
return r;
}
}
dev->num_children = 0;
dev->children = NULL;
libusb_ref_device(newlib_dev);
return 0;
}
static void free_device(struct usbbus_device *dev)
{
clear_device(dev);
libusb_unref_device(dev->dev);
free(dev);
}
static int usb_find_devices(void)
{
struct usbbus_bus *bus;
libusb_device **dev_list;
int dev_list_len;
int changes = 0;
/* libusb-1.0 initialization might have failed, but we can't indicate
* this with libusb-0.1, so trap that situation here */
if (!ctx)
return 0;
dev_list_len = libusb_get_device_list(ctx, &dev_list);
if (dev_list_len < 0)
return dev_list_len;
for (bus = usb_busses; bus; bus = bus->next) {
int r;
struct usbbus_device *new_devices = NULL;
struct usbbus_device *dev;
r = find_devices(dev_list, dev_list_len, bus, &new_devices);
if (r < 0) {
libusb_free_device_list(dev_list, 1);
return r;
}
/* walk through the devices we already know about, removing duplicates
* from the new list. if we do not find it in the new list, the device
* has been removed. */
dev = bus->devices;
while (dev) {
int found = 0;
struct usbbus_device *tdev = dev->next;
struct usbbus_device *ndev = new_devices;
while (ndev) {
if (ndev->devnum == dev->devnum) {
LIST_DEL(new_devices, ndev);
free(ndev);
found = 1;
break;
}
ndev = ndev->next;
}
if (!found) {
LIST_DEL(bus->devices, dev);
free_device(dev);
changes++;
}
dev = tdev;
}
/* anything left in new_devices is a new device */
dev = new_devices;
while (dev) {
struct usbbus_device *tdev = dev->next;
r = initialize_device(dev);
if (r < 0) {
dev = tdev;
continue;
}
LIST_DEL(new_devices, dev);
LIST_ADD(bus->devices, dev);
changes++;
dev = tdev;
}
}
libusb_free_device_list(dev_list, 1);
return changes;
}
int usbbus_prepare(void)
{ {
static bool usb_initialized = false; static bool usb_initialized = false;
int res;
if (!usb_initialized) { if (!usb_initialized) {
#ifdef ENVVARS #ifdef ENVVARS
char *env_log_level = getenv("LIBNFC_LOG_LEVEL"); char *env_log_level = getenv("LIBNFC_LOG_LEVEL");
// Set libusb debug only if asked explicitely: // Set libusb debug only if asked explicitely:
// LIBUSB_LOG_LEVEL=12288 (= NFC_LOG_PRIORITY_DEBUG * 2 ^ NFC_LOG_GROUP_LIBUSB) // LIBUSB_LOG_LEVEL=12288 // (= NFC_LOG_PRIORITY_DEBUG * 2 ^ NFC_LOG_GROUP_LIBUSB)
if (env_log_level && (((atoi(env_log_level) >> (NFC_LOG_GROUP_LIBUSB * 2)) & 0x00000003) >= NFC_LOG_PRIORITY_DEBUG)) { if (env_log_level
setenv("USB_DEBUG", "255", 1); && (((atoi(env_log_level) >> (NFC_LOG_GROUP_LIBUSB * 2)) & 0x00000003) >= NFC_LOG_PRIORITY_DEBUG)) {
setenv("USB_DEBUG", "255", 0);
} }
#endif #endif
usb_init(); res = libusb_init(&ctx);
if (res != 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to init libusb (%s)",
libusb_strerror(res));
return res;
}
usb_initialized = true; usb_initialized = true;
} }
int res;
// usb_find_busses will find all of the busses on the system. Returns the
// number of changes since previous call to this function (total of new
// busses and busses removed).
if ((res = usb_find_busses()) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to find USB busses (%s)", usbbus_strerror(res));
return -1;
}
// usb_find_devices will find all of the devices on each bus. This should be // usb_find_devices will find all of the devices on each bus. This should be
// called after usb_find_busses. Returns the number of changes since the // called after usb_find_busses. Returns the number of changes since the
// previous call to this function (total of new device and devices removed). // previous call to this function (total of new device and devices removed).
if ((res = usb_find_devices()) < 0) { libusb_device **tmp_devices;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to find USB devices (%s)", usbbus_strerror(res)); ssize_t num_devices = libusb_get_device_list(ctx, &tmp_devices);
libusb_free_device_list(tmp_devices, (int) num_devices);
if (num_devices <= 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to find USB devices (%s)",
libusb_strerror((int) num_devices));
return -1; return -1;
} }
return 0; return 0;
} }
usbbus_device_handle *usbbus_open(struct usbbus_device *dev)
//TODO
//release things again at the end of the program libusb
size_t usbbus_usb_scan(nfc_connstring connstrings[],
const size_t connstrings_len,
struct usbbus_device *nfc_usb_devices,
const size_t num_nfc_usb_devices,
char *usb_driver_name)
{ {
int r; usbbus_prepare();
usbbus_device_handle *udev;
r = libusb_open((libusb_device *) dev->dev, (libusb_device_handle **)&udev); size_t device_found = 0;
if (r < 0) { struct libusb_device **devices;
return NULL; ssize_t num_devices = libusb_get_device_list(ctx, &devices);
for (size_t i = 0; i < num_devices; i++) {
struct libusb_device *dev = devices[i];
for (size_t nfc_dev_idx = 0; nfc_dev_idx < num_nfc_usb_devices; nfc_dev_idx++) {
if (nfc_usb_devices[nfc_dev_idx].vendor_id == usbbus_get_vendor_id(dev)
&& nfc_usb_devices[nfc_dev_idx].product_id == usbbus_get_product_id(dev)) {
size_t valid_config_idx = 1;
// Make sure there are 2 endpoints available
// with libusb-win32 we got some null pointers so be robust before looking at endpoints
if (nfc_usb_devices[nfc_dev_idx].max_packet_size == 0) {
bool found_valid_config = false;
for (size_t config_idx = 0; config_idx < get_usb_num_configs(dev); i++) {
struct libusb_config_descriptor *usb_config;
int r = libusb_get_config_descriptor(dev, config_idx, &usb_config);
if (r != 0
|| usb_config->interface == NULL
|| usb_config->interface->altsetting == NULL
|| usb_config->interface->altsetting->bNumEndpoints < 2) {
// Nope, we maybe want the next one, let's try to find another
libusb_free_config_descriptor(usb_config);
continue;
}
libusb_free_config_descriptor(usb_config);
found_valid_config = true;
valid_config_idx = config_idx;
break;
}
if (!found_valid_config) {
libusb_unref_device(dev);
continue;
}
}
libusb_device_handle *udev;
int res = libusb_open(dev, &udev);
if (res < 0 && udev == NULL) {
libusb_unref_device(dev);
continue;
}
// Set configuration
res = libusb_set_configuration(udev, (int) valid_config_idx);
if (res < 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to set USB configuration (%s)",
libusb_strerror(res));
libusb_close(udev);
libusb_unref_device(dev);
// we failed to use the device
continue;
}
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Vendor-Id: %d Product-Id %d",
usbbus_get_vendor_id(dev), usbbus_get_product_id(dev));
libusb_close(udev);
uint8_t dev_address = libusb_get_device_address(dev);
printf("%s:%03d:%03d",
"Test",
dev_address,
(int) valid_config_idx);
size_t size_new_str = snprintf(
connstrings[device_found],
sizeof(connstrings[device_found]),
"%s:%03d:%03d",
usb_driver_name,
dev_address,
(int) valid_config_idx);
if (size_new_str >= (int) sizeof(nfc_connstring)) {
// truncation occurred, skipping that one
libusb_unref_device(dev);
continue;
}
device_found++;
// Test if we reach the maximum "wanted" devices
if (device_found == connstrings_len) {
libusb_free_device_list(devices, 0);
return device_found;
}
}
}
} }
return (usbbus_device_handle *)udev; libusb_free_device_list(devices, 0);
return device_found;
} }
void usbbus_close(usbbus_device_handle *dev) void usbbus_get_usb_endpoints(struct libusb_device *dev,
uint8_t *endpoint_in,
uint8_t *endpoint_out,
uint16_t *max_packet_size)
{ {
libusb_close((libusb_device_handle *)dev);
bool endpoint_in_set = false;
bool endpoint_out_set = false;
size_t num_configs = get_usb_num_configs(dev);
for (size_t config_idx = 0; config_idx < num_configs; config_idx++) {
struct libusb_config_descriptor *usb_config;
int r = libusb_get_config_descriptor(dev, config_idx, &usb_config);
if (r != 0) {
continue;
}
if (!usb_config->interface) {
continue;
}
for (size_t interface_idx = 0; interface_idx < usb_config->bNumInterfaces; interface_idx++) {
struct libusb_interface interface = usb_config->interface[interface_idx];
if (!interface.altsetting) {
continue;
}
for (size_t settings_idx = 0; settings_idx < interface.num_altsetting; settings_idx++) {
struct libusb_interface_descriptor settings = interface.altsetting[settings_idx];
if (!settings.endpoint) {
continue;
}
// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
for (size_t endpoint_idx = 0; endpoint_idx < settings.bNumEndpoints; endpoint_idx++) {
struct libusb_endpoint_descriptor endpoint = settings.endpoint[endpoint_idx];
// Only accept bulk transfer endpoints (ignore interrupt endpoints)
if (endpoint.bmAttributes != LIBUSB_ENDPOINT_TRANSFER_TYPE_BULK) {
continue;
}
// Copy the endpoint to a local var, makes it more readable code
uint8_t endpoint_address = endpoint.bEndpointAddress;
// Test if we dealing with a bulk IN endpoint
if ((endpoint_address & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN && !endpoint_in_set) {
*endpoint_in = endpoint_address;
*max_packet_size = endpoint.wMaxPacketSize;
endpoint_in_set = true;
}
// Test if we dealing with a bulk OUT endpoint
if ((endpoint_address & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_OUT && !endpoint_out_set) {
*endpoint_out = endpoint_address;
*max_packet_size = endpoint.wMaxPacketSize;
endpoint_out_set = true;
}
if (endpoint_in_set && endpoint_out_set) {
libusb_free_config_descriptor(usb_config);
return;
}
}
}
}
libusb_free_config_descriptor(usb_config);
}
} }
int usbbus_set_configuration(usbbus_device_handle *dev, int configuration) uint8_t get_usb_num_configs(struct libusb_device *dev)
{ {
return libusb_set_configuration((libusb_device_handle *)dev, configuration); struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
return descriptor.bNumConfigurations;
} }
int usbbus_get_string_simple(usbbus_device_handle *dev, int index, char *buf, size_t buflen) void usbbus_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len)
{ {
return libusb_get_string_descriptor_ascii((libusb_device_handle *)dev, index & 0xff, struct libusb_device_descriptor descriptor;
(unsigned char *) buf, (int) buflen); libusb_get_device_descriptor(dev, &descriptor);
if (descriptor.iManufacturer || descriptor.iProduct) {
if (udev) {
libusb_get_string_descriptor_ascii(udev, descriptor.iManufacturer & 0xff, (unsigned char *) buffer, len);
if (strlen(buffer) > 0) {
strncpy(buffer + strlen(buffer), " / ", 4);
}
libusb_get_string_descriptor_ascii(udev,
descriptor.iProduct & 0xff,
(unsigned char *) buffer + strlen(buffer),
len - strlen(buffer));
}
}
} }
int usbbus_bulk_transfer(usbbus_device_handle *dev, int ep, char *bytes, int size, int *actual_length, int timeout)
void usbbus_get_device(uint8_t dev_address, struct libusb_device **dev, struct libusb_device_handle **dev_handle)
{ {
return libusb_bulk_transfer((libusb_device_handle *)dev, ep & 0xff, (unsigned char *)bytes, size, actual_length, timeout); struct libusb_device **device_list;
ssize_t num_devices = libusb_get_device_list(ctx, &device_list);
for (size_t i = 0; i < num_devices; i++) {
if (libusb_get_device_address(device_list[i]) != dev_address) {
continue;
} else {
*dev = device_list[i];
int res = libusb_open(*dev, dev_handle);
if (res != 0 || dev_handle == NULL) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR,
"Unable to open libusb device (%s)", libusb_strerror(res));
continue;
}
}
}
// libusb works with a reference counter which is set to 1 for each device when calling libusb_get_device_list and increased
// by libusb_open. Thus we decrease the counter by 1 for all devices and only the "real" device will survive
libusb_free_device_list(device_list, num_devices);
} }
int usbbus_claim_interface(usbbus_device_handle *dev, int interface)
void usbbus_close(struct libusb_device *dev, struct libusb_device_handle *dev_handle)
{ {
return libusb_claim_interface((libusb_device_handle *)dev, interface); libusb_close(dev_handle);
libusb_unref_device(dev);
libusb_exit(ctx);
} }
int usbbus_release_interface(usbbus_device_handle *dev, int interface) uint16_t usbbus_get_vendor_id(struct libusb_device *dev)
{ {
return libusb_release_interface((libusb_device_handle *)dev, interface); struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
return descriptor.idVendor;
} }
int usbbus_set_interface_alt_setting(usbbus_device_handle *dev, int interface, int alternate) uint16_t usbbus_get_product_id(struct libusb_device *dev)
{ {
return libusb_set_interface_alt_setting((libusb_device_handle *)dev, interface, alternate); struct libusb_device_descriptor descriptor;
libusb_get_device_descriptor(dev, &descriptor);
return descriptor.idProduct;
} }
int usbbus_reset(usbbus_device_handle *dev)
int usbbus_get_num_alternate_settings(struct libusb_device *dev, uint8_t config_idx)
{ {
return libusb_reset_device((libusb_device_handle *)dev); struct libusb_config_descriptor *usb_config;
int r = libusb_get_config_descriptor(dev, config_idx, &usb_config);
if (r != 0 || usb_config == NULL) {
return -1;
}
libusb_free_config_descriptor(usb_config);
return usb_config->interface->num_altsetting;
} }
const char *usbbus_strerror(int errcode)
{
return libusb_strerror((enum libusb_error)errcode);
}
struct usbbus_bus *usbbus_get_busses(void)
{
return usb_busses;
}

View File

@ -7,6 +7,7 @@
* Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2010-2013 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* Copyright (C) 2022 Kenspeckle
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* *
@ -25,150 +26,32 @@
* *
*/ */
/** #ifndef __NFC_BUS_USBBUS_H__
* @file usbbus.h #define __NFC_BUS_USBBUS_H__
* @brief libusb 0.1 driver header
*/
#ifndef __NFC_BUS_USB_H__ #include <libusb-1.0/libusb.h>
# define __NFC_BUS_USB_H__ #include <stdlib.h>
#include "nfc/nfc-types.h"
#include <stdbool.h> #define EMPTY_STRING ((unsigned char *)"\0")
#include <string.h>
#define USBBUS_ERROR_ACCESS -3
#define USBBUS_ERROR_TIMEOUT -7
int usbbus_prepare(void);
// Libusb-0.1 API:
#define USBBUS_ENDPOINT_DIR_MASK 0x80
#define USBBUS_ENDPOINT_TYPE_BULK 2
#define USBBUS_ENDPOINT_IN 0x80
#define USBBUS_ENDPOINT_OUT 0x00
#ifdef PATH_MAX
#define USBBUS_PATH_MAX PATH_MAX
#else
#define USBBUS_PATH_MAX 4096
#endif
struct usbbus_device_handle;
typedef struct usbbus_device_handle usbbus_device_handle;
struct usbbus_endpoint_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bEndpointAddress;
uint8_t bmAttributes;
uint16_t wMaxPacketSize;
uint8_t bInterval;
uint8_t bRefresh;
uint8_t bSynchAddress;
unsigned char *extra;
int extralen;
};
struct usbbus_interface_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint8_t bInterfaceNumber;
uint8_t bAlternateSetting;
uint8_t bNumEndpoints;
uint8_t bInterfaceClass;
uint8_t bInterfaceSubClass;
uint8_t bInterfaceProtocol;
uint8_t iInterface;
struct usbbus_endpoint_descriptor *endpoint;
unsigned char *extra;
int extralen;
};
struct usbbus_interface {
struct usbbus_interface_descriptor *altsetting;
int num_altsetting;
};
struct usbbus_config_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
uint8_t bNumInterfaces;
uint8_t bConfigurationValue;
uint8_t iConfiguration;
uint8_t bmAttributes;
uint8_t MaxPower;
struct usbbus_interface *interface;
unsigned char *extra;
int extralen;
};
/* Device descriptor */
struct usbbus_device_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t bcdUSB;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint8_t bMaxPacketSize0;
uint16_t idVendor;
uint16_t idProduct;
uint16_t bcdDevice;
uint8_t iManufacturer;
uint8_t iProduct;
uint8_t iSerialNumber;
uint8_t bNumConfigurations;
};
struct usbbus_bus;
struct usbbus_device { struct usbbus_device {
struct usbbus_device *next, *prev; uint16_t vendor_id;
uint16_t product_id;
char filename[USBBUS_PATH_MAX + 1]; const char *name;
uint16_t max_packet_size;
struct usbbus_bus *bus;
struct usbbus_device_descriptor descriptor;
struct usbbus_config_descriptor *config;
void *dev;
uint8_t devnum;
unsigned char num_children;
struct usbbus_device **children;
};
struct usbbus_bus {
struct usbbus_bus *next, *prev;
char dirname[USBBUS_PATH_MAX + 1];
struct usbbus_device *devices;
uint32_t location;
struct usbbus_device *root_dev;
}; };
usbbus_device_handle *usbbus_open(struct usbbus_device *dev);
void usbbus_close(usbbus_device_handle *dev);
int usbbus_set_configuration(usbbus_device_handle *dev, int configuration);
int usbbus_get_string_simple(usbbus_device_handle *dev, int index, char *buf, size_t buflen);
int usbbus_bulk_transfer(usbbus_device_handle *dev, int ep, char *bytes, int size, int *actual_length, int timeout);
int usbbus_claim_interface(usbbus_device_handle *dev, int interface);
int usbbus_release_interface(usbbus_device_handle *dev, int interface);
int usbbus_set_interface_alt_setting(usbbus_device_handle *dev, int interface, int alternate);
int usbbus_reset(usbbus_device_handle *dev);
const char *usbbus_strerror(int errcode);
struct usbbus_bus *usbbus_get_busses(void);
#endif // __NFC_BUS_USB_H__ int usbbus_prepare();
size_t usbbus_usb_scan(nfc_connstring connstrings[], size_t connstrings_len, struct usbbus_device *nfc_usb_devices, size_t num_nfc_usb_devices, char *usb_driver_name);
void usbbus_get_usb_endpoints(struct libusb_device *dev, uint8_t *endpoint_in, uint8_t *endpoint_out, uint16_t *max_packet_size);
void usbbus_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len);
void usbbus_get_device(uint8_t dev_address, struct libusb_device **dev, struct libusb_device_handle **dev_handle);
void usbbus_close(struct libusb_device *dev, struct libusb_device_handle *dev_handle);
uint16_t usbbus_get_vendor_id(struct libusb_device *dev);
uint16_t usbbus_get_product_id(struct libusb_device *dev);
int usbbus_get_num_alternate_settings(struct libusb_device *dev, uint8_t config_idx);
#endif

View File

@ -81,32 +81,38 @@
#define TgGetTargetStatus 0x8A #define TgGetTargetStatus 0x8A
/** @note PN53x's normal frame: /** @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 * .-- Preamble
* | .-- Packet length * | .-- Start
* | | .-- Length checksum * | | .-- Packet length
* | | | .-- Direction (D4 Host to PN, D5 PN to Host) * | | | .-- Length checksum
* | | | | .-- Code * | | | | .-- Direction (D4 Host to PN, D5 PN to Host)
* | | | | | .-- Packet checksum * | | | | | .-- Code
* | | | | | | .-- Postamble * | | | | | | .-- Packet checksum
* V | | | | | | * | | | | | | | .-- Postamble
* ----- V V V V V V * | V | | | | | |
* 00 FF 02 FE D4 02 2A 00 * V ----- V V V V V V
* 00 00 FF 02 FE D4 02 2A 00
*/ */
/** @note PN53x's extended frame: /** @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 * .-- Preamble
* | .-- Fixed to FF to enable extended frame * | .-- Start
* | | .-- Packet length * | | .-- Fixed to FF to enable extended frame
* | | | .-- Length checksum * | | | .-- Packet length
* | | | | .-- Direction (D4 Host to PN, D5 PN to Host) * | | | | .-- Length checksum
* | | | | | .-- Code * | | | | | .-- Direction (D4 Host to PN, D5 PN to Host)
* | | | | | | .-- Packet checksum * | | | | | | .-- Code
* | | | | | | | .-- Postamble * | | | | | | | .-- Packet checksum
* V V V | | | | | * | | | | | | | | .-- Postamble
* ----- ----- ----- V V V V V * | V V V | | | | |
* 00 FF FF FF 00 02 FE D4 02 2A 00 * V ----- ----- ----- V V V V V
* 00 00 FF FF FF 00 02 FE D4 02 2A 00
*/ */
/** /**

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -210,6 +211,7 @@ struct pn53x_data {
/** Supported modulation type */ /** Supported modulation type */
nfc_modulation_type *supported_modulation_as_initiator; nfc_modulation_type *supported_modulation_as_initiator;
nfc_modulation_type *supported_modulation_as_target; nfc_modulation_type *supported_modulation_as_target;
bool progressive_field;
}; };
#define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data)) #define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data))
@ -231,6 +233,8 @@ typedef enum {
PM_ISO14443B_106 = 0x03, PM_ISO14443B_106 = 0x03,
/** Jewel Topaz (Innovision Research & Development) (Not supported by PN531) */ /** Jewel Topaz (Innovision Research & Development) (Not supported by PN531) */
PM_JEWEL_106 = 0x04, PM_JEWEL_106 = 0x04,
/** Thinfilm NFC Barcode (Not supported by PN531) */
PM_BARCODE_106 = 0x05,
/** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */
PM_ISO14443B_212 = 0x06, PM_ISO14443B_212 = 0x06,
/** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */
@ -319,6 +323,7 @@ int pn53x_idle(struct nfc_device *pnd);
// NFC device as Initiator functions // NFC device as Initiator functions
int pn53x_initiator_init(struct nfc_device *pnd); int pn53x_initiator_init(struct nfc_device *pnd);
void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd);
int pn532_initiator_init_secure_element(struct nfc_device *pnd); int pn532_initiator_init_secure_element(struct nfc_device *pnd);
int pn53x_initiator_select_passive_target(struct nfc_device *pnd, int pn53x_initiator_select_passive_target(struct nfc_device *pnd,
const nfc_modulation nm, const nfc_modulation nm,
@ -392,7 +397,7 @@ int pn53x_check_ack_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame,
int pn53x_check_error_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen); int pn53x_check_error_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen);
int pn53x_build_frame(uint8_t *pbtFrame, size_t *pszFrame, const uint8_t *pbtData, const size_t szData); int pn53x_build_frame(uint8_t *pbtFrame, size_t *pszFrame, const uint8_t *pbtData, const size_t szData);
int pn53x_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); int pn53x_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt);
int pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); int pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
int pn53x_get_information_about(nfc_device *pnd, char **pbuf); int pn53x_get_information_about(nfc_device *pnd, char **pbuf);
void *pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io); void *pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io);

View File

@ -33,9 +33,9 @@
#ifdef CONFFILES #ifdef CONFFILES
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h>
#include <dirent.h> #include <dirent.h>
#include <string.h> #include <string.h>
#include <regex.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <nfc/nfc.h> #include <nfc/nfc.h>
@ -56,30 +56,129 @@
#define LIBNFC_CONFFILE LIBNFC_SYSCONFDIR"/libnfc.conf" #define LIBNFC_CONFFILE LIBNFC_SYSCONFDIR"/libnfc.conf"
#define LIBNFC_DEVICECONFDIR LIBNFC_SYSCONFDIR"/devices.d" #define LIBNFC_DEVICECONFDIR LIBNFC_SYSCONFDIR"/devices.d"
static bool static int
conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const char *key, const char *value), void *data) escaped_value(const char line[BUFSIZ], int i, char **value)
{
if (line[i] != '"')
goto FAIL;
i++;
if (line[i] == 0 || line[i] == '\n')
goto FAIL;
int c = 0;
while (line[i] && line[i] != '"') {
i++;
c++;
}
if (line[i] != '"')
goto FAIL;
*value = malloc(c + 1);
if (!*value)
goto FAIL;
memset(*value, 0, c + 1);
memcpy(*value, &line[i - c], c);
i++;
while (line[i] && isspace(line[i]))
i++;
if (line[i] != 0 && line[i] != '\n')
goto FAIL;
return 0;
FAIL:
free(*value);
*value = NULL;
return -1;
}
static int
non_escaped_value(const char line[BUFSIZ], int i, char **value)
{
int c = 0;
while (line[i] && !isspace(line[i])) {
i++;
c++;
}
*value = malloc(c + 1);
if (!*value)
goto FAIL;
memset(*value, 0, c + 1);
memcpy(*value, &line[i - c], c);
i++;
while (line[i] && isspace(line[i]))
i++;
if (line[i] != 0)
goto FAIL;
return 0;
FAIL:
free(*value);
*value = NULL;
return -1;
}
static int
parse_line(const char line[BUFSIZ], char **key, char **value)
{
*key = NULL;
*value = NULL;
int i = 0;
int c = 0;
// optional initial spaces
while (isspace(line[i]))
i++;
if (line[i] == 0 || line[i] == '\n')
return -1;
// key
while (isalnum(line[i]) || line[i] == '_' || line[i] == '.') {
i++;
c++;
}
if (c == 0 || line[i] == 0 || line[i] == '\n') // key is empty
return -1;
*key = malloc(c + 1);
if (!*key)
return -1;
memset(*key, 0, c + 1);
memcpy(*key, &line[i - c], c);
// space before '='
while (isspace(line[i]))
i++;
if (line[i] != '=')
return -1;
i++;
if (line[i] == 0 || line[i] == '\n')
return -1;
// space after '='
while (isspace(line[i]))
i++;
if (line[i] == 0 || line[i] == '\n')
return -1;
if (escaped_value(line, i, value) == 0)
return 0;
else if (non_escaped_value(line, i, value) == 0)
return 0;
// Extracting key or value failed
free(*key);
*key = NULL;
free(*value);
*value = NULL;
return -1;
}
static void
conf_parse_file(const char *filename,
void (*conf_keyvalue)(void *data, const char *key, const char *value),
void *data)
{ {
FILE *f = fopen(filename, "r"); FILE *f = fopen(filename, "r");
if (!f) { if (!f) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Unable to open file: %s", filename); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Unable to open file: %s", filename);
return false; return;
} }
char line[BUFSIZ]; char line[BUFSIZ];
const char *str_regex = "^[[:space:]]*([[:alnum:]_.]+)[[:space:]]*=[[:space:]]*(\"(.+)\"|([^[:space:]]+))[[:space:]]*$";
regex_t preg;
if (regcomp(&preg, str_regex, REG_EXTENDED | REG_NOTEOL) != 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Regular expression used for configuration file parsing is not valid.");
fclose(f);
return false;
}
size_t nmatch = preg.re_nsub + 1;
regmatch_t *pmatch = malloc(sizeof(*pmatch) * nmatch);
if (!pmatch) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not enough memory: malloc failed.");
regfree(&preg);
fclose(f);
return false;
}
int lineno = 0; int lineno = 0;
while (fgets(line, BUFSIZ, f) != NULL) { while (fgets(line, BUFSIZ, f) != NULL) {
@ -89,30 +188,22 @@ conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const ch
case '\n': case '\n':
break; break;
default: { default: {
int match; char *key;
if ((match = regexec(&preg, line, nmatch, pmatch, 0)) == 0) { char *value;
const size_t key_size = pmatch[1].rm_eo - pmatch[1].rm_so; if (parse_line(line, &key, &value) == 0) {
const off_t value_pmatch = pmatch[3].rm_eo != -1 ? 3 : 4;
const size_t value_size = pmatch[value_pmatch].rm_eo - pmatch[value_pmatch].rm_so;
char key[key_size + 1];
char value[value_size + 1];
strncpy(key, line + (pmatch[1].rm_so), key_size);
key[key_size] = '\0';
strncpy(value, line + (pmatch[value_pmatch].rm_so), value_size);
value[value_size] = '\0';
conf_keyvalue(data, key, value); conf_keyvalue(data, key, value);
free(key);
free(value);
} else { } else {
free(key);
free(value);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line);
} }
} }
break;
} }
} }
free(pmatch);
regfree(&preg);
fclose(f); fclose(f);
return false; return;
} }
static void static void
@ -177,10 +268,8 @@ conf_devices_load(const char *dirname, nfc_context *context)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open directory: %s", dirname); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open directory: %s", dirname);
} else { } else {
struct dirent *de; struct dirent *de;
struct dirent entry; while ((de = readdir(d)) != NULL) {
struct dirent *result; // FIXME add a way to sort devices
while ((readdir_r(d, &entry, &result) == 0) && (result != NULL)) {
de = &entry;
if (de->d_name[0] != '.') { if (de->d_name[0] != '.') {
const size_t filename_len = strlen(de->d_name); const size_t filename_len = strlen(de->d_name);
const size_t extension_len = strlen(".conf"); const size_t extension_len = strlen(".conf");

View File

@ -7,6 +7,10 @@ libnfcdrivers_la_SOURCES =
libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses
libnfcdrivers_la_LIBADD = libnfcdrivers_la_LIBADD =
if DRIVER_PCSC_ENABLED
libnfcdrivers_la_SOURCES += pcsc.c pcsc.h
endif
if DRIVER_ACR122_PCSC_ENABLED if DRIVER_ACR122_PCSC_ENABLED
libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h
endif endif
@ -39,6 +43,11 @@ if DRIVER_PN532_I2C_ENABLED
libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h
endif endif
if DRIVER_PN71XX_ENABLED
libnfcdrivers_la_LIBADD += @LIBNFC_NCI_LIBS@
libnfcdrivers_la_SOURCES += pn71xx.c pn71xx.h
endif
if PCSC_ENABLED if PCSC_ENABLED
libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@ libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@
libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@ libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@

View File

@ -59,7 +59,7 @@
# define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500) # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
#elif defined(__APPLE__) #elif defined(__APPLE__)
# define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2)) # 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)) # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
#elif defined (__linux__) #elif defined (__linux__)
# include <reader.h> # include <reader.h>
@ -93,7 +93,7 @@ const struct pn53x_io acr122_pcsc_io;
// Prototypes // Prototypes
char *acr122_pcsc_firmware(nfc_device *pnd); char *acr122_pcsc_firmware(nfc_device *pnd);
const char *supported_devices[] = { static const char *supported_devices[] = {
"ACS ACR122", // ACR122U & Touchatag, last version "ACS ACR122", // ACR122U & Touchatag, last version
"ACS ACR 38U-CCID", // Touchatag, early version "ACS ACR 38U-CCID", // Touchatag, early version
"ACS ACR38U-CCID", // Touchatag, early version, under MacOSX "ACS ACR38U-CCID", // Touchatag, early version, under MacOSX
@ -400,15 +400,14 @@ acr122_pcsc_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szData, int
{ {
// FIXME: timeout is not handled // FIXME: timeout is not handled
(void) timeout; (void) timeout;
int len; int len;
uint8_t abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 };
if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_T0) { if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_T0) {
/* /*
* Retrieve the PN532 response. * Retrieve the PN532 response.
*/ */
DWORD dwRxLen = sizeof(DRIVER_DATA(pnd)->abtRx); DWORD dwRxLen = sizeof(DRIVER_DATA(pnd)->abtRx);
uint8_t abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 };
abtRxCmd[4] = DRIVER_DATA(pnd)->abtRx[1]; abtRxCmd[4] = DRIVER_DATA(pnd)->abtRx[1];
if (SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), abtRxCmd, sizeof(abtRxCmd), NULL, DRIVER_DATA(pnd)->abtRx, &dwRxLen) != SCARD_S_SUCCESS) { if (SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), abtRxCmd, sizeof(abtRxCmd), NULL, DRIVER_DATA(pnd)->abtRx, &dwRxLen) != SCARD_S_SUCCESS) {
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;

View File

@ -48,6 +48,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
/* /*
@ -60,13 +61,17 @@ Thanks to d18c7db and Okko for example code
#include <sys/select.h> #include <sys/select.h>
#include <string.h> #include <string.h>
#ifdef _MSC_VER
#include <sys/types.h>
#endif
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include <libusb.h>
#include "nfc-internal.h" #include "nfc-internal.h"
#include "buses/usbbus.h"
#include "chips/pn53x.h" #include "chips/pn53x.h"
#include "chips/pn53x-internal.h" #include "chips/pn53x-internal.h"
#include "drivers/acr122_usb.h" #include "drivers/acr122_usb.h"
#include "buses/usbbus.h"
#define ACR122_USB_DRIVER_NAME "acr122_usb" #define ACR122_USB_DRIVER_NAME "acr122_usb"
@ -159,7 +164,8 @@ struct acr122_usb_tama_frame {
struct ccid_header ccid_header; struct ccid_header ccid_header;
struct apdu_header apdu_header; struct apdu_header apdu_header;
uint8_t tama_header; uint8_t tama_header;
uint8_t tama_payload[254]; // According to ACR122U manual: Pseudo APDUs (Section 6.0), Lc is 1-byte long (Data In: 255-bytes). uint8_t tama_payload[254
]; // According to ACR122U manual: Pseudo APDUs (Section 6.0), Lc is 1-byte long (Data In: 255-bytes).
}; };
struct acr122_usb_apdu_frame { struct acr122_usb_apdu_frame {
@ -171,10 +177,12 @@ struct acr122_usb_apdu_frame {
// Internal data struct // Internal data struct
struct acr122_usb_data { struct acr122_usb_data {
usbbus_device_handle *pudh; libusb_device *dev;
uint32_t uiEndPointIn; libusb_device_handle *pudh;
uint32_t uiEndPointOut; uint8_t configIdx;
uint32_t uiMaxPacketSize; uint8_t uiEndPointIn;
uint8_t uiEndPointOut;
uint16_t uiMaxPacketSize;
volatile bool abort_flag; volatile bool abort_flag;
// Keep some buffers to reduce memcpy() usage // Keep some buffers to reduce memcpy() usage
struct acr122_usb_tama_frame tama_frame; struct acr122_usb_tama_frame tama_frame;
@ -182,17 +190,16 @@ struct acr122_usb_data {
}; };
// CCID Bulk-Out messages type // CCID Bulk-Out messages type
#define PC_to_RDR_IccPowerOn 0x62 #define PC_to_RDR_IccPowerOn 0x62
#define PC_to_RDR_XfrBlock 0x6f #define PC_to_RDR_XfrBlock 0x6f
#define RDR_to_PC_DataBlock 0x80 #define RDR_to_PC_DataBlock 0x80
// ISO 7816-4 // ISO 7816-4
#define SW1_More_Data_Available 0x61 #define SW1_More_Data_Available 0x61
#define SW1_Warning_with_NV_changed 0x63 #define SW1_Warning_with_NV_changed 0x63
#define PN53x_Specific_Application_Level_Error_Code 0x7f #define PN53x_Specific_Application_Level_Error_Code 0x7f
// This frame template is copied at init time // This frame template is copied at init time
// Its designed for TAMA sending but is also used for simple ADPU frame: acr122_build_frame_from_apdu() will overwrite needed bytes // Its designed for TAMA sending but is also used for simple ADPU frame: acr122_build_frame_from_apdu() will overwrite needed bytes
const uint8_t acr122_usb_frame_template[] = { const uint8_t acr122_usb_frame_template[] = {
@ -211,21 +218,31 @@ const struct pn53x_io acr122_usb_io;
static int acr122_usb_init(nfc_device *pnd); static int acr122_usb_init(nfc_device *pnd);
static int acr122_usb_ack(nfc_device *pnd); static int acr122_usb_ack(nfc_device *pnd);
static int acr122_usb_send_apdu(nfc_device *pnd, static int acr122_usb_send_apdu(nfc_device *pnd,
const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *const data, size_t data_len, const uint8_t le, const uint8_t ins,
uint8_t *out, const size_t out_size); const uint8_t p1,
const uint8_t p2,
const uint8_t *const data,
size_t data_len,
const uint8_t le,
uint8_t *out,
const size_t out_size);
static int static int
acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) acr122_usb_bulk_read(struct acr122_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout)
{ {
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointIn, (unsigned char *) abtRx, szRx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length); LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length);
res = actual_length; res = actual_length;
} else { } else {
if (res != USBBUS_ERROR_TIMEOUT) { if (res != LIBUSB_ERROR_TIMEOUT) {
res = NFC_EIO; res = NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", usbbus_strerror(res)); log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to read from USB (%s)",
libusb_strerror(res));
} else { } else {
res = NFC_ETIMEOUT; res = NFC_ETIMEOUT;
} }
@ -238,15 +255,15 @@ acr122_usb_bulk_write(struct acr122_usb_data *data, uint8_t abtTx[], const size_
{ {
LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx); LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx);
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointOut, (unsigned char *) abtTx, szTx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
// HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details // HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details
if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) { if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) {
usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, "\0", 0, &actual_length, timeout); libusb_bulk_transfer(data->pudh, data->uiEndPointOut, EMPTY_STRING, 0, &actual_length, timeout);
} }
} else { } else {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", usbbus_strerror(res)); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", libusb_strerror(res));
if (res == USBBUS_ERROR_TIMEOUT) { if (res == LIBUSB_ERROR_TIMEOUT) {
res = NFC_ETIMEOUT; res = NFC_ETIMEOUT;
} else { } else {
res = NFC_EIO; res = NFC_EIO;
@ -259,116 +276,49 @@ struct acr122_usb_supported_device {
uint16_t vendor_id; uint16_t vendor_id;
uint16_t product_id; uint16_t product_id;
const char *name; const char *name;
uint16_t max_packet_size;
}; };
const struct acr122_usb_supported_device acr122_usb_supported_devices[] = { const struct acr122_usb_supported_device acr122_usb_supported_devices[] = {
{ 0x072F, 0x2200, "ACS ACR122" }, //TODO find real max_packet_sizes
{ 0x072F, 0x90CC, "Touchatag" }, {0x072F, 0x2200, "ACS ACR122", 0x40},
{0x072F, 0x90CC, "Touchatag", 0x40},
{0x072F, 0x2214, "ACS ACR1222", 0x40},
}; };
// Find transfer endpoints for bulk transfers const size_t
static void num_acr122_usb_supported_device = sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device);
acr122_usb_get_end_points(struct usbbus_device *dev, struct acr122_usb_data *data)
{
uint32_t uiIndex;
uint32_t uiEndPoint;
struct usbbus_interface_descriptor *puid = dev->config->interface->altsetting;
// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
for (uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) {
// Only accept bulk transfer endpoints (ignore interrupt endpoints)
if (puid->endpoint[uiIndex].bmAttributes != USBBUS_ENDPOINT_TYPE_BULK)
continue;
// Copy the endpoint to a local var, makes it more readable code
uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress;
// Test if we dealing with a bulk IN endpoint
if ((uiEndPoint & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_ENDPOINT_IN) {
data->uiEndPointIn = uiEndPoint;
data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize;
}
// Test if we dealing with a bulk OUT endpoint
if ((uiEndPoint & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_ENDPOINT_OUT) {
data->uiEndPointOut = uiEndPoint;
data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize;
}
}
}
static size_t static size_t
acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) acr122_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
{ {//fix for compiling on Windows VS2022:
(void)context; (void) context;
struct usbbus_device *devices = (struct usbbus_device *)malloc(num_acr122_usb_supported_device * sizeof(struct usbbus_device));
usbbus_prepare(); for (size_t i = 0; i < num_acr122_usb_supported_device; i++) {
devices[i].product_id = acr122_usb_supported_devices[i].product_id;
size_t device_found = 0; devices[i].vendor_id = acr122_usb_supported_devices[i].vendor_id;
uint32_t uiBusIndex = 0; devices[i].name = acr122_usb_supported_devices[i].name;
struct usbbus_bus *bus; devices[i].max_packet_size = acr122_usb_supported_devices[i].max_packet_size;
for (bus = usbbus_get_busses(); bus; bus = bus->next) {
struct usbbus_device *dev;
for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++) {
for (size_t n = 0; n < sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); n++) {
if ((acr122_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) &&
(acr122_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) {
// Make sure there are 2 endpoints available
// with libusb-win32 we got some null pointers so be robust before looking at endpoints:
if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL) {
// Nope, we maybe want the next one, let's try to find another
continue;
}
if (dev->config->interface->altsetting->bNumEndpoints < 2) {
// Nope, we maybe want the next one, let's try to find another
continue;
}
usbbus_device_handle *udev = usbbus_open(dev);
if (udev == NULL)
continue;
// Set configuration
// acr122_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice));
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s Name %s", bus->dirname, dev->filename, acr122_usb_supported_devices[n].name);
usbbus_close(udev);
snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename);
device_found++;
// Test if we reach the maximum "wanted" devices
if (device_found == connstrings_len) {
return device_found;
}
}
}
}
} }
size_t res = usbbus_usb_scan(connstrings, connstrings_len, devices, num_acr122_usb_supported_device, ACR122_USB_DRIVER_NAME);
return device_found; free(devices);
return res;
} }
struct acr122_usb_descriptor {
char *dirname;
char *filename;
};
static bool static bool
acr122_usb_get_usb_device_name(struct usbbus_device *dev, usbbus_device_handle *udev, char *buffer, size_t len) acr122_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len)
{ {
*buffer = '\0'; *buffer = '\0';
if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { usbbus_get_usb_device_name(dev, udev, buffer, len);
if (udev) { uint16_t vendor_id = usbbus_get_vendor_id(dev);
usbbus_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); uint16_t product_id = usbbus_get_product_id(dev);
if (strlen(buffer) > 0)
strcpy(buffer + strlen(buffer), " / ");
usbbus_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer));
}
}
if (!*buffer) { if (!*buffer) {
for (size_t n = 0; n < sizeof(acr122_usb_supported_devices) / sizeof(struct acr122_usb_supported_device); n++) { for (size_t n = 0; n < num_acr122_usb_supported_device; n++) {
if ((acr122_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && if ((acr122_usb_supported_devices[n].vendor_id == vendor_id) &&
(acr122_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { (acr122_usb_supported_devices[n].product_id == product_id)) {
strncpy(buffer, acr122_usb_supported_devices[n].name, len); strncpy(buffer, acr122_usb_supported_devices[n].name, len);
buffer[len - 1] = '\0'; buffer[len - 1] = '\0';
return true; return true;
@ -383,103 +333,119 @@ static nfc_device *
acr122_usb_open(const nfc_context *context, const nfc_connstring connstring) acr122_usb_open(const nfc_context *context, const nfc_connstring connstring)
{ {
nfc_device *pnd = NULL; nfc_device *pnd = NULL;
struct acr122_usb_descriptor desc = { NULL, NULL }; char *dev_address_str;
int connstring_decode_level = connstring_decode(connstring, ACR122_USB_DRIVER_NAME, "usb", &desc.dirname, &desc.filename); char *config_idx_str;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d element(s) have been decoded from \"%s\"", connstring_decode_level, connstring); int connstring_decode_level =
if (connstring_decode_level < 1) { connstring_decode(connstring, ACR122_USB_DRIVER_NAME, "usb", &dev_address_str, &config_idx_str);
goto free_mem; log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_DEBUG,
"%d element(s) have been decoded from \"%s\"",
connstring_decode_level,
connstring);
if (connstring_decode_level < 2) {
free(dev_address_str);
free(config_idx_str);
return NULL;
} }
struct acr122_usb_data data = { uint8_t dev_addres = atoi(dev_address_str);
.pudh = NULL, uint8_t config_idx = atoi(config_idx_str);
.uiEndPointIn = 0,
.uiEndPointOut = 0,
};
struct usbbus_bus *bus;
struct usbbus_device *dev;
usbbus_prepare(); usbbus_prepare();
for (bus = usbbus_get_busses(); bus; bus = bus->next) { struct acr122_usb_data data = {
if (connstring_decode_level > 1) { .dev = NULL,
// A specific bus have been specified .pudh = NULL,
if (0 != strcmp(bus->dirname, desc.dirname)) .configIdx = config_idx,
continue; .uiEndPointIn = 0,
} .uiEndPointOut = 0,
for (dev = bus->devices; dev; dev = dev->next) { };
if (connstring_decode_level > 2) {
// A specific dev have been specified
if (0 != strcmp(dev->filename, desc.filename))
continue;
}
// Open the USB device
if ((data.pudh = usbbus_open(dev)) == NULL)
continue;
// Reset device
usbbus_reset(data.pudh);
// Retrieve end points
acr122_usb_get_end_points(dev, &data);
// Claim interface
int res = usbbus_claim_interface(data.pudh, 0);
if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", usbbus_strerror(res));
usbbus_close(data.pudh);
// we failed to use the specified device
goto free_mem;
}
res = usbbus_set_interface_alt_setting(data.pudh, 0, 0); usbbus_get_device(dev_addres, &data.dev, &data.pudh);
if (res < 0) { // Reset device
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set alternate setting on USB interface (%s)", usbbus_strerror(res)); libusb_reset_device(data.pudh);
usbbus_close(data.pudh);
// we failed to use the specified device
goto free_mem;
}
// Allocate memory for the device info and specification, fill it and return the info // Retrieve end points
pnd = nfc_device_new(context, connstring); usbbus_get_usb_endpoints(data.dev, &(data.uiEndPointIn), &(data.uiEndPointOut), &(data.uiMaxPacketSize));
if (!pnd) { // Claim interface
perror("malloc"); int res = libusb_claim_interface(data.pudh, 0);
goto error; if (res < 0) {
} log_put(LOG_GROUP,
acr122_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name)); LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to claim USB interface (%s)",
libusb_strerror(res));
libusb_close(data.pudh);
// we failed to use the specified device
free(dev_address_str);
free(config_idx_str);
return NULL;
}
pnd->driver_data = malloc(sizeof(struct acr122_usb_data)); // Check if there are more than 0 alternative interfaces and claim the first one
if (!pnd->driver_data) { // TODO would it not be better to iterate the alterative interfaces (and alternative settings) and check each one?
perror("malloc"); if (usbbus_get_num_alternate_settings(data.dev, data.configIdx) > 0) {
goto error; res = libusb_set_interface_alt_setting(data.pudh, 0, 0);
} if (res < 0) {
*DRIVER_DATA(pnd) = data; log_put(LOG_GROUP,
LOG_CATEGORY,
// Alloc and init chip's data NFC_LOG_PRIORITY_ERROR,
if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) { "Unable to set alternate setting on USB interface (%s)",
perror("malloc"); libusb_strerror(res));
goto error; libusb_close(data.pudh);
} // we failed to use the specified device
free(dev_address_str);
memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); free(config_idx_str);
memcpy(&(DRIVER_DATA(pnd)->apdu_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template)); return NULL;
CHIP_DATA(pnd)->timer_correction = 46; // empirical tuning
pnd->driver = &acr122_usb_driver;
if (acr122_usb_init(pnd) < 0) {
usbbus_close(data.pudh);
goto error;
}
DRIVER_DATA(pnd)->abort_flag = false;
goto free_mem;
} }
} }
// We ran out of devices before the index required
goto free_mem;
error: // Allocate memory for the device info and specification, fill it and return the info
// Free allocated structure on error. pnd = nfc_device_new(context, connstring);
nfc_device_free(pnd); if (!pnd) {
pnd = NULL; perror("malloc");
free_mem: free(dev_address_str);
free(desc.dirname); free(config_idx_str);
free(desc.filename); return NULL;
}
acr122_usb_get_usb_device_name(data.dev, data.pudh, pnd->name, sizeof(pnd->name));
pnd->driver_data = malloc(sizeof(struct acr122_usb_data));
if (!pnd->driver_data) {
perror("malloc");
nfc_device_free(pnd);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
*DRIVER_DATA(pnd) = data;
// Alloc and init chip's data
if (pn53x_data_new(pnd, &acr122_usb_io) == NULL) {
perror("malloc");
nfc_device_free(pnd);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
memcpy(&(DRIVER_DATA(pnd)->tama_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template));
memcpy(&(DRIVER_DATA(pnd)->apdu_frame), acr122_usb_frame_template, sizeof(acr122_usb_frame_template));
CHIP_DATA(pnd)->timer_correction = 46; // empirical tuning
pnd->driver = &acr122_usb_driver;
if (acr122_usb_init(pnd) < 0) {
libusb_close(data.pudh);
nfc_device_free(pnd);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
DRIVER_DATA(pnd)->abort_flag = false;
free(dev_address_str);
free(config_idx_str);
return pnd; return pnd;
} }
@ -489,12 +455,17 @@ acr122_usb_close(nfc_device *pnd)
acr122_usb_ack(pnd); acr122_usb_ack(pnd);
pn53x_idle(pnd); pn53x_idle(pnd);
int res; int res = libusb_release_interface(DRIVER_DATA(pnd)->pudh, 0);
if ((res = usbbus_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) { if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", usbbus_strerror(res)); log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to release USB interface (%s)",
libusb_strerror(res));
} }
usbbus_close(DRIVER_DATA(pnd)->pudh); usbbus_close(DRIVER_DATA(pnd)->dev, DRIVER_DATA(pnd)->pudh);
pn53x_data_free(pnd); pn53x_data_free(pnd);
nfc_device_free(pnd); nfc_device_free(pnd);
} }
@ -520,7 +491,13 @@ htole32(uint32_t u32)
#endif /* !defined(htole32) */ #endif /* !defined(htole32) */
static int static int
acr122_build_frame_from_apdu(nfc_device *pnd, const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *data, const size_t data_len, const uint8_t le) acr122_build_frame_from_apdu(nfc_device *pnd,
const uint8_t ins,
const uint8_t p1,
const uint8_t p2,
const uint8_t *data,
const size_t data_len,
const uint8_t le)
{ {
if (data_len > sizeof(DRIVER_DATA(pnd)->apdu_frame.apdu_payload)) if (data_len > sizeof(DRIVER_DATA(pnd)->apdu_frame.apdu_payload))
return NFC_EINVARG; return NFC_EINVARG;
@ -563,7 +540,8 @@ acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, co
return pnd->last_error; return pnd->last_error;
} }
if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, timeout)) < 0) { if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, timeout))
< 0) {
pnd->last_error = res; pnd->last_error = res;
return pnd->last_error; return pnd->last_error;
} }
@ -571,12 +549,13 @@ acr122_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, co
} }
#define USBBUS_TIMEOUT_PER_PASS 200 #define USBBUS_TIMEOUT_PER_PASS 200
static int static int
acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) acr122_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout)
{ {
off_t offset = 0; off_t offset = 0;
uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)];
int res; int res;
/* /*
@ -589,7 +568,7 @@ read:
if (timeout == USBBUS_INFINITE_TIMEOUT) { if (timeout == USBBUS_INFINITE_TIMEOUT) {
usbbus_timeout = USBBUS_TIMEOUT_PER_PASS; usbbus_timeout = USBBUS_TIMEOUT_PER_PASS;
} else { } else {
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
remaining_time -= USBBUS_TIMEOUT_PER_PASS; remaining_time -= USBBUS_TIMEOUT_PER_PASS;
if (remaining_time <= 0) { if (remaining_time <= 0) {
pnd->last_error = NFC_ETIMEOUT; pnd->last_error = NFC_ETIMEOUT;
@ -603,6 +582,7 @@ read:
uint8_t attempted_response = RDR_to_PC_DataBlock; uint8_t attempted_response = RDR_to_PC_DataBlock;
size_t len; size_t len;
int error, status;
if (res == NFC_ETIMEOUT) { if (res == NFC_ETIMEOUT) {
if (DRIVER_DATA(pnd)->abort_flag) { if (DRIVER_DATA(pnd)->abort_flag) {
@ -614,7 +594,7 @@ read:
goto read; goto read;
} }
} }
if (res < 12) { if (res < 10) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Invalid RDR_to_PC_DataBlock frame");
// try to interrupt current device state // try to interrupt current device state
acr122_usb_ack(pnd); acr122_usb_ack(pnd);
@ -629,6 +609,16 @@ read:
offset++; offset++;
len = abtRxBuf[offset++]; len = abtRxBuf[offset++];
status = abtRxBuf[7];
error = abtRxBuf[8];
if (len == 0 && error == 0xFE) { // ICC_MUTE; XXX check for more errors
// Do not check status; my ACR122U seemingly has status=0 in this case,
// even though the spec says it should have had bmCommandStatus=1
// and bmICCStatus=1.
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "Command timed out");
pnd->last_error = NFC_ETIMEOUT;
return pnd->last_error;
}
if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer: if (!((len > 1) && (abtRxBuf[10] == 0xd5))) { // In case we didn't get an immediate answer:
if (len != 2) { if (len != 2) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Wrong reply");
@ -636,17 +626,35 @@ read:
return pnd->last_error; return pnd->last_error;
} }
if (abtRxBuf[10] != SW1_More_Data_Available) { if (abtRxBuf[10] != SW1_More_Data_Available) {
if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == PN53x_Specific_Application_Level_Error_Code)) { if ((abtRxBuf[10] == SW1_Warning_with_NV_changed)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 has detected an error at the application level"); && (abtRxBuf[11] == PN53x_Specific_Application_Level_Error_Code)) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"%s",
"PN532 has detected an error at the application level");
} else if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == 0x00)) { } else if ((abtRxBuf[10] == SW1_Warning_with_NV_changed) && (abtRxBuf[11] == 0x00)) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 didn't reply"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "PN532 didn't reply");
} else { } else {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unexpected Status Word (SW1: %02x SW2: %02x)", abtRxBuf[10], abtRxBuf[11]); log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unexpected Status Word (SW1: %02x SW2: %02x)",
abtRxBuf[10],
abtRxBuf[11]);
} }
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
return pnd->last_error; return pnd->last_error;
} }
res = acr122_usb_send_apdu(pnd, APDU_GetAdditionnalData, 0x00, 0x00, NULL, 0, abtRxBuf[11], abtRxBuf, sizeof(abtRxBuf)); res = acr122_usb_send_apdu(pnd,
APDU_GetAdditionnalData,
0x00,
0x00,
NULL,
0,
abtRxBuf[11],
abtRxBuf,
sizeof(abtRxBuf));
if (res == NFC_ETIMEOUT) { if (res == NFC_ETIMEOUT) {
if (DRIVER_DATA(pnd)->abort_flag) { if (DRIVER_DATA(pnd)->abort_flag) {
DRIVER_DATA(pnd)->abort_flag = false; DRIVER_DATA(pnd)->abort_flag = false;
@ -657,7 +665,7 @@ read:
goto read; // FIXME May cause some trouble on Touchatag, right ? goto read; // FIXME May cause some trouble on Touchatag, right ?
} }
} }
if (res < 12) { if (res < 10) {
// try to interrupt current device state // try to interrupt current device state
acr122_usb_ack(pnd); acr122_usb_ack(pnd);
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
@ -675,7 +683,11 @@ read:
// XXX In CCID specification, len is a 32-bits (dword), do we need to decode more than 1 byte ? (0-255 bytes for PN532 reply) // XXX In CCID specification, len is a 32-bits (dword), do we need to decode more than 1 byte ? (0-255 bytes for PN532 reply)
len = abtRxBuf[offset++]; len = abtRxBuf[offset++];
if ((abtRxBuf[offset] != 0x00) && (abtRxBuf[offset + 1] != 0x00) && (abtRxBuf[offset + 2] != 0x00)) { if ((abtRxBuf[offset] != 0x00) && (abtRxBuf[offset + 1] != 0x00) && (abtRxBuf[offset + 2] != 0x00)) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not implemented: only 1-byte length is supported, please report this bug with a full trace."); log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"%s",
"Not implemented: only 1-byte length is supported, please report this bug with a full trace.");
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
return pnd->last_error; return pnd->last_error;
} }
@ -686,17 +698,23 @@ read:
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
return pnd->last_error; return pnd->last_error;
} }
len -= 4; // We skip 2 bytes for PN532 direction byte (D5) and command byte (CMD+1), then 2 bytes for APDU status (90 00). len -=
4; // We skip 2 bytes for PN532 direction byte (D5) and command byte (CMD+1), then 2 bytes for APDU status (90 00).
if (len > szDataLen) { if (len > szDataLen) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")",
szDataLen,
len);
pnd->last_error = NFC_EOVFLOW; pnd->last_error = NFC_EOVFLOW;
return pnd->last_error; return pnd->last_error;
} }
// Skip CCID remaining bytes // Skip CCID remaining bytes
offset += 2; // bSlot and bSeq are not used offset += 2; // bSlot and bSeq are not used
offset += 2; // XXX bStatus and bError should maybe checked ? offset += 2; // XXX bStatus and bError is partially checked ?
offset += 1; // bRFU should be 0x00 offset += 1; // bRFU should be 0x00
// TFI + PD0 (CC+1) // TFI + PD0 (CC+1)
@ -724,25 +742,36 @@ acr122_usb_ack(nfc_device *pnd)
{ {
(void) pnd; (void) pnd;
int res = 0; int res = 0;
uint8_t acr122_ack_frame[] = { GetFirmwareVersion }; // We can't send a PN532's ACK frame, so we use a normal command to cancel current command uint8_t acr122_ack_frame[] =
{GetFirmwareVersion}; // We can't send a PN532's ACK frame, so we use a normal command to cancel current command
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Abort"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ACR122 Abort");
if ((res = acr122_build_frame_from_tama(pnd, acr122_ack_frame, sizeof(acr122_ack_frame))) < 0) if ((res = acr122_build_frame_from_tama(pnd, acr122_ack_frame, sizeof(acr122_ack_frame))) < 0)
return res; return res;
if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, 1000)) < 0) if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->tama_frame), res, 1000))
< 0)
return res; return res;
uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)];
res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000); res = acr122_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), 1000);
return res; return res;
} }
static int static int
acr122_usb_send_apdu(nfc_device *pnd, acr122_usb_send_apdu(nfc_device *pnd,
const uint8_t ins, const uint8_t p1, const uint8_t p2, const uint8_t *const data, size_t data_len, const uint8_t le, const uint8_t ins,
uint8_t *out, const size_t out_size) const uint8_t p1,
const uint8_t p2,
const uint8_t *const data,
size_t data_len,
const uint8_t le,
uint8_t *out,
const size_t out_size)
{ {
int res; int res;
size_t frame_len = acr122_build_frame_from_apdu(pnd, ins, p1, p2, data, data_len, le); size_t frame_len = acr122_build_frame_from_apdu(pnd, ins, p1, p2, data, data_len, le);
if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd), (unsigned char *) & (DRIVER_DATA(pnd)->apdu_frame), frame_len, 1000)) < 0) if ((res = acr122_usb_bulk_write(DRIVER_DATA(pnd),
(unsigned char *) & (DRIVER_DATA(pnd)->apdu_frame),
frame_len,
1000)) < 0)
return res; return res;
if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), out, out_size, 1000)) < 0) if ((res = acr122_usb_bulk_read(DRIVER_DATA(pnd), out, out_size, 1000)) < 0)
return res; return res;
@ -754,7 +783,7 @@ acr122_usb_init(nfc_device *pnd)
{ {
int res = 0; int res = 0;
int i; int i;
uint8_t abtRxBuf[255 + sizeof(struct ccid_header)]; uint8_t abtRxBuf[255 + sizeof(struct ccid_header)];
/* /*
// See ACR122 manual: "Bi-Color LED and Buzzer Control" section // See ACR122 manual: "Bi-Color LED and Buzzer Control" section

View File

@ -422,7 +422,7 @@ acr122s_scan(const nfc_context *context, nfc_connstring connstrings[], const siz
while ((acPort = acPorts[iDevice++])) { while ((acPort = acPorts[iDevice++])) {
sp = uart_open(acPort); sp = uart_open(acPort);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find ACR122S device on serial port: %s at %d bauds.", acPort, ACR122S_DEFAULT_SPEED); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find ACR122S device on serial port: %s at %d baud.", acPort, ACR122S_DEFAULT_SPEED);
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) {
// We need to flush input to be sure first reply does not comes from older byte transceive // We need to flush input to be sure first reply does not comes from older byte transceive
@ -527,7 +527,7 @@ acr122s_close(nfc_device *pnd)
uart_close(DRIVER_DATA(pnd)->port); uart_close(DRIVER_DATA(pnd)->port);
#ifndef WIN32 #ifndef WIN32
// Release file descriptors used for abort mecanism // Release file descriptors used for abort mechanism
close(DRIVER_DATA(pnd)->abort_fds[0]); close(DRIVER_DATA(pnd)->abort_fds[0]);
close(DRIVER_DATA(pnd)->abort_fds[1]); close(DRIVER_DATA(pnd)->abort_fds[1]);
#endif #endif
@ -562,7 +562,7 @@ acr122s_open(const nfc_context *context, const nfc_connstring connstring)
} }
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG,
"Attempt to connect to: %s at %d bauds.", ndd.port, ndd.speed); "Attempt to connect to: %s at %d baud.", ndd.port, ndd.speed);
sp = uart_open(ndd.port); sp = uart_open(ndd.port);
if (sp == INVALID_SERIAL_PORT) { if (sp == INVALID_SERIAL_PORT) {

View File

@ -91,7 +91,6 @@ struct arygon_data {
// ARYGON frames // ARYGON frames
static const uint8_t arygon_error_none[] = "FF000000\x0d\x0a"; static const uint8_t arygon_error_none[] = "FF000000\x0d\x0a";
static const uint8_t arygon_error_incomplete_command[] = "FF0C0000\x0d\x0a";
static const uint8_t arygon_error_unknown_mode[] = "FF060000\x0d\x0a"; static const uint8_t arygon_error_unknown_mode[] = "FF060000\x0d\x0a";
// Prototypes // Prototypes
@ -109,7 +108,7 @@ arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size
while ((acPort = acPorts[iDevice++])) { while ((acPort = acPorts[iDevice++])) {
sp = uart_open(acPort); sp = uart_open(acPort);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find ARYGON device on serial port: %s at %d bauds.", acPort, ARYGON_DEFAULT_SPEED); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find ARYGON device on serial port: %s at %d baud.", acPort, ARYGON_DEFAULT_SPEED);
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) {
// We need to flush input to be sure first reply does not comes from older byte transceive // We need to flush input to be sure first reply does not comes from older byte transceive
@ -159,7 +158,7 @@ arygon_scan(const nfc_context *context, nfc_connstring connstrings[], const size
} }
#ifndef WIN32 #ifndef WIN32
// pipe-based abort mecanism // pipe-based abort mechanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port); uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd); pn53x_data_free(pnd);
@ -212,7 +211,7 @@ arygon_close_step2(nfc_device *pnd)
uart_close(DRIVER_DATA(pnd)->port); uart_close(DRIVER_DATA(pnd)->port);
#ifndef WIN32 #ifndef WIN32
// Release file descriptors used for abort mecanism // Release file descriptors used for abort mechanism
close(DRIVER_DATA(pnd)->iAbortFds[0]); close(DRIVER_DATA(pnd)->iAbortFds[0]);
close(DRIVER_DATA(pnd)->iAbortFds[1]); close(DRIVER_DATA(pnd)->iAbortFds[1]);
#endif #endif
@ -253,7 +252,7 @@ arygon_open(const nfc_context *context, const nfc_connstring connstring)
serial_port sp; serial_port sp;
nfc_device *pnd = NULL; nfc_device *pnd = NULL;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d bauds.", ndd.port, ndd.speed); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d baud.", ndd.port, ndd.speed);
sp = uart_open(ndd.port); sp = uart_open(ndd.port);
if (sp == INVALID_SERIAL_PORT) if (sp == INVALID_SERIAL_PORT)
@ -305,7 +304,7 @@ arygon_open(const nfc_context *context, const nfc_connstring connstring)
pnd->driver = &arygon_driver; pnd->driver = &arygon_driver;
#ifndef WIN32 #ifndef WIN32
// pipe-based abort mecanism // pipe-based abort mechanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port); uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd); pn53x_data_free(pnd);

1080
libnfc/drivers/pcsc.c Normal file

File diff suppressed because it is too large Load Diff

35
libnfc/drivers/pcsc.h Normal file
View File

@ -0,0 +1,35 @@
/*-
* Free/Libre Near Field Communication (NFC) library
*
* Libnfc historical contributors:
* Copyright (C) 2019 Frank Morgner
* See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file:
*
* 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 <http://www.gnu.org/licenses/>
*/
/**
* @file pcsc.h
* @brief Driver for non-ACR122 devices (behind PC/SC daemon)
*/
#ifndef __NFC_DRIVER_PCSC_H__
#define __NFC_DRIVER_PCSC_H__
#include <nfc/nfc-types.h>
extern const struct nfc_driver pcsc_driver;
#endif // ! __NFC_DRIVER_PCSC_H__

View File

@ -59,6 +59,13 @@
// I2C address of the PN532 chip. // I2C address of the PN532 chip.
#define PN532_I2C_ADDR 0x24 #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 // Internal data structs
const struct pn53x_io pn532_i2c_io; const struct pn53x_io pn532_i2c_io;
@ -67,13 +74,9 @@ struct pn532_i2c_data {
volatile bool abort_flag; volatile bool abort_flag;
}; };
/* Delay for the loop waiting for READY frame (in ms) */ /* preamble and start bytes, see pn532-internal.h for details */
#define PN532_RDY_LOOP_DELAY 90 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]))
const struct timespec rdyDelay = {
.tv_sec = 0,
.tv_nsec = PN532_RDY_LOOP_DELAY * 1000 * 1000
};
/* Private Functions Prototypes */ /* 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)) #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, 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, 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. * @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) pn532_i2c_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout)
{ {
int res = 0; int res = 0;
uint8_t retries;
// Discard any existing data ? // Discard any existing data ?
@ -334,15 +402,22 @@ pn532_i2c_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int
break; 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; 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) { if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) {
pnd->last_error = res; pnd->last_error = res;
return pnd->last_error; 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) { if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); 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 { do {
// Wait a little bit before reading int recCount = pn532_i2c_read(DRIVER_DATA(pnd)->dev, i2cRx, szDataLen + 1);
nanosleep(&rdyDelay, (struct timespec *) NULL);
int recCount = i2c_read(DRIVER_DATA(pnd)->dev, i2cRx, szDataLen + 1);
if (DRIVER_DATA(pnd)->abort_flag) { if (DRIVER_DATA(pnd)->abort_flag) {
// Reset 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; goto error;
} }
const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; if (0 != (memcmp(frameBuf, pn53x_preamble_and_start, PN53X_PREAMBLE_AND_START_LEN))) {
if (0 != (memcmp(frameBuf, pn53x_preamble, 3))) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch");
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
goto error; goto error;
@ -572,7 +642,7 @@ error:
int int
pn532_i2c_ack(nfc_device *pnd) 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));
} }
/** /**

View File

@ -433,7 +433,7 @@ pn532_spi_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, int
goto error; goto error;
} }
pnd->last_error = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf , 4, true); pnd->last_error = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf, 4, true);
if (pnd->last_error < 0) { if (pnd->last_error < 0) {
goto error; goto error;

View File

@ -82,7 +82,7 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
while ((acPort = acPorts[iDevice++])) { while ((acPort = acPorts[iDevice++])) {
sp = uart_open(acPort); sp = uart_open(acPort);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find PN532 device on serial port: %s at %d bauds.", acPort, PN532_UART_DEFAULT_SPEED); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Trying to find PN532 device on serial port: %s at %d baud.", acPort, PN532_UART_DEFAULT_SPEED);
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) {
// We need to flush input to be sure first reply does not comes from older byte transceive // We need to flush input to be sure first reply does not comes from older byte transceive
@ -136,7 +136,7 @@ pn532_uart_scan(const nfc_context *context, nfc_connstring connstrings[], const
CHIP_DATA(pnd)->power_mode = LOWVBAT; CHIP_DATA(pnd)->power_mode = LOWVBAT;
#ifndef WIN32 #ifndef WIN32
// pipe-based abort mecanism // pipe-based abort mechanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port); uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd); pn53x_data_free(pnd);
@ -191,7 +191,7 @@ pn532_uart_close(nfc_device *pnd)
uart_close(DRIVER_DATA(pnd)->port); uart_close(DRIVER_DATA(pnd)->port);
#ifndef WIN32 #ifndef WIN32
// Release file descriptors used for abort mecanism // Release file descriptors used for abort mechanism
close(DRIVER_DATA(pnd)->iAbortFds[0]); close(DRIVER_DATA(pnd)->iAbortFds[0]);
close(DRIVER_DATA(pnd)->iAbortFds[1]); close(DRIVER_DATA(pnd)->iAbortFds[1]);
#endif #endif
@ -225,7 +225,7 @@ pn532_uart_open(const nfc_context *context, const nfc_connstring connstring)
serial_port sp; serial_port sp;
nfc_device *pnd = NULL; nfc_device *pnd = NULL;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d bauds.", ndd.port, ndd.speed); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d baud.", ndd.port, ndd.speed);
sp = uart_open(ndd.port); sp = uart_open(ndd.port);
if (sp == INVALID_SERIAL_PORT) if (sp == INVALID_SERIAL_PORT)
@ -277,7 +277,7 @@ pn532_uart_open(const nfc_context *context, const nfc_connstring connstring)
pnd->driver = &pn532_uart_driver; pnd->driver = &pn532_uart_driver;
#ifndef WIN32 #ifndef WIN32
// pipe-based abort mecanism // pipe-based abort mechanism
if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) { if (pipe(DRIVER_DATA(pnd)->iAbortFds) < 0) {
uart_close(DRIVER_DATA(pnd)->port); uart_close(DRIVER_DATA(pnd)->port);
pn53x_data_free(pnd); pn53x_data_free(pnd);
@ -290,7 +290,7 @@ pn532_uart_open(const nfc_context *context, const nfc_connstring connstring)
// Check communication using "Diagnose" command, with "Communication test" (0x00) // Check communication using "Diagnose" command, with "Communication test" (0x00)
if (pn53x_check_communication(pnd) < 0) { if (pn53x_check_communication(pnd) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "pn53x_check_communication error on %s", ndd.port); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "pn53x_check_communication error");
pn532_uart_close(pnd); pn532_uart_close(pnd);
return NULL; return NULL;
} }

View File

@ -5,7 +5,7 @@
* Copyright (C) 2009 Roel Verdult * Copyright (C) 2009 Roel Verdult
* Copyright (C) 2009-2013 Romuald Conty * Copyright (C) 2009-2013 Romuald Conty
* Copyright (C) 2010-2012 Romain Tartière * Copyright (C) 2010-2012 Romain Tartière
* Copyright (C) 2010-2013 Philippe Teuwen * Copyright (C) 2010-2017 Philippe Teuwen
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
@ -31,6 +31,7 @@
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include "config.h" # include "config.h"
#endif // HAVE_CONFIG_H #endif // HAVE_CONFIG_H
/* /*
@ -43,8 +44,11 @@ Thanks to d18c7db and Okko for example code
#include <sys/select.h> #include <sys/select.h>
#include <string.h> #include <string.h>
#ifdef _MSC_VER
#include <sys/types.h>
#endif
#include <nfc/nfc.h> #include <nfc/nfc.h>
#include <libusb.h>
#include "nfc-internal.h" #include "nfc-internal.h"
#include "buses/usbbus.h" #include "buses/usbbus.h"
#include "chips/pn53x.h" #include "chips/pn53x.h"
@ -59,6 +63,8 @@ Thanks to d18c7db and Okko for example code
#define DRIVER_DATA(pnd) ((struct pn53x_usb_data*)(pnd->driver_data)) #define DRIVER_DATA(pnd) ((struct pn53x_usb_data*)(pnd->driver_data))
const nfc_modulation_type no_target_support[] = {0};
typedef enum { typedef enum {
UNKNOWN, UNKNOWN,
NXP_PN531, NXP_PN531,
@ -66,37 +72,45 @@ typedef enum {
NXP_PN533, NXP_PN533,
ASK_LOGO, ASK_LOGO,
SCM_SCL3711, SCM_SCL3711,
SCM_SCL3712,
SONY_RCS360 SONY_RCS360
} pn53x_usb_model; } pn53x_usb_model;
// Internal data struct // Internal data struct
struct pn53x_usb_data { struct pn53x_usb_data {
usbbus_device_handle *pudh; libusb_device *dev;
libusb_device_handle *pudh;
uint8_t configIdx;
pn53x_usb_model model; pn53x_usb_model model;
uint32_t uiEndPointIn; uint8_t uiEndPointIn;
uint32_t uiEndPointOut; uint8_t uiEndPointOut;
uint32_t uiMaxPacketSize; uint16_t uiMaxPacketSize;
volatile bool abort_flag; volatile bool abort_flag;
bool possibly_corrupted_usbdesc;
}; };
// Internal io struct // Internal io struct
const struct pn53x_io pn53x_usb_io; const struct pn53x_io pn53x_usb_io;
// Prototypes // Prototypes
bool pn53x_usb_get_usb_device_name(struct usbbus_device *dev, usbbus_device_handle *udev, char *buffer, size_t len); bool pn53x_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len);
int pn53x_usb_init(nfc_device *pnd); int pn53x_usb_init(nfc_device *pnd);
static int static int
pn53x_usb_bulk_read(struct pn53x_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout) pn53x_usb_bulk_read(struct pn53x_usb_data *data, uint8_t abtRx[], const size_t szRx, const int timeout)
{ {
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointIn, (char *) abtRx, szRx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointIn & 0xff, abtRx, szRx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length); LOG_HEX(NFC_LOG_GROUP_COM, "RX", abtRx, actual_length);
res = actual_length; res = actual_length;
} else { } else {
if (res != USBBUS_ERROR_TIMEOUT) if (res != LIBUSB_ERROR_TIMEOUT)
log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to read from USB (%s)", usbbus_strerror(res)); log_put(NFC_LOG_GROUP_COM,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to read from USB (%s)",
libusb_strerror(res));
} }
return res; return res;
} }
@ -106,14 +120,18 @@ pn53x_usb_bulk_write(struct pn53x_usb_data *data, uint8_t abtTx[], const size_t
{ {
LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx); LOG_HEX(NFC_LOG_GROUP_COM, "TX", abtTx, szTx);
int actual_length; int actual_length;
int res = usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, (char *) abtTx, szTx, &actual_length, timeout); int res = libusb_bulk_transfer(data->pudh, data->uiEndPointOut & 0xff, abtTx, szTx, &actual_length, timeout);
if (res == 0) { if (res == 0) {
// HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details // HACK This little hack is a well know problem of USB, see http://www.libusb.org/ticket/6 for more details
if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) { if ((actual_length > 0) && ((actual_length % data->uiMaxPacketSize) == 0)) {
usbbus_bulk_transfer(data->pudh, data->uiEndPointOut, "\0", 0, &actual_length, timeout); libusb_bulk_transfer(data->pudh, data->uiEndPointOut & 0xff, EMPTY_STRING, 0, &actual_length, timeout);
} }
} else { } else {
log_put(NFC_LOG_GROUP_COM, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to write to USB (%s)", usbbus_strerror(res)); log_put(NFC_LOG_GROUP_COM,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to write to USB (%s)",
libusb_strerror(res));
} }
return res; return res;
} }
@ -123,17 +141,107 @@ struct pn53x_usb_supported_device {
uint16_t product_id; uint16_t product_id;
pn53x_usb_model model; pn53x_usb_model model;
const char *name; const char *name;
/* hardcoded known values for buggy hardware whose configuration vanishes */
uint32_t uiEndPointIn;
uint32_t uiEndPointOut;
uint32_t uiMaxPacketSize;
}; };
const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = { const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = {
{ 0x04CC, 0x0531, NXP_PN531, "Philips / PN531" }, {0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40},
{ 0x04CC, 0x2533, NXP_PN533, "NXP / PN533" }, {0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x84, 0x04, 0x40},
{ 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW" }, {0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x84, 0x04, 0x40},
{ 0x054c, 0x0193, SONY_PN531, "Sony / PN531" }, {0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0}, // to check on real device
{ 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO" }, {0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40},
{ 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]" } {0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40},
{0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0x84, 0x04, 0x40}
}; };
const size_t num_pn53x_usb_supported_devices = sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device);
// PN533 USB descriptors backup buffers
const uint8_t btXramUsbDesc_scl3711[] = {
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00,
0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00,
0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x1e, 0x03, 0x53, 0x00,
0x43, 0x00, 0x4c, 0x00, 0x33, 0x00, 0x37, 0x00, 0x31, 0x00, 0x31, 0x00,
0x2d, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x43, 0x00, 0x26, 0x00, 0x52, 0x00,
0x57,
};
const uint8_t btXramUsbDesc_nxppn533[] = {
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00,
0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00,
0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0c, 0x03, 0x50, 0x00,
0x4e, 0x00, 0x35, 0x00, 0x33, 0x00, 0x33, 0x00, 0x04, 0x03, 0x09, 0x04,
0x08, 0x03, 0x4e, 0x00, 0x58, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
};
const uint8_t btXramUsbDesc_asklogo[] = {
0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, 0x04, 0x00,
0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00,
0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0a, 0x03, 0x4c, 0x00,
0x6f, 0x00, 0x47, 0x00, 0x4f, 0x00, 0x04, 0x03, 0x09, 0x04, 0x08, 0x03,
0x41, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,
};
static void pn533_fix_usbdesc(nfc_device *pnd)
{
// PN533 USB descriptors may have been corrupted by large commands/responses
// so they need to be restored before closing usb connection.
// cf PN5331B3HNC270 Release Note
uint32_t szXramUsbDesc = 0;
uint8_t *btXramUsbDesc = NULL;
if (DRIVER_DATA(pnd)->model == NXP_PN533) {
btXramUsbDesc = (uint8_t *) btXramUsbDesc_nxppn533;
szXramUsbDesc = sizeof(btXramUsbDesc_nxppn533);
} else if (DRIVER_DATA(pnd)->model == SCM_SCL3711) {
btXramUsbDesc = (uint8_t *) btXramUsbDesc_scl3711;
szXramUsbDesc = sizeof(btXramUsbDesc_scl3711);
} else if (DRIVER_DATA(pnd)->model == ASK_LOGO) {
btXramUsbDesc = (uint8_t *) btXramUsbDesc_asklogo;
szXramUsbDesc = sizeof(btXramUsbDesc_asklogo);
}
#define MAXSZXRAMUSBDESC 61
if ((szXramUsbDesc == 0) || (MAXSZXRAMUSBDESC > 61))
return;
#if 0
// Debug routine to check if corruption occurred:
// Don't read more regs at once or it will trigger the bug and corrupt what we're busy reading!
uint8_t abtCmdRR[] = { ReadRegister, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t nRRreg = ((sizeof(abtCmdRR) - 1) / 2);
uint8_t abtRxRR[1 + nRRreg];
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Checking USB descriptors corruption in XRAM");
for (uint8_t i = 0x19, j = 0; i < 0x19 + szXramUsbDesc;) {
for (uint8_t k = 0; k < nRRreg; k++) {
abtCmdRR[(2 * k) + 2] = i++;
}
if (pn53x_transceive(pnd, abtCmdRR, sizeof(abtCmdRR), abtRxRR, sizeof(abtRxRR), -1) < 0) {
return; // void
}
for (int k = 0; (k < nRRreg) && (j < szXramUsbDesc); k++) {
//printf("0x%02x, ", abtRxRR[1 + k]);
if (btXramUsbDesc[j] != abtRxRR[1 + k])
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "XRAM corruption @ addr 0x00%02X: got %02x, expected %02x", 0x0019 + (j - 1), abtRxRR[1 + k], btXramUsbDesc[j]);
j++;
}
}
#endif
// Abuse the overflow bug to restore USB descriptors in one go
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Fixing USB descriptors corruption");
uint8_t abtCmdWR[19 + MAXSZXRAMUSBDESC] = {GetFirmwareVersion};
for (size_t i = 0; i < szXramUsbDesc; i++) {
abtCmdWR[i + 19] = btXramUsbDesc[i];
}
size_t szCmdWR = sizeof(abtCmdWR);
uint8_t abtRxWR[4];
if (pn53x_transceive(pnd, abtCmdWR, szCmdWR, abtRxWR, sizeof(abtRxWR), -1) < 0) {
return; // void
}
DRIVER_DATA(pnd)->possibly_corrupted_usbdesc = false;
}
static pn53x_usb_model static pn53x_usb_model
pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id) pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id)
{ {
@ -146,119 +254,57 @@ pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id)
return UNKNOWN; return UNKNOWN;
} }
int pn53x_usb_ack(nfc_device *pnd); static bool
pn53x_usb_get_end_points_default(struct pn53x_usb_data *data)
// Find transfer endpoints for bulk transfers
static void
pn53x_usb_get_end_points(struct usbbus_device *dev, struct pn53x_usb_data *data)
{ {
uint32_t uiIndex; struct libusb_device_descriptor descriptor;
uint32_t uiEndPoint; libusb_get_device_descriptor(data->dev, &descriptor);
struct usbbus_interface_descriptor *puid = dev->config->interface->altsetting;
// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) {
for (uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++) { if ((descriptor.idVendor == pn53x_usb_supported_devices[n].vendor_id) &&
// Only accept bulk transfer endpoints (ignore interrupt endpoints) (descriptor.idProduct == pn53x_usb_supported_devices[n].product_id)) {
if (puid->endpoint[uiIndex].bmAttributes != USBBUS_ENDPOINT_TYPE_BULK) if (pn53x_usb_supported_devices[n].uiMaxPacketSize != 0) {
continue; data->uiEndPointIn = pn53x_usb_supported_devices[n].uiEndPointIn;
data->uiEndPointOut = pn53x_usb_supported_devices[n].uiEndPointOut;
data->uiMaxPacketSize = pn53x_usb_supported_devices[n].uiMaxPacketSize;
// Copy the endpoint to a local var, makes it more readable code return true;
uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress;
// Test if we dealing with a bulk IN endpoint
if ((uiEndPoint & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_ENDPOINT_IN) {
data->uiEndPointIn = uiEndPoint;
data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize;
}
// Test if we dealing with a bulk OUT endpoint
if ((uiEndPoint & USBBUS_ENDPOINT_DIR_MASK) == USBBUS_ENDPOINT_OUT) {
data->uiEndPointOut = uiEndPoint;
data->uiMaxPacketSize = puid->endpoint[uiIndex].wMaxPacketSize;
}
}
}
static size_t
pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
{
(void)context;
usbbus_prepare();
size_t device_found = 0;
uint32_t uiBusIndex = 0;
struct usbbus_bus *bus;
for (bus = usbbus_get_busses(); bus; bus = bus->next) {
struct usbbus_device *dev;
for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++) {
for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) {
if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) &&
(pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) {
// Make sure there are 2 endpoints available
// with libusb-win32 we got some null pointers so be robust before looking at endpoints:
if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL) {
// Nope, we maybe want the next one, let's try to find another
continue;
}
if (dev->config->interface->altsetting->bNumEndpoints < 2) {
// Nope, we maybe want the next one, let's try to find another
continue;
}
usbbus_device_handle *udev = usbbus_open(dev);
if (udev == NULL)
continue;
// Set configuration
int res = usbbus_set_configuration(udev, 1);
if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", usbbus_strerror(res));
usbbus_close(udev);
// we failed to use the device
continue;
}
// pn53x_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice));
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s", bus->dirname, dev->filename);
usbbus_close(udev);
snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename);
device_found++;
// Test if we reach the maximum "wanted" devices
if (device_found == connstrings_len) {
return device_found;
}
}
} }
} }
} }
return device_found; return false;
} }
struct pn53x_usb_descriptor { int pn53x_usb_ack(nfc_device *pnd);
char *dirname;
char *filename;
};
static size_t
pn53x_usb_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
{//fix for compiling on Windows VS2022:
struct usbbus_device *devices = (struct usbbus_device*)malloc(num_pn53x_usb_supported_devices*sizeof(struct usbbus_device));
for (size_t i = 0; i < num_pn53x_usb_supported_devices; i++) {
devices[i].product_id = pn53x_usb_supported_devices[i].product_id;
devices[i].vendor_id = pn53x_usb_supported_devices[i].vendor_id;
devices[i].name = pn53x_usb_supported_devices[i].name;
devices[i].max_packet_size = pn53x_usb_supported_devices[i].uiMaxPacketSize;
}
size_t res = usbbus_usb_scan(connstrings, connstrings_len, devices, num_pn53x_usb_supported_devices, PN53X_USB_DRIVER_NAME);
free(devices);
return res;
}
bool bool
pn53x_usb_get_usb_device_name(struct usbbus_device *dev, usbbus_device_handle *udev, char *buffer, size_t len) pn53x_usb_get_usb_device_name(struct libusb_device *dev, libusb_device_handle *udev, char *buffer, size_t len)
{ {
*buffer = '\0'; *buffer = '\0';
if (dev->descriptor.iManufacturer || dev->descriptor.iProduct) { usbbus_get_usb_device_name(dev, udev, buffer, len);
if (udev) { uint16_t vendor_id = usbbus_get_vendor_id(dev);
usbbus_get_string_simple(udev, dev->descriptor.iManufacturer, buffer, len); uint16_t product_id = usbbus_get_product_id(dev);
if (strlen(buffer) > 0)
strcpy(buffer + strlen(buffer), " / ");
usbbus_get_string_simple(udev, dev->descriptor.iProduct, buffer + strlen(buffer), len - strlen(buffer));
}
}
if (!*buffer) { if (!*buffer) {
for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { for (size_t n = 0; n < num_pn53x_usb_supported_devices; n++) {
if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && if ((pn53x_usb_supported_devices[n].vendor_id == vendor_id) &&
(pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { (pn53x_usb_supported_devices[n].product_id == product_id)) {
strncpy(buffer, pn53x_usb_supported_devices[n].name, len); strncpy(buffer, pn53x_usb_supported_devices[n].name, len);
buffer[len - 1] = '\0'; buffer[len - 1] = '\0';
return true; return true;
@ -273,126 +319,153 @@ static nfc_device *
pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring) pn53x_usb_open(const nfc_context *context, const nfc_connstring connstring)
{ {
nfc_device *pnd = NULL; nfc_device *pnd = NULL;
struct pn53x_usb_descriptor desc = { NULL, NULL };
int connstring_decode_level = connstring_decode(connstring, PN53X_USB_DRIVER_NAME, "usb", &desc.dirname, &desc.filename); char *dev_address_str;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%d element(s) have been decoded from \"%s\"", connstring_decode_level, connstring); char *config_idx_str;
if (connstring_decode_level < 1) { int connstring_decode_level =
goto free_mem; connstring_decode(connstring, PN53X_USB_DRIVER_NAME, "usb", &dev_address_str, &config_idx_str);
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_DEBUG,
"%d element(s) have been decoded from \"%s\"",
connstring_decode_level,
connstring);
// At least the driver and the dev address need to be decoded
if (connstring_decode_level < 2) {
return NULL;
} }
struct pn53x_usb_data data = { uint8_t dev_addres = atoi(dev_address_str);
.pudh = NULL, uint8_t config_idx = atoi(config_idx_str);
.uiEndPointIn = 0,
.uiEndPointOut = 0,
};
struct usbbus_bus *bus;
struct usbbus_device *dev;
usbbus_prepare(); usbbus_prepare();
for (bus = usbbus_get_busses(); bus; bus = bus->next) {
if (connstring_decode_level > 1) {
// A specific bus have been specified
if (0 != strcmp(bus->dirname, desc.dirname))
continue;
}
for (dev = bus->devices; dev; dev = dev->next) {
if (connstring_decode_level > 2) {
// A specific dev have been specified
if (0 != strcmp(dev->filename, desc.filename))
continue;
}
// Open the USB device
if ((data.pudh = usbbus_open(dev)) == NULL)
continue;
// Retrieve end points
pn53x_usb_get_end_points(dev, &data);
// Set configuration
int res = usbbus_set_configuration(data.pudh, 1);
if (res < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set USB configuration (%s)", usbbus_strerror(res));
if (res == USBBUS_ERROR_ACCESS) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: Please double check USB permissions for device %04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
}
usbbus_close(data.pudh);
// we failed to use the specified device
goto free_mem;
}
res = usbbus_claim_interface(data.pudh, 0); struct pn53x_usb_data data = {
if (res < 0) { .dev = NULL,
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to claim USB interface (%s)", usbbus_strerror(res)); .pudh = NULL,
usbbus_close(data.pudh); .configIdx = config_idx,
// we failed to use the specified device .uiEndPointIn = 0,
goto free_mem; .uiEndPointOut = 0,
} .possibly_corrupted_usbdesc = false,
data.model = pn53x_usb_get_device_model(dev->descriptor.idVendor, dev->descriptor.idProduct); };
// Allocate memory for the device info and specification, fill it and return the info
pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
goto error;
}
pn53x_usb_get_usb_device_name(dev, data.pudh, pnd->name, sizeof(pnd->name));
pnd->driver_data = malloc(sizeof(struct pn53x_usb_data)); usbbus_get_device(dev_addres, &data.dev, &data.pudh);
if (!pnd->driver_data) {
perror("malloc");
goto error;
}
*DRIVER_DATA(pnd) = data;
// Alloc and init chip's data // Retrieve end points, using hardcoded defaults if available
if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) { // or using the descriptors otherwise.
perror("malloc"); if (!pn53x_usb_get_end_points_default(&data)) {
goto error; // Find transfer endpoints for bulk transfers
} usbbus_get_usb_endpoints(data.dev, &(data.uiEndPointIn), &(data.uiEndPointOut), &(data.uiMaxPacketSize));
switch (DRIVER_DATA(pnd)->model) {
// empirical tuning
case ASK_LOGO:
CHIP_DATA(pnd)->timer_correction = 50;
break;
case SCM_SCL3711:
case NXP_PN533:
CHIP_DATA(pnd)->timer_correction = 46;
break;
case NXP_PN531:
CHIP_DATA(pnd)->timer_correction = 50;
break;
case SONY_PN531:
CHIP_DATA(pnd)->timer_correction = 54;
break;
case SONY_RCS360:
case UNKNOWN:
CHIP_DATA(pnd)->timer_correction = 0; // TODO: allow user to know if timed functions are available
break;
}
pnd->driver = &pn53x_usb_driver;
// HACK1: Send first an ACK as Abort command, to reset chip before talking to it:
pn53x_usb_ack(pnd);
// HACK2: Then send a GetFirmware command to resync USB toggle bit between host & device
// in case host used set_configuration and expects the device to have reset its toggle bit, which PN53x doesn't do
if (pn53x_usb_init(pnd) < 0) {
usbbus_close(data.pudh);
goto error;
}
DRIVER_DATA(pnd)->abort_flag = false;
goto free_mem;
}
} }
// We ran out of devices before the index required // Set configuration
goto free_mem; int res = libusb_set_configuration(data.pudh, data.configIdx);
if (res < 0) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to set USB configuration (%s)",
libusb_strerror(res));
if (res == LIBUSB_ERROR_ACCESS) {
log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_INFO,
"Warning: Please double check USB permissions for device %04x:%04x:%03d",
usbbus_get_vendor_id(data.dev),
usbbus_get_product_id(data.dev),
data.configIdx);
}
// we failed to use the specified device
usbbus_close(data.dev, data.pudh);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
error: res = libusb_claim_interface(data.pudh, 0);
// Free allocated structure on error. if (res < 0) {
nfc_device_free(pnd); log_put(LOG_GROUP,
pnd = NULL; LOG_CATEGORY,
free_mem: NFC_LOG_PRIORITY_ERROR,
free(desc.dirname); "Unable to claim USB interface (%s)",
free(desc.filename); libusb_strerror(res));
// we failed to use the specified device
usbbus_close(data.dev, data.pudh);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
data.model = pn53x_usb_get_device_model(usbbus_get_vendor_id(data.dev), usbbus_get_product_id(data.dev));
// Allocate memory for the device info and specification, fill it and return the info
pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
usbbus_close(data.dev, data.pudh);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
pn53x_usb_get_usb_device_name(data.dev, data.pudh, pnd->name, sizeof(pnd->name));
pnd->driver_data = malloc(sizeof(struct pn53x_usb_data));
if (!pnd->driver_data) {
perror("malloc");
nfc_device_free(pnd);
usbbus_close(data.dev, data.pudh);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
*DRIVER_DATA(pnd) = data;
// Alloc and init chip's data
if (pn53x_data_new(pnd, &pn53x_usb_io) == NULL) {
perror("malloc");
nfc_device_free(pnd);
usbbus_close(data.dev, data.pudh);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
switch (DRIVER_DATA(pnd)->model) {
// empirical tuning
case ASK_LOGO:
CHIP_DATA(pnd)->timer_correction = 50;
CHIP_DATA(pnd)->progressive_field = true;
break;
case SCM_SCL3711:
case SCM_SCL3712:
case NXP_PN533:
CHIP_DATA(pnd)->timer_correction = 46;
break;
case NXP_PN531:
CHIP_DATA(pnd)->timer_correction = 50;
break;
case SONY_PN531:
CHIP_DATA(pnd)->timer_correction = 54;
break;
case SONY_RCS360:
case UNKNOWN:
CHIP_DATA(pnd)->timer_correction = 0; // TODO: allow user to know if timed functions are available
break;
}
pnd->driver = &pn53x_usb_driver;
// HACK1: Send first an ACK as Abort command, to reset chip before talking to it:
pn53x_usb_ack(pnd);
// HACK2: Then send a GetFirmware command to resync USB toggle bit between host & device
// in case host used set_configuration and expects the device to have reset its toggle bit, which PN53x doesn't do
if (pn53x_usb_init(pnd) < 0) {
nfc_device_free(pnd);
usbbus_close(data.dev, data.pudh);
free(dev_address_str);
free(config_idx_str);
return NULL;
}
DRIVER_DATA(pnd)->abort_flag = false;
return pnd; return pnd;
} }
@ -407,14 +480,14 @@ pn53x_usb_close(nfc_device *pnd)
pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P32) | _BV(P33) | _BV(P35)); pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P32) | _BV(P33) | _BV(P35));
} }
pn53x_idle(pnd); if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) {
pn533_fix_usbdesc(pnd);
int res;
if ((res = usbbus_release_interface(DRIVER_DATA(pnd)->pudh, 0)) < 0) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to release USB interface (%s)", usbbus_strerror(res));
} }
usbbus_close(DRIVER_DATA(pnd)->pudh); pn53x_idle(pnd);
usbbus_close(DRIVER_DATA(pnd)->dev, DRIVER_DATA(pnd)->pudh);
pn53x_data_free(pnd); pn53x_data_free(pnd);
nfc_device_free(pnd); nfc_device_free(pnd);
} }
@ -424,7 +497,7 @@ pn53x_usb_close(nfc_device *pnd)
static int static int
pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout) pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, const int timeout)
{ {
uint8_t abtFrame[PN53X_USB_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" uint8_t abtFrame[PN53X_USB_BUFFER_LEN] = {0x00, 0x00, 0xff}; // Every packet must start with "00 00 ff"
size_t szFrame = 0; size_t szFrame = 0;
int res = 0; int res = 0;
@ -433,6 +506,7 @@ pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, con
return pnd->last_error; return pnd->last_error;
} }
DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= szData > 17;
if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), abtFrame, szFrame, timeout)) < 0) { if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), abtFrame, szFrame, timeout)) < 0) {
pnd->last_error = res; pnd->last_error = res;
return pnd->last_error; return pnd->last_error;
@ -452,29 +526,32 @@ pn53x_usb_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, con
// For some reasons (eg. send another command while a previous one is // For some reasons (eg. send another command while a previous one is
// running), the PN533 sometimes directly replies the response packet // running), the PN533 sometimes directly replies the response packet
// instead of ACK frame, so we send a NACK frame to force PN533 to resend // instead of ACK frame, so we send a NACK frame to force PN533 to resend
// response packet. With this hack, the nextly executed function (ie. // response packet. With this hack, the next executed function (ie.
// pn53x_usb_receive()) will be able to retreive the correct response // pn53x_usb_receive()) will be able to retrieve the correct response
// packet. // packet.
// FIXME Sony reader is also affected by this bug but NACK is not supported // FIXME Sony reader is also affected by this bug but NACK is not supported
if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *)pn53x_nack_frame, sizeof(pn53x_nack_frame), timeout)) < 0) { if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd),
(uint8_t *) pn53x_nack_frame,
sizeof(pn53x_nack_frame),
timeout)) < 0) {
pnd->last_error = res; pnd->last_error = res;
// try to interrupt current device state // try to interrupt current device state
pn53x_usb_ack(pnd); pn53x_usb_ack(pnd);
return pnd->last_error; return pnd->last_error;
} }
} }
return NFC_SUCCESS; return NFC_SUCCESS;
} }
#define USBBUS_TIMEOUT_PER_PASS 200 #define USBBUS_TIMEOUT_PER_PASS 200
static int static int
pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout) pn53x_usb_receive(nfc_device *pnd, uint8_t *pbtData, const size_t szDataLen, const int timeout)
{ {
size_t len; size_t len;
off_t offset = 0; off_t offset = 0;
uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN]; uint8_t abtRxBuf[PN53X_USB_BUFFER_LEN];
int res; int res;
/* /*
@ -487,7 +564,7 @@ read:
if (timeout == USBBUS_INFINITE_TIMEOUT) { if (timeout == USBBUS_INFINITE_TIMEOUT) {
usbbus_timeout = USBBUS_TIMEOUT_PER_PASS; usbbus_timeout = USBBUS_TIMEOUT_PER_PASS;
} else { } else {
// A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mecanism // A user-provided timeout is set, we have to cut it in multiple chunk to be able to keep an nfc_abort_command() mechanism
remaining_time -= USBBUS_TIMEOUT_PER_PASS; remaining_time -= USBBUS_TIMEOUT_PER_PASS;
if (remaining_time <= 0) { if (remaining_time <= 0) {
pnd->last_error = NFC_ETIMEOUT; pnd->last_error = NFC_ETIMEOUT;
@ -499,7 +576,7 @@ read:
res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usbbus_timeout); res = pn53x_usb_bulk_read(DRIVER_DATA(pnd), abtRxBuf, sizeof(abtRxBuf), usbbus_timeout);
if (res == USBBUS_ERROR_TIMEOUT) { if (res == LIBUSB_ERROR_TIMEOUT) {
if (DRIVER_DATA(pnd)->abort_flag) { if (DRIVER_DATA(pnd)->abort_flag) {
DRIVER_DATA(pnd)->abort_flag = false; DRIVER_DATA(pnd)->abort_flag = false;
pn53x_usb_ack(pnd); pn53x_usb_ack(pnd);
@ -517,7 +594,7 @@ read:
return pnd->last_error; return pnd->last_error;
} }
const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; const uint8_t pn53x_preamble[3] = {0x00, 0x00, 0xff};
if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) { if (0 != (memcmp(abtRxBuf, pn53x_preamble, 3))) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch");
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
@ -558,7 +635,12 @@ read:
} }
if (len > szDataLen) { if (len > szDataLen) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")", szDataLen, len); log_put(LOG_GROUP,
LOG_CATEGORY,
NFC_LOG_PRIORITY_ERROR,
"Unable to receive data: buffer too small. (szDataLen: %" PRIuPTR ", len: %" PRIuPTR ")",
szDataLen,
len);
pnd->last_error = NFC_EIO; pnd->last_error = NFC_EIO;
return pnd->last_error; return pnd->last_error;
} }
@ -601,6 +683,7 @@ read:
} }
// The PN53x command is done and we successfully received the reply // The PN53x command is done and we successfully received the reply
pnd->last_error = 0; pnd->last_error = 0;
DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= len > 16;
return len; return len;
} }
@ -616,13 +699,13 @@ pn53x_usb_init(nfc_device *pnd)
int res = 0; int res = 0;
// Sometimes PN53x USB doesn't reply ACK one the first frame, so we need to send a dummy one... // Sometimes PN53x USB doesn't reply ACK one the first frame, so we need to send a dummy one...
//pn53x_check_communication (pnd); // Sony RC-S360 doesn't support this command for now so let's use a get_firmware_version instead: //pn53x_check_communication (pnd); // Sony RC-S360 doesn't support this command for now so let's use a get_firmware_version instead:
const uint8_t abtCmd[] = { GetFirmwareVersion }; const uint8_t abtCmd[] = {GetFirmwareVersion};
pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1); pn53x_transceive(pnd, abtCmd, sizeof(abtCmd), NULL, 0, -1);
// ...and we don't care about error // ...and we don't care about error
pnd->last_error = 0; pnd->last_error = 0;
if (SONY_RCS360 == DRIVER_DATA(pnd)->model) { if (SONY_RCS360 == DRIVER_DATA(pnd)->model) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "SONY RC-S360 initialization."); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "SONY RC-S360 initialization.");
const uint8_t abtCmd2[] = { 0x18, 0x01 }; const uint8_t abtCmd2[] = {0x18, 0x01};
pn53x_transceive(pnd, abtCmd2, sizeof(abtCmd2), NULL, 0, -1); pn53x_transceive(pnd, abtCmd2, sizeof(abtCmd2), NULL, 0, -1);
pn53x_usb_ack(pnd); pn53x_usb_ack(pnd);
} }
@ -634,7 +717,10 @@ pn53x_usb_init(nfc_device *pnd)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ASK LoGO initialization."); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "ASK LoGO initialization.");
/* Internal registers */ /* Internal registers */
/* Disable 100mA current limit, Power on Secure IC (SVDD) */ /* Disable 100mA current limit, Power on Secure IC (SVDD) */
pn53x_write_register(pnd, PN53X_REG_Control_switch_rng, 0xFF, SYMBOL_CURLIMOFF | SYMBOL_SIC_SWITCH_EN | SYMBOL_RANDOM_DATAREADY); pn53x_write_register(pnd,
PN53X_REG_Control_switch_rng,
0xFF,
SYMBOL_CURLIMOFF | SYMBOL_SIC_SWITCH_EN | SYMBOL_RANDOM_DATAREADY);
/* Select the signal to be output on SIGOUT: Modulation signal (envelope) from the internal coder */ /* Select the signal to be output on SIGOUT: Modulation signal (envelope) from the internal coder */
pn53x_write_register(pnd, PN53X_REG_CIU_TxSel, 0xFF, 0x14); pn53x_write_register(pnd, PN53X_REG_CIU_TxSel, 0xFF, 0x14);
@ -664,6 +750,8 @@ pn53x_usb_init(nfc_device *pnd)
/* ie. Switch LED1 on and turn off progressive field */ /* ie. Switch LED1 on and turn off progressive field */
pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P33) | _BV(P35)); pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P33) | _BV(P35));
} }
if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc)
pn533_fix_usbdesc(pnd);
return NFC_SUCCESS; return NFC_SUCCESS;
} }
@ -679,12 +767,17 @@ pn53x_usb_set_property_bool(nfc_device *pnd, const nfc_property property, const
case ASK_LOGO: case ASK_LOGO:
if (NP_ACTIVATE_FIELD == property) { if (NP_ACTIVATE_FIELD == property) {
/* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */ /* Switch on/off LED2 and Progressive Field GPIO according to ACTIVATE_FIELD option */
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Switch progressive field %s", bEnable ? "On" : "Off"); log_put(LOG_GROUP,
if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31))) < 0) LOG_CATEGORY,
NFC_LOG_PRIORITY_DEBUG,
"Switch progressive field %s",
bEnable ? "On" : "Off");
if (pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P31) | _BV(P34), bEnable ? _BV(P34) : _BV(P31)) < 0)
return NFC_ECHIP; return NFC_ECHIP;
} }
break; break;
case SCM_SCL3711: case SCM_SCL3711:
case SCM_SCL3712:
if (NP_ACTIVATE_FIELD == property) { if (NP_ACTIVATE_FIELD == property) {
// Switch on/off LED according to ACTIVATE_FIELD option // Switch on/off LED according to ACTIVATE_FIELD option
if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0) if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0)
@ -709,6 +802,18 @@ pn53x_usb_abort_command(nfc_device *pnd)
return NFC_SUCCESS; return NFC_SUCCESS;
} }
static int
pn53x_usb_get_supported_modulation(nfc_device *pnd,
const nfc_mode mode,
const nfc_modulation_type **const supported_mt)
{
if ((DRIVER_DATA(pnd)->model != ASK_LOGO) || (mode != N_TARGET))
return pn53x_get_supported_modulation(pnd, mode, supported_mt);
else // ASK_LOGO has no N_TARGET support
*supported_mt = no_target_support;
return NFC_SUCCESS;
}
const struct pn53x_io pn53x_usb_io = { const struct pn53x_io pn53x_usb_io = {
.send = pn53x_usb_send, .send = pn53x_usb_send,
.receive = pn53x_usb_receive, .receive = pn53x_usb_receive,
@ -742,7 +847,7 @@ const struct nfc_driver pn53x_usb_driver = {
.device_set_property_bool = pn53x_usb_set_property_bool, .device_set_property_bool = pn53x_usb_set_property_bool,
.device_set_property_int = pn53x_set_property_int, .device_set_property_int = pn53x_set_property_int,
.get_supported_modulation = pn53x_get_supported_modulation, .get_supported_modulation = pn53x_usb_get_supported_modulation,
.get_supported_baud_rate = pn53x_get_supported_baud_rate, .get_supported_baud_rate = pn53x_get_supported_baud_rate,
.device_get_information_about = pn53x_get_information_about, .device_get_information_about = pn53x_get_information_about,

589
libnfc/drivers/pn71xx.c Normal file
View File

@ -0,0 +1,589 @@
/**
* @file pn71xx.h
* @brief Driver for PN71XX using libnfc-nci library
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif // HAVE_CONFIG_H
#include "pn71xx.h"
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <nfc/nfc.h>
#include "drivers.h"
#include "nfc-internal.h"
#include "linux_nfc_api.h"
#define PN71XX_DRIVER_NAME "pn71xx"
#define LOG_CATEGORY "libnfc.driver.pn71xx"
#define LOG_GROUP NFC_LOG_GROUP_DRIVER
const nfc_modulation_type pn71xx_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0};
const nfc_modulation_type pn71xx_supported_modulation_as_initiator[] = {NMT_ISO14443A, NMT_FELICA, NMT_ISO14443B, NMT_ISO14443BI, NMT_ISO14443B2SR, NMT_ISO14443B2CT, NMT_JEWEL, NMT_DEP, 0};
const nfc_baud_rate pn71xx_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn71xx_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 };
const nfc_baud_rate pn71xx_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn71xx_jewel_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
const nfc_baud_rate pn71xx_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 };
static nfcTagCallback_t TagCB;
static nfc_tag_info_t *TagInfo = NULL;
static void onTagArrival(nfc_tag_info_t *pTagInfo);
static void onTagDeparture(void);
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
/**
* @brief Initialize libnfc_nci library to verify presence of PN71xx device.
*
* @param context NFC context.
* @param connstrings array of 'nfc_connstring' buffer (allocated by caller). It is used to store the
* connection info strings of devices found.
* @param connstrings_len length of the connstrings array.
* @return number of devices found.
*/
static size_t
pn71xx_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len)
{
size_t device_found = 0;
if ((context == NULL) || (connstrings_len == 0)) return 0;
if (nfcManager_doInitialize() == 0) {
nfc_connstring connstring = "pn71xx";
memcpy(connstrings[device_found++], connstring, sizeof(nfc_connstring));
}
return device_found;
}
/**
* @brief Close connection to PN71xx by stopping the discovery loop and deinitializing the libnfc_nci library.
*
* @param pnd pointer on the device to close.
*/
static void
pn71xx_close(nfc_device *pnd)
{
nfcManager_disableDiscovery();
nfcManager_deregisterTagCallback();
nfcManager_doDeinitialize();
nfc_device_free(pnd);
pnd = NULL;
}
/**
* @brief Open a connection to PN71xx, starting the discovery loop for tag detection.
*
* @param context NFC context.
* @param connstring connection info to the device
* @return pointer to the device, or NULL in case of error.
*/
static nfc_device *
pn71xx_open(const nfc_context *context, const nfc_connstring connstring)
{
nfc_device *pnd;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "open: %s", connstring);
pnd = nfc_device_new(context, connstring);
if (!pnd) {
perror("malloc");
return NULL;
}
pnd->driver = &pn71xx_driver;
strcpy(pnd->name, "pn71xx-device");
strcpy(pnd->connstring, connstring);
TagCB.onTagArrival = onTagArrival;
TagCB.onTagDeparture = onTagDeparture;
nfcManager_registerTagCallback(&TagCB);
nfcManager_enableDiscovery(DEFAULT_NFA_TECH_MASK, 1, 0, 0);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "wait 1 seconds for polling");
sleep(1);
return pnd;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static bool IsTechnology(nfc_tag_info_t *TagInfo, nfc_modulation_type nmt)
{
switch (nmt) {
case NMT_ISO14443A:
if (TagInfo->technology == TARGET_TYPE_ISO14443_4
|| TagInfo->technology == TARGET_TYPE_ISO14443_3A
|| TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC
|| TagInfo->technology == TARGET_TYPE_MIFARE_UL)
return true;
break;
case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT:
if (TagInfo->technology == TARGET_TYPE_ISO14443_3B)
return true;
break;
case NMT_FELICA:
if (TagInfo->technology == TARGET_TYPE_FELICA)
return true;
break;
case NMT_JEWEL:
if (TagInfo->technology == TARGET_TYPE_ISO14443_3A
&& TagInfo->protocol == NFA_PROTOCOL_T1T)
return true;
break;
default:
return false;
}
return false;
}
static void BufferPrintBytes(char *buffer, unsigned int buflen, const uint8_t *data, unsigned int datalen)
{
int cx = 0;
for (unsigned int i = 0x00; i < datalen; i++) {
cx += snprintf(buffer + cx, buflen - cx, "%02X ", data[i]);
}
}
static void PrintTagInfo(nfc_tag_info_t *TagInfo)
{
switch (TagInfo->technology) {
case TARGET_TYPE_UNKNOWN: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Unknown'");
}
break;
case TARGET_TYPE_ISO14443_3A: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3A'");
}
break;
case TARGET_TYPE_ISO14443_3B: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3B'");
}
break;
case TARGET_TYPE_ISO14443_4: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 4A'");
}
break;
case TARGET_TYPE_FELICA: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type F'");
}
break;
case TARGET_TYPE_ISO15693: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type V'");
}
break;
case TARGET_TYPE_NDEF: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type NDEF'");
}
break;
case TARGET_TYPE_NDEF_FORMATABLE: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Formatable'");
}
break;
case TARGET_TYPE_MIFARE_CLASSIC: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Classic'");
}
break;
case TARGET_TYPE_MIFARE_UL: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Ul'");
}
break;
case TARGET_TYPE_KOVIO_BARCODE: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Kovio Barcode'");
}
break;
case TARGET_TYPE_ISO14443_3A_3B: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A/B'");
}
break;
default: {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type %d (Unknown or not supported)'\n", TagInfo->technology);
}
break;
}
/*32 is max UID len (Kovio tags)*/
if ((0x00 != TagInfo->uid_length) && (32 >= TagInfo->uid_length)) {
char buffer [100];
int cx = 0;
if (4 == TagInfo->uid_length || 7 == TagInfo->uid_length || 10 == TagInfo->uid_length) {
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID1 : \t'");
} else if (8 == TagInfo->uid_length) {
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID2 : \t'");
} else {
cx += snprintf(buffer + cx, sizeof(buffer) - cx, "UID : \t'");
}
BufferPrintBytes(buffer + cx, sizeof(buffer) - cx, (unsigned char *) TagInfo->uid, TagInfo->uid_length);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s'", buffer);
}
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static void onTagArrival(nfc_tag_info_t *pTagInfo)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag found");
TagInfo = malloc(sizeof(nfc_tag_info_t));
memcpy(TagInfo, pTagInfo, sizeof(nfc_tag_info_t));
PrintTagInfo(TagInfo);
}
static void onTagDeparture(void)
{
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag lost");
free(TagInfo);
TagInfo = NULL;
}
static int
pn71xx_initiator_init(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
return NFC_SUCCESS;
}
static int
pn71xx_initiator_select_passive_target(struct nfc_device *pnd,
const nfc_modulation nm,
const uint8_t *pbtInitData, const size_t szInitData,
nfc_target *pnt)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "select_passive_target");
if (TagInfo) {
nfc_target nttmp;
memset(&nttmp, 0x00, sizeof(nfc_target));
nttmp.nm = nm;
void *uidPtr = NULL;
unsigned int maxLen = 0;
switch (nm.nmt) {
case NMT_ISO14443A:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 10;
uidPtr = nttmp.nti.nai.abtUid;
if (TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC) {
nttmp.nti.nai.btSak = 0x08;
} else {
// make hardcoded desfire for freefare lib check
nttmp.nti.nai.btSak = 0x20;
nttmp.nti.nai.szAtsLen = 5;
memcpy(nttmp.nti.nai.abtAts, "\x75\x77\x81\x02", 4);
}
}
break;
case NMT_ISO14443B:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nbi.abtPupi;
}
break;
case NMT_ISO14443BI:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nii.abtDIV;
}
break;
case NMT_ISO14443B2SR:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 8;
uidPtr = nttmp.nti.nsi.abtUID;
}
break;
case NMT_ISO14443B2CT:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nci.abtUID;
}
break;
case NMT_FELICA:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 8;
uidPtr = nttmp.nti.nfi.abtId;
}
break;
case NMT_JEWEL:
if (IsTechnology(TagInfo, nm.nmt)) {
maxLen = 4;
uidPtr = nttmp.nti.nji.btId;
}
break;
default:
return 0;
}
if (uidPtr && TagInfo->uid_length) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "target found");
int len = TagInfo->uid_length > maxLen ? maxLen : TagInfo->uid_length;
memcpy(uidPtr, TagInfo->uid, len);
if (nm.nmt == NMT_ISO14443A)
nttmp.nti.nai.szUidLen = len;
// Is a tag info struct available
if (pnt) {
memcpy(pnt, &nttmp, sizeof(nfc_target));
}
return 1;
}
}
return 0;
}
static int
pn71xx_initiator_deselect_target(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "deselect_passive_target");
return NFC_SUCCESS;
}
static int
pn71xx_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx,
const size_t szRx, int timeout)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "transceive_bytes timeout=%d", timeout);
if (!TagInfo) return NFC_EINVARG;
char buffer[500];
BufferPrintBytes(buffer, sizeof(buffer), pbtTx, szTx);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "===> %s", buffer);
int received = nfcTag_transceive(TagInfo->handle, (uint8_t *) pbtTx, szTx, pbtRx, szRx, 500);
if (received <= 0)
return NFC_EIO;
BufferPrintBytes(buffer, sizeof(buffer), pbtRx, received);
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "<=== %s", buffer);
return received;
}
static int
pn71xx_initiator_poll_target(struct nfc_device *pnd,
const nfc_modulation *pnmModulations, const size_t szModulations,
const uint8_t uiPollNr, const uint8_t uiPeriod,
nfc_target *pnt)
{
static int periodFactor = 150000;
int period = uiPeriod * periodFactor;
if (pnd == NULL) return 0;
for (int j = 0; j < uiPollNr; j++) {
for (unsigned int i = 0; i < szModulations; i++) {
const nfc_modulation nm = pnmModulations[i];
nfc_target nt;
int res = pn71xx_initiator_select_passive_target(pnd, nm, 0, 0, &nt);
if (res > 0 && pnt) {
memcpy(pnt, &nt, sizeof(nfc_target));
return res;
}
}
usleep(period);
}
return 0;
}
static int
pn71xx_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt)
{
if ((pnd == NULL) || (pnt == NULL)) return 1;
return !TagInfo;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static int
pn71xx_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt)
{
if (pnd == NULL) return NFC_EIO;
switch (mode) {
case N_TARGET:
*supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_target;
break;
case N_INITIATOR:
*supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_initiator;
break;
default:
return NFC_EINVARG;
}
return NFC_SUCCESS;
}
static int
pn71xx_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br)
{
if (pnd == NULL) return NFC_EIO;
if (mode) {}
switch (nmt) {
case NMT_FELICA:
*supported_br = (nfc_baud_rate *)pn71xx_felica_supported_baud_rates;
break;
case NMT_ISO14443A:
*supported_br = (nfc_baud_rate *)pn71xx_iso14443a_supported_baud_rates;
break;
case NMT_ISO14443B:
case NMT_ISO14443BI:
case NMT_ISO14443B2SR:
case NMT_ISO14443B2CT:
*supported_br = (nfc_baud_rate *)pn71xx_iso14443b_supported_baud_rates;
break;
case NMT_JEWEL:
*supported_br = (nfc_baud_rate *)pn71xx_jewel_supported_baud_rates;
break;
case NMT_DEP:
*supported_br = (nfc_baud_rate *)pn71xx_dep_supported_baud_rates;
break;
default:
return NFC_EINVARG;
}
return NFC_SUCCESS;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
static int
pn71xx_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable)
{
if (pnd == NULL) return NFC_EIO;
return NFC_SUCCESS;
}
static int
pn71xx_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value)
{
if (pnd == NULL) return NFC_EIO;
return NFC_SUCCESS;
}
static int
pn71xx_get_information_about(nfc_device *pnd, char **pbuf)
{
static const char *info = "PN71XX nfc driver using libnfc-nci userspace library";
size_t buflen = strlen(info) + 1;
if (pnd == NULL) return NFC_EIO;
*pbuf = malloc(buflen);
memcpy(*pbuf, info, buflen);
return buflen;
}
/**
* @brief Abort any pending operation
*
* @param pnd pointer on the NFC device.
* @return NFC_SUCCESS
*/
static int
pn71xx_abort_command(nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "abort_command");
return NFC_SUCCESS;
}
static int
pn71xx_idle(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "idle");
return NFC_SUCCESS;
}
static int
pn71xx_PowerDown(struct nfc_device *pnd)
{
if (pnd == NULL) return NFC_EIO;
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "PowerDown");
return NFC_SUCCESS;
}
/** ------------------------------------------------------------------------ */
/** ------------------------------------------------------------------------ */
const struct nfc_driver pn71xx_driver = {
.name = PN71XX_DRIVER_NAME,
.scan_type = NOT_INTRUSIVE,
.scan = pn71xx_scan,
.open = pn71xx_open,
.close = pn71xx_close,
.strerror = NULL,
.initiator_init = pn71xx_initiator_init,
.initiator_init_secure_element = NULL,
.initiator_select_passive_target = pn71xx_initiator_select_passive_target,
.initiator_poll_target = pn71xx_initiator_poll_target,
.initiator_select_dep_target = NULL,
.initiator_deselect_target = pn71xx_initiator_deselect_target,
.initiator_transceive_bytes = pn71xx_initiator_transceive_bytes,
.initiator_transceive_bits = NULL,
.initiator_transceive_bytes_timed = NULL,
.initiator_transceive_bits_timed = NULL,
.initiator_target_is_present = pn71xx_initiator_target_is_present,
.target_init = NULL,
.target_send_bytes = NULL,
.target_receive_bytes = NULL,
.target_send_bits = NULL,
.target_receive_bits = NULL,
.device_set_property_bool = pn71xx_set_property_bool,
.device_set_property_int = pn71xx_set_property_int,
.get_supported_modulation = pn71xx_get_supported_modulation,
.get_supported_baud_rate = pn71xx_get_supported_baud_rate,
.device_get_information_about = pn71xx_get_information_about,
.abort_command = pn71xx_abort_command,
.idle = pn71xx_idle,
.powerdown = pn71xx_PowerDown,
};

14
libnfc/drivers/pn71xx.h Normal file
View File

@ -0,0 +1,14 @@
/**
* @file pn71xx.h
* @brief Driver for PN71XX using libnfc-nci library
*/
#ifndef __NFC_DRIVER_PN71XX_H__
#define __NFC_DRIVER_PN71XX_H__
#include <nfc/nfc-types.h>
/* Reference to the driver structure */
extern const struct nfc_driver pn71xx_driver;
#endif // ! __NFC_DRIVER_7120_H__

View File

@ -47,10 +47,10 @@
void void
iso14443a_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) iso14443a_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc)
{ {
uint8_t bt;
uint32_t wCrc = 0x6363; uint32_t wCrc = 0x6363;
do { do {
uint8_t bt;
bt = *pbtData++; bt = *pbtData++;
bt = (bt ^ (uint8_t)(wCrc & 0x00FF)); bt = (bt ^ (uint8_t)(wCrc & 0x00FF));
bt = (bt ^ (bt << 4)); bt = (bt ^ (bt << 4));
@ -78,10 +78,10 @@ iso14443a_crc_append(uint8_t *pbtData, size_t szLen)
void void
iso14443b_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) iso14443b_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc)
{ {
uint8_t bt;
uint32_t wCrc = 0xFFFF; uint32_t wCrc = 0xFFFF;
do { do {
uint8_t bt;
bt = *pbtData++; bt = *pbtData++;
bt = (bt ^ (uint8_t)(wCrc & 0x00FF)); bt = (bt ^ (uint8_t)(wCrc & 0x00FF));
bt = (bt ^ (bt << 4)); bt = (bt ^ (bt << 4));

View File

@ -39,6 +39,5 @@
uint8_t mirror(uint8_t bt); uint8_t mirror(uint8_t bt);
uint32_t mirror32(uint32_t ui32Bits); uint32_t mirror32(uint32_t ui32Bits);
uint64_t mirror64(uint64_t ui64Bits); uint64_t mirror64(uint64_t ui64Bits);
void mirror_uint8_ts(uint8_t *pbts, size_t szLen);
#endif // _LIBNFC_MIRROR_SUBR_H_ #endif // _LIBNFC_MIRROR_SUBR_H_

View File

@ -57,6 +57,7 @@ nfc_device_new(const nfc_context *context, const nfc_connstring connstring)
res->bCrc = false; res->bCrc = false;
res->bPar = false; res->bPar = false;
res->bEasyFraming = false; res->bEasyFraming = false;
res->bInfiniteSelect = false;
res->bAutoIso14443_4 = false; res->bAutoIso14443_4 = false;
res->last_error = 0; res->last_error = 0;
memcpy(res->connstring, connstring, sizeof(res->connstring)); memcpy(res->connstring, connstring, sizeof(res->connstring));

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -169,38 +170,27 @@ void
prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData) prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData)
{ {
switch (nm.nmt) { switch (nm.nmt) {
case NMT_ISO14443B: { case NMT_ISO14443B:
// Application Family Identifier (AFI) must equals 0x00 in order to wakeup all ISO14443-B PICCs (see ISO/IEC 14443-3) // Application Family Identifier (AFI) must equals 0x00 in order to wakeup all ISO14443-B PICCs (see ISO/IEC 14443-3)
*ppbtInitiatorData = (uint8_t *) "\x00"; *ppbtInitiatorData = (uint8_t *) "\x00";
*pszInitiatorData = 1; *pszInitiatorData = 1;
} break;
break; case NMT_ISO14443BI:
case NMT_ISO14443BI: {
// APGEN // APGEN
*ppbtInitiatorData = (uint8_t *) "\x01\x0b\x3f\x80"; *ppbtInitiatorData = (uint8_t *) "\x01\x0b\x3f\x80";
*pszInitiatorData = 4; *pszInitiatorData = 4;
} break;
break; case NMT_FELICA:
case NMT_ISO14443B2SR: {
// Get_UID
*ppbtInitiatorData = (uint8_t *) "\x0b";
*pszInitiatorData = 1;
}
break;
case NMT_ISO14443B2CT: {
// SELECT-ALL
*ppbtInitiatorData = (uint8_t *) "\x9F\xFF\xFF";
*pszInitiatorData = 3;
}
break;
case NMT_FELICA: {
// polling payload must be present (see ISO/IEC 18092 11.2.2.5) // polling payload must be present (see ISO/IEC 18092 11.2.2.5)
*ppbtInitiatorData = (uint8_t *) "\x00\xff\xff\x01\x00"; *ppbtInitiatorData = (uint8_t *) "\x00\xff\xff\x01\x00";
*pszInitiatorData = 5; *pszInitiatorData = 5;
} break;
break;
case NMT_ISO14443A: case NMT_ISO14443A:
case NMT_ISO14443B2CT:
case NMT_ISO14443B2SR:
case NMT_ISO14443BICLASS:
case NMT_JEWEL: case NMT_JEWEL:
case NMT_BARCODE:
case NMT_DEP: case NMT_DEP:
*ppbtInitiatorData = NULL; *ppbtInitiatorData = NULL;
*pszInitiatorData = 0; *pszInitiatorData = 0;
@ -242,7 +232,6 @@ connstring_decode(const nfc_connstring connstring, const char *driver_name, cons
int res = sscanf(connstring, format, param0, param1, param2); int res = sscanf(connstring, format, param0, param1, param2);
if (res < 1 || ((0 != strcmp(param0, driver_name)) && if (res < 1 || ((0 != strcmp(param0, driver_name)) &&
(bus_name != NULL) &&
(0 != strcmp(param0, bus_name)))) { (0 != strcmp(param0, bus_name)))) {
// Driver name does not match. // Driver name does not match.
res = 0; res = 0;

View File

@ -34,7 +34,9 @@
#include <stdbool.h> #include <stdbool.h>
#include <err.h> #include <err.h>
#if !defined(_MSC_VER)
# include <sys/time.h> # include <sys/time.h>
#endif
#include "nfc/nfc.h" #include "nfc/nfc.h"
@ -148,7 +150,7 @@ struct nfc_driver {
int (*device_set_property_bool)(struct nfc_device *pnd, const nfc_property property, const bool bEnable); int (*device_set_property_bool)(struct nfc_device *pnd, const nfc_property property, const bool bEnable);
int (*device_set_property_int)(struct nfc_device *pnd, const nfc_property property, const int value); int (*device_set_property_int)(struct nfc_device *pnd, const nfc_property property, const int value);
int (*get_supported_modulation)(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); int (*get_supported_modulation)(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt);
int (*get_supported_baud_rate)(struct nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); int (*get_supported_baud_rate)(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br);
int (*device_get_information_about)(struct nfc_device *pnd, char **buf); int (*device_get_information_about)(struct nfc_device *pnd, char **buf);
int (*abort_command)(struct nfc_device *pnd); int (*abort_command)(struct nfc_device *pnd);
@ -203,6 +205,8 @@ struct nfc_device {
bool bPar; bool bPar;
/** Should the chip handle frames encapsulation and chaining */ /** Should the chip handle frames encapsulation and chaining */
bool bEasyFraming; bool bEasyFraming;
/** Should the chip try forever on select? */
bool bInfiniteSelect;
/** Should the chip switch automatically activate ISO14443-4 when /** Should the chip switch automatically activate ISO14443-4 when
selecting tags supporting it? */ selecting tags supporting it? */
bool bAutoIso14443_4; bool bAutoIso14443_4;

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -79,6 +80,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <assert.h>
#include <nfc/nfc.h> #include <nfc/nfc.h>
@ -86,6 +88,10 @@
#include "target-subr.h" #include "target-subr.h"
#include "drivers.h" #include "drivers.h"
#if defined (DRIVER_PCSC_ENABLED)
# include "drivers/pcsc.h"
#endif /* DRIVER_PCSC_ENABLED */
#if defined (DRIVER_ACR122_PCSC_ENABLED) #if defined (DRIVER_ACR122_PCSC_ENABLED)
# include "drivers/acr122_pcsc.h" # include "drivers/acr122_pcsc.h"
#endif /* DRIVER_ACR122_PCSC_ENABLED */ #endif /* DRIVER_ACR122_PCSC_ENABLED */
@ -118,6 +124,10 @@
# include "drivers/pn532_i2c.h" # include "drivers/pn532_i2c.h"
#endif /* DRIVER_PN532_I2C_ENABLED */ #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_CATEGORY "libnfc.general"
#define LOG_GROUP NFC_LOG_GROUP_GENERAL #define LOG_GROUP NFC_LOG_GROUP_GENERAL
@ -129,12 +139,34 @@ struct nfc_driver_list {
const struct nfc_driver_list *nfc_drivers = NULL; 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 static void
nfc_drivers_init(void) nfc_drivers_init(void)
{ {
#if defined (DRIVER_PN53X_USB_ENABLED) #if defined (DRIVER_PN53X_USB_ENABLED)
nfc_register_driver(&pn53x_usb_driver); nfc_register_driver(&pn53x_usb_driver);
#endif /* DRIVER_PN53X_USB_ENABLED */ #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) #if defined (DRIVER_ACR122_PCSC_ENABLED)
nfc_register_driver(&acr122_pcsc_driver); nfc_register_driver(&acr122_pcsc_driver);
#endif /* DRIVER_ACR122_PCSC_ENABLED */ #endif /* DRIVER_ACR122_PCSC_ENABLED */
@ -156,8 +188,13 @@ nfc_drivers_init(void)
#if defined (DRIVER_ARYGON_ENABLED) #if defined (DRIVER_ARYGON_ENABLED)
nfc_register_driver(&arygon_driver); nfc_register_driver(&arygon_driver);
#endif /* DRIVER_ARYGON_ENABLED */ #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 /** @ingroup lib
* @brief Register an NFC device driver with libnfc. * @brief Register an NFC device driver with libnfc.
@ -169,8 +206,10 @@ nfc_drivers_init(void)
int int
nfc_register_driver(const struct nfc_driver *ndr) nfc_register_driver(const struct nfc_driver *ndr)
{ {
if (!ndr) if (!ndr) {
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_register_driver returning NFC_EINVARG");
return NFC_EINVARG; return NFC_EINVARG;
}
struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list)); struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list));
if (!pndl) if (!pndl)
@ -274,7 +313,7 @@ nfc_open(nfc_context *context, const nfc_connstring connstring)
log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open \"%s\".", ncs); log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open \"%s\".", ncs);
return NULL; return NULL;
} }
for (uint32_t i = 0; i > context->user_defined_device_count; i++) { for (uint32_t i = 0; i < context->user_defined_device_count; i++) {
if (strcmp(ncs, context->user_defined_devices[i].connstring) == 0) { 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 // This is a device sets by user, we use the device name given by user
strcpy(pnd->name, context->user_defined_devices[i].name); strcpy(pnd->name, context->user_defined_devices[i].name);
@ -386,7 +425,7 @@ nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_
pndl = pndl->next; pndl = pndl->next;
} }
} else if (context->user_defined_device_count == 0) { } 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"); 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; return device_found;
@ -406,6 +445,7 @@ nfc_list_devices(nfc_context *context, nfc_connstring connstrings[], const size_
int int
nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value) 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); HAL(device_set_property_int, pnd, property, value);
} }
@ -425,6 +465,7 @@ nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const
int int
nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) 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); HAL(device_set_property_bool, pnd, property, bEnable);
} }
@ -480,13 +521,13 @@ nfc_initiator_init(nfc_device *pnd)
} }
/** @ingroup initiator /** @ingroup initiator
* @brief Initialize NFC device as initiator with its secure element initiator (reader) * @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) * @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 pnd \a nfc_device struct pointer that represent currently used device
* *
* The NFC device is configured to function as secure element reader. * The NFC device is configured to function as secure element reader.
* After initialization it can be used to communicate with the secure element. * After initialization it can be used to communicate with the secure element.
* @note RF field is desactvated in order to some power * @note RF field is deactivated in order to save some power
*/ */
int int
nfc_initiator_init_secure_element(nfc_device *pnd) nfc_initiator_init_secure_element(nfc_device *pnd)
@ -500,12 +541,15 @@ nfc_initiator_init_secure_element(nfc_device *pnd)
* *
* @param pnd \a nfc_device struct pointer that represent currently used device * @param pnd \a nfc_device struct pointer that represent currently used device
* @param nm desired modulation * @param nm desired modulation
* @param pbtInitData optional initiator data used for Felica, ISO14443B, Topaz polling or to select a specific UID in ISO14443A. * @param pbtInitData optional initiator data, NULL for using the default values.
* @param szInitData length of initiator data \a pbtInitData. * @param szInitData length of initiator data \a pbtInitData.
* @note pbtInitData is used with different kind of data depending on modulation type: * @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 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); * - for an ISO/IEC 14443 type B modulation, pbbInitData contains Application Family Identifier (AFI) (see ISO/IEC 14443-3)
* - for a FeliCa modulation, pbbInitData contains polling payload (see ISO/IEC 18092 11.2.2.5). 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 * @param[out] pnt \a nfc_target struct pointer which will filled if available
* *
@ -520,27 +564,31 @@ nfc_initiator_select_passive_target(nfc_device *pnd,
const uint8_t *pbtInitData, const size_t szInitData, const uint8_t *pbtInitData, const size_t szInitData,
nfc_target *pnt) nfc_target *pnt)
{ {
uint8_t abtInit[MAX(12, szInitData)]; uint8_t *abtInit = NULL;
size_t szInit; uint8_t maxAbt = MAX(12, szInitData);
uint8_t *abtTmpInit = malloc(sizeof(uint8_t) * maxAbt);
switch (nm.nmt) { size_t szInit = 0;
case NMT_ISO14443A: int res;
iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit); if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) {
break; free(abtTmpInit);
return res;
case NMT_JEWEL: }
case NMT_ISO14443B: if (szInitData == 0) {
case NMT_ISO14443BI: // Provide default values, if any
case NMT_ISO14443B2SR: prepare_initiator_data(nm, &abtInit, &szInit);
case NMT_ISO14443B2CT: free(abtTmpInit);
case NMT_FELICA: } else if (nm.nmt == NMT_ISO14443A) {
case NMT_DEP: abtInit = abtTmpInit;
memcpy(abtInit, pbtInitData, szInitData); iso14443_cascade_uid(pbtInitData, szInitData, abtInit, &szInit);
szInit = szInitData; } else {
break; abtInit = abtTmpInit;
memcpy(abtInit, pbtInitData, szInitData);
free(abtTmpInit);
szInit = szInitData;
} }
HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt); HAL(initiator_select_passive_target, pnd, nm, abtInit, szInit, pnt);
free(abtTmpInit);
} }
/** @ingroup initiator /** @ingroup initiator
@ -573,6 +621,7 @@ nfc_initiator_list_passive_targets(nfc_device *pnd,
pnd->last_error = 0; pnd->last_error = 0;
// Let the reader only try once to find a tag // 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) { if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) {
return res; return res;
} }
@ -597,12 +646,18 @@ nfc_initiator_list_passive_targets(nfc_device *pnd,
break; break;
} }
nfc_initiator_deselect_target(pnd); nfc_initiator_deselect_target(pnd);
// deselect has no effect on FeliCa and Jewel cards so we'll stop after one... // 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 // 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_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) { 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; break;
} }
} }
if (bInfiniteSelect) {
if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) {
return res;
}
}
return szTargetFound; return szTargetFound;
} }
@ -636,7 +691,7 @@ nfc_initiator_poll_target(nfc_device *pnd,
* @param pnd \a nfc_device struct pointer that represent currently used device * @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 ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode)
* @param nbr desired baud rate * @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[out] pnt is a \a nfc_target struct pointer where target information will be put.
* @param timeout in milliseconds * @param timeout in milliseconds
* *
@ -664,7 +719,7 @@ nfc_initiator_select_dep_target(nfc_device *pnd,
* @param pnd \a nfc_device struct pointer that represent currently used device * @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 ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode)
* @param nbr desired baud rate * @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[out] pnt is a \a nfc_target struct pointer where target information will be put.
* @param timeout in milliseconds * @param timeout in milliseconds
* *
@ -684,18 +739,30 @@ nfc_initiator_poll_dep_target(struct nfc_device *pnd,
const int period = 300; const int period = 300;
int remaining_time = timeout; int remaining_time = timeout;
int res; int res;
int result = 0;
bool bInfiniteSelect = pnd->bInfiniteSelect;
if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0) if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, true)) < 0)
return res; return res;
while (remaining_time > 0) { while (remaining_time > 0) {
if ((res = nfc_initiator_select_dep_target(pnd, ndm, nbr, pndiInitiator, pnt, period)) < 0) { if ((res = nfc_initiator_select_dep_target(pnd, ndm, nbr, pndiInitiator, pnt, period)) < 0) {
if (res != NFC_ETIMEOUT) if (res != NFC_ETIMEOUT) {
return res; result = res;
goto end;
}
}
if (res == 1) {
result = res;
goto end;
} }
if (res == 1)
return res;
remaining_time -= period; remaining_time -= period;
} }
return 0; end:
if (! bInfiniteSelect) {
if ((res = nfc_device_set_property_bool(pnd, NP_INFINITE_SELECT, false)) < 0) {
return res;
}
}
return result;
} }
/** @ingroup initiator /** @ingroup initiator
@ -836,7 +903,9 @@ nfc_initiator_transceive_bytes_timed(nfc_device *pnd,
* @brief Check target presence * @brief Check target presence
* @return Returns 0 on success, otherwise returns libnfc's error code. * @return Returns 0 on success, otherwise returns libnfc's error code.
* *
* This function tests if \a nfc_target is currently present on NFC device. * @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 The target have to be selected before check its presence
* @warning To run the test, one or more commands will be sent to target * @warning To run the test, one or more commands will be sent to target
*/ */
@ -949,7 +1018,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 * @param pnd \a nfc_device struct pointer that represent currently used device
* *
* This function switch the device in idle mode. * 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). * 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 int
@ -1175,7 +1244,7 @@ nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const
} }
/** @ingroup data /** @ingroup data
* @brief Get supported baud rates. * @brief Get supported baud rates (initiator mode).
* @return Returns 0 on success, otherwise returns libnfc's error code (negative 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 pnd \a nfc_device struct pointer that represent currently used device
* @param nmt \a nfc_modulation_type. * @param nmt \a nfc_modulation_type.
@ -1185,7 +1254,63 @@ nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const
int int
nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) 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, nmt, 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 */ /* Misc. functions */
@ -1234,7 +1359,7 @@ nfc_device_get_information_about(nfc_device *pnd, char **buf)
/** @ingroup string-converter /** @ingroup string-converter
* @brief Convert \a nfc_baud_rate value to string * @brief Convert \a nfc_baud_rate value to string
* @return Returns nfc baud rate * @return Returns nfc baud rate
* @param \a nfc_baud_rate to convert * @param nbr \a nfc_baud_rate to convert
*/ */
const char * const char *
str_nfc_baud_rate(const nfc_baud_rate nbr) str_nfc_baud_rate(const nfc_baud_rate nbr)
@ -1242,28 +1367,23 @@ str_nfc_baud_rate(const nfc_baud_rate nbr)
switch (nbr) { switch (nbr) {
case NBR_UNDEFINED: case NBR_UNDEFINED:
return "undefined baud rate"; return "undefined baud rate";
break;
case NBR_106: case NBR_106:
return "106 kbps"; return "106 kbps";
break;
case NBR_212: case NBR_212:
return "212 kbps"; return "212 kbps";
break;
case NBR_424: case NBR_424:
return "424 kbps"; return "424 kbps";
break;
case NBR_847: case NBR_847:
return "847 kbps"; return "847 kbps";
break;
} }
// Should never go there..
return ""; return "???";
} }
/** @ingroup string-converter /** @ingroup string-converter
* @brief Convert \a nfc_modulation_type value to string * @brief Convert \a nfc_modulation_type value to string
* @return Returns nfc modulation type * @return Returns nfc modulation type
* @param \a nfc_modulation_type to convert * @param nmt \a nfc_modulation_type to convert
*/ */
const char * const char *
str_nfc_modulation_type(const nfc_modulation_type nmt) str_nfc_modulation_type(const nfc_modulation_type nmt)
@ -1271,38 +1391,35 @@ str_nfc_modulation_type(const nfc_modulation_type nmt)
switch (nmt) { switch (nmt) {
case NMT_ISO14443A: case NMT_ISO14443A:
return "ISO/IEC 14443A"; return "ISO/IEC 14443A";
break;
case NMT_ISO14443B: case NMT_ISO14443B:
return "ISO/IEC 14443-4B"; return "ISO/IEC 14443-4B";
break;
case NMT_ISO14443BI: case NMT_ISO14443BI:
return "ISO/IEC 14443-4B'"; return "ISO/IEC 14443-4B'";
break; case NMT_ISO14443BICLASS:
return "ISO/IEC 14443-2B-3B iClass (Picopass)";
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
return "ISO/IEC 14443-2B ASK CTx"; return "ISO/IEC 14443-2B ASK CTx";
break;
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
return "ISO/IEC 14443-2B ST SRx"; return "ISO/IEC 14443-2B ST SRx";
break;
case NMT_FELICA: case NMT_FELICA:
return "FeliCa"; return "FeliCa";
break;
case NMT_JEWEL: case NMT_JEWEL:
return "Innovision Jewel"; return "Innovision Jewel";
break; case NMT_BARCODE:
return "Thinfilm NFC Barcode";
case NMT_DEP: case NMT_DEP:
return "D.E.P."; return "D.E.P.";
break;
} }
// Should never go there..
return ""; return "???";
} }
/** @ingroup string-converter /** @ingroup string-converter
* @brief Convert \a nfc_modulation_type value to string * @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) * @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 nt \a nfc_target struct to print * @param pnt \a nfc_target struct pointer to print
* @param buf pointer where string will be allocated, then nfc target information printed * @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() * @warning *buf must be freed using nfc_free()
*/ */

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -498,6 +499,22 @@ snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool
snprint_hex(dst + off, size - off, pnji->btId, 4); snprint_hex(dst + off, size - off, pnji->btId, 4);
} }
void
snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, bool verbose)
{
(void) verbose;
int off = 0;
off += snprintf(dst + off, size - off, " Size (bits): %lu\n", (unsigned long)(pnti->szDataLen * 8));
off += snprintf(dst + off, size - off, " Content: ");
for (uint8_t i = 0; i < pnti->szDataLen; i++) {
off += snprintf(dst + off, size - off, "%02X", pnti->abtData[i]);
if ((i % 8 == 7) && (i < (pnti->szDataLen - 1))) {
off += snprintf(dst + off, size - off, "\n ");
}
}
snprintf(dst + off, size - off, "\n");
}
#define PI_ISO14443_4_SUPPORTED 0x01 #define PI_ISO14443_4_SUPPORTED 0x01
#define PI_NAD_SUPPORTED 0x01 #define PI_NAD_SUPPORTED 0x01
#define PI_CID_SUPPORTED 0x02 #define PI_CID_SUPPORTED 0x02
@ -593,6 +610,15 @@ snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_inf
snprint_hex(dst + off, size - off, pnsi->abtUID, 8); snprint_hex(dst + off, size - off, pnsi->abtUID, 8);
} }
void
snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose)
{
(void) verbose;
int off = 0;
off += snprintf(dst + off, size - off, " UID: ");
snprint_hex(dst + off, size - off, pnic->abtUID, 8);
}
void void
snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose) snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose)
{ {
@ -637,6 +663,9 @@ snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose)
case NMT_JEWEL: case NMT_JEWEL:
snprint_nfc_jewel_info(dst + off, size - off, &pnt->nti.nji, verbose); snprint_nfc_jewel_info(dst + off, size - off, &pnt->nti.nji, verbose);
break; break;
case NMT_BARCODE:
snprint_nfc_barcode_info(dst + off, size - off, &pnt->nti.nti, verbose);
break;
case NMT_FELICA: case NMT_FELICA:
snprint_nfc_felica_info(dst + off, size - off, &pnt->nti.nfi, verbose); snprint_nfc_felica_info(dst + off, size - off, &pnt->nti.nfi, verbose);
break; break;
@ -649,6 +678,9 @@ snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose)
case NMT_ISO14443B2SR: case NMT_ISO14443B2SR:
snprint_nfc_iso14443b2sr_info(dst + off, size - off, &pnt->nti.nsi, verbose); snprint_nfc_iso14443b2sr_info(dst + off, size - off, &pnt->nti.nsi, verbose);
break; break;
case NMT_ISO14443BICLASS:
snprint_nfc_iso14443biclass_info(dst + off, size - off, &pnt->nti.nhi, verbose);
break;
case NMT_ISO14443B2CT: case NMT_ISO14443B2CT:
snprint_nfc_iso14443b2ct_info(dst + off, size - off, &pnt->nti.nci, verbose); snprint_nfc_iso14443b2ct_info(dst + off, size - off, &pnt->nti.nci, verbose);
break; break;

View File

@ -9,6 +9,7 @@
* Copyright (C) 2012-2013 Ludovic Rousseau * Copyright (C) 2012-2013 Ludovic Rousseau
* See AUTHORS file for a more comprehensive list of contributors. * See AUTHORS file for a more comprehensive list of contributors.
* Additional contributors of this file: * Additional contributors of this file:
* Copyright (C) 2020 Adam Laurie
* *
* This program is free software: you can redistribute it and/or modify it * 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 * under the terms of the GNU Lesser General Public License as published by the
@ -37,9 +38,11 @@ void snprint_nfc_iso14443a_info(char *dst, size_t size, const nfc_iso14443a_i
void snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info *pnbi, bool verbose); void snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info *pnbi, bool verbose);
void snprint_nfc_iso14443bi_info(char *dst, size_t size, const nfc_iso14443bi_info *pnii, bool verbose); void snprint_nfc_iso14443bi_info(char *dst, size_t size, const nfc_iso14443bi_info *pnii, bool verbose);
void snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info *pnsi, bool verbose); void snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info *pnsi, bool verbose);
void snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose);
void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose); void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose);
void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info *pnfi, bool verbose); void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info *pnfi, bool verbose);
void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose); void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose);
void snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, bool verbose);
void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info *pndi, bool verbose); void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info *pndi, bool verbose);
void snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose); void snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose);

View File

@ -4,7 +4,8 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
[ [
AC_MSG_CHECKING(which drivers to build) AC_MSG_CHECKING(which drivers to build)
AC_ARG_WITH(drivers, AC_ARG_WITH(drivers,
AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pn532_i2c', 'pn532_spi', 'pn532_uart' and 'pn53x_usb'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]), AS_HELP_STRING([--with-drivers=DRIVERS], [Use a custom driver set, where DRIVERS is a coma-separated list of drivers to build support for. Available drivers are: 'acr122_pcsc', 'acr122_usb', 'acr122s', 'arygon', 'pcsc', 'pn532_i2c', 'pn532_spi', 'pn532_uart', 'pn53x_usb' and 'pn71xx'. Default drivers set is 'acr122_usb,acr122s,arygon,pn532_i2c,pn532_spi,pn532_uart,pn53x_usb'. The special driver set 'all' compile all available drivers.]),
[ case "${withval}" in [ case "${withval}" in
yes | no) yes | no)
dnl ignore calls without any arguments dnl ignore calls without any arguments
@ -36,7 +37,8 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
fi fi
;; ;;
all) all)
DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart" DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart pcsc"
if test x"$spi_available" = x"yes" if test x"$spi_available" = x"yes"
then then
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi" DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi"
@ -45,11 +47,16 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
then then
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c" DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c"
fi fi
if test x"$nfc_nci_available" = x"yes"
then
DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn71xx"
fi
;; ;;
esac esac
DRIVERS_CFLAGS="" DRIVERS_CFLAGS=""
driver_pcsc_enabled="no"
driver_acr122_pcsc_enabled="no" driver_acr122_pcsc_enabled="no"
driver_acr122_usb_enabled="no" driver_acr122_usb_enabled="no"
driver_acr122s_enabled="no" driver_acr122s_enabled="no"
@ -58,10 +65,16 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
driver_pn532_uart_enabled="no" driver_pn532_uart_enabled="no"
driver_pn532_spi_enabled="no" driver_pn532_spi_enabled="no"
driver_pn532_i2c_enabled="no" driver_pn532_i2c_enabled="no"
driver_pn71xx_enabled="no"
for driver in ${DRIVER_BUILD_LIST} for driver in ${DRIVER_BUILD_LIST}
do do
case "${driver}" in case "${driver}" in
pcsc)
pcsc_required="yes"
driver_pcsc_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PCSC_ENABLED"
;;
acr122_pcsc) acr122_pcsc)
pcsc_required="yes" pcsc_required="yes"
driver_acr122_pcsc_enabled="yes" driver_acr122_pcsc_enabled="yes"
@ -102,6 +115,11 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
driver_pn532_i2c_enabled="yes" driver_pn532_i2c_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED" DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED"
;; ;;
pn71xx)
nfc_nci_required="yes"
driver_pn71xx_enabled="yes"
DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN71XX_ENABLED"
;;
*) *)
AC_MSG_ERROR([Unknow driver: $driver]) AC_MSG_ERROR([Unknow driver: $driver])
;; ;;
@ -109,6 +127,7 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
done done
AC_SUBST(DRIVERS_CFLAGS) AC_SUBST(DRIVERS_CFLAGS)
AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_pcsc_enabled" = xyes]) AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_pcsc_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PCSC_ENABLED, [test x"$driver_pcsc_enabled" = xyes])
AM_CONDITIONAL(DRIVER_ACR122_USB_ENABLED, [test x"$driver_acr122_usb_enabled" = xyes]) AM_CONDITIONAL(DRIVER_ACR122_USB_ENABLED, [test x"$driver_acr122_usb_enabled" = xyes])
AM_CONDITIONAL(DRIVER_ACR122S_ENABLED, [test x"$driver_acr122s_enabled" = xyes]) AM_CONDITIONAL(DRIVER_ACR122S_ENABLED, [test x"$driver_acr122s_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN53X_USB_ENABLED, [test x"$driver_pn53x_usb_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN53X_USB_ENABLED, [test x"$driver_pn53x_usb_enabled" = xyes])
@ -116,11 +135,13 @@ AC_DEFUN([LIBNFC_ARG_WITH_DRIVERS],
AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN532_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN532_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes]) AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes])
AM_CONDITIONAL(DRIVER_PN71XX_ENABLED, [test x"$driver_pn71xx_enabled" = xyes])
]) ])
AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[ AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[
echo echo
echo "Selected drivers:" echo "Selected drivers:"
echo " pcsc............. $driver_pcsc_enabled"
echo " acr122_pcsc...... $driver_acr122_pcsc_enabled" echo " acr122_pcsc...... $driver_acr122_pcsc_enabled"
echo " acr122_usb....... $driver_acr122_usb_enabled" echo " acr122_usb....... $driver_acr122_usb_enabled"
echo " acr122s.......... $driver_acr122s_enabled" echo " acr122s.......... $driver_acr122s_enabled"
@ -129,4 +150,5 @@ echo " pn53x_usb........ $driver_pn53x_usb_enabled"
echo " pn532_uart....... $driver_pn532_uart_enabled" echo " pn532_uart....... $driver_pn532_uart_enabled"
echo " pn532_spi....... $driver_pn532_spi_enabled" echo " pn532_spi....... $driver_pn532_spi_enabled"
echo " pn532_i2c........ $driver_pn532_i2c_enabled" echo " pn532_i2c........ $driver_pn532_i2c_enabled"
echo " pn71xx........... $driver_pn71xx_enabled"
]) ])

34
mingw-cross-compile.sh Normal file
View File

@ -0,0 +1,34 @@
#!/bin/sh
PROJECT_DIR=$(readlink -e $(dirname $0))
cd "$PROJECT_DIR"
WITH_USB=1
LIBUSB_WIN32_BIN_VERSION="1.2.6.0"
LIBUSB_WIN32_BIN_ARCHIVE="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION.zip"
LIBUSB_WIN32_BIN_URL="http://freefr.dl.sourceforge.net/project/libusb-win32/libusb-win32-releases/$LIBUSB_WIN32_BIN_VERSION/$LIBUSB_WIN32_BIN_ARCHIVE"
LIBUSB_WIN32_BIN_DIR="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION"
if [ "$WITH_USB" = "1" ]; then
if [ ! -d $LIBUSB_WIN32_BIN_DIR ]; then
wget -c $LIBUSB_WIN32_BIN_URL
unzip $LIBUSB_WIN32_BIN_ARCHIVE
fi
fi
rm -rf build
mkdir build
cd build
case $1 in
32*)
mingw32-cmake .. -DLIBUSB_INCLUDE_DIRS="$PROJECT_DIR"/libusb-win32-bin-1.2.6.0/include -DLIBUSB_LIBRARIES="$PROJECT_DIR"/libusb-win32-bin-1.2.6.0/bin/x86/libusb0_x86.dll -DLIBNFC_ROOT_DIR=$PWD/.. -DLIBNFC_SYSCONFDIR='C:\\Program Files (x86)\\libnfc\\config'
mingw32-make;;
64*)
mingw64-cmake .. -DLIBUSB_INCLUDE_DIRS="$PROJECT_DIR"/libusb-win32-bin-1.2.6.0/include -DLIBUSB_LIBRARIES="$PROJECT_DIR"/libusb-win32-bin-1.2.6.0/bin/amd64/libusb0.dll -DLIBNFC_ROOT_DIR=.. -DLIBNFC_SYSCONFDIR='C:\\Program Files\\libnfc\\config'
mingw64-make;;
*)
echo "specify whether to build 32-bit or 64-bit version by supplying 32 or 64 as parameter";;
esac

View File

@ -45,7 +45,7 @@ test_register_endianness_la_LIBADD = $(top_builddir)/libnfc/libnfc.la
echo-cutter: echo-cutter:
@echo $(CUTTER) @echo $(CUTTER)
EXTRA_DIST = run-test.sh
CLEANFILES = *.gcno CLEANFILES = *.gcno
endif endif
EXTRA_DIST = run-test.sh

View File

@ -45,7 +45,7 @@ test_access_storm(void)
.nbr = NBR_106, .nbr = NBR_106,
}; };
res = nfc_initiator_list_passive_targets(device, nm, ant, MAX_TARGET_COUNT); res = nfc_initiator_list_passive_targets(device, nm, ant, MAX_TARGET_COUNT);
cut_assert_operator_int(res, >= , 0, cut_message("nfc_initiator_list_passive_targets")); cut_assert_operator_int(res, >=, 0, cut_message("nfc_initiator_list_passive_targets"));
nfc_close(device); nfc_close(device);
} }

View File

@ -86,18 +86,18 @@ target_thread(void *arg)
uint8_t abtRx[1024]; uint8_t abtRx[1024];
int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 0); int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 0);
cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device)));
const uint8_t abtAttRx[] = "Hello DEP target!"; const uint8_t abtAttRx[] = "Hello DEP target!";
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
const uint8_t abtTx[] = "Hello DEP initiator!"; const uint8_t abtTx[] = "Hello DEP initiator!";
res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device)));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
return (void *) thread_res; return (void *) thread_res;
@ -125,7 +125,7 @@ initiator_thread(void *arg)
// Active mode // Active mode
printf("=========== INITIATOR %s (Active mode / %s Kbps) =========\n", nfc_device_get_name(device), str_nfc_baud_rate(nbr)); printf("=========== INITIATOR %s (Active mode / %s Kbps) =========\n", nfc_device_get_name(device), str_nfc_baud_rate(nbr));
res = nfc_initiator_select_dep_target(device, NDM_ACTIVE, nbr, NULL, &nt, 1000); res = nfc_initiator_select_dep_target(device, NDM_ACTIVE, nbr, NULL, &nt, 1000);
cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device)));
cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation"));
cut_assert_equal_int(nbr, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_int(nbr, nt.nm.nbr, cut_message("Invalid target baud rate"));
cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3"));
@ -136,13 +136,13 @@ initiator_thread(void *arg)
const uint8_t abtTx[] = "Hello DEP target!"; const uint8_t abtTx[] = "Hello DEP target!";
uint8_t abtRx[1024]; uint8_t abtRx[1024];
res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000);
cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device)));
const uint8_t abtAttRx[] = "Hello DEP initiator!"; const uint8_t abtAttRx[] = "Hello DEP initiator!";
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data (as initiator)")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data (as initiator)"));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_deselect_target(device); res = nfc_initiator_deselect_target(device);
cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
return (void *) thread_res; return (void *) thread_res;

View File

@ -86,12 +86,12 @@ target_thread(void *arg)
uint8_t abtRx[1024]; uint8_t abtRx[1024];
size_t szRx = sizeof(abtRx); size_t szRx = sizeof(abtRx);
int res = nfc_target_init(device, &nt, abtRx, szRx, 0); int res = nfc_target_init(device, &nt, abtRx, szRx, 0);
cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
// First pass // First pass
res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device)));
const uint8_t abtAttRx[] = "Hello DEP target!"; const uint8_t abtAttRx[] = "Hello DEP target!";
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
@ -99,40 +99,40 @@ target_thread(void *arg)
const uint8_t abtTx[] = "Hello DEP initiator!"; const uint8_t abtTx[] = "Hello DEP initiator!";
res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device)));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
// Second pass // Second pass
res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device)));
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device)));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
// Third pass // Third pass
res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device)));
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device)));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
// Fourth pass // Fourth pass
res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device)));
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device)));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
return (void *) thread_res; return (void *) thread_res;
@ -160,7 +160,7 @@ initiator_thread(void *arg)
// Passive mode / 106Kbps // Passive mode / 106Kbps
printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device)); printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device));
res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt, 5000); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt, 5000);
cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device)));
cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation"));
cut_assert_equal_int(NBR_106, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_int(NBR_106, nt.nm.nbr, cut_message("Invalid target baud rate"));
cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3"));
@ -171,20 +171,20 @@ initiator_thread(void *arg)
const uint8_t abtTx[] = "Hello DEP target!"; const uint8_t abtTx[] = "Hello DEP target!";
uint8_t abtRx[1024]; uint8_t abtRx[1024];
res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500); res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device)));
const uint8_t abtAttRx[] = "Hello DEP initiator!"; const uint8_t abtAttRx[] = "Hello DEP initiator!";
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_deselect_target(device); res = nfc_initiator_deselect_target(device);
cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
// Passive mode / 212Kbps (second pass) // Passive mode / 212Kbps (second pass)
printf("=========== INITIATOR %s (Passive mode / 212Kbps) =========\n", nfc_device_get_name(device)); printf("=========== INITIATOR %s (Passive mode / 212Kbps) =========\n", nfc_device_get_name(device));
res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000);
cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device)));
cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation"));
cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate"));
cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3"));
@ -193,19 +193,19 @@ initiator_thread(void *arg)
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 1000); res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 1000);
cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device)));
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_deselect_target(device); res = nfc_initiator_deselect_target(device);
cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
// Passive mode / 212Kbps // Passive mode / 212Kbps
printf("=========== INITIATOR %s (Passive mode / 212Kbps, second pass) =========\n", nfc_device_get_name(device)); printf("=========== INITIATOR %s (Passive mode / 212Kbps, second pass) =========\n", nfc_device_get_name(device));
res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000);
cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device)));
cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation"));
cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate"));
cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3"));
@ -214,19 +214,19 @@ initiator_thread(void *arg)
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000);
cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device)));
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_deselect_target(device); res = nfc_initiator_deselect_target(device);
cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
// Passive mode / 424Kbps // Passive mode / 424Kbps
printf("=========== INITIATOR %s (Passive mode / 424Kbps) =========\n", nfc_device_get_name(device)); printf("=========== INITIATOR %s (Passive mode / 424Kbps) =========\n", nfc_device_get_name(device));
res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_424, NULL, &nt, 1000); res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_424, NULL, &nt, 1000);
cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device)));
cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation"));
cut_assert_equal_int(NBR_424, nt.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_int(NBR_424, nt.nm.nbr, cut_message("Invalid target baud rate"));
cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3"));
@ -235,13 +235,13 @@ initiator_thread(void *arg)
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000);
cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device)));
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_deselect_target(device); res = nfc_initiator_deselect_target(device);
cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
return (void *) thread_res; return (void *) thread_res;

View File

@ -66,7 +66,7 @@ target_thread(void *arg)
// 1) nfc_target_init should take target in idle mode // 1) nfc_target_init should take target in idle mode
int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 500); int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, >= , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
// 2) act as target // 2) act as target
@ -92,11 +92,11 @@ target_thread(void *arg)
}; };
sleep(6); sleep(6);
res = nfc_target_init(device, &nt1, abtRx, sizeof(abtRx), 0); res = nfc_target_init(device, &nt1, abtRx, sizeof(abtRx), 0);
cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device)));
const uint8_t abtAttRx[] = "Hello DEP target!"; const uint8_t abtAttRx[] = "Hello DEP target!";
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
@ -104,7 +104,7 @@ target_thread(void *arg)
const uint8_t abtTx[] = "Hello DEP initiator!"; const uint8_t abtTx[] = "Hello DEP initiator!";
res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500);
cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device)));
if (res <= 0) { thread_res = -1; return (void *) thread_res; } if (res <= 0) { thread_res = -1; return (void *) thread_res; }
// 3) idle mode // 3) idle mode
@ -144,7 +144,7 @@ initiator_thread(void *arg)
// Passive mode / 106Kbps // Passive mode / 106Kbps
printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device)); printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device));
res = nfc_initiator_poll_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt1, 5000); res = nfc_initiator_poll_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt1, 5000);
cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device)));
cut_assert_equal_int(NMT_DEP, nt1.nm.nmt, cut_message("Invalid target modulation")); cut_assert_equal_int(NMT_DEP, nt1.nm.nmt, cut_message("Invalid target modulation"));
cut_assert_equal_int(NBR_106, nt1.nm.nbr, cut_message("Invalid target baud rate")); cut_assert_equal_int(NBR_106, nt1.nm.nbr, cut_message("Invalid target baud rate"));
cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt1.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3")); cut_assert_equal_memory("\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA", 10, nt1.nti.ndi.abtNFCID3, 10, cut_message("Invalid target NFCID3"));
@ -155,14 +155,14 @@ initiator_thread(void *arg)
const uint8_t abtTx[] = "Hello DEP target!"; const uint8_t abtTx[] = "Hello DEP target!";
uint8_t abtRx[1024]; uint8_t abtRx[1024];
res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500); res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500);
cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device)));
const uint8_t abtAttRx[] = "Hello DEP initiator!"; const uint8_t abtAttRx[] = "Hello DEP initiator!";
cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data"));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
res = nfc_initiator_deselect_target(device); res = nfc_initiator_deselect_target(device);
cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device)));
if (res < 0) { thread_res = -1; return (void *) thread_res; } if (res < 0) { thread_res = -1; return (void *) thread_res; }
// 3) As other device should be in idle mode, nfc_initiator_poll_dep_target should return 0 // 3) As other device should be in idle mode, nfc_initiator_poll_dep_target should return 0

View File

@ -1,11 +1,14 @@
SET(UTILS-SOURCES SET(UTILS-SOURCES
nfc-barcode
nfc-emulate-forum-tag4 nfc-emulate-forum-tag4
nfc-jewel
nfc-list nfc-list
nfc-mfclassic nfc-mfclassic
nfc-mfultralight nfc-mfultralight
nfc-read-forum-tag3 nfc-read-forum-tag3
nfc-relay-picc nfc-relay-picc
nfc-scan-device nfc-scan-device
mfcuk
) )
ADD_LIBRARY(nfcutils STATIC ADD_LIBRARY(nfcutils STATIC
@ -21,11 +24,16 @@ FOREACH(source ${UTILS-SOURCES})
SET(RC_COMMENT "${PACKAGE_NAME} utility") SET(RC_COMMENT "${PACKAGE_NAME} utility")
SET(RC_INTERNAL_NAME ${source}) SET(RC_INTERNAL_NAME ${source})
SET(RC_ORIGINAL_NAME ${source}.exe) SET(RC_ORIGINAL_NAME ${source}.exe)
SET(RC_FILE_TYPE VFT_APP) # RC_FILE_TYPE: VFT_APP
SET(RC_FILE_TYPE 0x00000001L)
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY) CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/version.rc.in ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc @ONLY)
LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc) LIST(APPEND TARGETS ${CMAKE_CURRENT_BINARY_DIR}/../windows/${source}.rc)
ENDIF(WIN32) ENDIF(WIN32)
IF(${source} MATCHES "nfc-jewel")
LIST(APPEND TARGETS jewel)
ENDIF(${source} MATCHES "nfc-jewel")
IF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic")) IF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic"))
LIST(APPEND TARGETS mifare) LIST(APPEND TARGETS mifare)
ENDIF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic")) ENDIF((${source} MATCHES "nfc-mfultralight") OR (${source} MATCHES "nfc-mfclassic"))
@ -35,6 +43,12 @@ FOREACH(source ${UTILS-SOURCES})
LIST(APPEND TARGETS ../contrib/win32/stdlib) LIST(APPEND TARGETS ../contrib/win32/stdlib)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32)
ENDIF(${source} MATCHES "nfc-scan-device") ENDIF(${source} MATCHES "nfc-scan-device")
IF((${source} MATCHES "nfc-read-forum-tag3") OR (${source} MATCHES "mfcuk"))
LIST(APPEND TARGETS ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/getopt.c)
ENDIF() #mfcuk added (@xavave)
IF(${source} MATCHES "mfcuk")
LIST(APPEND TARGETS mfcuk_mifare crypto1 crapto1 mfcuk_utils mfcuk_finger mifare)
ENDIF()
ENDIF(WIN32) ENDIF(WIN32)
ADD_EXECUTABLE(${source} ${TARGETS}) ADD_EXECUTABLE(${source} ${TARGETS})

View File

@ -1,5 +1,7 @@
bin_PROGRAMS = \ bin_PROGRAMS = \
nfc-barcode \
nfc-emulate-forum-tag4 \ nfc-emulate-forum-tag4 \
nfc-jewel \
nfc-list \ nfc-list \
nfc-mfclassic \ nfc-mfclassic \
nfc-mfultralight \ nfc-mfultralight \
@ -13,11 +15,19 @@ AM_CPPFLAGS = $(all_includes) $(LIBNFC_CFLAGS)
noinst_LTLIBRARIES = libnfcutils.la noinst_LTLIBRARIES = libnfcutils.la
libnfcutils_la_SOURCES = nfc-utils.c libnfcutils_la_SOURCES = nfc-utils.c
libnfcutils_la_LIBADD = -lnfc
nfc_barcode_SOURCES = nfc-barcode.c
nfc_barcode_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la
nfc_emulate_forum_tag4_SOURCES = nfc-emulate-forum-tag4.c nfc-utils.h nfc_emulate_forum_tag4_SOURCES = nfc-emulate-forum-tag4.c nfc-utils.h
nfc_emulate_forum_tag4_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_emulate_forum_tag4_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la libnfcutils.la
nfc_jewel_SOURCES = nfc-jewel.c jewel.c jewel.h nfc-utils.h
nfc_jewel_LDADD = $(top_builddir)/libnfc/libnfc.la
nfc_list_SOURCES = nfc-list.c nfc-utils.h nfc_list_SOURCES = nfc-list.c nfc-utils.h
nfc_list_LDADD = $(top_builddir)/libnfc/libnfc.la \ nfc_list_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la libnfcutils.la
@ -42,7 +52,9 @@ nfc_scan_device_LDADD = $(top_builddir)/libnfc/libnfc.la \
libnfcutils.la libnfcutils.la
dist_man_MANS = \ dist_man_MANS = \
nfc-barcode.1 \
nfc-emulate-forum-tag4.1 \ nfc-emulate-forum-tag4.1 \
nfc-jewel.1 \
nfc-list.1 \ nfc-list.1 \
nfc-mfclassic.1 \ nfc-mfclassic.1 \
nfc-mfultralight.1 \ nfc-mfultralight.1 \

Some files were not shown because too many files have changed in this diff Show More