Update upstream source from tag 'upstream/1.8.0'
Update to upstream version '1.8.0'
with Debian dir d55986ebfe909ecafd716162860c9bcaf7d72d17
Ludovic Rousseau
3 years ago
0 | **/.deps/ | |
1 | **/.libs/ | |
2 | **/Makefile | |
3 | **/Makefile.in | |
4 | *.exe | |
5 | *.la | |
6 | *.lo | |
7 | *.o | |
0 | 8 | *~ |
1 | 9 | Doxyfile |
2 | 10 | INSTALL |
3 | Makefile | |
4 | Makefile.in | |
5 | 11 | aclocal.m4 |
6 | 12 | ar-lib |
7 | 13 | autom4te.cache/ |
8 | 14 | build |
9 | cmake/Makefile | |
10 | cmake/Makefile.in | |
11 | cmake/modules/Makefile | |
12 | cmake/modules/Makefile.in | |
15 | compile | |
13 | 16 | config.guess |
14 | 17 | config.h |
15 | 18 | config.h.in |
17 | 20 | config.status |
18 | 21 | config.sub |
19 | 22 | configure |
20 | contrib/Makefile | |
21 | contrib/Makefile.in | |
22 | contrib/devd/Makefile | |
23 | contrib/devd/Makefile.in | |
24 | contrib/udev/Makefile | |
25 | contrib/udev/Makefile.in | |
26 | contrib/win32/Makefile | |
27 | contrib/win32/Makefile.in | |
28 | contrib/win32/sys/Makefile | |
29 | contrib/win32/sys/Makefile.in | |
30 | 23 | debian/ |
31 | 24 | depcomp |
32 | examples/*.o | |
33 | examples/.deps/ | |
34 | examples/.libs/ | |
35 | examples/Makefile | |
36 | examples/Makefile.in | |
37 | examples/doc/.deps/ | |
38 | 25 | examples/nfc-anticol |
39 | 26 | examples/nfc-dep-initiator |
40 | 27 | examples/nfc-dep-target |
47 | 34 | examples/pn53x-diagnose |
48 | 35 | examples/pn53x-sam |
49 | 36 | examples/pn53x-tamashell |
50 | examples/pn53x-tamashell-scripts/Makefile | |
51 | examples/pn53x-tamashell-scripts/Makefile.in | |
52 | 37 | examples/quick_start_example1 |
53 | 38 | examples/quick_start_example2 |
54 | include/Makefile | |
55 | include/Makefile.in | |
56 | include/nfc/Makefile | |
57 | include/nfc/Makefile.in | |
58 | 39 | install-sh |
59 | 40 | libnfc.pc |
60 | libnfc/*.lo | |
61 | libnfc/*.o | |
62 | libnfc/.deps/ | |
63 | libnfc/.libs/ | |
64 | libnfc/Makefile | |
65 | libnfc/Makefile.in | |
66 | libnfc/buses/*.la | |
67 | libnfc/buses/*.lo | |
68 | libnfc/buses/*.o | |
69 | libnfc/buses/.deps/ | |
70 | libnfc/buses/.libs/ | |
71 | libnfc/buses/Makefile | |
72 | libnfc/buses/Makefile.in | |
73 | libnfc/chips/*.la | |
74 | libnfc/chips/*.lo | |
75 | libnfc/chips/*.o | |
76 | libnfc/chips/.deps/ | |
77 | libnfc/chips/.libs/ | |
78 | libnfc/chips/Makefile | |
79 | libnfc/chips/Makefile.in | |
80 | libnfc/drivers/*.la | |
81 | libnfc/drivers/*.lo | |
82 | libnfc/drivers/*.o | |
83 | libnfc/drivers/.deps/ | |
84 | libnfc/drivers/.libs/ | |
85 | libnfc/drivers/Makefile | |
86 | libnfc/drivers/Makefile.in | |
87 | libnfc/libnfc.la | |
88 | 41 | libtool |
89 | 42 | ltmain.sh |
90 | 43 | m4/libtool.m4 |
94 | 47 | m4/lt~obsolete.m4 |
95 | 48 | missing |
96 | 49 | stamp-h1 |
97 | test/*.la | |
98 | test/*.lo | |
99 | test/*.o | |
100 | test/.deps/ | |
101 | test/.libs/ | |
102 | test/Makefile | |
103 | test/Makefile.in | |
104 | utils/*.la | |
105 | utils/*.lo | |
106 | utils/*.o | |
107 | utils/.deps/ | |
108 | utils/.libs/ | |
109 | utils/Makefile | |
110 | utils/Makefile.in | |
50 | test-driver | |
51 | test/run-test.sh.log | |
52 | test/run-test.sh.trs | |
53 | test/test-suite.log | |
111 | 54 | utils/nfc-emulate-forum-tag4 |
55 | utils/nfc-jewel | |
112 | 56 | utils/nfc-list |
113 | 57 | utils/nfc-mfclassic |
114 | 58 | utils/nfc-mfultralight |
0 | language: c | |
1 | ||
2 | compiler: | |
3 | - clang | |
4 | - gcc | |
5 | ||
6 | env: | |
7 | - BLD=cmake | |
8 | - BLD=autoconf | |
9 | ||
10 | addons: | |
11 | apt: | |
12 | packages: | |
13 | - libusb-dev | |
14 | - doxygen | |
15 | - cmake | |
16 | ||
17 | script: | |
18 | - if [ $BLD == autoconf ]; then autoreconf -vfi && mkdir build && cd build && ../configure --prefix=$HOME/.local/ && make -j2 && make install; fi | |
19 | - if [ $BLD == cmake ]; then mkdir build && cd build && cmake -DCMAKE_INSTALL_PREFIX=~/.local .. && make -j2 && make install; fi |
1 | 1 | Adam Laurie <adam@algroup.co.uk> |
2 | 2 | Ahti Legonkov <ahti.legonkov@gmail.com> |
3 | 3 | Alex Lian <alian@alum.mit.edu> |
4 | Alexander Inyukhin <shurick@sectorb.msk.ru> | |
4 | 5 | Anugrah Redja Kusuma <anugrah.redja@gmail.com> |
5 | 6 | Audrey Diacre <adiacre@il4p.fr> |
7 | Boris Moiseev <cyberbobs@gmail.com> | |
8 | Christoph Gritschenberger <christoph.gritschenberger@gmail.com> | |
9 | Dario Carluccio <dario.carluccio@gmail.com> | |
10 | David Kreitschmann <david@kreitschmann.de> | |
6 | 11 | Emanuele Bertoldi <emanuele.bertoldi@gmail.com> |
12 | Emmanuel Dreyfus <manu@netbsd.org> | |
7 | 13 | Eugeny Boger <eugenyboger@gmail.com> |
8 | 14 | Francois Kooman <fkooman@tuxed.net> |
15 | Frank Morgner <frankmorgner@gmail.com> | |
16 | Frédéric Bourgeois <bourgeoislab@gmail.com> | |
17 | Hidde Wieringa <hidde@hiddewieringa.nl> | |
18 | Jairo Andres Suarez <andres4005@gmail.com> | |
9 | 19 | Jiapeng Li <gapleehit@gmail.com> |
20 | Jim Anastassiou <jim.anastassiou@gmail.com> | |
21 | John Galt <centromere@users.noreply.github.com> | |
22 | Julien Ehrhart <julien.ehrhart@live.com> | |
10 | 23 | Julien Schueller <julien.schueller@gmail.com> |
11 | 24 | Laurent Latil <laurent@latil.nom.fr> |
12 | 25 | Ludovic Rousseau <ludovic.rousseau@gmail.com> |
13 | 26 | Marcello Morena <marcello.morena@gmail.com> |
27 | Marcos Vives Del Sol <socram8888@gmail.com> | |
28 | Mati Vait <mativait@gmail.com> | |
29 | Maxim Martyanov <llorephie@gmail.com> | |
14 | 30 | Mike Auty <mike.auty@gmail.com> |
15 | 31 | Nobuhiro Iwamatsu <iwamatsu@nigauri.org> |
32 | Olliver Schinagl <oliver@schinagl.nl> | |
33 | Paul Menzel <paul.menzel@giantmonkey.de> | |
16 | 34 | Peter Meerwald <pmeerw@pmeerw.net> |
17 | 35 | Philippe Teuwen <yobibe@gmail.com> |
18 | 36 | Pim 't Hart <pimmeyproductions@gmail.com> |
37 | Ray Lee <rayleesky@outlook.com> | |
19 | 38 | Roel Verdult <roel@libnfc.org> |
20 | 39 | Romain Tartiere <romain.tartiere@gmail.com> |
21 | 40 | Romuald Conty <romuald@libnfc.org> |
41 | Simon Yorkston <simon.yorkston@gmail.com> | |
42 | bhack <s.fabri@email.it> | |
22 | 43 | lego <lego@debian-fresh.prx> |
44 | quantum-x <simon.yorkston@gmail.com> | |
45 | timzi <developers@make-gadget.ru> | |
46 | xantares <xantares09@hotmail.com> | |
47 | xaqq <kapp.arno@gmail.com> | |
48 | yerzhanm <yerzhan.mukhamejan@gmail.com> |
0 | PROJECT(libnfc C) | |
1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) | |
0 | cmake_minimum_required (VERSION 2.6) | |
1 | ||
2 | if (NOT DEFINED CMAKE_BUILD_TYPE) | |
3 | set (CMAKE_BUILD_TYPE Release CACHE STRING "Build type") | |
4 | endif () | |
5 | ||
6 | project (libnfc C) | |
7 | ||
2 | 8 | SET(VERSION_MAJOR "1") |
3 | SET(VERSION_MINOR "7") | |
4 | SET(VERSION_PATCH "1") | |
9 | SET(VERSION_MINOR "8") | |
10 | SET(VERSION_PATCH "0") | |
5 | 11 | |
6 | 12 | SET(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") |
7 | 13 | |
11 | 17 | |
12 | 18 | # config.h |
13 | 19 | IF(WIN32) |
14 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) | |
20 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_windows.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) | |
15 | 21 | SET(LIBNFC_SYSCONFDIR "${CMAKE_INSTALL_PREFIX}/config" CACHE PATH "libnfc configuration directory") |
16 | 22 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/contrib/win32) |
17 | 23 | ELSE(WIN32) |
18 | 24 | SET(_XOPEN_SOURCE 600) |
19 | 25 | SET(SYSCONFDIR "/etc" CACHE PATH "System configuration directory") |
20 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_SOURCE_DIR}/config.h) | |
21 | ENDIF(WIN32) | |
26 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config_posix.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) | |
27 | ENDIF(WIN32) | |
28 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) | |
22 | 29 | |
23 | 30 | ADD_DEFINITIONS("-DHAVE_CONFIG_H") |
24 | 31 | |
25 | 32 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) |
26 | 33 | |
27 | 34 | # make it easy to locate CMake modules for finding libraries |
28 | SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules/") | |
35 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/modules/") | |
29 | 36 | |
30 | 37 | # Options |
31 | SET(LIBNFC_LOG ON CACHE BOOL "Enable log facility (errors, warning, info and debug messages)") | |
38 | option (LIBNFC_LOG "Enable log facility (errors, warning, info and debug messages)" ON) | |
32 | 39 | IF(LIBNFC_LOG) |
33 | 40 | ADD_DEFINITIONS(-DLOG) |
34 | 41 | ENDIF(LIBNFC_LOG) |
35 | 42 | |
36 | SET(LIBNFC_ENVVARS ON CACHE BOOL "Enable envvars facility") | |
43 | option (LIBNFC_ENVVARS "Enable envvars facility" ON) | |
37 | 44 | IF(LIBNFC_ENVVARS) |
38 | 45 | ADD_DEFINITIONS(-DENVVARS) |
39 | 46 | ENDIF(LIBNFC_ENVVARS) |
48 | 55 | SET(WIN32_MODE "release") |
49 | 56 | ENDIF(LIBNFC_DEBUG_MODE) |
50 | 57 | |
51 | SET(LIBNFC_CONFFILES_MODE ON CACHE BOOL "Enable configuration files") | |
58 | option (LIBNFC_CONFFILES_MODE "Enable configuration files" ON) | |
52 | 59 | IF(LIBNFC_CONFFILES_MODE) |
53 | 60 | ADD_DEFINITIONS(-DCONFFILES) |
54 | 61 | ENDIF(LIBNFC_CONFFILES_MODE) |
62 | ||
63 | option (BUILD_EXAMPLES "build examples ON/OFF" ON) | |
64 | option (BUILD_UTILS "build utils ON/OFF" ON) | |
65 | ||
66 | option (BUILD_DEBPKG "build debian package ON/OFF" OFF) | |
67 | ||
55 | 68 | |
56 | 69 | # Doxygen |
57 | 70 | SET(builddir "${CMAKE_BINARY_DIR}") |
86 | 99 | ADD_DEFINITIONS(-Du_int8_t=uint8_t -Du_int16_t=uint16_t) |
87 | 100 | |
88 | 101 | IF(MINGW) |
89 | # force MinGW-w64 in 32bit mode | |
90 | SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}") | |
91 | SET(CMAKE_MODULE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") | |
92 | SET(CMAKE_SHARED_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") | |
93 | SET(CMAKE_EXE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}") | |
94 | SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}") | |
102 | IF (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") | |
103 | # force MinGW-w64 in 32bit mode | |
104 | SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}") | |
105 | SET(CMAKE_MODULE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") | |
106 | SET(CMAKE_SHARED_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") | |
107 | SET(CMAKE_EXE_LINKER_FLAGS "-m32 -Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}") | |
108 | SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}") | |
109 | ELSE(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") | |
110 | IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86") | |
111 | # force MinGW-w64 in 32bit mode | |
112 | MESSAGE("Building 32-bit Windows DLL") | |
113 | #SET(CMAKE_C_FLAGS "-m32 ${CMAKE_C_FLAGS}") | |
114 | #SET(CMAKE_MODULE_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") | |
115 | #SET(CMAKE_SHARED_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_SHARED_LINKER_FLAGS}") | |
116 | #SET(CMAKE_EXE_LINKER_FLAGS "--Wl,--enable-stdcall-fixup ${CMAKE_EXE_LINKER_FLAGS}") | |
117 | SET(CMAKE_RC_FLAGS "--target=pe-i386 --output-format=coff ${CMAKE_RC_FLAGS}") | |
118 | ELSEIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") | |
119 | MESSAGE("Building 64-bit Windows DLL") | |
120 | SET(CMAKE_RC_FLAGS "--target=pe-x86-64 --output-format=coff ${CMAKE_RC_FLAGS}") | |
121 | ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86") | |
122 | MESSAGE(FATAL_ERROR "Unknown Processor: ${CMAKE_SYSTEM_PROCESSOR}") | |
123 | ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86") | |
124 | ENDIF(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") | |
125 | ||
126 | FIND_PROGRAM(DLLTOOL dlltool CMAKE_FIND_ROOT_PATH_BOTH) | |
127 | IF (NOT DLLTOOL) | |
128 | MESSAGE(FATAL_ERROR "Could not find dlltool command") | |
129 | ENDIF (NOT DLLTOOL) | |
95 | 130 | ENDIF(MINGW) |
96 | 131 | |
97 | 132 | IF(NOT WIN32) |
102 | 137 | IF(LIBNFC_DRIVER_PN53X_USB) |
103 | 138 | SET(PKG_REQ ${PKG_REQ} "libusb") |
104 | 139 | ENDIF(LIBNFC_DRIVER_PN53X_USB) |
105 | IF(LIBNFC_DRIVER_ACR122) | |
140 | IF(LIBNFC_DRIVER_PCSC) | |
106 | 141 | SET(PKG_REQ ${PKG_REQ} "libpcsclite") |
107 | 142 | ENDIF(LIBNFC_DRIVER_ACR122) |
143 | IF(LIBNFC_DRIVER_ACR122_PCSC) | |
144 | SET(PKG_REQ ${PKG_REQ} "libpcsclite") | |
145 | ENDIF(LIBNFC_DRIVER_ACR122_PCSC) | |
108 | 146 | # CMake lists are separated by a semi colon, replace with colon |
109 | 147 | STRING(REPLACE ";" "," PKG_CONFIG_REQUIRES "${PKG_REQ}") |
110 | 148 | CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/libnfc.pc.in ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc @ONLY) |
111 | 149 | INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libnfc.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) |
112 | 150 | ENDIF(NOT WIN32) |
113 | 151 | |
114 | # Require PCRE for Win32 | |
115 | IF (WIN32) | |
116 | FIND_PACKAGE(PCRE REQUIRED) | |
117 | IF(PCRE_INCLUDE_DIRS) | |
118 | INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIRS}) | |
119 | LINK_DIRECTORIES(${PCRE_LIBRARY_DIRS}) | |
120 | ENDIF(PCRE_INCLUDE_DIRS) | |
121 | ENDIF(WIN32) | |
122 | ||
123 | 152 | INCLUDE(LibnfcDrivers) |
153 | ||
154 | IF(UNIX AND NOT APPLE) | |
155 | IF(I2C_REQUIRED) | |
156 | # Inspired from http://cmake.3232098.n2.nabble.com/RFC-cmake-analog-to-AC-SEARCH-LIBS-td7585423.html | |
157 | INCLUDE (CheckFunctionExists) | |
158 | INCLUDE (CheckLibraryExists) | |
159 | CHECK_FUNCTION_EXISTS (clock_gettime HAVE_CLOCK_GETTIME) | |
160 | IF (NOT HAVE_CLOCK_GETTIME) | |
161 | CHECK_LIBRARY_EXISTS (rt clock_gettime "" HAVE_CLOCK_GETTIME_IN_RT) | |
162 | IF (HAVE_CLOCK_GETTIME_IN_RT) | |
163 | SET(LIBRT_FOUND TRUE) | |
164 | SET(LIBRT_LIBRARIES "rt") | |
165 | ENDIF (HAVE_CLOCK_GETTIME_IN_RT) | |
166 | ENDIF (NOT HAVE_CLOCK_GETTIME) | |
167 | ENDIF(I2C_REQUIRED) | |
168 | ENDIF(UNIX AND NOT APPLE) | |
124 | 169 | |
125 | 170 | IF(PCSC_INCLUDE_DIRS) |
126 | 171 | INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS}) |
136 | 181 | # version.rc for Windows |
137 | 182 | IF(WIN32) |
138 | 183 | # Date for filling in rc file information |
139 | MACRO (GET_CURRENT_YEAR RESULT) | |
140 | EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT}) | |
141 | STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}}) | |
142 | STRING(REGEX REPLACE ".*(..)/(..)/(....).*" "\\3" ${RESULT} ${${RESULT}}) | |
143 | ENDMACRO (GET_CURRENT_YEAR) | |
184 | IF (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") | |
185 | MACRO (GET_CURRENT_YEAR RESULT) | |
186 | EXECUTE_PROCESS(COMMAND "cmd" " /C date /T" OUTPUT_VARIABLE ${RESULT}) | |
187 | STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}}) | |
188 | STRING(REGEX REPLACE ".*(..)/(..)/(....).*" "\\3" ${RESULT} ${${RESULT}}) | |
189 | ENDMACRO (GET_CURRENT_YEAR) | |
190 | ELSE(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") | |
191 | MACRO (GET_CURRENT_YEAR RESULT) | |
192 | EXECUTE_PROCESS(COMMAND "date" "+%Y" OUTPUT_VARIABLE ${RESULT}) | |
193 | STRING(REGEX REPLACE "\n" "" ${RESULT} ${${RESULT}}) | |
194 | ENDMACRO (GET_CURRENT_YEAR) | |
195 | ENDIF(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") | |
144 | 196 | GET_CURRENT_YEAR(CURRENT_YEAR) |
145 | 197 | MESSAGE("Year for copyright is " ${CURRENT_YEAR}) |
146 | 198 | |
199 | SET(prefix ${CMAKE_INSTALL_PREFIX}) | |
147 | 200 | SET(RC_COMMENT "${PACKAGE_NAME} library") |
148 | 201 | SET(RC_INTERNAL_NAME "${PACKAGE_NAME} ${WIN32_MODE}") |
149 | 202 | SET(RC_ORIGINAL_NAME ${PACKAGE_NAME}.dll) |
153 | 206 | |
154 | 207 | ADD_SUBDIRECTORY(libnfc) |
155 | 208 | ADD_SUBDIRECTORY(include) |
156 | ADD_SUBDIRECTORY(utils) | |
157 | ADD_SUBDIRECTORY(examples) | |
209 | ||
210 | if (BUILD_UTILS) | |
211 | add_subdirectory (utils) | |
212 | endif () | |
213 | ||
214 | if (BUILD_EXAMPLES) | |
215 | add_subdirectory (examples) | |
216 | endif () | |
217 | ||
218 | if (NOT MSVC) | |
219 | # config script install path | |
220 | if ( NOT DEFINED LIBNFC_CMAKE_CONFIG_DIR ) | |
221 | set ( LIBNFC_CMAKE_CONFIG_DIR lib${LIB_SUFFIX}/cmake/libnfc ) | |
222 | endif () | |
223 | ||
224 | set ( LIBNFC_INCLUDE_DIR ${includedir} ) | |
225 | set ( LIBNFC_INCLUDE_DIRS ${LIBNFC_INCLUDE_DIR} ) | |
226 | list ( APPEND LIBNFC_INCLUDE_DIRS ${LIBUSB_INCLUDE_DIRS} ) | |
227 | set ( LIBNFC_LIBRARY nfc ) | |
228 | set ( LIBNFC_LIBRARIES ${LIBNFC_LIBRARY} ) | |
229 | list ( APPEND LIBNFC_LIBRARIES ${LIBUSB_LIBRARIES} ) | |
230 | set ( LIBNFC_LIBRARY_DIRS ${libdir} ) | |
231 | set ( LIBNFC_ROOT_DIR ${prefix} ) | |
232 | set ( LIBNFC_VERSION_STRING ${VERSION} ) | |
233 | set ( LIBNFC_VERSION_MAJOR ${VERSION_MAJOR} ) | |
234 | set ( LIBNFC_VERSION_MINOR ${VERSION_MINOR} ) | |
235 | set ( LIBNFC_VERSION_PATCH ${VERSION_PATCH} ) | |
236 | ||
237 | set ( LIBNFC_USE_FILE ${CMAKE_INSTALL_PREFIX}/${LIBNFC_CMAKE_CONFIG_DIR}/UseLibNFC.cmake ) | |
238 | ||
239 | ||
240 | ||
241 | if(CMAKE_VERSION VERSION_LESS 2.8.8) | |
242 | configure_file ( cmake/LibNFCConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfig.cmake @ONLY ) | |
243 | configure_file ( cmake/LibNFCConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfigVersion.cmake @ONLY ) | |
244 | else () | |
245 | include(CMakePackageConfigHelpers) | |
246 | configure_package_config_file ( | |
247 | cmake/LibNFCConfig.cmake.in | |
248 | ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfig.cmake | |
249 | INSTALL_DESTINATION ${LIBNFC_CMAKE_CONFIG_DIR} | |
250 | PATH_VARS | |
251 | LIBNFC_USE_FILE | |
252 | LIBNFC_ROOT_DIR | |
253 | LIBNFC_INCLUDE_DIR | |
254 | LIBNFC_INCLUDE_DIRS | |
255 | LIBNFC_LIBRARY_DIRS | |
256 | NO_CHECK_REQUIRED_COMPONENTS_MACRO | |
257 | ) | |
258 | write_basic_package_version_file ( | |
259 | LibNFCConfigVersion.cmake | |
260 | VERSION ${LIBNFC_VERSION_STRING} | |
261 | COMPATIBILITY AnyNewerVersion | |
262 | ) | |
263 | endif () | |
264 | ||
265 | install ( FILES ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfig.cmake | |
266 | ${CMAKE_CURRENT_BINARY_DIR}/LibNFCConfigVersion.cmake | |
267 | cmake/UseLibNFC.cmake | |
268 | DESTINATION ${LIBNFC_CMAKE_CONFIG_DIR} | |
269 | ) | |
270 | ||
271 | endif () | |
158 | 272 | |
159 | 273 | # Binary Package |
160 | 274 | IF(WIN32) |
161 | 275 | SET(CPACK_GENERATOR "ZIP") |
162 | 276 | ELSE(WIN32) |
163 | 277 | SET(CPACK_GENERATOR "TBZ2") |
278 | IF(BUILD_DEBPKG) | |
279 | SET(CPACK_GENERATOR "DEB") | |
280 | ENDIF(BUILD_DEBPKG) | |
164 | 281 | ENDIF(WIN32) |
165 | 282 | |
166 | 283 | SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Near Field Communication (NFC) library") |
167 | 284 | SET(CPACK_PACKAGE_VENDOR "Roel Verdult") |
168 | SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README") | |
285 | SET(CPACK_PACKAGE_CONTACT "Roel Verdult <roel@libnfc.org>") | |
286 | ||
287 | #Readme file | |
288 | IF(WIN32) | |
289 | SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README-Windows.md") | |
290 | ELSE(WIN32) | |
291 | SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md") | |
292 | ENDIF(WIN32) | |
293 | ||
169 | 294 | SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING") |
170 | 295 | SET(CPACK_PACKAGE_INSTALL_DIRECTORY "libnfc") |
171 | 296 | SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) |
0 | May 22, 2020 - 1.8.0 | |
1 | -------------------- | |
2 | ||
3 | Fixes: | |
4 | - Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1 | |
5 | ||
6 | Changes: | |
7 | - Bump revision due to changes in API introduced in v1.7.2 | |
8 | - Bump library version to 6.0.0 | |
9 | ||
10 | May 21, 2020 - 1.7.2 (avoid using it, incompatible with 1.7.1) | |
11 | -------------------- | |
12 | ||
13 | Fixes: | |
14 | - Remove unreachable code | |
15 | - nfc_emulate_uid: cleaner exit on interrupt | |
16 | - Fix reporting of modulations and baud rates by nfc-scan-device -v | |
17 | - Fix out-of-bounds access in nfc-mfultralight | |
18 | - Several Cygwin compilation fixes | |
19 | - Fix comparison when nfc_initiator_target_is_present() with a specified target | |
20 | - Fix nfc_initiator_poll_target without tag on PN532 | |
21 | - Export iso14443b* symbols | |
22 | - Fix udev rule which was executed too early | |
23 | - Fix improper device name initialization | |
24 | - Fix setenv()/unsetenv() for Windows | |
25 | - Fix win32/nfc.def according to nfc.h | |
26 | - Fix missing timeout in pn53x_initiator_select_passive_target() | |
27 | - nfc-mfclassic: fix option to tolerate write errors | |
28 | - nfc-poll: fix card removing check | |
29 | - nfc-relay-picc: fix wrong open mode for file descriptor | |
30 | ||
31 | Improvements: | |
32 | - Allow ISO14443A to be used at higher baud rates | |
33 | - nfc_initiator_select_passive_target() now checks against | |
34 | reported modulations and baud rates for current device | |
35 | - More serial devices on MAC OS X | |
36 | - Add section to README to help to configure libnfc | |
37 | - Various cmake improvements | |
38 | - Drop PCRE dependency on Windows | |
39 | - Remove deprecated readdir_r | |
40 | - Markdown conversion of the text files | |
41 | - Use hardcoded PN533 descriptors to be more robust on Windows | |
42 | - Add support for SCL3712 | |
43 | - Add support for ACR1222U-C1 | |
44 | - Add support for NetBSD | |
45 | - Add support for PN532 on RPi3 UART | |
46 | - Add support for cross-compilation of 32b & 64b versions of the library for Windows | |
47 | - Add pn533_usb to the kernel modules blacklist | |
48 | - Add support for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested) | |
49 | - Add support for contactless PC/SC readers (only as initiator) | |
50 | - Add support for Feitian R502 and bR500 into pcsc driver | |
51 | - Add support for HID iClass (Picopass) support (nfc-iclass tool in external nfc-tools repo) | |
52 | - Allows for sending empty data in nfc_initiator_transceive_bits | |
53 | - driver i2c: respect proper timing specifications | |
54 | - driver i2c: add retry on error mechanism | |
55 | - nfc-mfclassic: improvements fo magic cards | |
56 | - nfc-mfclassic: add option to specify UID | |
57 | - nfc-mfclassic/nfc-mfsetuid: add support for new gen (1b) of magic 4K cards | |
58 | - nfc-mfclassic: Add RATS support indicator | |
59 | - nfc-mfsetuid: allow to write complete Block0, instead of only UID | |
60 | - nfc-mfultralight: add automatic modes and --check-magic | |
61 | - nfc-mfultralight: add support for magic gen2 cards | |
62 | - nfc-mfultralight: add option to specify UID | |
63 | - nfc-mfultralight: add support for Ultralight NTAG213/215/216 | |
64 | - nfc-barcode: new command to read and decode NFC Barcodes (Tag-Talks-First) | |
65 | ||
66 | Changes: | |
67 | - nfc_device_get_supported_baud_rate() takes now a "mode" parameter | |
68 | - New nfc_device_get_supported_baud_rate_target_mode() | |
69 | - New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol | |
70 | - New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass) | |
71 | - pn53x_transceive() is now part of public API | |
72 | ||
73 | Special thanks to: | |
74 | - Jim Anastassiou, Frédéric Bourgeois, Dario Carluccio, Emmanuel Dreyfus, | |
75 | Julien Ehrhart, S. Fabri, John Galt, Christoph Gritschenberger, | |
76 | Alexander Inyukhin, Arnaud Kapp, David Kreitschmann, Adam Laurie, Ray Lee, | |
77 | Maxim Martyanov, Paul Menzel, Boris Moiseev, Yerzhan Mukhamejan, | |
78 | Olliver Shinagl, Jairo Andres Suarez, Mati Vait, Marcos Vives Del Sol, | |
79 | Hidde Wieringa, Simon Yorkston, timzi, usk-johnny-s, xantares, Hanno | |
80 | Heinrichs, jgeslin, Mikolaj Stawiski, rstular, Khem Raj, Frank Morgner, jpwidera, | |
81 | Feitian Technologies | |
82 | ||
0 | 83 | Feb 24, 2014 - 1.7.1 |
1 | ------------------ | |
84 | -------------------- | |
2 | 85 | |
3 | 86 | Fixes: |
4 | 87 | - Fix several issues reported by Coverity Scan |
0 | # Doxyfile 1.6.1 | |
0 | # Doxyfile 1.8.13 | |
1 | 1 | |
2 | 2 | # This file describes the settings to be used by the documentation system |
3 | # doxygen (www.doxygen.org) for a project | |
4 | # | |
5 | # All text after a hash (#) is considered a comment and will be ignored | |
3 | # doxygen (www.doxygen.org) for a project. | |
4 | # | |
5 | # All text after a double hash (##) is considered a comment and is placed in | |
6 | # front of the TAG it is preceding. | |
7 | # | |
8 | # All text after a single hash (#) is considered a comment and will be ignored. | |
6 | 9 | # The format is: |
7 | # TAG = value [value, ...] | |
8 | # For lists items can also be appended using: | |
9 | # TAG += value [value, ...] | |
10 | # Values that contain spaces should be placed between quotes (" ") | |
10 | # TAG = value [value, ...] | |
11 | # For lists, items can also be appended using: | |
12 | # TAG += value [value, ...] | |
13 | # Values that contain spaces should be placed between quotes (\" \"). | |
11 | 14 | |
12 | 15 | #--------------------------------------------------------------------------- |
13 | 16 | # Project related configuration options |
14 | 17 | #--------------------------------------------------------------------------- |
15 | 18 | |
16 | 19 | # This tag specifies the encoding used for all characters in the config file |
17 | # that follow. The default is UTF-8 which is also the encoding used for all | |
18 | # text before the first occurrence of this tag. Doxygen uses libiconv (or the | |
19 | # iconv built into libc) for the transcoding. See | |
20 | # http://www.gnu.org/software/libiconv for the list of possible encodings. | |
20 | # that follow. The default is UTF-8 which is also the encoding used for all text | |
21 | # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv | |
22 | # built into libc) for the transcoding. See http://www.gnu.org/software/libiconv | |
23 | # for the list of possible encodings. | |
24 | # The default value is: UTF-8. | |
21 | 25 | |
22 | 26 | DOXYFILE_ENCODING = UTF-8 |
23 | 27 | |
24 | # The PROJECT_NAME tag is a single word (or a sequence of words surrounded | |
25 | # by quotes) that should identify the project. | |
28 | # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by | |
29 | # double-quotes, unless you are using Doxywizard) that should identify the | |
30 | # project for which the documentation is generated. This name is used in the | |
31 | # title of most generated pages and in a few other places. | |
32 | # The default value is: My Project. | |
26 | 33 | |
27 | 34 | PROJECT_NAME = libnfc |
28 | 35 | |
29 | # The PROJECT_NUMBER tag can be used to enter a project or revision number. | |
30 | # This could be handy for archiving the generated documentation or | |
31 | # if some version control system is used. | |
36 | # The PROJECT_NUMBER tag can be used to enter a project or revision number. This | |
37 | # could be handy for archiving the generated documentation or if some version | |
38 | # control system is used. | |
32 | 39 | |
33 | 40 | PROJECT_NUMBER = @VERSION@ |
34 | 41 | |
35 | # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) | |
36 | # base path where the generated documentation will be put. | |
37 | # If a relative path is entered, it will be relative to the location | |
38 | # where doxygen was started. If left blank the current directory will be used. | |
42 | # Using the PROJECT_BRIEF tag one can provide an optional one line description | |
43 | # for a project that appears at the top of each page and should give viewer a | |
44 | # quick idea about the purpose of the project. Keep the description short. | |
45 | ||
46 | PROJECT_BRIEF = | |
47 | ||
48 | # With the PROJECT_LOGO tag one can specify a logo or an icon that is included | |
49 | # in the documentation. The maximum height of the logo should not exceed 55 | |
50 | # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy | |
51 | # the logo to the output directory. | |
52 | ||
53 | PROJECT_LOGO = | |
54 | ||
55 | # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path | |
56 | # into which the generated documentation will be written. If a relative path is | |
57 | # entered, it will be relative to the location where doxygen was started. If | |
58 | # left blank the current directory will be used. | |
39 | 59 | |
40 | 60 | OUTPUT_DIRECTORY = @builddir@/doc |
41 | 61 | |
42 | # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create | |
43 | # 4096 sub-directories (in 2 levels) under the output directory of each output | |
44 | # format and will distribute the generated files over these directories. | |
45 | # Enabling this option can be useful when feeding doxygen a huge amount of | |
46 | # source files, where putting all generated files in the same directory would | |
47 | # otherwise cause performance problems for the file system. | |
62 | # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- | |
63 | # directories (in 2 levels) under the output directory of each output format and | |
64 | # will distribute the generated files over these directories. Enabling this | |
65 | # option can be useful when feeding doxygen a huge amount of source files, where | |
66 | # putting all generated files in the same directory would otherwise causes | |
67 | # performance problems for the file system. | |
68 | # The default value is: NO. | |
48 | 69 | |
49 | 70 | CREATE_SUBDIRS = NO |
71 | ||
72 | # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII | |
73 | # characters to appear in the names of generated files. If set to NO, non-ASCII | |
74 | # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode | |
75 | # U+3044. | |
76 | # The default value is: NO. | |
77 | ||
78 | ALLOW_UNICODE_NAMES = NO | |
50 | 79 | |
51 | 80 | # The OUTPUT_LANGUAGE tag is used to specify the language in which all |
52 | 81 | # documentation generated by doxygen is written. Doxygen will use this |
53 | 82 | # information to generate all constant output in the proper language. |
54 | # The default language is English, other supported languages are: | |
55 | # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, | |
56 | # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, | |
57 | # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English | |
58 | # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, | |
59 | # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, | |
60 | # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. | |
83 | # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, | |
84 | # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), | |
85 | # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, | |
86 | # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), | |
87 | # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, | |
88 | # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, | |
89 | # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, | |
90 | # Ukrainian and Vietnamese. | |
91 | # The default value is: English. | |
61 | 92 | |
62 | 93 | OUTPUT_LANGUAGE = English |
63 | 94 | |
64 | # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will | |
65 | # include brief member descriptions after the members that are listed in | |
66 | # the file and class documentation (similar to JavaDoc). | |
67 | # Set to NO to disable this. | |
95 | # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member | |
96 | # descriptions after the members that are listed in the file and class | |
97 | # documentation (similar to Javadoc). Set to NO to disable this. | |
98 | # The default value is: YES. | |
68 | 99 | |
69 | 100 | BRIEF_MEMBER_DESC = YES |
70 | 101 | |
71 | # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend | |
72 | # the brief description of a member or function before the detailed description. | |
73 | # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the | |
102 | # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief | |
103 | # description of a member or function before the detailed description | |
104 | # | |
105 | # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the | |
74 | 106 | # brief descriptions will be completely suppressed. |
107 | # The default value is: YES. | |
75 | 108 | |
76 | 109 | REPEAT_BRIEF = YES |
77 | 110 | |
78 | # This tag implements a quasi-intelligent brief description abbreviator | |
79 | # that is used to form the text in various listings. Each string | |
80 | # in this list, if found as the leading text of the brief description, will be | |
81 | # stripped from the text and the result after processing the whole list, is | |
82 | # used as the annotated text. Otherwise, the brief description is used as-is. | |
83 | # If left blank, the following values are used ("$name" is automatically | |
84 | # replaced with the name of the entity): "The $name class" "The $name widget" | |
85 | # "The $name file" "is" "provides" "specifies" "contains" | |
86 | # "represents" "a" "an" "the" | |
111 | # This tag implements a quasi-intelligent brief description abbreviator that is | |
112 | # used to form the text in various listings. Each string in this list, if found | |
113 | # as the leading text of the brief description, will be stripped from the text | |
114 | # and the result, after processing the whole list, is used as the annotated | |
115 | # text. Otherwise, the brief description is used as-is. If left blank, the | |
116 | # following values are used ($name is automatically replaced with the name of | |
117 | # the entity):The $name class, The $name widget, The $name file, is, provides, | |
118 | # specifies, contains, represents, a, an and the. | |
87 | 119 | |
88 | 120 | ABBREVIATE_BRIEF = "The $name class" \ |
89 | 121 | "The $name widget" \ |
98 | 130 | the |
99 | 131 | |
100 | 132 | # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then |
101 | # Doxygen will generate a detailed section even if there is only a brief | |
133 | # doxygen will generate a detailed section even if there is only a brief | |
102 | 134 | # description. |
135 | # The default value is: NO. | |
103 | 136 | |
104 | 137 | ALWAYS_DETAILED_SEC = NO |
105 | 138 | |
107 | 140 | # inherited members of a class in the documentation of that class as if those |
108 | 141 | # members were ordinary class members. Constructors, destructors and assignment |
109 | 142 | # operators of the base classes will not be shown. |
143 | # The default value is: NO. | |
110 | 144 | |
111 | 145 | INLINE_INHERITED_MEMB = NO |
112 | 146 | |
113 | # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full | |
114 | # path before files name in the file list and in the header files. If set | |
115 | # to NO the shortest path that makes the file name unique will be used. | |
147 | # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path | |
148 | # before files name in the file list and in the header files. If set to NO the | |
149 | # shortest path that makes the file name unique will be used | |
150 | # The default value is: YES. | |
116 | 151 | |
117 | 152 | FULL_PATH_NAMES = NO |
118 | 153 | |
119 | # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag | |
120 | # can be used to strip a user-defined part of the path. Stripping is | |
121 | # only done if one of the specified strings matches the left-hand part of | |
122 | # the path. The tag can be used to show relative paths in the file list. | |
123 | # If left blank the directory from which doxygen is run is used as the | |
124 | # path to strip. | |
154 | # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. | |
155 | # Stripping is only done if one of the specified strings matches the left-hand | |
156 | # part of the path. The tag can be used to show relative paths in the file list. | |
157 | # If left blank the directory from which doxygen is run is used as the path to | |
158 | # strip. | |
159 | # | |
160 | # Note that you can specify absolute paths here, but also relative paths, which | |
161 | # will be relative from the directory where doxygen is started. | |
162 | # This tag requires that the tag FULL_PATH_NAMES is set to YES. | |
125 | 163 | |
126 | 164 | STRIP_FROM_PATH = |
127 | 165 | |
128 | # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of | |
129 | # the path mentioned in the documentation of a class, which tells | |
130 | # the reader which header file to include in order to use a class. | |
131 | # If left blank only the name of the header file containing the class | |
132 | # definition is used. Otherwise one should specify the include paths that | |
133 | # are normally passed to the compiler using the -I flag. | |
166 | # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the | |
167 | # path mentioned in the documentation of a class, which tells the reader which | |
168 | # header file to include in order to use a class. If left blank only the name of | |
169 | # the header file containing the class definition is used. Otherwise one should | |
170 | # specify the list of include paths that are normally passed to the compiler | |
171 | # using the -I flag. | |
134 | 172 | |
135 | 173 | STRIP_FROM_INC_PATH = |
136 | 174 | |
137 | # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter | |
138 | # (but less readable) file names. This can be useful is your file systems | |
139 | # doesn't support long names like on DOS, Mac, or CD-ROM. | |
175 | # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but | |
176 | # less readable) file names. This can be useful is your file systems doesn't | |
177 | # support long names like on DOS, Mac, or CD-ROM. | |
178 | # The default value is: NO. | |
140 | 179 | |
141 | 180 | SHORT_NAMES = NO |
142 | 181 | |
143 | # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen | |
144 | # will interpret the first line (until the first dot) of a JavaDoc-style | |
145 | # comment as the brief description. If set to NO, the JavaDoc | |
146 | # comments will behave just like regular Qt-style comments | |
147 | # (thus requiring an explicit @brief command for a brief description.) | |
182 | # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the | |
183 | # first line (until the first dot) of a Javadoc-style comment as the brief | |
184 | # description. If set to NO, the Javadoc-style will behave just like regular Qt- | |
185 | # style comments (thus requiring an explicit @brief command for a brief | |
186 | # description.) | |
187 | # The default value is: NO. | |
148 | 188 | |
149 | 189 | JAVADOC_AUTOBRIEF = NO |
150 | 190 | |
151 | # If the QT_AUTOBRIEF tag is set to YES then Doxygen will | |
152 | # interpret the first line (until the first dot) of a Qt-style | |
153 | # comment as the brief description. If set to NO, the comments | |
154 | # will behave just like regular Qt-style comments (thus requiring | |
155 | # an explicit \brief command for a brief description.) | |
191 | # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first | |
192 | # line (until the first dot) of a Qt-style comment as the brief description. If | |
193 | # set to NO, the Qt-style will behave just like regular Qt-style comments (thus | |
194 | # requiring an explicit \brief command for a brief description.) | |
195 | # The default value is: NO. | |
156 | 196 | |
157 | 197 | QT_AUTOBRIEF = NO |
158 | 198 | |
159 | # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen | |
160 | # treat a multi-line C++ special comment block (i.e. a block of //! or /// | |
161 | # comments) as a brief description. This used to be the default behaviour. | |
162 | # The new default is to treat a multi-line C++ comment block as a detailed | |
163 | # description. Set this tag to YES if you prefer the old behaviour instead. | |
199 | # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a | |
200 | # multi-line C++ special comment block (i.e. a block of //! or /// comments) as | |
201 | # a brief description. This used to be the default behavior. The new default is | |
202 | # to treat a multi-line C++ comment block as a detailed description. Set this | |
203 | # tag to YES if you prefer the old behavior instead. | |
204 | # | |
205 | # Note that setting this tag to YES also means that rational rose comments are | |
206 | # not recognized any more. | |
207 | # The default value is: NO. | |
164 | 208 | |
165 | 209 | MULTILINE_CPP_IS_BRIEF = NO |
166 | 210 | |
167 | # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented | |
168 | # member inherits the documentation from any documented member that it | |
169 | # re-implements. | |
211 | # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the | |
212 | # documentation from any documented member that it re-implements. | |
213 | # The default value is: YES. | |
170 | 214 | |
171 | 215 | INHERIT_DOCS = YES |
172 | 216 | |
173 | # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce | |
174 | # a new page for each member. If set to NO, the documentation of a member will | |
175 | # be part of the file/class/namespace that contains it. | |
217 | # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new | |
218 | # page for each member. If set to NO, the documentation of a member will be part | |
219 | # of the file/class/namespace that contains it. | |
220 | # The default value is: NO. | |
176 | 221 | |
177 | 222 | SEPARATE_MEMBER_PAGES = NO |
178 | 223 | |
179 | # The TAB_SIZE tag can be used to set the number of spaces in a tab. | |
180 | # Doxygen uses this value to replace tabs by spaces in code fragments. | |
224 | # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen | |
225 | # uses this value to replace tabs by spaces in code fragments. | |
226 | # Minimum value: 1, maximum value: 16, default value: 4. | |
181 | 227 | |
182 | 228 | TAB_SIZE = 2 |
183 | 229 | |
184 | # This tag can be used to specify a number of aliases that acts | |
185 | # as commands in the documentation. An alias has the form "name=value". | |
186 | # For example adding "sideeffect=\par Side Effects:\n" will allow you to | |
187 | # put the command \sideeffect (or @sideeffect) in the documentation, which | |
188 | # will result in a user-defined paragraph with heading "Side Effects:". | |
189 | # You can put \n's in the value part of an alias to insert newlines. | |
230 | # This tag can be used to specify a number of aliases that act as commands in | |
231 | # the documentation. An alias has the form: | |
232 | # name=value | |
233 | # For example adding | |
234 | # "sideeffect=@par Side Effects:\n" | |
235 | # will allow you to put the command \sideeffect (or @sideeffect) in the | |
236 | # documentation, which will result in a user-defined paragraph with heading | |
237 | # "Side Effects:". You can put \n's in the value part of an alias to insert | |
238 | # newlines. | |
190 | 239 | |
191 | 240 | ALIASES = |
192 | 241 | |
193 | # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C | |
194 | # sources only. Doxygen will then generate output that is more tailored for C. | |
195 | # For instance, some of the names that are used will be different. The list | |
196 | # of all members will be omitted, etc. | |
242 | # This tag can be used to specify a number of word-keyword mappings (TCL only). | |
243 | # A mapping has the form "name=value". For example adding "class=itcl::class" | |
244 | # will allow you to use the command class in the itcl::class meaning. | |
245 | ||
246 | TCL_SUBST = | |
247 | ||
248 | # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources | |
249 | # only. Doxygen will then generate output that is more tailored for C. For | |
250 | # instance, some of the names that are used will be different. The list of all | |
251 | # members will be omitted, etc. | |
252 | # The default value is: NO. | |
197 | 253 | |
198 | 254 | OPTIMIZE_OUTPUT_FOR_C = YES |
199 | 255 | |
200 | # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java | |
201 | # sources only. Doxygen will then generate output that is more tailored for | |
202 | # Java. For instance, namespaces will be presented as packages, qualified | |
203 | # scopes will look different, etc. | |
256 | # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or | |
257 | # Python sources only. Doxygen will then generate output that is more tailored | |
258 | # for that language. For instance, namespaces will be presented as packages, | |
259 | # qualified scopes will look different, etc. | |
260 | # The default value is: NO. | |
204 | 261 | |
205 | 262 | OPTIMIZE_OUTPUT_JAVA = NO |
206 | 263 | |
207 | 264 | # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran |
208 | # sources only. Doxygen will then generate output that is more tailored for | |
209 | # Fortran. | |
265 | # sources. Doxygen will then generate output that is tailored for Fortran. | |
266 | # The default value is: NO. | |
210 | 267 | |
211 | 268 | OPTIMIZE_FOR_FORTRAN = NO |
212 | 269 | |
213 | 270 | # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL |
214 | # sources. Doxygen will then generate output that is tailored for | |
215 | # VHDL. | |
271 | # sources. Doxygen will then generate output that is tailored for VHDL. | |
272 | # The default value is: NO. | |
216 | 273 | |
217 | 274 | OPTIMIZE_OUTPUT_VHDL = NO |
218 | 275 | |
219 | # Doxygen selects the parser to use depending on the extension of the files it parses. | |
220 | # With this tag you can assign which parser to use for a given extension. | |
221 | # Doxygen has a built-in mapping, but you can override or extend it using this tag. | |
222 | # The format is ext=language, where ext is a file extension, and language is one of | |
223 | # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, | |
224 | # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat | |
225 | # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), | |
226 | # use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. | |
276 | # Doxygen selects the parser to use depending on the extension of the files it | |
277 | # parses. With this tag you can assign which parser to use for a given | |
278 | # extension. Doxygen has a built-in mapping, but you can override or extend it | |
279 | # using this tag. The format is ext=language, where ext is a file extension, and | |
280 | # language is one of the parsers supported by doxygen: IDL, Java, Javascript, | |
281 | # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: | |
282 | # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: | |
283 | # Fortran. In the later case the parser tries to guess whether the code is fixed | |
284 | # or free formatted code, this is the default for Fortran type files), VHDL. For | |
285 | # instance to make doxygen treat .inc files as Fortran files (default is PHP), | |
286 | # and .f files as C (default is Fortran), use: inc=Fortran f=C. | |
287 | # | |
288 | # Note: For files without extension you can use no_extension as a placeholder. | |
289 | # | |
290 | # Note that for custom extensions you also need to set FILE_PATTERNS otherwise | |
291 | # the files are not read by doxygen. | |
227 | 292 | |
228 | 293 | EXTENSION_MAPPING = |
229 | 294 | |
295 | # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments | |
296 | # according to the Markdown format, which allows for more readable | |
297 | # documentation. See http://daringfireball.net/projects/markdown/ for details. | |
298 | # The output of markdown processing is further processed by doxygen, so you can | |
299 | # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in | |
300 | # case of backward compatibilities issues. | |
301 | # The default value is: YES. | |
302 | ||
303 | MARKDOWN_SUPPORT = YES | |
304 | ||
305 | # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up | |
306 | # to that level are automatically included in the table of contents, even if | |
307 | # they do not have an id attribute. | |
308 | # Note: This feature currently applies only to Markdown headings. | |
309 | # Minimum value: 0, maximum value: 99, default value: 0. | |
310 | # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. | |
311 | ||
312 | TOC_INCLUDE_HEADINGS = 0 | |
313 | ||
314 | # When enabled doxygen tries to link words that correspond to documented | |
315 | # classes, or namespaces to their corresponding documentation. Such a link can | |
316 | # be prevented in individual cases by putting a % sign in front of the word or | |
317 | # globally by setting AUTOLINK_SUPPORT to NO. | |
318 | # The default value is: YES. | |
319 | ||
320 | AUTOLINK_SUPPORT = YES | |
321 | ||
230 | 322 | # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want |
231 | # to include (a tag file for) the STL sources as input, then you should | |
232 | # set this tag to YES in order to let doxygen match functions declarations and | |
233 | # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. | |
234 | # func(std::string) {}). This also make the inheritance and collaboration | |
323 | # to include (a tag file for) the STL sources as input, then you should set this | |
324 | # tag to YES in order to let doxygen match functions declarations and | |
325 | # definitions whose arguments contain STL classes (e.g. func(std::string); | |
326 | # versus func(std::string) {}). This also make the inheritance and collaboration | |
235 | 327 | # diagrams that involve STL classes more complete and accurate. |
328 | # The default value is: NO. | |
236 | 329 | |
237 | 330 | BUILTIN_STL_SUPPORT = NO |
238 | 331 | |
239 | 332 | # If you use Microsoft's C++/CLI language, you should set this option to YES to |
240 | 333 | # enable parsing support. |
334 | # The default value is: NO. | |
241 | 335 | |
242 | 336 | CPP_CLI_SUPPORT = NO |
243 | 337 | |
244 | # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. | |
245 | # Doxygen will parse them like normal C++ but will assume all classes use public | |
246 | # instead of private inheritance when no explicit protection keyword is present. | |
338 | # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: | |
339 | # http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen | |
340 | # will parse them like normal C++ but will assume all classes use public instead | |
341 | # of private inheritance when no explicit protection keyword is present. | |
342 | # The default value is: NO. | |
247 | 343 | |
248 | 344 | SIP_SUPPORT = NO |
249 | 345 | |
250 | # For Microsoft's IDL there are propget and propput attributes to indicate getter | |
251 | # and setter methods for a property. Setting this option to YES (the default) | |
252 | # will make doxygen to replace the get and set methods by a property in the | |
253 | # documentation. This will only work if the methods are indeed getting or | |
254 | # setting a simple type. If this is not the case, or you want to show the | |
255 | # methods anyway, you should set this option to NO. | |
346 | # For Microsoft's IDL there are propget and propput attributes to indicate | |
347 | # getter and setter methods for a property. Setting this option to YES will make | |
348 | # doxygen to replace the get and set methods by a property in the documentation. | |
349 | # This will only work if the methods are indeed getting or setting a simple | |
350 | # type. If this is not the case, or you want to show the methods anyway, you | |
351 | # should set this option to NO. | |
352 | # The default value is: YES. | |
256 | 353 | |
257 | 354 | IDL_PROPERTY_SUPPORT = YES |
258 | 355 | |
259 | 356 | # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC |
260 | # tag is set to YES, then doxygen will reuse the documentation of the first | |
357 | # tag is set to YES then doxygen will reuse the documentation of the first | |
261 | 358 | # member in the group (if any) for the other members of the group. By default |
262 | 359 | # all members of a group must be documented explicitly. |
360 | # The default value is: NO. | |
263 | 361 | |
264 | 362 | DISTRIBUTE_GROUP_DOC = NO |
265 | 363 | |
266 | # Set the SUBGROUPING tag to YES (the default) to allow class member groups of | |
267 | # the same type (for instance a group of public functions) to be put as a | |
268 | # subgroup of that type (e.g. under the Public Functions section). Set it to | |
269 | # NO to prevent subgrouping. Alternatively, this can be done per class using | |
270 | # the \nosubgrouping command. | |
364 | # If one adds a struct or class to a group and this option is enabled, then also | |
365 | # any nested class or struct is added to the same group. By default this option | |
366 | # is disabled and one has to add nested compounds explicitly via \ingroup. | |
367 | # The default value is: NO. | |
368 | ||
369 | GROUP_NESTED_COMPOUNDS = NO | |
370 | ||
371 | # Set the SUBGROUPING tag to YES to allow class member groups of the same type | |
372 | # (for instance a group of public functions) to be put as a subgroup of that | |
373 | # type (e.g. under the Public Functions section). Set it to NO to prevent | |
374 | # subgrouping. Alternatively, this can be done per class using the | |
375 | # \nosubgrouping command. | |
376 | # The default value is: YES. | |
271 | 377 | |
272 | 378 | SUBGROUPING = YES |
273 | 379 | |
274 | # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum | |
275 | # is documented as struct, union, or enum with the name of the typedef. So | |
380 | # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions | |
381 | # are shown inside the group in which they are included (e.g. using \ingroup) | |
382 | # instead of on a separate page (for HTML and Man pages) or section (for LaTeX | |
383 | # and RTF). | |
384 | # | |
385 | # Note that this feature does not work in combination with | |
386 | # SEPARATE_MEMBER_PAGES. | |
387 | # The default value is: NO. | |
388 | ||
389 | INLINE_GROUPED_CLASSES = NO | |
390 | ||
391 | # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions | |
392 | # with only public data fields or simple typedef fields will be shown inline in | |
393 | # the documentation of the scope in which they are defined (i.e. file, | |
394 | # namespace, or group documentation), provided this scope is documented. If set | |
395 | # to NO, structs, classes, and unions are shown on a separate page (for HTML and | |
396 | # Man pages) or section (for LaTeX and RTF). | |
397 | # The default value is: NO. | |
398 | ||
399 | INLINE_SIMPLE_STRUCTS = NO | |
400 | ||
401 | # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or | |
402 | # enum is documented as struct, union, or enum with the name of the typedef. So | |
276 | 403 | # typedef struct TypeS {} TypeT, will appear in the documentation as a struct |
277 | 404 | # with name TypeT. When disabled the typedef will appear as a member of a file, |
278 | # namespace, or class. And the struct will be named TypeS. This can typically | |
279 | # be useful for C code in case the coding convention dictates that all compound | |
405 | # namespace, or class. And the struct will be named TypeS. This can typically be | |
406 | # useful for C code in case the coding convention dictates that all compound | |
280 | 407 | # types are typedef'ed and only the typedef is referenced, never the tag name. |
408 | # The default value is: NO. | |
281 | 409 | |
282 | 410 | TYPEDEF_HIDES_STRUCT = NO |
283 | 411 | |
284 | # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to | |
285 | # determine which symbols to keep in memory and which to flush to disk. | |
286 | # When the cache is full, less often used symbols will be written to disk. | |
287 | # For small to medium size projects (<1000 input files) the default value is | |
288 | # probably good enough. For larger projects a too small cache size can cause | |
289 | # doxygen to be busy swapping symbols to and from disk most of the time | |
290 | # causing a significant performance penality. | |
291 | # If the system has enough physical memory increasing the cache will improve the | |
292 | # performance by keeping more symbols in memory. Note that the value works on | |
293 | # a logarithmic scale so increasing the size by one will rougly double the | |
294 | # memory usage. The cache size is given by this formula: | |
295 | # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, | |
296 | # corresponding to a cache size of 2^16 = 65536 symbols | |
297 | ||
298 | SYMBOL_CACHE_SIZE = 0 | |
412 | # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This | |
413 | # cache is used to resolve symbols given their name and scope. Since this can be | |
414 | # an expensive process and often the same symbol appears multiple times in the | |
415 | # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small | |
416 | # doxygen will become slower. If the cache is too large, memory is wasted. The | |
417 | # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range | |
418 | # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 | |
419 | # symbols. At the end of a run doxygen will report the cache usage and suggest | |
420 | # the optimal cache size from a speed point of view. | |
421 | # Minimum value: 0, maximum value: 9, default value: 0. | |
422 | ||
423 | LOOKUP_CACHE_SIZE = 0 | |
299 | 424 | |
300 | 425 | #--------------------------------------------------------------------------- |
301 | 426 | # Build related configuration options |
302 | 427 | #--------------------------------------------------------------------------- |
303 | 428 | |
304 | # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in | |
305 | # documentation are documented, even if no documentation was available. | |
306 | # Private class members and static file members will be hidden unless | |
307 | # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES | |
429 | # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in | |
430 | # documentation are documented, even if no documentation was available. Private | |
431 | # class members and static file members will be hidden unless the | |
432 | # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. | |
433 | # Note: This will also disable the warnings about undocumented members that are | |
434 | # normally produced when WARNINGS is set to YES. | |
435 | # The default value is: NO. | |
308 | 436 | |
309 | 437 | EXTRACT_ALL = NO |
310 | 438 | |
311 | # If the EXTRACT_PRIVATE tag is set to YES all private members of a class | |
312 | # will be included in the documentation. | |
439 | # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will | |
440 | # be included in the documentation. | |
441 | # The default value is: NO. | |
313 | 442 | |
314 | 443 | EXTRACT_PRIVATE = NO |
315 | 444 | |
316 | # If the EXTRACT_STATIC tag is set to YES all static members of a file | |
317 | # will be included in the documentation. | |
445 | # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal | |
446 | # scope will be included in the documentation. | |
447 | # The default value is: NO. | |
448 | ||
449 | EXTRACT_PACKAGE = NO | |
450 | ||
451 | # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be | |
452 | # included in the documentation. | |
453 | # The default value is: NO. | |
318 | 454 | |
319 | 455 | EXTRACT_STATIC = YES |
320 | 456 | |
321 | # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) | |
322 | # defined locally in source files will be included in the documentation. | |
323 | # If set to NO only classes defined in header files are included. | |
457 | # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined | |
458 | # locally in source files will be included in the documentation. If set to NO, | |
459 | # only classes defined in header files are included. Does not have any effect | |
460 | # for Java sources. | |
461 | # The default value is: YES. | |
324 | 462 | |
325 | 463 | EXTRACT_LOCAL_CLASSES = YES |
326 | 464 | |
327 | # This flag is only useful for Objective-C code. When set to YES local | |
328 | # methods, which are defined in the implementation section but not in | |
329 | # the interface are included in the documentation. | |
330 | # If set to NO (the default) only methods in the interface are included. | |
465 | # This flag is only useful for Objective-C code. If set to YES, local methods, | |
466 | # which are defined in the implementation section but not in the interface are | |
467 | # included in the documentation. If set to NO, only methods in the interface are | |
468 | # included. | |
469 | # The default value is: NO. | |
331 | 470 | |
332 | 471 | EXTRACT_LOCAL_METHODS = NO |
333 | 472 | |
334 | 473 | # If this flag is set to YES, the members of anonymous namespaces will be |
335 | 474 | # extracted and appear in the documentation as a namespace called |
336 | # 'anonymous_namespace{file}', where file will be replaced with the base | |
337 | # name of the file that contains the anonymous namespace. By default | |
338 | # anonymous namespace are hidden. | |
475 | # 'anonymous_namespace{file}', where file will be replaced with the base name of | |
476 | # the file that contains the anonymous namespace. By default anonymous namespace | |
477 | # are hidden. | |
478 | # The default value is: NO. | |
339 | 479 | |
340 | 480 | EXTRACT_ANON_NSPACES = NO |
341 | 481 | |
342 | # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all | |
343 | # undocumented members of documented classes, files or namespaces. | |
344 | # If set to NO (the default) these members will be included in the | |
345 | # various overviews, but no documentation section is generated. | |
346 | # This option has no effect if EXTRACT_ALL is enabled. | |
482 | # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all | |
483 | # undocumented members inside documented classes or files. If set to NO these | |
484 | # members will be included in the various overviews, but no documentation | |
485 | # section is generated. This option has no effect if EXTRACT_ALL is enabled. | |
486 | # The default value is: NO. | |
347 | 487 | |
348 | 488 | HIDE_UNDOC_MEMBERS = YES |
349 | 489 | |
350 | # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all | |
351 | # undocumented classes that are normally visible in the class hierarchy. | |
352 | # If set to NO (the default) these classes will be included in the various | |
353 | # overviews. This option has no effect if EXTRACT_ALL is enabled. | |
490 | # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all | |
491 | # undocumented classes that are normally visible in the class hierarchy. If set | |
492 | # to NO, these classes will be included in the various overviews. This option | |
493 | # has no effect if EXTRACT_ALL is enabled. | |
494 | # The default value is: NO. | |
354 | 495 | |
355 | 496 | HIDE_UNDOC_CLASSES = YES |
356 | 497 | |
357 | # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all | |
358 | # friend (class|struct|union) declarations. | |
359 | # If set to NO (the default) these declarations will be included in the | |
360 | # documentation. | |
498 | # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend | |
499 | # (class|struct|union) declarations. If set to NO, these declarations will be | |
500 | # included in the documentation. | |
501 | # The default value is: NO. | |
361 | 502 | |
362 | 503 | HIDE_FRIEND_COMPOUNDS = YES |
363 | 504 | |
364 | # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any | |
365 | # documentation blocks found inside the body of a function. | |
366 | # If set to NO (the default) these blocks will be appended to the | |
367 | # function's detailed documentation block. | |
505 | # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any | |
506 | # documentation blocks found inside the body of a function. If set to NO, these | |
507 | # blocks will be appended to the function's detailed documentation block. | |
508 | # The default value is: NO. | |
368 | 509 | |
369 | 510 | HIDE_IN_BODY_DOCS = NO |
370 | 511 | |
371 | # The INTERNAL_DOCS tag determines if documentation | |
372 | # that is typed after a \internal command is included. If the tag is set | |
373 | # to NO (the default) then the documentation will be excluded. | |
374 | # Set it to YES to include the internal documentation. | |
512 | # The INTERNAL_DOCS tag determines if documentation that is typed after a | |
513 | # \internal command is included. If the tag is set to NO then the documentation | |
514 | # will be excluded. Set it to YES to include the internal documentation. | |
515 | # The default value is: NO. | |
375 | 516 | |
376 | 517 | INTERNAL_DOCS = NO |
377 | 518 | |
378 | # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate | |
379 | # file names in lower-case letters. If set to YES upper-case letters are also | |
519 | # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file | |
520 | # names in lower-case letters. If set to YES, upper-case letters are also | |
380 | 521 | # allowed. This is useful if you have classes or files whose names only differ |
381 | 522 | # in case and if your file system supports case sensitive file names. Windows |
382 | 523 | # and Mac users are advised to set this option to NO. |
524 | # The default value is: system dependent. | |
383 | 525 | |
384 | 526 | CASE_SENSE_NAMES = YES |
385 | 527 | |
386 | # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen | |
387 | # will show members with their full class and namespace scopes in the | |
388 | # documentation. If set to YES the scope will be hidden. | |
528 | # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with | |
529 | # their full class and namespace scopes in the documentation. If set to YES, the | |
530 | # scope will be hidden. | |
531 | # The default value is: NO. | |
389 | 532 | |
390 | 533 | HIDE_SCOPE_NAMES = NO |
391 | 534 | |
392 | # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen | |
393 | # will put a list of the files that are included by a file in the documentation | |
394 | # of that file. | |
535 | # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will | |
536 | # append additional text to a page's title, such as Class Reference. If set to | |
537 | # YES the compound reference will be hidden. | |
538 | # The default value is: NO. | |
539 | ||
540 | HIDE_COMPOUND_REFERENCE= NO | |
541 | ||
542 | # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of | |
543 | # the files that are included by a file in the documentation of that file. | |
544 | # The default value is: YES. | |
395 | 545 | |
396 | 546 | SHOW_INCLUDE_FILES = YES |
397 | 547 | |
398 | # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] | |
399 | # is inserted in the documentation for inline members. | |
548 | # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each | |
549 | # grouped member an include statement to the documentation, telling the reader | |
550 | # which file to include in order to use the member. | |
551 | # The default value is: NO. | |
552 | ||
553 | SHOW_GROUPED_MEMB_INC = NO | |
554 | ||
555 | # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include | |
556 | # files with double quotes in the documentation rather than with sharp brackets. | |
557 | # The default value is: NO. | |
558 | ||
559 | FORCE_LOCAL_INCLUDES = NO | |
560 | ||
561 | # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the | |
562 | # documentation for inline members. | |
563 | # The default value is: YES. | |
400 | 564 | |
401 | 565 | INLINE_INFO = YES |
402 | 566 | |
403 | # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen | |
404 | # will sort the (detailed) documentation of file and class members | |
405 | # alphabetically by member name. If set to NO the members will appear in | |
406 | # declaration order. | |
567 | # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the | |
568 | # (detailed) documentation of file and class members alphabetically by member | |
569 | # name. If set to NO, the members will appear in declaration order. | |
570 | # The default value is: YES. | |
407 | 571 | |
408 | 572 | SORT_MEMBER_DOCS = YES |
409 | 573 | |
410 | # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the | |
411 | # brief documentation of file, namespace and class members alphabetically | |
412 | # by member name. If set to NO (the default) the members will appear in | |
413 | # declaration order. | |
574 | # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief | |
575 | # descriptions of file, namespace and class members alphabetically by member | |
576 | # name. If set to NO, the members will appear in declaration order. Note that | |
577 | # this will also influence the order of the classes in the class list. | |
578 | # The default value is: NO. | |
414 | 579 | |
415 | 580 | SORT_BRIEF_DOCS = NO |
416 | 581 | |
417 | # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. | |
582 | # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the | |
583 | # (brief and detailed) documentation of class members so that constructors and | |
584 | # destructors are listed first. If set to NO the constructors will appear in the | |
585 | # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. | |
586 | # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief | |
587 | # member documentation. | |
588 | # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting | |
589 | # detailed member documentation. | |
590 | # The default value is: NO. | |
418 | 591 | |
419 | 592 | SORT_MEMBERS_CTORS_1ST = NO |
420 | 593 | |
421 | # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the | |
422 | # hierarchy of group names into alphabetical order. If set to NO (the default) | |
423 | # the group names will appear in their defined order. | |
594 | # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy | |
595 | # of group names into alphabetical order. If set to NO the group names will | |
596 | # appear in their defined order. | |
597 | # The default value is: NO. | |
424 | 598 | |
425 | 599 | SORT_GROUP_NAMES = NO |
426 | 600 | |
427 | # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be | |
428 | # sorted by fully-qualified names, including namespaces. If set to | |
429 | # NO (the default), the class list will be sorted only by class name, | |
430 | # not including the namespace part. | |
601 | # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by | |
602 | # fully-qualified names, including namespaces. If set to NO, the class list will | |
603 | # be sorted only by class name, not including the namespace part. | |
431 | 604 | # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. |
432 | # Note: This option applies only to the class list, not to the | |
433 | # alphabetical list. | |
605 | # Note: This option applies only to the class list, not to the alphabetical | |
606 | # list. | |
607 | # The default value is: NO. | |
434 | 608 | |
435 | 609 | SORT_BY_SCOPE_NAME = NO |
436 | 610 | |
437 | # The GENERATE_TODOLIST tag can be used to enable (YES) or | |
438 | # disable (NO) the todo list. This list is created by putting \todo | |
439 | # commands in the documentation. | |
611 | # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper | |
612 | # type resolution of all parameters of a function it will reject a match between | |
613 | # the prototype and the implementation of a member function even if there is | |
614 | # only one candidate or it is obvious which candidate to choose by doing a | |
615 | # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still | |
616 | # accept a match between prototype and implementation in such cases. | |
617 | # The default value is: NO. | |
618 | ||
619 | STRICT_PROTO_MATCHING = NO | |
620 | ||
621 | # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo | |
622 | # list. This list is created by putting \todo commands in the documentation. | |
623 | # The default value is: YES. | |
440 | 624 | |
441 | 625 | GENERATE_TODOLIST = YES |
442 | 626 | |
443 | # The GENERATE_TESTLIST tag can be used to enable (YES) or | |
444 | # disable (NO) the test list. This list is created by putting \test | |
445 | # commands in the documentation. | |
627 | # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test | |
628 | # list. This list is created by putting \test commands in the documentation. | |
629 | # The default value is: YES. | |
446 | 630 | |
447 | 631 | GENERATE_TESTLIST = YES |
448 | 632 | |
449 | # The GENERATE_BUGLIST tag can be used to enable (YES) or | |
450 | # disable (NO) the bug list. This list is created by putting \bug | |
451 | # commands in the documentation. | |
633 | # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug | |
634 | # list. This list is created by putting \bug commands in the documentation. | |
635 | # The default value is: YES. | |
452 | 636 | |
453 | 637 | GENERATE_BUGLIST = YES |
454 | 638 | |
455 | # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or | |
456 | # disable (NO) the deprecated list. This list is created by putting | |
457 | # \deprecated commands in the documentation. | |
639 | # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) | |
640 | # the deprecated list. This list is created by putting \deprecated commands in | |
641 | # the documentation. | |
642 | # The default value is: YES. | |
458 | 643 | |
459 | 644 | GENERATE_DEPRECATEDLIST= YES |
460 | 645 | |
461 | # The ENABLED_SECTIONS tag can be used to enable conditional | |
462 | # documentation sections, marked by \if sectionname ... \endif. | |
646 | # The ENABLED_SECTIONS tag can be used to enable conditional documentation | |
647 | # sections, marked by \if <section_label> ... \endif and \cond <section_label> | |
648 | # ... \endcond blocks. | |
463 | 649 | |
464 | 650 | ENABLED_SECTIONS = |
465 | 651 | |
466 | # The MAX_INITIALIZER_LINES tag determines the maximum number of lines | |
467 | # the initial value of a variable or define consists of for it to appear in | |
468 | # the documentation. If the initializer consists of more lines than specified | |
469 | # here it will be hidden. Use a value of 0 to hide initializers completely. | |
470 | # The appearance of the initializer of individual variables and defines in the | |
471 | # documentation can be controlled using \showinitializer or \hideinitializer | |
472 | # command in the documentation regardless of this setting. | |
652 | # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the | |
653 | # initial value of a variable or macro / define can have for it to appear in the | |
654 | # documentation. If the initializer consists of more lines than specified here | |
655 | # it will be hidden. Use a value of 0 to hide initializers completely. The | |
656 | # appearance of the value of individual variables and macros / defines can be | |
657 | # controlled using \showinitializer or \hideinitializer command in the | |
658 | # documentation regardless of this setting. | |
659 | # Minimum value: 0, maximum value: 10000, default value: 30. | |
473 | 660 | |
474 | 661 | MAX_INITIALIZER_LINES = 30 |
475 | 662 | |
476 | # Set the SHOW_USED_FILES tag to NO to disable the list of files generated | |
477 | # at the bottom of the documentation of classes and structs. If set to YES the | |
663 | # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at | |
664 | # the bottom of the documentation of classes and structs. If set to YES, the | |
478 | 665 | # list will mention the files that were used to generate the documentation. |
666 | # The default value is: YES. | |
479 | 667 | |
480 | 668 | SHOW_USED_FILES = YES |
481 | 669 | |
482 | # If the sources in your project are distributed over multiple directories | |
483 | # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy | |
484 | # in the documentation. The default is NO. | |
485 | ||
486 | SHOW_DIRECTORIES = YES | |
487 | ||
488 | # Set the SHOW_FILES tag to NO to disable the generation of the Files page. | |
489 | # This will remove the Files entry from the Quick Index and from the | |
490 | # Folder Tree View (if specified). The default is YES. | |
670 | # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This | |
671 | # will remove the Files entry from the Quick Index and from the Folder Tree View | |
672 | # (if specified). | |
673 | # The default value is: YES. | |
491 | 674 | |
492 | 675 | SHOW_FILES = YES |
493 | 676 | |
494 | # Set the SHOW_NAMESPACES tag to NO to disable the generation of the | |
495 | # Namespaces page. | |
496 | # This will remove the Namespaces entry from the Quick Index | |
497 | # and from the Folder Tree View (if specified). The default is YES. | |
677 | # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces | |
678 | # page. This will remove the Namespaces entry from the Quick Index and from the | |
679 | # Folder Tree View (if specified). | |
680 | # The default value is: YES. | |
498 | 681 | |
499 | 682 | SHOW_NAMESPACES = YES |
500 | 683 | |
501 | 684 | # The FILE_VERSION_FILTER tag can be used to specify a program or script that |
502 | 685 | # doxygen should invoke to get the current version for each file (typically from |
503 | 686 | # the version control system). Doxygen will invoke the program by executing (via |
504 | # popen()) the command <command> <input-file>, where <command> is the value of | |
505 | # the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file | |
506 | # provided by doxygen. Whatever the program writes to standard output | |
507 | # is used as the file version. See the manual for examples. | |
687 | # popen()) the command command input-file, where command is the value of the | |
688 | # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided | |
689 | # by doxygen. Whatever the program writes to standard output is used as the file | |
690 | # version. For an example see the documentation. | |
508 | 691 | |
509 | 692 | FILE_VERSION_FILTER = |
510 | 693 | |
511 | # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by | |
512 | # doxygen. The layout file controls the global structure of the generated output files | |
513 | # in an output format independent way. The create the layout file that represents | |
514 | # doxygen's defaults, run doxygen with the -l option. You can optionally specify a | |
515 | # file name after the option, if omitted DoxygenLayout.xml will be used as the name | |
516 | # of the layout file. | |
694 | # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed | |
695 | # by doxygen. The layout file controls the global structure of the generated | |
696 | # output files in an output format independent way. To create the layout file | |
697 | # that represents doxygen's defaults, run doxygen with the -l option. You can | |
698 | # optionally specify a file name after the option, if omitted DoxygenLayout.xml | |
699 | # will be used as the name of the layout file. | |
700 | # | |
701 | # Note that if you run doxygen from a directory containing a file called | |
702 | # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE | |
703 | # tag is left empty. | |
517 | 704 | |
518 | 705 | LAYOUT_FILE = |
519 | 706 | |
520 | #--------------------------------------------------------------------------- | |
521 | # configuration options related to warning and progress messages | |
522 | #--------------------------------------------------------------------------- | |
523 | ||
524 | # The QUIET tag can be used to turn on/off the messages that are generated | |
525 | # by doxygen. Possible values are YES and NO. If left blank NO is used. | |
707 | # The CITE_BIB_FILES tag can be used to specify one or more bib files containing | |
708 | # the reference definitions. This must be a list of .bib files. The .bib | |
709 | # extension is automatically appended if omitted. This requires the bibtex tool | |
710 | # to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. | |
711 | # For LaTeX the style of the bibliography can be controlled using | |
712 | # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the | |
713 | # search path. See also \cite for info how to create references. | |
714 | ||
715 | CITE_BIB_FILES = | |
716 | ||
717 | #--------------------------------------------------------------------------- | |
718 | # Configuration options related to warning and progress messages | |
719 | #--------------------------------------------------------------------------- | |
720 | ||
721 | # The QUIET tag can be used to turn on/off the messages that are generated to | |
722 | # standard output by doxygen. If QUIET is set to YES this implies that the | |
723 | # messages are off. | |
724 | # The default value is: NO. | |
526 | 725 | |
527 | 726 | QUIET = NO |
528 | 727 | |
529 | 728 | # The WARNINGS tag can be used to turn on/off the warning messages that are |
530 | # generated by doxygen. Possible values are YES and NO. If left blank | |
531 | # NO is used. | |
729 | # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES | |
730 | # this implies that the warnings are on. | |
731 | # | |
732 | # Tip: Turn warnings on while writing the documentation. | |
733 | # The default value is: YES. | |
532 | 734 | |
533 | 735 | WARNINGS = YES |
534 | 736 | |
535 | # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings | |
536 | # for undocumented members. If EXTRACT_ALL is set to YES then this flag will | |
537 | # automatically be disabled. | |
737 | # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate | |
738 | # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag | |
739 | # will automatically be disabled. | |
740 | # The default value is: YES. | |
538 | 741 | |
539 | 742 | WARN_IF_UNDOCUMENTED = YES |
540 | 743 | |
541 | # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for | |
542 | # potential errors in the documentation, such as not documenting some | |
543 | # parameters in a documented function, or documenting parameters that | |
544 | # don't exist or using markup commands wrongly. | |
744 | # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for | |
745 | # potential errors in the documentation, such as not documenting some parameters | |
746 | # in a documented function, or documenting parameters that don't exist or using | |
747 | # markup commands wrongly. | |
748 | # The default value is: YES. | |
545 | 749 | |
546 | 750 | WARN_IF_DOC_ERROR = YES |
547 | 751 | |
548 | # This WARN_NO_PARAMDOC option can be abled to get warnings for | |
549 | # functions that are documented, but have no documentation for their parameters | |
550 | # or return value. If set to NO (the default) doxygen will only warn about | |
551 | # wrong or incomplete parameter documentation, but not about the absence of | |
552 | # documentation. | |
752 | # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that | |
753 | # are documented, but have no documentation for their parameters or return | |
754 | # value. If set to NO, doxygen will only warn about wrong or incomplete | |
755 | # parameter documentation, but not about the absence of documentation. | |
756 | # The default value is: NO. | |
553 | 757 | |
554 | 758 | WARN_NO_PARAMDOC = NO |
555 | 759 | |
556 | # The WARN_FORMAT tag determines the format of the warning messages that | |
557 | # doxygen can produce. The string should contain the $file, $line, and $text | |
558 | # tags, which will be replaced by the file and line number from which the | |
559 | # warning originated and the warning text. Optionally the format may contain | |
560 | # $version, which will be replaced by the version of the file (if it could | |
561 | # be obtained via FILE_VERSION_FILTER) | |
760 | # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when | |
761 | # a warning is encountered. | |
762 | # The default value is: NO. | |
763 | ||
764 | WARN_AS_ERROR = NO | |
765 | ||
766 | # The WARN_FORMAT tag determines the format of the warning messages that doxygen | |
767 | # can produce. The string should contain the $file, $line, and $text tags, which | |
768 | # will be replaced by the file and line number from which the warning originated | |
769 | # and the warning text. Optionally the format may contain $version, which will | |
770 | # be replaced by the version of the file (if it could be obtained via | |
771 | # FILE_VERSION_FILTER) | |
772 | # The default value is: $file:$line: $text. | |
562 | 773 | |
563 | 774 | WARN_FORMAT = "$file:$line: $text" |
564 | 775 | |
565 | # The WARN_LOGFILE tag can be used to specify a file to which warning | |
566 | # and error messages should be written. If left blank the output is written | |
567 | # to stderr. | |
776 | # The WARN_LOGFILE tag can be used to specify a file to which warning and error | |
777 | # messages should be written. If left blank the output is written to standard | |
778 | # error (stderr). | |
568 | 779 | |
569 | 780 | WARN_LOGFILE = Doxygen.log |
570 | 781 | |
571 | 782 | #--------------------------------------------------------------------------- |
572 | # configuration options related to the input files | |
573 | #--------------------------------------------------------------------------- | |
574 | ||
575 | # The INPUT tag can be used to specify the files and/or directories that contain | |
576 | # documented source files. You may enter file names like "myfile.cpp" or | |
577 | # directories like "/usr/src/myproject". Separate the files or directories | |
578 | # with spaces. | |
579 | ||
580 | INPUT = @top_srcdir@/libnfc @top_srcdir@/examples @top_srcdir@/include/nfc @top_srcdir@/utils | |
783 | # Configuration options related to the input files | |
784 | #--------------------------------------------------------------------------- | |
785 | ||
786 | # The INPUT tag is used to specify the files and/or directories that contain | |
787 | # documented source files. You may enter file names like myfile.cpp or | |
788 | # directories like /usr/src/myproject. Separate the files or directories with | |
789 | # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING | |
790 | # Note: If this tag is empty the current directory is searched. | |
791 | ||
792 | INPUT = @top_srcdir@/libnfc \ | |
793 | @top_srcdir@/examples \ | |
794 | @top_srcdir@/include/nfc \ | |
795 | @top_srcdir@/utils | |
581 | 796 | |
582 | 797 | # This tag can be used to specify the character encoding of the source files |
583 | # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is | |
584 | # also the default input encoding. Doxygen uses libiconv (or the iconv built | |
585 | # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for | |
586 | # the list of possible encodings. | |
798 | # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses | |
799 | # libiconv (or the iconv built into libc) for the transcoding. See the libiconv | |
800 | # documentation (see: http://www.gnu.org/software/libiconv) for the list of | |
801 | # possible encodings. | |
802 | # The default value is: UTF-8. | |
587 | 803 | |
588 | 804 | INPUT_ENCODING = UTF-8 |
589 | 805 | |
590 | 806 | # If the value of the INPUT tag contains directories, you can use the |
591 | # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp | |
592 | # and *.h) to filter out the source-files in the directories. If left | |
593 | # blank the following patterns are tested: | |
594 | # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx | |
595 | # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 | |
807 | # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and | |
808 | # *.h) to filter out the source-files in the directories. | |
809 | # | |
810 | # Note that for custom extensions or not directly supported extensions you also | |
811 | # need to set EXTENSION_MAPPING for the extension otherwise the files are not | |
812 | # read by doxygen. | |
813 | # | |
814 | # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, | |
815 | # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, | |
816 | # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, | |
817 | # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, | |
818 | # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. | |
596 | 819 | |
597 | 820 | FILE_PATTERNS = *.c \ |
598 | 821 | *.h \ |
599 | 822 | *.dox |
600 | 823 | |
601 | # The RECURSIVE tag can be used to turn specify whether or not subdirectories | |
602 | # should be searched for input files as well. Possible values are YES and NO. | |
603 | # If left blank NO is used. | |
824 | # The RECURSIVE tag can be used to specify whether or not subdirectories should | |
825 | # be searched for input files as well. | |
826 | # The default value is: NO. | |
604 | 827 | |
605 | 828 | RECURSIVE = NO |
606 | 829 | |
607 | # The EXCLUDE tag can be used to specify files and/or directories that should | |
830 | # The EXCLUDE tag can be used to specify files and/or directories that should be | |
608 | 831 | # excluded from the INPUT source files. This way you can easily exclude a |
609 | 832 | # subdirectory from a directory tree whose root is specified with the INPUT tag. |
833 | # | |
834 | # Note that relative paths are relative to the directory from which doxygen is | |
835 | # run. | |
610 | 836 | |
611 | 837 | EXCLUDE = @top_srcdir@/libnfc/drivers.h \ |
612 | 838 | @top_srcdir@/libnfc/iso14443-subr.c \ |
614 | 840 | @top_srcdir@/libnfc/log-printf.c \ |
615 | 841 | @top_srcdir@/libnfc/log.h \ |
616 | 842 | @top_srcdir@/libnfc/mirror-subrc.c \ |
617 | @top_srcdir@/libnfc/mirror-subrc.h \ | |
618 | ||
619 | # The EXCLUDE_SYMLINKS tag can be used select whether or not files or | |
620 | # directories that are symbolic links (a Unix filesystem feature) are excluded | |
843 | @top_srcdir@/libnfc/mirror-subrc.h | |
844 | ||
845 | # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or | |
846 | # directories that are symbolic links (a Unix file system feature) are excluded | |
621 | 847 | # from the input. |
848 | # The default value is: NO. | |
622 | 849 | |
623 | 850 | EXCLUDE_SYMLINKS = NO |
624 | 851 | |
625 | 852 | # If the value of the INPUT tag contains directories, you can use the |
626 | 853 | # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude |
627 | # certain files from those directories. Note that the wildcards are matched | |
628 | # against the file with absolute path, so to exclude all test directories | |
629 | # for example use the pattern */test/* | |
854 | # certain files from those directories. | |
855 | # | |
856 | # Note that the wildcards are matched against the file with absolute path, so to | |
857 | # exclude all test directories for example use the pattern */test/* | |
630 | 858 | |
631 | 859 | EXCLUDE_PATTERNS = .git/* |
632 | 860 | |
635 | 863 | # output. The symbol name can be a fully qualified name, a word, or if the |
636 | 864 | # wildcard * is used, a substring. Examples: ANamespace, AClass, |
637 | 865 | # AClass::ANamespace, ANamespace::*Test |
866 | # | |
867 | # Note that the wildcards are matched against the file with absolute path, so to | |
868 | # exclude all test directories use the pattern */test/* | |
638 | 869 | |
639 | 870 | EXCLUDE_SYMBOLS = |
640 | 871 | |
641 | # The EXAMPLE_PATH tag can be used to specify one or more files or | |
642 | # directories that contain example code fragments that are included (see | |
643 | # the \include command). | |
872 | # The EXAMPLE_PATH tag can be used to specify one or more files or directories | |
873 | # that contain example code fragments that are included (see the \include | |
874 | # command). | |
644 | 875 | |
645 | 876 | EXAMPLE_PATH = @top_srcdir@/ \ |
646 | 877 | @top_srcdir@/src/examples/doc |
647 | 878 | |
648 | 879 | # If the value of the EXAMPLE_PATH tag contains directories, you can use the |
649 | # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp | |
650 | # and *.h) to filter out the source-files in the directories. If left | |
651 | # blank all files are included. | |
880 | # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and | |
881 | # *.h) to filter out the source-files in the directories. If left blank all | |
882 | # files are included. | |
652 | 883 | |
653 | 884 | EXAMPLE_PATTERNS = ChangeLog \ |
654 | 885 | *.c |
655 | 886 | |
656 | 887 | # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be |
657 | # searched for input files to be used with the \include or \dontinclude | |
658 | # commands irrespective of the value of the RECURSIVE tag. | |
659 | # Possible values are YES and NO. If left blank NO is used. | |
888 | # searched for input files to be used with the \include or \dontinclude commands | |
889 | # irrespective of the value of the RECURSIVE tag. | |
890 | # The default value is: NO. | |
660 | 891 | |
661 | 892 | EXAMPLE_RECURSIVE = NO |
662 | 893 | |
663 | # The IMAGE_PATH tag can be used to specify one or more files or | |
664 | # directories that contain image that are included in the documentation (see | |
665 | # the \image command). | |
894 | # The IMAGE_PATH tag can be used to specify one or more files or directories | |
895 | # that contain images that are to be included in the documentation (see the | |
896 | # \image command). | |
666 | 897 | |
667 | 898 | IMAGE_PATH = |
668 | 899 | |
669 | 900 | # The INPUT_FILTER tag can be used to specify a program that doxygen should |
670 | 901 | # invoke to filter for each input file. Doxygen will invoke the filter program |
671 | # by executing (via popen()) the command <filter> <input-file>, where <filter> | |
672 | # is the value of the INPUT_FILTER tag, and <input-file> is the name of an | |
673 | # input file. Doxygen will then use the output that the filter program writes | |
674 | # to standard output. | |
675 | # If FILTER_PATTERNS is specified, this tag will be | |
676 | # ignored. | |
902 | # by executing (via popen()) the command: | |
903 | # | |
904 | # <filter> <input-file> | |
905 | # | |
906 | # where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the | |
907 | # name of an input file. Doxygen will then use the output that the filter | |
908 | # program writes to standard output. If FILTER_PATTERNS is specified, this tag | |
909 | # will be ignored. | |
910 | # | |
911 | # Note that the filter must not add or remove lines; it is applied before the | |
912 | # code is scanned, but not when the output code is generated. If lines are added | |
913 | # or removed, the anchors will not be placed correctly. | |
914 | # | |
915 | # Note that for custom extensions or not directly supported extensions you also | |
916 | # need to set EXTENSION_MAPPING for the extension otherwise the files are not | |
917 | # properly processed by doxygen. | |
677 | 918 | |
678 | 919 | INPUT_FILTER = |
679 | 920 | |
680 | 921 | # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern |
681 | # basis. | |
682 | # Doxygen will compare the file name with each pattern and apply the | |
683 | # filter if there is a match. | |
684 | # The filters are a list of the form: | |
685 | # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further | |
686 | # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER | |
687 | # is applied to all files. | |
922 | # basis. Doxygen will compare the file name with each pattern and apply the | |
923 | # filter if there is a match. The filters are a list of the form: pattern=filter | |
924 | # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how | |
925 | # filters are used. If the FILTER_PATTERNS tag is empty or if none of the | |
926 | # patterns match the file name, INPUT_FILTER is applied. | |
927 | # | |
928 | # Note that for custom extensions or not directly supported extensions you also | |
929 | # need to set EXTENSION_MAPPING for the extension otherwise the files are not | |
930 | # properly processed by doxygen. | |
688 | 931 | |
689 | 932 | FILTER_PATTERNS = |
690 | 933 | |
691 | 934 | # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using |
692 | # INPUT_FILTER) will be used to filter the input files when producing source | |
693 | # files to browse (i.e. when SOURCE_BROWSER is set to YES). | |
935 | # INPUT_FILTER) will also be used to filter the input files that are used for | |
936 | # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). | |
937 | # The default value is: NO. | |
694 | 938 | |
695 | 939 | FILTER_SOURCE_FILES = NO |
696 | 940 | |
697 | #--------------------------------------------------------------------------- | |
698 | # configuration options related to source browsing | |
699 | #--------------------------------------------------------------------------- | |
700 | ||
701 | # If the SOURCE_BROWSER tag is set to YES then a list of source files will | |
702 | # be generated. Documented entities will be cross-referenced with these sources. | |
703 | # Note: To get rid of all source code in the generated output, make sure also | |
704 | # VERBATIM_HEADERS is set to NO. | |
941 | # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file | |
942 | # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and | |
943 | # it is also possible to disable source filtering for a specific pattern using | |
944 | # *.ext= (so without naming a filter). | |
945 | # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. | |
946 | ||
947 | FILTER_SOURCE_PATTERNS = | |
948 | ||
949 | # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that | |
950 | # is part of the input, its contents will be placed on the main page | |
951 | # (index.html). This can be useful if you have a project on for instance GitHub | |
952 | # and want to reuse the introduction page also for the doxygen output. | |
953 | ||
954 | USE_MDFILE_AS_MAINPAGE = | |
955 | ||
956 | #--------------------------------------------------------------------------- | |
957 | # Configuration options related to source browsing | |
958 | #--------------------------------------------------------------------------- | |
959 | ||
960 | # If the SOURCE_BROWSER tag is set to YES then a list of source files will be | |
961 | # generated. Documented entities will be cross-referenced with these sources. | |
962 | # | |
963 | # Note: To get rid of all source code in the generated output, make sure that | |
964 | # also VERBATIM_HEADERS is set to NO. | |
965 | # The default value is: NO. | |
705 | 966 | |
706 | 967 | SOURCE_BROWSER = YES |
707 | 968 | |
708 | # Setting the INLINE_SOURCES tag to YES will include the body | |
709 | # of functions and classes directly in the documentation. | |
969 | # Setting the INLINE_SOURCES tag to YES will include the body of functions, | |
970 | # classes and enums directly into the documentation. | |
971 | # The default value is: NO. | |
710 | 972 | |
711 | 973 | INLINE_SOURCES = NO |
712 | 974 | |
713 | # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct | |
714 | # doxygen to hide any special comment blocks from generated source code | |
715 | # fragments. Normal C and C++ comments will always remain visible. | |
975 | # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any | |
976 | # special comment blocks from generated source code fragments. Normal C, C++ and | |
977 | # Fortran comments will always remain visible. | |
978 | # The default value is: YES. | |
716 | 979 | |
717 | 980 | STRIP_CODE_COMMENTS = YES |
718 | 981 | |
719 | # If the REFERENCED_BY_RELATION tag is set to YES | |
720 | # then for each documented function all documented | |
721 | # functions referencing it will be listed. | |
982 | # If the REFERENCED_BY_RELATION tag is set to YES then for each documented | |
983 | # function all documented functions referencing it will be listed. | |
984 | # The default value is: NO. | |
722 | 985 | |
723 | 986 | REFERENCED_BY_RELATION = NO |
724 | 987 | |
725 | # If the REFERENCES_RELATION tag is set to YES | |
726 | # then for each documented function all documented entities | |
727 | # called/used by that function will be listed. | |
988 | # If the REFERENCES_RELATION tag is set to YES then for each documented function | |
989 | # all documented entities called/used by that function will be listed. | |
990 | # The default value is: NO. | |
728 | 991 | |
729 | 992 | REFERENCES_RELATION = NO |
730 | 993 | |
731 | # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) | |
732 | # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from | |
733 | # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will | |
734 | # link to the source code. | |
735 | # Otherwise they will link to the documentation. | |
994 | # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set | |
995 | # to YES then the hyperlinks from functions in REFERENCES_RELATION and | |
996 | # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will | |
997 | # link to the documentation. | |
998 | # The default value is: YES. | |
736 | 999 | |
737 | 1000 | REFERENCES_LINK_SOURCE = YES |
738 | 1001 | |
739 | # If the USE_HTAGS tag is set to YES then the references to source code | |
740 | # will point to the HTML generated by the htags(1) tool instead of doxygen | |
741 | # built-in source browser. The htags tool is part of GNU's global source | |
742 | # tagging system (see http://www.gnu.org/software/global/global.html). You | |
743 | # will need version 4.8.6 or higher. | |
1002 | # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the | |
1003 | # source code will show a tooltip with additional information such as prototype, | |
1004 | # brief description and links to the definition and documentation. Since this | |
1005 | # will make the HTML file larger and loading of large files a bit slower, you | |
1006 | # can opt to disable this feature. | |
1007 | # The default value is: YES. | |
1008 | # This tag requires that the tag SOURCE_BROWSER is set to YES. | |
1009 | ||
1010 | SOURCE_TOOLTIPS = YES | |
1011 | ||
1012 | # If the USE_HTAGS tag is set to YES then the references to source code will | |
1013 | # point to the HTML generated by the htags(1) tool instead of doxygen built-in | |
1014 | # source browser. The htags tool is part of GNU's global source tagging system | |
1015 | # (see http://www.gnu.org/software/global/global.html). You will need version | |
1016 | # 4.8.6 or higher. | |
1017 | # | |
1018 | # To use it do the following: | |
1019 | # - Install the latest version of global | |
1020 | # - Enable SOURCE_BROWSER and USE_HTAGS in the config file | |
1021 | # - Make sure the INPUT points to the root of the source tree | |
1022 | # - Run doxygen as normal | |
1023 | # | |
1024 | # Doxygen will invoke htags (and that will in turn invoke gtags), so these | |
1025 | # tools must be available from the command line (i.e. in the search path). | |
1026 | # | |
1027 | # The result: instead of the source browser generated by doxygen, the links to | |
1028 | # source code will now point to the output of htags. | |
1029 | # The default value is: NO. | |
1030 | # This tag requires that the tag SOURCE_BROWSER is set to YES. | |
744 | 1031 | |
745 | 1032 | USE_HTAGS = NO |
746 | 1033 | |
747 | # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen | |
748 | # will generate a verbatim copy of the header file for each class for | |
749 | # which an include is specified. Set to NO to disable this. | |
1034 | # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a | |
1035 | # verbatim copy of the header file for each class for which an include is | |
1036 | # specified. Set to NO to disable this. | |
1037 | # See also: Section \class. | |
1038 | # The default value is: YES. | |
750 | 1039 | |
751 | 1040 | VERBATIM_HEADERS = YES |
752 | 1041 | |
753 | #--------------------------------------------------------------------------- | |
754 | # configuration options related to the alphabetical class index | |
755 | #--------------------------------------------------------------------------- | |
756 | ||
757 | # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index | |
758 | # of all compounds will be generated. Enable this if the project | |
759 | # contains a lot of classes, structs, unions or interfaces. | |
1042 | # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the | |
1043 | # clang parser (see: http://clang.llvm.org/) for more accurate parsing at the | |
1044 | # cost of reduced performance. This can be particularly helpful with template | |
1045 | # rich C++ code for which doxygen's built-in parser lacks the necessary type | |
1046 | # information. | |
1047 | # Note: The availability of this option depends on whether or not doxygen was | |
1048 | # generated with the -Duse-libclang=ON option for CMake. | |
1049 | # The default value is: NO. | |
1050 | ||
1051 | CLANG_ASSISTED_PARSING = NO | |
1052 | ||
1053 | # If clang assisted parsing is enabled you can provide the compiler with command | |
1054 | # line options that you would normally use when invoking the compiler. Note that | |
1055 | # the include paths will already be set by doxygen for the files and directories | |
1056 | # specified with INPUT and INCLUDE_PATH. | |
1057 | # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. | |
1058 | ||
1059 | CLANG_OPTIONS = | |
1060 | ||
1061 | #--------------------------------------------------------------------------- | |
1062 | # Configuration options related to the alphabetical class index | |
1063 | #--------------------------------------------------------------------------- | |
1064 | ||
1065 | # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all | |
1066 | # compounds will be generated. Enable this if the project contains a lot of | |
1067 | # classes, structs, unions or interfaces. | |
1068 | # The default value is: YES. | |
760 | 1069 | |
761 | 1070 | ALPHABETICAL_INDEX = NO |
762 | 1071 | |
763 | # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then | |
764 | # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns | |
765 | # in which this list will be split (can be a number in the range [1..20]) | |
1072 | # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in | |
1073 | # which the alphabetical index list will be split. | |
1074 | # Minimum value: 1, maximum value: 20, default value: 5. | |
1075 | # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. | |
766 | 1076 | |
767 | 1077 | COLS_IN_ALPHA_INDEX = 5 |
768 | 1078 | |
769 | # In case all classes in a project start with a common prefix, all | |
770 | # classes will be put under the same header in the alphabetical index. | |
771 | # The IGNORE_PREFIX tag can be used to specify one or more prefixes that | |
772 | # should be ignored while generating the index headers. | |
1079 | # In case all classes in a project start with a common prefix, all classes will | |
1080 | # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag | |
1081 | # can be used to specify a prefix (or a list of prefixes) that should be ignored | |
1082 | # while generating the index headers. | |
1083 | # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. | |
773 | 1084 | |
774 | 1085 | IGNORE_PREFIX = |
775 | 1086 | |
776 | 1087 | #--------------------------------------------------------------------------- |
777 | # configuration options related to the HTML output | |
778 | #--------------------------------------------------------------------------- | |
779 | ||
780 | # If the GENERATE_HTML tag is set to YES (the default) Doxygen will | |
781 | # generate HTML output. | |
1088 | # Configuration options related to the HTML output | |
1089 | #--------------------------------------------------------------------------- | |
1090 | ||
1091 | # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output | |
1092 | # The default value is: YES. | |
782 | 1093 | |
783 | 1094 | GENERATE_HTML = YES |
784 | 1095 | |
785 | # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. | |
786 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be | |
787 | # put in front of it. If left blank `html' will be used as the default path. | |
1096 | # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a | |
1097 | # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1098 | # it. | |
1099 | # The default directory is: html. | |
1100 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
788 | 1101 | |
789 | 1102 | HTML_OUTPUT = html |
790 | 1103 | |
791 | # The HTML_FILE_EXTENSION tag can be used to specify the file extension for | |
792 | # each generated HTML page (for example: .htm,.php,.asp). If it is left blank | |
793 | # doxygen will generate files with .html extension. | |
1104 | # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each | |
1105 | # generated HTML page (for example: .htm, .php, .asp). | |
1106 | # The default value is: .html. | |
1107 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
794 | 1108 | |
795 | 1109 | HTML_FILE_EXTENSION = .html |
796 | 1110 | |
797 | # The HTML_HEADER tag can be used to specify a personal HTML header for | |
798 | # each generated HTML page. If it is left blank doxygen will generate a | |
1111 | # The HTML_HEADER tag can be used to specify a user-defined HTML header file for | |
1112 | # each generated HTML page. If the tag is left blank doxygen will generate a | |
799 | 1113 | # standard header. |
1114 | # | |
1115 | # To get valid HTML the header file that includes any scripts and style sheets | |
1116 | # that doxygen needs, which is dependent on the configuration options used (e.g. | |
1117 | # the setting GENERATE_TREEVIEW). It is highly recommended to start with a | |
1118 | # default header using | |
1119 | # doxygen -w html new_header.html new_footer.html new_stylesheet.css | |
1120 | # YourConfigFile | |
1121 | # and then modify the file new_header.html. See also section "Doxygen usage" | |
1122 | # for information on how to generate the default header that doxygen normally | |
1123 | # uses. | |
1124 | # Note: The header is subject to change so you typically have to regenerate the | |
1125 | # default header when upgrading to a newer version of doxygen. For a description | |
1126 | # of the possible markers and block names see the documentation. | |
1127 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
800 | 1128 | |
801 | 1129 | HTML_HEADER = |
802 | 1130 | |
803 | # The HTML_FOOTER tag can be used to specify a personal HTML footer for | |
804 | # each generated HTML page. If it is left blank doxygen will generate a | |
805 | # standard footer. | |
1131 | # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each | |
1132 | # generated HTML page. If the tag is left blank doxygen will generate a standard | |
1133 | # footer. See HTML_HEADER for more information on how to generate a default | |
1134 | # footer and what special commands can be used inside the footer. See also | |
1135 | # section "Doxygen usage" for information on how to generate the default footer | |
1136 | # that doxygen normally uses. | |
1137 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
806 | 1138 | |
807 | 1139 | HTML_FOOTER = |
808 | 1140 | |
809 | # The HTML_STYLESHEET tag can be used to specify a user-defined cascading | |
810 | # style sheet that is used by each HTML page. It can be used to | |
811 | # fine-tune the look of the HTML output. If the tag is left blank doxygen | |
812 | # will generate a default style sheet. Note that doxygen will try to copy | |
813 | # the style sheet file to the HTML output directory, so don't put your own | |
814 | # stylesheet in the HTML output directory as well, or it will be erased! | |
1141 | # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style | |
1142 | # sheet that is used by each HTML page. It can be used to fine-tune the look of | |
1143 | # the HTML output. If left blank doxygen will generate a default style sheet. | |
1144 | # See also section "Doxygen usage" for information on how to generate the style | |
1145 | # sheet that doxygen normally uses. | |
1146 | # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as | |
1147 | # it is more robust and this tag (HTML_STYLESHEET) will in the future become | |
1148 | # obsolete. | |
1149 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
815 | 1150 | |
816 | 1151 | HTML_STYLESHEET = |
817 | 1152 | |
818 | # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, | |
819 | # files or namespaces will be aligned in HTML using tables. If set to | |
820 | # NO a bullet list will be used. | |
821 | ||
822 | HTML_ALIGN_MEMBERS = YES | |
1153 | # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined | |
1154 | # cascading style sheets that are included after the standard style sheets | |
1155 | # created by doxygen. Using this option one can overrule certain style aspects. | |
1156 | # This is preferred over using HTML_STYLESHEET since it does not replace the | |
1157 | # standard style sheet and is therefore more robust against future updates. | |
1158 | # Doxygen will copy the style sheet files to the output directory. | |
1159 | # Note: The order of the extra style sheet files is of importance (e.g. the last | |
1160 | # style sheet in the list overrules the setting of the previous ones in the | |
1161 | # list). For an example see the documentation. | |
1162 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1163 | ||
1164 | HTML_EXTRA_STYLESHEET = | |
1165 | ||
1166 | # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or | |
1167 | # other source files which should be copied to the HTML output directory. Note | |
1168 | # that these files will be copied to the base HTML output directory. Use the | |
1169 | # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these | |
1170 | # files. In the HTML_STYLESHEET file, use the file name only. Also note that the | |
1171 | # files will be copied as-is; there are no commands or markers available. | |
1172 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1173 | ||
1174 | HTML_EXTRA_FILES = | |
1175 | ||
1176 | # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen | |
1177 | # will adjust the colors in the style sheet and background images according to | |
1178 | # this color. Hue is specified as an angle on a colorwheel, see | |
1179 | # http://en.wikipedia.org/wiki/Hue for more information. For instance the value | |
1180 | # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 | |
1181 | # purple, and 360 is red again. | |
1182 | # Minimum value: 0, maximum value: 359, default value: 220. | |
1183 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1184 | ||
1185 | HTML_COLORSTYLE_HUE = 220 | |
1186 | ||
1187 | # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors | |
1188 | # in the HTML output. For a value of 0 the output will use grayscales only. A | |
1189 | # value of 255 will produce the most vivid colors. | |
1190 | # Minimum value: 0, maximum value: 255, default value: 100. | |
1191 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1192 | ||
1193 | HTML_COLORSTYLE_SAT = 100 | |
1194 | ||
1195 | # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the | |
1196 | # luminance component of the colors in the HTML output. Values below 100 | |
1197 | # gradually make the output lighter, whereas values above 100 make the output | |
1198 | # darker. The value divided by 100 is the actual gamma applied, so 80 represents | |
1199 | # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not | |
1200 | # change the gamma. | |
1201 | # Minimum value: 40, maximum value: 240, default value: 80. | |
1202 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1203 | ||
1204 | HTML_COLORSTYLE_GAMMA = 80 | |
1205 | ||
1206 | # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML | |
1207 | # page will contain the date and time when the page was generated. Setting this | |
1208 | # to YES can help to show when doxygen was last run and thus if the | |
1209 | # documentation is up to date. | |
1210 | # The default value is: NO. | |
1211 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1212 | ||
1213 | HTML_TIMESTAMP = NO | |
823 | 1214 | |
824 | 1215 | # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML |
825 | 1216 | # documentation will contain sections that can be hidden and shown after the |
826 | # page has loaded. For this to work a browser that supports | |
827 | # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox | |
828 | # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). | |
1217 | # page has loaded. | |
1218 | # The default value is: NO. | |
1219 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
829 | 1220 | |
830 | 1221 | HTML_DYNAMIC_SECTIONS = NO |
831 | 1222 | |
832 | # If the GENERATE_DOCSET tag is set to YES, additional index files | |
833 | # will be generated that can be used as input for Apple's Xcode 3 | |
834 | # integrated development environment, introduced with OSX 10.5 (Leopard). | |
835 | # To create a documentation set, doxygen will generate a Makefile in the | |
836 | # HTML output directory. Running make will produce the docset in that | |
837 | # directory and running "make install" will install the docset in | |
838 | # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find | |
839 | # it at startup. | |
840 | # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. | |
1223 | # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries | |
1224 | # shown in the various tree structured indices initially; the user can expand | |
1225 | # and collapse entries dynamically later on. Doxygen will expand the tree to | |
1226 | # such a level that at most the specified number of entries are visible (unless | |
1227 | # a fully collapsed tree already exceeds this amount). So setting the number of | |
1228 | # entries 1 will produce a full collapsed tree by default. 0 is a special value | |
1229 | # representing an infinite number of entries and will result in a full expanded | |
1230 | # tree by default. | |
1231 | # Minimum value: 0, maximum value: 9999, default value: 100. | |
1232 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1233 | ||
1234 | HTML_INDEX_NUM_ENTRIES = 100 | |
1235 | ||
1236 | # If the GENERATE_DOCSET tag is set to YES, additional index files will be | |
1237 | # generated that can be used as input for Apple's Xcode 3 integrated development | |
1238 | # environment (see: http://developer.apple.com/tools/xcode/), introduced with | |
1239 | # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a | |
1240 | # Makefile in the HTML output directory. Running make will produce the docset in | |
1241 | # that directory and running make install will install the docset in | |
1242 | # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at | |
1243 | # startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html | |
1244 | # for more information. | |
1245 | # The default value is: NO. | |
1246 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
841 | 1247 | |
842 | 1248 | GENERATE_DOCSET = NO |
843 | 1249 | |
844 | # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the | |
845 | # feed. A documentation feed provides an umbrella under which multiple | |
846 | # documentation sets from a single provider (such as a company or product suite) | |
847 | # can be grouped. | |
1250 | # This tag determines the name of the docset feed. A documentation feed provides | |
1251 | # an umbrella under which multiple documentation sets from a single provider | |
1252 | # (such as a company or product suite) can be grouped. | |
1253 | # The default value is: Doxygen generated docs. | |
1254 | # This tag requires that the tag GENERATE_DOCSET is set to YES. | |
848 | 1255 | |
849 | 1256 | DOCSET_FEEDNAME = "Doxygen generated docs" |
850 | 1257 | |
851 | # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that | |
852 | # should uniquely identify the documentation set bundle. This should be a | |
853 | # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen | |
854 | # will append .docset to the name. | |
1258 | # This tag specifies a string that should uniquely identify the documentation | |
1259 | # set bundle. This should be a reverse domain-name style string, e.g. | |
1260 | # com.mycompany.MyDocSet. Doxygen will append .docset to the name. | |
1261 | # The default value is: org.doxygen.Project. | |
1262 | # This tag requires that the tag GENERATE_DOCSET is set to YES. | |
855 | 1263 | |
856 | 1264 | DOCSET_BUNDLE_ID = org.doxygen.Project |
857 | 1265 | |
858 | # If the GENERATE_HTMLHELP tag is set to YES, additional index files | |
859 | # will be generated that can be used as input for tools like the | |
860 | # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) | |
861 | # of the generated HTML documentation. | |
1266 | # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify | |
1267 | # the documentation publisher. This should be a reverse domain-name style | |
1268 | # string, e.g. com.mycompany.MyDocSet.documentation. | |
1269 | # The default value is: org.doxygen.Publisher. | |
1270 | # This tag requires that the tag GENERATE_DOCSET is set to YES. | |
1271 | ||
1272 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher | |
1273 | ||
1274 | # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. | |
1275 | # The default value is: Publisher. | |
1276 | # This tag requires that the tag GENERATE_DOCSET is set to YES. | |
1277 | ||
1278 | DOCSET_PUBLISHER_NAME = Publisher | |
1279 | ||
1280 | # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three | |
1281 | # additional HTML index files: index.hhp, index.hhc, and index.hhk. The | |
1282 | # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop | |
1283 | # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on | |
1284 | # Windows. | |
1285 | # | |
1286 | # The HTML Help Workshop contains a compiler that can convert all HTML output | |
1287 | # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML | |
1288 | # files are now used as the Windows 98 help format, and will replace the old | |
1289 | # Windows help format (.hlp) on all Windows platforms in the future. Compressed | |
1290 | # HTML files also contain an index, a table of contents, and you can search for | |
1291 | # words in the documentation. The HTML workshop also contains a viewer for | |
1292 | # compressed HTML files. | |
1293 | # The default value is: NO. | |
1294 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
862 | 1295 | |
863 | 1296 | GENERATE_HTMLHELP = NO |
864 | 1297 | |
865 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can | |
866 | # be used to specify the file name of the resulting .chm file. You | |
867 | # can add a path in front of the file if the result should not be | |
1298 | # The CHM_FILE tag can be used to specify the file name of the resulting .chm | |
1299 | # file. You can add a path in front of the file if the result should not be | |
868 | 1300 | # written to the html output directory. |
1301 | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
869 | 1302 | |
870 | 1303 | CHM_FILE = |
871 | 1304 | |
872 | # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can | |
873 | # be used to specify the location (absolute path including file name) of | |
874 | # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run | |
875 | # the HTML help compiler on the generated index.hhp. | |
1305 | # The HHC_LOCATION tag can be used to specify the location (absolute path | |
1306 | # including file name) of the HTML help compiler (hhc.exe). If non-empty, | |
1307 | # doxygen will try to run the HTML help compiler on the generated index.hhp. | |
1308 | # The file has to be specified with full path. | |
1309 | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
876 | 1310 | |
877 | 1311 | HHC_LOCATION = |
878 | 1312 | |
879 | # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag | |
880 | # controls if a separate .chi index file is generated (YES) or that | |
881 | # it should be included in the master .chm file (NO). | |
1313 | # The GENERATE_CHI flag controls if a separate .chi index file is generated | |
1314 | # (YES) or that it should be included in the master .chm file (NO). | |
1315 | # The default value is: NO. | |
1316 | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
882 | 1317 | |
883 | 1318 | GENERATE_CHI = NO |
884 | 1319 | |
885 | # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING | |
886 | # is used to encode HtmlHelp index (hhk), content (hhc) and project file | |
887 | # content. | |
1320 | # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) | |
1321 | # and project file content. | |
1322 | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
888 | 1323 | |
889 | 1324 | CHM_INDEX_ENCODING = |
890 | 1325 | |
891 | # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag | |
892 | # controls whether a binary table of contents is generated (YES) or a | |
893 | # normal table of contents (NO) in the .chm file. | |
1326 | # The BINARY_TOC flag controls whether a binary table of contents is generated | |
1327 | # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it | |
1328 | # enables the Previous and Next buttons. | |
1329 | # The default value is: NO. | |
1330 | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
894 | 1331 | |
895 | 1332 | BINARY_TOC = NO |
896 | 1333 | |
897 | # The TOC_EXPAND flag can be set to YES to add extra items for group members | |
898 | # to the contents of the HTML help documentation and to the tree view. | |
1334 | # The TOC_EXPAND flag can be set to YES to add extra items for group members to | |
1335 | # the table of contents of the HTML help documentation and to the tree view. | |
1336 | # The default value is: NO. | |
1337 | # This tag requires that the tag GENERATE_HTMLHELP is set to YES. | |
899 | 1338 | |
900 | 1339 | TOC_EXPAND = NO |
901 | 1340 | |
902 | # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER | |
903 | # are set, an additional index file will be generated that can be used as input for | |
904 | # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated | |
905 | # HTML documentation. | |
1341 | # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and | |
1342 | # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that | |
1343 | # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help | |
1344 | # (.qch) of the generated HTML documentation. | |
1345 | # The default value is: NO. | |
1346 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
906 | 1347 | |
907 | 1348 | GENERATE_QHP = NO |
908 | 1349 | |
909 | # If the QHG_LOCATION tag is specified, the QCH_FILE tag can | |
910 | # be used to specify the file name of the resulting .qch file. | |
911 | # The path specified is relative to the HTML output folder. | |
1350 | # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify | |
1351 | # the file name of the resulting .qch file. The path specified is relative to | |
1352 | # the HTML output folder. | |
1353 | # This tag requires that the tag GENERATE_QHP is set to YES. | |
912 | 1354 | |
913 | 1355 | QCH_FILE = |
914 | 1356 | |
915 | # The QHP_NAMESPACE tag specifies the namespace to use when generating | |
916 | # Qt Help Project output. For more information please see | |
917 | # http://doc.trolltech.com/qthelpproject.html#namespace | |
1357 | # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help | |
1358 | # Project output. For more information please see Qt Help Project / Namespace | |
1359 | # (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). | |
1360 | # The default value is: org.doxygen.Project. | |
1361 | # This tag requires that the tag GENERATE_QHP is set to YES. | |
918 | 1362 | |
919 | 1363 | QHP_NAMESPACE = |
920 | 1364 | |
921 | # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating | |
922 | # Qt Help Project output. For more information please see | |
923 | # http://doc.trolltech.com/qthelpproject.html#virtual-folders | |
1365 | # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt | |
1366 | # Help Project output. For more information please see Qt Help Project / Virtual | |
1367 | # Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- | |
1368 | # folders). | |
1369 | # The default value is: doc. | |
1370 | # This tag requires that the tag GENERATE_QHP is set to YES. | |
924 | 1371 | |
925 | 1372 | QHP_VIRTUAL_FOLDER = doc |
926 | 1373 | |
927 | # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. | |
928 | # For more information please see | |
929 | # http://doc.trolltech.com/qthelpproject.html#custom-filters | |
1374 | # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom | |
1375 | # filter to add. For more information please see Qt Help Project / Custom | |
1376 | # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- | |
1377 | # filters). | |
1378 | # This tag requires that the tag GENERATE_QHP is set to YES. | |
930 | 1379 | |
931 | 1380 | QHP_CUST_FILTER_NAME = |
932 | 1381 | |
933 | # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see | |
934 | # <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>. | |
1382 | # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the | |
1383 | # custom filter to add. For more information please see Qt Help Project / Custom | |
1384 | # Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- | |
1385 | # filters). | |
1386 | # This tag requires that the tag GENERATE_QHP is set to YES. | |
935 | 1387 | |
936 | 1388 | QHP_CUST_FILTER_ATTRS = |
937 | 1389 | |
938 | # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's | |
939 | # filter section matches. | |
940 | # <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>. | |
1390 | # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this | |
1391 | # project's filter section matches. Qt Help Project / Filter Attributes (see: | |
1392 | # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). | |
1393 | # This tag requires that the tag GENERATE_QHP is set to YES. | |
941 | 1394 | |
942 | 1395 | QHP_SECT_FILTER_ATTRS = |
943 | 1396 | |
944 | # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can | |
945 | # be used to specify the location of Qt's qhelpgenerator. | |
946 | # If non-empty doxygen will try to run qhelpgenerator on the generated | |
947 | # .qhp file. | |
1397 | # The QHG_LOCATION tag can be used to specify the location of Qt's | |
1398 | # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the | |
1399 | # generated .qhp file. | |
1400 | # This tag requires that the tag GENERATE_QHP is set to YES. | |
948 | 1401 | |
949 | 1402 | QHG_LOCATION = |
950 | 1403 | |
951 | # The DISABLE_INDEX tag can be used to turn on/off the condensed index at | |
952 | # top of each HTML page. The value NO (the default) enables the index and | |
953 | # the value YES disables it. | |
1404 | # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be | |
1405 | # generated, together with the HTML files, they form an Eclipse help plugin. To | |
1406 | # install this plugin and make it available under the help contents menu in | |
1407 | # Eclipse, the contents of the directory containing the HTML and XML files needs | |
1408 | # to be copied into the plugins directory of eclipse. The name of the directory | |
1409 | # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. | |
1410 | # After copying Eclipse needs to be restarted before the help appears. | |
1411 | # The default value is: NO. | |
1412 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1413 | ||
1414 | GENERATE_ECLIPSEHELP = NO | |
1415 | ||
1416 | # A unique identifier for the Eclipse help plugin. When installing the plugin | |
1417 | # the directory name containing the HTML and XML files should also have this | |
1418 | # name. Each documentation set should have its own identifier. | |
1419 | # The default value is: org.doxygen.Project. | |
1420 | # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. | |
1421 | ||
1422 | ECLIPSE_DOC_ID = org.doxygen.Project | |
1423 | ||
1424 | # If you want full control over the layout of the generated HTML pages it might | |
1425 | # be necessary to disable the index and replace it with your own. The | |
1426 | # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top | |
1427 | # of each HTML page. A value of NO enables the index and the value YES disables | |
1428 | # it. Since the tabs in the index contain the same information as the navigation | |
1429 | # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. | |
1430 | # The default value is: NO. | |
1431 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
954 | 1432 | |
955 | 1433 | DISABLE_INDEX = NO |
956 | 1434 | |
957 | # This tag can be used to set the number of enum values (range [1..20]) | |
958 | # that doxygen will group on one line in the generated HTML documentation. | |
1435 | # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index | |
1436 | # structure should be generated to display hierarchical information. If the tag | |
1437 | # value is set to YES, a side panel will be generated containing a tree-like | |
1438 | # index structure (just like the one that is generated for HTML Help). For this | |
1439 | # to work a browser that supports JavaScript, DHTML, CSS and frames is required | |
1440 | # (i.e. any modern browser). Windows users are probably better off using the | |
1441 | # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can | |
1442 | # further fine-tune the look of the index. As an example, the default style | |
1443 | # sheet generated by doxygen has an example that shows how to put an image at | |
1444 | # the root of the tree instead of the PROJECT_NAME. Since the tree basically has | |
1445 | # the same information as the tab index, you could consider setting | |
1446 | # DISABLE_INDEX to YES when enabling this option. | |
1447 | # The default value is: NO. | |
1448 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1449 | ||
1450 | GENERATE_TREEVIEW = NONE | |
1451 | ||
1452 | # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that | |
1453 | # doxygen will group on one line in the generated HTML documentation. | |
1454 | # | |
1455 | # Note that a value of 0 will completely suppress the enum values from appearing | |
1456 | # in the overview section. | |
1457 | # Minimum value: 0, maximum value: 20, default value: 4. | |
1458 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
959 | 1459 | |
960 | 1460 | ENUM_VALUES_PER_LINE = 4 |
961 | 1461 | |
962 | # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index | |
963 | # structure should be generated to display hierarchical information. | |
964 | # If the tag value is set to YES, a side panel will be generated | |
965 | # containing a tree-like index structure (just like the one that | |
966 | # is generated for HTML Help). For this to work a browser that supports | |
967 | # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). | |
968 | # Windows users are probably better off using the HTML help feature. | |
969 | ||
970 | GENERATE_TREEVIEW = NONE | |
971 | ||
972 | # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, | |
973 | # and Class Hierarchy pages using a tree view instead of an ordered list. | |
974 | ||
975 | USE_INLINE_TREES = NO | |
976 | ||
977 | # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be | |
978 | # used to set the initial width (in pixels) of the frame in which the tree | |
979 | # is shown. | |
1462 | # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used | |
1463 | # to set the initial width (in pixels) of the frame in which the tree is shown. | |
1464 | # Minimum value: 0, maximum value: 1500, default value: 250. | |
1465 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
980 | 1466 | |
981 | 1467 | TREEVIEW_WIDTH = 250 |
982 | 1468 | |
983 | # Use this tag to change the font size of Latex formulas included | |
984 | # as images in the HTML documentation. The default is 10. Note that | |
985 | # when you change the font size after a successful doxygen run you need | |
986 | # to manually remove any form_*.png images from the HTML output directory | |
987 | # to force them to be regenerated. | |
1469 | # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to | |
1470 | # external symbols imported via tag files in a separate window. | |
1471 | # The default value is: NO. | |
1472 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1473 | ||
1474 | EXT_LINKS_IN_WINDOW = NO | |
1475 | ||
1476 | # Use this tag to change the font size of LaTeX formulas included as images in | |
1477 | # the HTML documentation. When you change the font size after a successful | |
1478 | # doxygen run you need to manually remove any form_*.png images from the HTML | |
1479 | # output directory to force them to be regenerated. | |
1480 | # Minimum value: 8, maximum value: 50, default value: 10. | |
1481 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
988 | 1482 | |
989 | 1483 | FORMULA_FONTSIZE = 10 |
990 | 1484 | |
991 | # When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript | |
992 | # and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP) | |
993 | # there is already a search function so this one should typically | |
994 | # be disabled. | |
1485 | # Use the FORMULA_TRANPARENT tag to determine whether or not the images | |
1486 | # generated for formulas are transparent PNGs. Transparent PNGs are not | |
1487 | # supported properly for IE 6.0, but are supported on all modern browsers. | |
1488 | # | |
1489 | # Note that when changing this option you need to delete any form_*.png files in | |
1490 | # the HTML output directory before the changes have effect. | |
1491 | # The default value is: YES. | |
1492 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1493 | ||
1494 | FORMULA_TRANSPARENT = YES | |
1495 | ||
1496 | # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see | |
1497 | # http://www.mathjax.org) which uses client side Javascript for the rendering | |
1498 | # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX | |
1499 | # installed or if you want to formulas look prettier in the HTML output. When | |
1500 | # enabled you may also need to install MathJax separately and configure the path | |
1501 | # to it using the MATHJAX_RELPATH option. | |
1502 | # The default value is: NO. | |
1503 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
1504 | ||
1505 | USE_MATHJAX = NO | |
1506 | ||
1507 | # When MathJax is enabled you can set the default output format to be used for | |
1508 | # the MathJax output. See the MathJax site (see: | |
1509 | # http://docs.mathjax.org/en/latest/output.html) for more details. | |
1510 | # Possible values are: HTML-CSS (which is slower, but has the best | |
1511 | # compatibility), NativeMML (i.e. MathML) and SVG. | |
1512 | # The default value is: HTML-CSS. | |
1513 | # This tag requires that the tag USE_MATHJAX is set to YES. | |
1514 | ||
1515 | MATHJAX_FORMAT = HTML-CSS | |
1516 | ||
1517 | # When MathJax is enabled you need to specify the location relative to the HTML | |
1518 | # output directory using the MATHJAX_RELPATH option. The destination directory | |
1519 | # should contain the MathJax.js script. For instance, if the mathjax directory | |
1520 | # is located at the same level as the HTML output directory, then | |
1521 | # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax | |
1522 | # Content Delivery Network so you can quickly see the result without installing | |
1523 | # MathJax. However, it is strongly recommended to install a local copy of | |
1524 | # MathJax from http://www.mathjax.org before deployment. | |
1525 | # The default value is: http://cdn.mathjax.org/mathjax/latest. | |
1526 | # This tag requires that the tag USE_MATHJAX is set to YES. | |
1527 | ||
1528 | MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest | |
1529 | ||
1530 | # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax | |
1531 | # extension names that should be enabled during MathJax rendering. For example | |
1532 | # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols | |
1533 | # This tag requires that the tag USE_MATHJAX is set to YES. | |
1534 | ||
1535 | MATHJAX_EXTENSIONS = | |
1536 | ||
1537 | # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces | |
1538 | # of code that will be used on startup of the MathJax code. See the MathJax site | |
1539 | # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an | |
1540 | # example see the documentation. | |
1541 | # This tag requires that the tag USE_MATHJAX is set to YES. | |
1542 | ||
1543 | MATHJAX_CODEFILE = | |
1544 | ||
1545 | # When the SEARCHENGINE tag is enabled doxygen will generate a search box for | |
1546 | # the HTML output. The underlying search engine uses javascript and DHTML and | |
1547 | # should work on any modern browser. Note that when using HTML help | |
1548 | # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) | |
1549 | # there is already a search function so this one should typically be disabled. | |
1550 | # For large projects the javascript based search engine can be slow, then | |
1551 | # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to | |
1552 | # search using the keyboard; to jump to the search box use <access key> + S | |
1553 | # (what the <access key> is depends on the OS and browser, but it is typically | |
1554 | # <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down | |
1555 | # key> to jump into the search results window, the results can be navigated | |
1556 | # using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel | |
1557 | # the search. The filter options can be selected when the cursor is inside the | |
1558 | # search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys> | |
1559 | # to select a filter and <Enter> or <escape> to activate or cancel the filter | |
1560 | # option. | |
1561 | # The default value is: YES. | |
1562 | # This tag requires that the tag GENERATE_HTML is set to YES. | |
995 | 1563 | |
996 | 1564 | SEARCHENGINE = NO |
997 | 1565 | |
998 | #--------------------------------------------------------------------------- | |
999 | # configuration options related to the LaTeX output | |
1000 | #--------------------------------------------------------------------------- | |
1001 | ||
1002 | # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will | |
1003 | # generate Latex output. | |
1566 | # When the SERVER_BASED_SEARCH tag is enabled the search engine will be | |
1567 | # implemented using a web server instead of a web client using Javascript. There | |
1568 | # are two flavors of web server based searching depending on the EXTERNAL_SEARCH | |
1569 | # setting. When disabled, doxygen will generate a PHP script for searching and | |
1570 | # an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing | |
1571 | # and searching needs to be provided by external tools. See the section | |
1572 | # "External Indexing and Searching" for details. | |
1573 | # The default value is: NO. | |
1574 | # This tag requires that the tag SEARCHENGINE is set to YES. | |
1575 | ||
1576 | SERVER_BASED_SEARCH = NO | |
1577 | ||
1578 | # When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP | |
1579 | # script for searching. Instead the search results are written to an XML file | |
1580 | # which needs to be processed by an external indexer. Doxygen will invoke an | |
1581 | # external search engine pointed to by the SEARCHENGINE_URL option to obtain the | |
1582 | # search results. | |
1583 | # | |
1584 | # Doxygen ships with an example indexer (doxyindexer) and search engine | |
1585 | # (doxysearch.cgi) which are based on the open source search engine library | |
1586 | # Xapian (see: http://xapian.org/). | |
1587 | # | |
1588 | # See the section "External Indexing and Searching" for details. | |
1589 | # The default value is: NO. | |
1590 | # This tag requires that the tag SEARCHENGINE is set to YES. | |
1591 | ||
1592 | EXTERNAL_SEARCH = NO | |
1593 | ||
1594 | # The SEARCHENGINE_URL should point to a search engine hosted by a web server | |
1595 | # which will return the search results when EXTERNAL_SEARCH is enabled. | |
1596 | # | |
1597 | # Doxygen ships with an example indexer (doxyindexer) and search engine | |
1598 | # (doxysearch.cgi) which are based on the open source search engine library | |
1599 | # Xapian (see: http://xapian.org/). See the section "External Indexing and | |
1600 | # Searching" for details. | |
1601 | # This tag requires that the tag SEARCHENGINE is set to YES. | |
1602 | ||
1603 | SEARCHENGINE_URL = | |
1604 | ||
1605 | # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed | |
1606 | # search data is written to a file for indexing by an external tool. With the | |
1607 | # SEARCHDATA_FILE tag the name of this file can be specified. | |
1608 | # The default file is: searchdata.xml. | |
1609 | # This tag requires that the tag SEARCHENGINE is set to YES. | |
1610 | ||
1611 | SEARCHDATA_FILE = searchdata.xml | |
1612 | ||
1613 | # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the | |
1614 | # EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is | |
1615 | # useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple | |
1616 | # projects and redirect the results back to the right project. | |
1617 | # This tag requires that the tag SEARCHENGINE is set to YES. | |
1618 | ||
1619 | EXTERNAL_SEARCH_ID = | |
1620 | ||
1621 | # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen | |
1622 | # projects other than the one defined by this configuration file, but that are | |
1623 | # all added to the same external search index. Each project needs to have a | |
1624 | # unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of | |
1625 | # to a relative location where the documentation can be found. The format is: | |
1626 | # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... | |
1627 | # This tag requires that the tag SEARCHENGINE is set to YES. | |
1628 | ||
1629 | EXTRA_SEARCH_MAPPINGS = | |
1630 | ||
1631 | #--------------------------------------------------------------------------- | |
1632 | # Configuration options related to the LaTeX output | |
1633 | #--------------------------------------------------------------------------- | |
1634 | ||
1635 | # If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output. | |
1636 | # The default value is: YES. | |
1004 | 1637 | |
1005 | 1638 | GENERATE_LATEX = NO |
1006 | 1639 | |
1007 | # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. | |
1008 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be | |
1009 | # put in front of it. If left blank `latex' will be used as the default path. | |
1640 | # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a | |
1641 | # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1642 | # it. | |
1643 | # The default directory is: latex. | |
1644 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1010 | 1645 | |
1011 | 1646 | LATEX_OUTPUT = latex |
1012 | 1647 | |
1013 | 1648 | # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be |
1014 | # invoked. If left blank `latex' will be used as the default command name. | |
1649 | # invoked. | |
1650 | # | |
1651 | # Note that when enabling USE_PDFLATEX this option is only used for generating | |
1652 | # bitmaps for formulas in the HTML output, but not in the Makefile that is | |
1653 | # written to the output directory. | |
1654 | # The default file is: latex. | |
1655 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1015 | 1656 | |
1016 | 1657 | LATEX_CMD_NAME = latex |
1017 | 1658 | |
1018 | # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to | |
1019 | # generate index for LaTeX. If left blank `makeindex' will be used as the | |
1020 | # default command name. | |
1659 | # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate | |
1660 | # index for LaTeX. | |
1661 | # The default file is: makeindex. | |
1662 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1021 | 1663 | |
1022 | 1664 | MAKEINDEX_CMD_NAME = makeindex |
1023 | 1665 | |
1024 | # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact | |
1025 | # LaTeX documents. This may be useful for small projects and may help to | |
1026 | # save some trees in general. | |
1666 | # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX | |
1667 | # documents. This may be useful for small projects and may help to save some | |
1668 | # trees in general. | |
1669 | # The default value is: NO. | |
1670 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1027 | 1671 | |
1028 | 1672 | COMPACT_LATEX = NO |
1029 | 1673 | |
1030 | # The PAPER_TYPE tag can be used to set the paper type that is used | |
1031 | # by the printer. Possible values are: a4, a4wide, letter, legal and | |
1032 | # executive. If left blank a4wide will be used. | |
1674 | # The PAPER_TYPE tag can be used to set the paper type that is used by the | |
1675 | # printer. | |
1676 | # Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x | |
1677 | # 14 inches) and executive (7.25 x 10.5 inches). | |
1678 | # The default value is: a4. | |
1679 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1033 | 1680 | |
1034 | 1681 | PAPER_TYPE = a4wide |
1035 | 1682 | |
1036 | # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX | |
1037 | # packages that should be included in the LaTeX output. | |
1683 | # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names | |
1684 | # that should be included in the LaTeX output. The package can be specified just | |
1685 | # by its name or with the correct syntax as to be used with the LaTeX | |
1686 | # \usepackage command. To get the times font for instance you can specify : | |
1687 | # EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} | |
1688 | # To use the option intlimits with the amsmath package you can specify: | |
1689 | # EXTRA_PACKAGES=[intlimits]{amsmath} | |
1690 | # If left blank no extra packages will be included. | |
1691 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1038 | 1692 | |
1039 | 1693 | EXTRA_PACKAGES = |
1040 | 1694 | |
1041 | # The LATEX_HEADER tag can be used to specify a personal LaTeX header for | |
1042 | # the generated latex document. The header should contain everything until | |
1043 | # the first chapter. If it is left blank doxygen will generate a | |
1044 | # standard header. Notice: only use this tag if you know what you are doing! | |
1695 | # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the | |
1696 | # generated LaTeX document. The header should contain everything until the first | |
1697 | # chapter. If it is left blank doxygen will generate a standard header. See | |
1698 | # section "Doxygen usage" for information on how to let doxygen write the | |
1699 | # default header to a separate file. | |
1700 | # | |
1701 | # Note: Only use a user-defined header if you know what you are doing! The | |
1702 | # following commands have a special meaning inside the header: $title, | |
1703 | # $datetime, $date, $doxygenversion, $projectname, $projectnumber, | |
1704 | # $projectbrief, $projectlogo. Doxygen will replace $title with the empty | |
1705 | # string, for the replacement values of the other commands the user is referred | |
1706 | # to HTML_HEADER. | |
1707 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1045 | 1708 | |
1046 | 1709 | LATEX_HEADER = |
1047 | 1710 | |
1048 | # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated | |
1049 | # is prepared for conversion to pdf (using ps2pdf). The pdf file will | |
1050 | # contain links (just like the HTML output) instead of page references | |
1051 | # This makes the output suitable for online browsing using a pdf viewer. | |
1711 | # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the | |
1712 | # generated LaTeX document. The footer should contain everything after the last | |
1713 | # chapter. If it is left blank doxygen will generate a standard footer. See | |
1714 | # LATEX_HEADER for more information on how to generate a default footer and what | |
1715 | # special commands can be used inside the footer. | |
1716 | # | |
1717 | # Note: Only use a user-defined footer if you know what you are doing! | |
1718 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1719 | ||
1720 | LATEX_FOOTER = | |
1721 | ||
1722 | # The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined | |
1723 | # LaTeX style sheets that are included after the standard style sheets created | |
1724 | # by doxygen. Using this option one can overrule certain style aspects. Doxygen | |
1725 | # will copy the style sheet files to the output directory. | |
1726 | # Note: The order of the extra style sheet files is of importance (e.g. the last | |
1727 | # style sheet in the list overrules the setting of the previous ones in the | |
1728 | # list). | |
1729 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1730 | ||
1731 | LATEX_EXTRA_STYLESHEET = | |
1732 | ||
1733 | # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or | |
1734 | # other source files which should be copied to the LATEX_OUTPUT output | |
1735 | # directory. Note that the files will be copied as-is; there are no commands or | |
1736 | # markers available. | |
1737 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1738 | ||
1739 | LATEX_EXTRA_FILES = | |
1740 | ||
1741 | # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is | |
1742 | # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will | |
1743 | # contain links (just like the HTML output) instead of page references. This | |
1744 | # makes the output suitable for online browsing using a PDF viewer. | |
1745 | # The default value is: YES. | |
1746 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1052 | 1747 | |
1053 | 1748 | PDF_HYPERLINKS = YES |
1054 | 1749 | |
1055 | # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of | |
1056 | # plain latex in the generated Makefile. Set this option to YES to get a | |
1750 | # If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate | |
1751 | # the PDF file directly from the LaTeX files. Set this option to YES, to get a | |
1057 | 1752 | # higher quality PDF documentation. |
1753 | # The default value is: YES. | |
1754 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1058 | 1755 | |
1059 | 1756 | USE_PDFLATEX = YES |
1060 | 1757 | |
1061 | # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. | |
1062 | # command to the generated LaTeX files. This will instruct LaTeX to keep | |
1063 | # running if errors occur, instead of asking the user for help. | |
1064 | # This option is also used when generating formulas in HTML. | |
1758 | # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode | |
1759 | # command to the generated LaTeX files. This will instruct LaTeX to keep running | |
1760 | # if errors occur, instead of asking the user for help. This option is also used | |
1761 | # when generating formulas in HTML. | |
1762 | # The default value is: NO. | |
1763 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1065 | 1764 | |
1066 | 1765 | LATEX_BATCHMODE = NO |
1067 | 1766 | |
1068 | # If LATEX_HIDE_INDICES is set to YES then doxygen will not | |
1069 | # include the index chapters (such as File Index, Compound Index, etc.) | |
1070 | # in the output. | |
1767 | # If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the | |
1768 | # index chapters (such as File Index, Compound Index, etc.) in the output. | |
1769 | # The default value is: NO. | |
1770 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1071 | 1771 | |
1072 | 1772 | LATEX_HIDE_INDICES = NO |
1073 | 1773 | |
1074 | # If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. | |
1774 | # If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source | |
1775 | # code with syntax highlighting in the LaTeX output. | |
1776 | # | |
1777 | # Note that which sources are shown also depends on other settings such as | |
1778 | # SOURCE_BROWSER. | |
1779 | # The default value is: NO. | |
1780 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1075 | 1781 | |
1076 | 1782 | LATEX_SOURCE_CODE = NO |
1077 | 1783 | |
1078 | #--------------------------------------------------------------------------- | |
1079 | # configuration options related to the RTF output | |
1080 | #--------------------------------------------------------------------------- | |
1081 | ||
1082 | # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output | |
1083 | # The RTF output is optimized for Word 97 and may not look very pretty with | |
1084 | # other RTF readers or editors. | |
1784 | # The LATEX_BIB_STYLE tag can be used to specify the style to use for the | |
1785 | # bibliography, e.g. plainnat, or ieeetr. See | |
1786 | # http://en.wikipedia.org/wiki/BibTeX and \cite for more info. | |
1787 | # The default value is: plain. | |
1788 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1789 | ||
1790 | LATEX_BIB_STYLE = plain | |
1791 | ||
1792 | # If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated | |
1793 | # page will contain the date and time when the page was generated. Setting this | |
1794 | # to NO can help when comparing the output of multiple runs. | |
1795 | # The default value is: NO. | |
1796 | # This tag requires that the tag GENERATE_LATEX is set to YES. | |
1797 | ||
1798 | LATEX_TIMESTAMP = NO | |
1799 | ||
1800 | #--------------------------------------------------------------------------- | |
1801 | # Configuration options related to the RTF output | |
1802 | #--------------------------------------------------------------------------- | |
1803 | ||
1804 | # If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The | |
1805 | # RTF output is optimized for Word 97 and may not look too pretty with other RTF | |
1806 | # readers/editors. | |
1807 | # The default value is: NO. | |
1085 | 1808 | |
1086 | 1809 | GENERATE_RTF = NO |
1087 | 1810 | |
1088 | # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. | |
1089 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be | |
1090 | # put in front of it. If left blank `rtf' will be used as the default path. | |
1811 | # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a | |
1812 | # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1813 | # it. | |
1814 | # The default directory is: rtf. | |
1815 | # This tag requires that the tag GENERATE_RTF is set to YES. | |
1091 | 1816 | |
1092 | 1817 | RTF_OUTPUT = rtf |
1093 | 1818 | |
1094 | # If the COMPACT_RTF tag is set to YES Doxygen generates more compact | |
1095 | # RTF documents. This may be useful for small projects and may help to | |
1096 | # save some trees in general. | |
1819 | # If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF | |
1820 | # documents. This may be useful for small projects and may help to save some | |
1821 | # trees in general. | |
1822 | # The default value is: NO. | |
1823 | # This tag requires that the tag GENERATE_RTF is set to YES. | |
1097 | 1824 | |
1098 | 1825 | COMPACT_RTF = NO |
1099 | 1826 | |
1100 | # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated | |
1101 | # will contain hyperlink fields. The RTF file will | |
1102 | # contain links (just like the HTML output) instead of page references. | |
1103 | # This makes the output suitable for online browsing using WORD or other | |
1104 | # programs which support those fields. | |
1105 | # Note: wordpad (write) and others do not support links. | |
1827 | # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will | |
1828 | # contain hyperlink fields. The RTF file will contain links (just like the HTML | |
1829 | # output) instead of page references. This makes the output suitable for online | |
1830 | # browsing using Word or some other Word compatible readers that support those | |
1831 | # fields. | |
1832 | # | |
1833 | # Note: WordPad (write) and others do not support links. | |
1834 | # The default value is: NO. | |
1835 | # This tag requires that the tag GENERATE_RTF is set to YES. | |
1106 | 1836 | |
1107 | 1837 | RTF_HYPERLINKS = NO |
1108 | 1838 | |
1109 | # Load stylesheet definitions from file. Syntax is similar to doxygen's | |
1110 | # config file, i.e. a series of assignments. You only have to provide | |
1111 | # replacements, missing definitions are set to their default value. | |
1839 | # Load stylesheet definitions from file. Syntax is similar to doxygen's config | |
1840 | # file, i.e. a series of assignments. You only have to provide replacements, | |
1841 | # missing definitions are set to their default value. | |
1842 | # | |
1843 | # See also section "Doxygen usage" for information on how to generate the | |
1844 | # default style sheet that doxygen normally uses. | |
1845 | # This tag requires that the tag GENERATE_RTF is set to YES. | |
1112 | 1846 | |
1113 | 1847 | RTF_STYLESHEET_FILE = |
1114 | 1848 | |
1115 | # Set optional variables used in the generation of an rtf document. | |
1116 | # Syntax is similar to doxygen's config file. | |
1849 | # Set optional variables used in the generation of an RTF document. Syntax is | |
1850 | # similar to doxygen's config file. A template extensions file can be generated | |
1851 | # using doxygen -e rtf extensionFile. | |
1852 | # This tag requires that the tag GENERATE_RTF is set to YES. | |
1117 | 1853 | |
1118 | 1854 | RTF_EXTENSIONS_FILE = |
1119 | 1855 | |
1120 | #--------------------------------------------------------------------------- | |
1121 | # configuration options related to the man page output | |
1122 | #--------------------------------------------------------------------------- | |
1123 | ||
1124 | # If the GENERATE_MAN tag is set to YES (the default) Doxygen will | |
1125 | # generate man pages | |
1856 | # If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code | |
1857 | # with syntax highlighting in the RTF output. | |
1858 | # | |
1859 | # Note that which sources are shown also depends on other settings such as | |
1860 | # SOURCE_BROWSER. | |
1861 | # The default value is: NO. | |
1862 | # This tag requires that the tag GENERATE_RTF is set to YES. | |
1863 | ||
1864 | RTF_SOURCE_CODE = NO | |
1865 | ||
1866 | #--------------------------------------------------------------------------- | |
1867 | # Configuration options related to the man page output | |
1868 | #--------------------------------------------------------------------------- | |
1869 | ||
1870 | # If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for | |
1871 | # classes and files. | |
1872 | # The default value is: NO. | |
1126 | 1873 | |
1127 | 1874 | GENERATE_MAN = NO |
1128 | 1875 | |
1129 | # The MAN_OUTPUT tag is used to specify where the man pages will be put. | |
1130 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be | |
1131 | # put in front of it. If left blank `man' will be used as the default path. | |
1876 | # The MAN_OUTPUT tag is used to specify where the man pages will be put. If a | |
1877 | # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1878 | # it. A directory man3 will be created inside the directory specified by | |
1879 | # MAN_OUTPUT. | |
1880 | # The default directory is: man. | |
1881 | # This tag requires that the tag GENERATE_MAN is set to YES. | |
1132 | 1882 | |
1133 | 1883 | MAN_OUTPUT = man |
1134 | 1884 | |
1135 | # The MAN_EXTENSION tag determines the extension that is added to | |
1136 | # the generated man pages (default is the subroutine's section .3) | |
1885 | # The MAN_EXTENSION tag determines the extension that is added to the generated | |
1886 | # man pages. In case the manual section does not start with a number, the number | |
1887 | # 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is | |
1888 | # optional. | |
1889 | # The default value is: .3. | |
1890 | # This tag requires that the tag GENERATE_MAN is set to YES. | |
1137 | 1891 | |
1138 | 1892 | MAN_EXTENSION = .3 |
1139 | 1893 | |
1140 | # If the MAN_LINKS tag is set to YES and Doxygen generates man output, | |
1141 | # then it will generate one additional man file for each entity | |
1142 | # documented in the real man page(s). These additional files | |
1143 | # only source the real man page, but without them the man command | |
1144 | # would be unable to find the correct page. The default is NO. | |
1894 | # The MAN_SUBDIR tag determines the name of the directory created within | |
1895 | # MAN_OUTPUT in which the man pages are placed. If defaults to man followed by | |
1896 | # MAN_EXTENSION with the initial . removed. | |
1897 | # This tag requires that the tag GENERATE_MAN is set to YES. | |
1898 | ||
1899 | MAN_SUBDIR = | |
1900 | ||
1901 | # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it | |
1902 | # will generate one additional man file for each entity documented in the real | |
1903 | # man page(s). These additional files only source the real man page, but without | |
1904 | # them the man command would be unable to find the correct page. | |
1905 | # The default value is: NO. | |
1906 | # This tag requires that the tag GENERATE_MAN is set to YES. | |
1145 | 1907 | |
1146 | 1908 | MAN_LINKS = NO |
1147 | 1909 | |
1148 | 1910 | #--------------------------------------------------------------------------- |
1149 | # configuration options related to the XML output | |
1150 | #--------------------------------------------------------------------------- | |
1151 | ||
1152 | # If the GENERATE_XML tag is set to YES Doxygen will | |
1153 | # generate an XML file that captures the structure of | |
1154 | # the code including all documentation. | |
1911 | # Configuration options related to the XML output | |
1912 | #--------------------------------------------------------------------------- | |
1913 | ||
1914 | # If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that | |
1915 | # captures the structure of the code including all documentation. | |
1916 | # The default value is: NO. | |
1155 | 1917 | |
1156 | 1918 | GENERATE_XML = NO |
1157 | 1919 | |
1158 | # The XML_OUTPUT tag is used to specify where the XML pages will be put. | |
1159 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be | |
1160 | # put in front of it. If left blank `xml' will be used as the default path. | |
1920 | # The XML_OUTPUT tag is used to specify where the XML pages will be put. If a | |
1921 | # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of | |
1922 | # it. | |
1923 | # The default directory is: xml. | |
1924 | # This tag requires that the tag GENERATE_XML is set to YES. | |
1161 | 1925 | |
1162 | 1926 | XML_OUTPUT = xml |
1163 | 1927 | |
1164 | # The XML_SCHEMA tag can be used to specify an XML schema, | |
1165 | # which can be used by a validating XML parser to check the | |
1166 | # syntax of the XML files. | |
1167 | ||
1168 | XML_SCHEMA = | |
1169 | ||
1170 | # The XML_DTD tag can be used to specify an XML DTD, | |
1171 | # which can be used by a validating XML parser to check the | |
1172 | # syntax of the XML files. | |
1173 | ||
1174 | XML_DTD = | |
1175 | ||
1176 | # If the XML_PROGRAMLISTING tag is set to YES Doxygen will | |
1177 | # dump the program listings (including syntax highlighting | |
1178 | # and cross-referencing information) to the XML output. Note that | |
1179 | # enabling this will significantly increase the size of the XML output. | |
1928 | # If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program | |
1929 | # listings (including syntax highlighting and cross-referencing information) to | |
1930 | # the XML output. Note that enabling this will significantly increase the size | |
1931 | # of the XML output. | |
1932 | # The default value is: YES. | |
1933 | # This tag requires that the tag GENERATE_XML is set to YES. | |
1180 | 1934 | |
1181 | 1935 | XML_PROGRAMLISTING = YES |
1182 | 1936 | |
1183 | 1937 | #--------------------------------------------------------------------------- |
1184 | # configuration options for the AutoGen Definitions output | |
1185 | #--------------------------------------------------------------------------- | |
1186 | ||
1187 | # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will | |
1188 | # generate an AutoGen Definitions (see autogen.sf.net) file | |
1189 | # that captures the structure of the code including all | |
1190 | # documentation. Note that this feature is still experimental | |
1191 | # and incomplete at the moment. | |
1938 | # Configuration options related to the DOCBOOK output | |
1939 | #--------------------------------------------------------------------------- | |
1940 | ||
1941 | # If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files | |
1942 | # that can be used to generate PDF. | |
1943 | # The default value is: NO. | |
1944 | ||
1945 | GENERATE_DOCBOOK = NO | |
1946 | ||
1947 | # The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put. | |
1948 | # If a relative path is entered the value of OUTPUT_DIRECTORY will be put in | |
1949 | # front of it. | |
1950 | # The default directory is: docbook. | |
1951 | # This tag requires that the tag GENERATE_DOCBOOK is set to YES. | |
1952 | ||
1953 | DOCBOOK_OUTPUT = docbook | |
1954 | ||
1955 | # If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the | |
1956 | # program listings (including syntax highlighting and cross-referencing | |
1957 | # information) to the DOCBOOK output. Note that enabling this will significantly | |
1958 | # increase the size of the DOCBOOK output. | |
1959 | # The default value is: NO. | |
1960 | # This tag requires that the tag GENERATE_DOCBOOK is set to YES. | |
1961 | ||
1962 | DOCBOOK_PROGRAMLISTING = NO | |
1963 | ||
1964 | #--------------------------------------------------------------------------- | |
1965 | # Configuration options for the AutoGen Definitions output | |
1966 | #--------------------------------------------------------------------------- | |
1967 | ||
1968 | # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an | |
1969 | # AutoGen Definitions (see http://autogen.sf.net) file that captures the | |
1970 | # structure of the code including all documentation. Note that this feature is | |
1971 | # still experimental and incomplete at the moment. | |
1972 | # The default value is: NO. | |
1192 | 1973 | |
1193 | 1974 | GENERATE_AUTOGEN_DEF = NO |
1194 | 1975 | |
1195 | 1976 | #--------------------------------------------------------------------------- |
1196 | # configuration options related to the Perl module output | |
1197 | #--------------------------------------------------------------------------- | |
1198 | ||
1199 | # If the GENERATE_PERLMOD tag is set to YES Doxygen will | |
1200 | # generate a Perl module file that captures the structure of | |
1201 | # the code including all documentation. Note that this | |
1202 | # feature is still experimental and incomplete at the | |
1203 | # moment. | |
1977 | # Configuration options related to the Perl module output | |
1978 | #--------------------------------------------------------------------------- | |
1979 | ||
1980 | # If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module | |
1981 | # file that captures the structure of the code including all documentation. | |
1982 | # | |
1983 | # Note that this feature is still experimental and incomplete at the moment. | |
1984 | # The default value is: NO. | |
1204 | 1985 | |
1205 | 1986 | GENERATE_PERLMOD = NO |
1206 | 1987 | |
1207 | # If the PERLMOD_LATEX tag is set to YES Doxygen will generate | |
1208 | # the necessary Makefile rules, Perl scripts and LaTeX code to be able | |
1209 | # to generate PDF and DVI output from the Perl module output. | |
1988 | # If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary | |
1989 | # Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI | |
1990 | # output from the Perl module output. | |
1991 | # The default value is: NO. | |
1992 | # This tag requires that the tag GENERATE_PERLMOD is set to YES. | |
1210 | 1993 | |
1211 | 1994 | PERLMOD_LATEX = NO |
1212 | 1995 | |
1213 | # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be | |
1214 | # nicely formatted so it can be parsed by a human reader. | |
1215 | # This is useful | |
1216 | # if you want to understand what is going on. | |
1217 | # On the other hand, if this | |
1218 | # tag is set to NO the size of the Perl module output will be much smaller | |
1219 | # and Perl will parse it just the same. | |
1996 | # If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely | |
1997 | # formatted so it can be parsed by a human reader. This is useful if you want to | |
1998 | # understand what is going on. On the other hand, if this tag is set to NO, the | |
1999 | # size of the Perl module output will be much smaller and Perl will parse it | |
2000 | # just the same. | |
2001 | # The default value is: YES. | |
2002 | # This tag requires that the tag GENERATE_PERLMOD is set to YES. | |
1220 | 2003 | |
1221 | 2004 | PERLMOD_PRETTY = YES |
1222 | 2005 | |
1223 | # The names of the make variables in the generated doxyrules.make file | |
1224 | # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. | |
1225 | # This is useful so different doxyrules.make files included by the same | |
1226 | # Makefile don't overwrite each other's variables. | |
2006 | # The names of the make variables in the generated doxyrules.make file are | |
2007 | # prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful | |
2008 | # so different doxyrules.make files included by the same Makefile don't | |
2009 | # overwrite each other's variables. | |
2010 | # This tag requires that the tag GENERATE_PERLMOD is set to YES. | |
1227 | 2011 | |
1228 | 2012 | PERLMOD_MAKEVAR_PREFIX = |
1229 | 2013 | |
1231 | 2015 | # Configuration options related to the preprocessor |
1232 | 2016 | #--------------------------------------------------------------------------- |
1233 | 2017 | |
1234 | # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will | |
1235 | # evaluate all C-preprocessor directives found in the sources and include | |
1236 | # files. | |
2018 | # If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all | |
2019 | # C-preprocessor directives found in the sources and include files. | |
2020 | # The default value is: YES. | |
1237 | 2021 | |
1238 | 2022 | ENABLE_PREPROCESSING = YES |
1239 | 2023 | |
1240 | # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro | |
1241 | # names in the source code. If set to NO (the default) only conditional | |
1242 | # compilation will be performed. Macro expansion can be done in a controlled | |
1243 | # way by setting EXPAND_ONLY_PREDEF to YES. | |
2024 | # If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names | |
2025 | # in the source code. If set to NO, only conditional compilation will be | |
2026 | # performed. Macro expansion can be done in a controlled way by setting | |
2027 | # EXPAND_ONLY_PREDEF to YES. | |
2028 | # The default value is: NO. | |
2029 | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1244 | 2030 | |
1245 | 2031 | MACRO_EXPANSION = NO |
1246 | 2032 | |
1247 | # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES | |
1248 | # then the macro expansion is limited to the macros specified with the | |
1249 | # PREDEFINED and EXPAND_AS_DEFINED tags. | |
2033 | # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then | |
2034 | # the macro expansion is limited to the macros specified with the PREDEFINED and | |
2035 | # EXPAND_AS_DEFINED tags. | |
2036 | # The default value is: NO. | |
2037 | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1250 | 2038 | |
1251 | 2039 | EXPAND_ONLY_PREDEF = NO |
1252 | 2040 | |
1253 | # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files | |
1254 | # in the INCLUDE_PATH (see below) will be search if a #include is found. | |
2041 | # If the SEARCH_INCLUDES tag is set to YES, the include files in the | |
2042 | # INCLUDE_PATH will be searched if a #include is found. | |
2043 | # The default value is: YES. | |
2044 | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1255 | 2045 | |
1256 | 2046 | SEARCH_INCLUDES = YES |
1257 | 2047 | |
1258 | 2048 | # The INCLUDE_PATH tag can be used to specify one or more directories that |
1259 | # contain include files that are not input files but should be processed by | |
1260 | # the preprocessor. | |
2049 | # contain include files that are not input files but should be processed by the | |
2050 | # preprocessor. | |
2051 | # This tag requires that the tag SEARCH_INCLUDES is set to YES. | |
1261 | 2052 | |
1262 | 2053 | INCLUDE_PATH = |
1263 | 2054 | |
1264 | 2055 | # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard |
1265 | 2056 | # patterns (like *.h and *.hpp) to filter out the header-files in the |
1266 | # directories. If left blank, the patterns specified with FILE_PATTERNS will | |
1267 | # be used. | |
2057 | # directories. If left blank, the patterns specified with FILE_PATTERNS will be | |
2058 | # used. | |
2059 | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1268 | 2060 | |
1269 | 2061 | INCLUDE_FILE_PATTERNS = |
1270 | 2062 | |
1271 | # The PREDEFINED tag can be used to specify one or more macro names that | |
1272 | # are defined before the preprocessor is started (similar to the -D option of | |
1273 | # gcc). The argument of the tag is a list of macros of the form: name | |
1274 | # or name=definition (no spaces). If the definition and the = are | |
1275 | # omitted =1 is assumed. To prevent a macro definition from being | |
1276 | # undefined via #undef or recursively expanded use the := operator | |
1277 | # instead of the = operator. | |
2063 | # The PREDEFINED tag can be used to specify one or more macro names that are | |
2064 | # defined before the preprocessor is started (similar to the -D option of e.g. | |
2065 | # gcc). The argument of the tag is a list of macros of the form: name or | |
2066 | # name=definition (no spaces). If the definition and the "=" are omitted, "=1" | |
2067 | # is assumed. To prevent a macro definition from being undefined via #undef or | |
2068 | # recursively expanded use the := operator instead of the = operator. | |
2069 | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1278 | 2070 | |
1279 | 2071 | PREDEFINED = |
1280 | 2072 | |
1281 | # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then | |
1282 | # this tag can be used to specify a list of macro names that should be expanded. | |
1283 | # The macro definition that is found in the sources will be used. | |
1284 | # Use the PREDEFINED tag if you want to use a different macro definition. | |
2073 | # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this | |
2074 | # tag can be used to specify a list of macro names that should be expanded. The | |
2075 | # macro definition that is found in the sources will be used. Use the PREDEFINED | |
2076 | # tag if you want to use a different macro definition that overrules the | |
2077 | # definition found in the source code. | |
2078 | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1285 | 2079 | |
1286 | 2080 | EXPAND_AS_DEFINED = |
1287 | 2081 | |
1288 | # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then | |
1289 | # doxygen's preprocessor will remove all function-like macros that are alone | |
1290 | # on a line, have an all uppercase name, and do not end with a semicolon. Such | |
1291 | # function macros are typically used for boiler-plate code, and will confuse | |
1292 | # the parser if not removed. | |
2082 | # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will | |
2083 | # remove all references to function-like macros that are alone on a line, have | |
2084 | # an all uppercase name, and do not end with a semicolon. Such function macros | |
2085 | # are typically used for boiler-plate code, and will confuse the parser if not | |
2086 | # removed. | |
2087 | # The default value is: YES. | |
2088 | # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. | |
1293 | 2089 | |
1294 | 2090 | SKIP_FUNCTION_MACROS = YES |
1295 | 2091 | |
1296 | 2092 | #--------------------------------------------------------------------------- |
1297 | # Configuration::additions related to external references | |
1298 | #--------------------------------------------------------------------------- | |
1299 | ||
1300 | # The TAGFILES option can be used to specify one or more tagfiles. | |
1301 | # Optionally an initial location of the external documentation | |
1302 | # can be added for each tagfile. The format of a tag file without | |
1303 | # this location is as follows: | |
1304 | # | |
2093 | # Configuration options related to external references | |
2094 | #--------------------------------------------------------------------------- | |
2095 | ||
2096 | # The TAGFILES tag can be used to specify one or more tag files. For each tag | |
2097 | # file the location of the external documentation should be added. The format of | |
2098 | # a tag file without this location is as follows: | |
1305 | 2099 | # TAGFILES = file1 file2 ... |
1306 | 2100 | # Adding location for the tag files is done as follows: |
1307 | # | |
1308 | 2101 | # TAGFILES = file1=loc1 "file2 = loc2" ... |
1309 | # where "loc1" and "loc2" can be relative or absolute paths or | |
1310 | # URLs. If a location is present for each tag, the installdox tool | |
1311 | # does not have to be run to correct the links. | |
1312 | # Note that each tag file must have a unique name | |
1313 | # (where the name does NOT include the path) | |
1314 | # If a tag file is not located in the directory in which doxygen | |
1315 | # is run, you must also specify the path to the tagfile here. | |
2102 | # where loc1 and loc2 can be relative or absolute paths or URLs. See the | |
2103 | # section "Linking to external documentation" for more information about the use | |
2104 | # of tag files. | |
2105 | # Note: Each tag file must have a unique name (where the name does NOT include | |
2106 | # the path). If a tag file is not located in the directory in which doxygen is | |
2107 | # run, you must also specify the path to the tagfile here. | |
1316 | 2108 | |
1317 | 2109 | TAGFILES = |
1318 | 2110 | |
1319 | # When a file name is specified after GENERATE_TAGFILE, doxygen will create | |
1320 | # a tag file that is based on the input files it reads. | |
2111 | # When a file name is specified after GENERATE_TAGFILE, doxygen will create a | |
2112 | # tag file that is based on the input files it reads. See section "Linking to | |
2113 | # external documentation" for more information about the usage of tag files. | |
1321 | 2114 | |
1322 | 2115 | GENERATE_TAGFILE = libnfc.tag |
1323 | 2116 | |
1324 | # If the ALLEXTERNALS tag is set to YES all external classes will be listed | |
1325 | # in the class index. If set to NO only the inherited external classes | |
1326 | # will be listed. | |
2117 | # If the ALLEXTERNALS tag is set to YES, all external class will be listed in | |
2118 | # the class index. If set to NO, only the inherited external classes will be | |
2119 | # listed. | |
2120 | # The default value is: NO. | |
1327 | 2121 | |
1328 | 2122 | ALLEXTERNALS = NO |
1329 | 2123 | |
1330 | # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed | |
1331 | # in the modules index. If set to NO, only the current project's groups will | |
2124 | # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed | |
2125 | # in the modules index. If set to NO, only the current project's groups will be | |
2126 | # listed. | |
2127 | # The default value is: YES. | |
2128 | ||
2129 | EXTERNAL_GROUPS = YES | |
2130 | ||
2131 | # If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in | |
2132 | # the related pages index. If set to NO, only the current project's pages will | |
1332 | 2133 | # be listed. |
1333 | ||
1334 | EXTERNAL_GROUPS = YES | |
2134 | # The default value is: YES. | |
2135 | ||
2136 | EXTERNAL_PAGES = YES | |
1335 | 2137 | |
1336 | 2138 | # The PERL_PATH should be the absolute path and name of the perl script |
1337 | # interpreter (i.e. the result of `which perl'). | |
2139 | # interpreter (i.e. the result of 'which perl'). | |
2140 | # The default file (with absolute path) is: /usr/bin/perl. | |
1338 | 2141 | |
1339 | 2142 | PERL_PATH = /usr/bin/perl |
1340 | 2143 | |
1342 | 2145 | # Configuration options related to the dot tool |
1343 | 2146 | #--------------------------------------------------------------------------- |
1344 | 2147 | |
1345 | # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will | |
1346 | # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base | |
1347 | # or super classes. Setting the tag to NO turns the diagrams off. Note that | |
1348 | # this option is superseded by the HAVE_DOT option below. This is only a | |
1349 | # fallback. It is recommended to install and use dot, since it yields more | |
2148 | # If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram | |
2149 | # (in HTML and LaTeX) for classes with base or super classes. Setting the tag to | |
2150 | # NO turns the diagrams off. Note that this option also works with HAVE_DOT | |
2151 | # disabled, but it is recommended to install and use dot, since it yields more | |
1350 | 2152 | # powerful graphs. |
2153 | # The default value is: YES. | |
1351 | 2154 | |
1352 | 2155 | CLASS_DIAGRAMS = YES |
1353 | 2156 | |
1354 | 2157 | # You can define message sequence charts within doxygen comments using the \msc |
1355 | # command. Doxygen will then run the mscgen tool (see | |
1356 | # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the | |
2158 | # command. Doxygen will then run the mscgen tool (see: | |
2159 | # http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the | |
1357 | 2160 | # documentation. The MSCGEN_PATH tag allows you to specify the directory where |
1358 | 2161 | # the mscgen tool resides. If left empty the tool is assumed to be found in the |
1359 | 2162 | # default search path. |
1360 | 2163 | |
1361 | 2164 | MSCGEN_PATH = |
1362 | 2165 | |
1363 | # If set to YES, the inheritance and collaboration graphs will hide | |
1364 | # inheritance and usage relations if the target is undocumented | |
1365 | # or is not a class. | |
2166 | # You can include diagrams made with dia in doxygen documentation. Doxygen will | |
2167 | # then run dia to produce the diagram and insert it in the documentation. The | |
2168 | # DIA_PATH tag allows you to specify the directory where the dia binary resides. | |
2169 | # If left empty dia is assumed to be found in the default search path. | |
2170 | ||
2171 | DIA_PATH = | |
2172 | ||
2173 | # If set to YES the inheritance and collaboration graphs will hide inheritance | |
2174 | # and usage relations if the target is undocumented or is not a class. | |
2175 | # The default value is: YES. | |
1366 | 2176 | |
1367 | 2177 | HIDE_UNDOC_RELATIONS = YES |
1368 | 2178 | |
1369 | 2179 | # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is |
1370 | # available from the path. This tool is part of Graphviz, a graph visualization | |
1371 | # toolkit from AT&T and Lucent Bell Labs. The other options in this section | |
1372 | # have no effect if this option is set to NO (the default) | |
2180 | # available from the path. This tool is part of Graphviz (see: | |
2181 | # http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent | |
2182 | # Bell Labs. The other options in this section have no effect if this option is | |
2183 | # set to NO | |
2184 | # The default value is: YES. | |
1373 | 2185 | |
1374 | 2186 | HAVE_DOT = NO |
1375 | 2187 | |
1376 | # By default doxygen will write a font called FreeSans.ttf to the output | |
1377 | # directory and reference it in all dot files that doxygen generates. This | |
1378 | # font does not include all possible unicode characters however, so when you need | |
1379 | # these (or just want a differently looking font) you can specify the font name | |
1380 | # using DOT_FONTNAME. You need need to make sure dot is able to find the font, | |
1381 | # which can be done by putting it in a standard location or by setting the | |
1382 | # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory | |
1383 | # containing the font. | |
1384 | ||
1385 | DOT_FONTNAME = FreeSans | |
1386 | ||
1387 | # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. | |
1388 | # The default size is 10pt. | |
2188 | # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed | |
2189 | # to run in parallel. When set to 0 doxygen will base this on the number of | |
2190 | # processors available in the system. You can set it explicitly to a value | |
2191 | # larger than 0 to get control over the balance between CPU load and processing | |
2192 | # speed. | |
2193 | # Minimum value: 0, maximum value: 32, default value: 0. | |
2194 | # This tag requires that the tag HAVE_DOT is set to YES. | |
2195 | ||
2196 | DOT_NUM_THREADS = 0 | |
2197 | ||
2198 | # When you want a differently looking font in the dot files that doxygen | |
2199 | # generates you can specify the font name using DOT_FONTNAME. You need to make | |
2200 | # sure dot is able to find the font, which can be done by putting it in a | |
2201 | # standard location or by setting the DOTFONTPATH environment variable or by | |
2202 | # setting DOT_FONTPATH to the directory containing the font. | |
2203 | # The default value is: Helvetica. | |
2204 | # This tag requires that the tag HAVE_DOT is set to YES. | |
2205 | ||
2206 | DOT_FONTNAME = | |
2207 | ||
2208 | # The DOT_FONTSIZE tag can be used to set the size (in points) of the font of | |
2209 | # dot graphs. | |
2210 | # Minimum value: 4, maximum value: 24, default value: 10. | |
2211 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1389 | 2212 | |
1390 | 2213 | DOT_FONTSIZE = 10 |
1391 | 2214 | |
1392 | # By default doxygen will tell dot to use the output directory to look for the | |
1393 | # FreeSans.ttf font (which doxygen will put there itself). If you specify a | |
1394 | # different font using DOT_FONTNAME you can set the path where dot | |
1395 | # can find it using this tag. | |
2215 | # By default doxygen will tell dot to use the default font as specified with | |
2216 | # DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set | |
2217 | # the path where dot can find it using this tag. | |
2218 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1396 | 2219 | |
1397 | 2220 | DOT_FONTPATH = |
1398 | 2221 | |
1399 | # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen | |
1400 | # will generate a graph for each documented class showing the direct and | |
1401 | # indirect inheritance relations. Setting this tag to YES will force the | |
1402 | # the CLASS_DIAGRAMS tag to NO. | |
2222 | # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for | |
2223 | # each documented class showing the direct and indirect inheritance relations. | |
2224 | # Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. | |
2225 | # The default value is: YES. | |
2226 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1403 | 2227 | |
1404 | 2228 | CLASS_GRAPH = YES |
1405 | 2229 | |
1406 | # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen | |
1407 | # will generate a graph for each documented class showing the direct and | |
1408 | # indirect implementation dependencies (inheritance, containment, and | |
1409 | # class references variables) of the class with other documented classes. | |
2230 | # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a | |
2231 | # graph for each documented class showing the direct and indirect implementation | |
2232 | # dependencies (inheritance, containment, and class references variables) of the | |
2233 | # class with other documented classes. | |
2234 | # The default value is: YES. | |
2235 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1410 | 2236 | |
1411 | 2237 | COLLABORATION_GRAPH = YES |
1412 | 2238 | |
1413 | # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen | |
1414 | # will generate a graph for groups, showing the direct groups dependencies | |
2239 | # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for | |
2240 | # groups, showing the direct groups dependencies. | |
2241 | # The default value is: YES. | |
2242 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1415 | 2243 | |
1416 | 2244 | GROUP_GRAPHS = YES |
1417 | 2245 | |
1418 | # If the UML_LOOK tag is set to YES doxygen will generate inheritance and | |
2246 | # If the UML_LOOK tag is set to YES, doxygen will generate inheritance and | |
1419 | 2247 | # collaboration diagrams in a style similar to the OMG's Unified Modeling |
1420 | 2248 | # Language. |
2249 | # The default value is: NO. | |
2250 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1421 | 2251 | |
1422 | 2252 | UML_LOOK = NO |
1423 | 2253 | |
1424 | # If set to YES, the inheritance and collaboration graphs will show the | |
1425 | # relations between templates and their instances. | |
2254 | # If the UML_LOOK tag is enabled, the fields and methods are shown inside the | |
2255 | # class node. If there are many fields or methods and many nodes the graph may | |
2256 | # become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the | |
2257 | # number of items for each type to make the size more manageable. Set this to 0 | |
2258 | # for no limit. Note that the threshold may be exceeded by 50% before the limit | |
2259 | # is enforced. So when you set the threshold to 10, up to 15 fields may appear, | |
2260 | # but if the number exceeds 15, the total amount of fields shown is limited to | |
2261 | # 10. | |
2262 | # Minimum value: 0, maximum value: 100, default value: 10. | |
2263 | # This tag requires that the tag HAVE_DOT is set to YES. | |
2264 | ||
2265 | UML_LIMIT_NUM_FIELDS = 10 | |
2266 | ||
2267 | # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and | |
2268 | # collaboration graphs will show the relations between templates and their | |
2269 | # instances. | |
2270 | # The default value is: NO. | |
2271 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1426 | 2272 | |
1427 | 2273 | TEMPLATE_RELATIONS = NO |
1428 | 2274 | |
1429 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT | |
1430 | # tags are set to YES then doxygen will generate a graph for each documented | |
1431 | # file showing the direct and indirect include dependencies of the file with | |
1432 | # other documented files. | |
2275 | # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to | |
2276 | # YES then doxygen will generate a graph for each documented file showing the | |
2277 | # direct and indirect include dependencies of the file with other documented | |
2278 | # files. | |
2279 | # The default value is: YES. | |
2280 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1433 | 2281 | |
1434 | 2282 | INCLUDE_GRAPH = YES |
1435 | 2283 | |
1436 | # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and | |
1437 | # HAVE_DOT tags are set to YES then doxygen will generate a graph for each | |
1438 | # documented header file showing the documented files that directly or | |
1439 | # indirectly include this file. | |
2284 | # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are | |
2285 | # set to YES then doxygen will generate a graph for each documented file showing | |
2286 | # the direct and indirect include dependencies of the file with other documented | |
2287 | # files. | |
2288 | # The default value is: YES. | |
2289 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1440 | 2290 | |
1441 | 2291 | INCLUDED_BY_GRAPH = YES |
1442 | 2292 | |
1443 | # If the CALL_GRAPH and HAVE_DOT options are set to YES then | |
1444 | # doxygen will generate a call dependency graph for every global function | |
1445 | # or class method. Note that enabling this option will significantly increase | |
1446 | # the time of a run. So in most cases it will be better to enable call graphs | |
1447 | # for selected functions only using the \callgraph command. | |
2293 | # If the CALL_GRAPH tag is set to YES then doxygen will generate a call | |
2294 | # dependency graph for every global function or class method. | |
2295 | # | |
2296 | # Note that enabling this option will significantly increase the time of a run. | |
2297 | # So in most cases it will be better to enable call graphs for selected | |
2298 | # functions only using the \callgraph command. Disabling a call graph can be | |
2299 | # accomplished by means of the command \hidecallgraph. | |
2300 | # The default value is: NO. | |
2301 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1448 | 2302 | |
1449 | 2303 | CALL_GRAPH = NO |
1450 | 2304 | |
1451 | # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then | |
1452 | # doxygen will generate a caller dependency graph for every global function | |
1453 | # or class method. Note that enabling this option will significantly increase | |
1454 | # the time of a run. So in most cases it will be better to enable caller | |
1455 | # graphs for selected functions only using the \callergraph command. | |
2305 | # If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller | |
2306 | # dependency graph for every global function or class method. | |
2307 | # | |
2308 | # Note that enabling this option will significantly increase the time of a run. | |
2309 | # So in most cases it will be better to enable caller graphs for selected | |
2310 | # functions only using the \callergraph command. Disabling a caller graph can be | |
2311 | # accomplished by means of the command \hidecallergraph. | |
2312 | # The default value is: NO. | |
2313 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1456 | 2314 | |
1457 | 2315 | CALLER_GRAPH = NO |
1458 | 2316 | |
1459 | # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen | |
1460 | # will graphical hierarchy of all classes instead of a textual one. | |
2317 | # If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical | |
2318 | # hierarchy of all classes instead of a textual one. | |
2319 | # The default value is: YES. | |
2320 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1461 | 2321 | |
1462 | 2322 | GRAPHICAL_HIERARCHY = YES |
1463 | 2323 | |
1464 | # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES | |
1465 | # then doxygen will show the dependencies a directory has on other directories | |
1466 | # in a graphical way. The dependency relations are determined by the #include | |
1467 | # relations between the files in the directories. | |
2324 | # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the | |
2325 | # dependencies a directory has on other directories in a graphical way. The | |
2326 | # dependency relations are determined by the #include relations between the | |
2327 | # files in the directories. | |
2328 | # The default value is: YES. | |
2329 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1468 | 2330 | |
1469 | 2331 | DIRECTORY_GRAPH = YES |
1470 | 2332 | |
1471 | 2333 | # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images |
1472 | # generated by dot. Possible values are png, jpg, or gif | |
1473 | # If left blank png will be used. | |
2334 | # generated by dot. For an explanation of the image formats see the section | |
2335 | # output formats in the documentation of the dot tool (Graphviz (see: | |
2336 | # http://www.graphviz.org/)). | |
2337 | # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order | |
2338 | # to make the SVG files visible in IE 9+ (other browsers do not have this | |
2339 | # requirement). | |
2340 | # Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, | |
2341 | # png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, | |
2342 | # gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, | |
2343 | # png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and | |
2344 | # png:gdiplus:gdiplus. | |
2345 | # The default value is: png. | |
2346 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1474 | 2347 | |
1475 | 2348 | DOT_IMAGE_FORMAT = png |
1476 | 2349 | |
1477 | # The tag DOT_PATH can be used to specify the path where the dot tool can be | |
2350 | # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to | |
2351 | # enable generation of interactive SVG images that allow zooming and panning. | |
2352 | # | |
2353 | # Note that this requires a modern browser other than Internet Explorer. Tested | |
2354 | # and working are Firefox, Chrome, Safari, and Opera. | |
2355 | # Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make | |
2356 | # the SVG files visible. Older versions of IE do not have SVG support. | |
2357 | # The default value is: NO. | |
2358 | # This tag requires that the tag HAVE_DOT is set to YES. | |
2359 | ||
2360 | INTERACTIVE_SVG = NO | |
2361 | ||
2362 | # The DOT_PATH tag can be used to specify the path where the dot tool can be | |
1478 | 2363 | # found. If left blank, it is assumed the dot tool can be found in the path. |
2364 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1479 | 2365 | |
1480 | 2366 | DOT_PATH = |
1481 | 2367 | |
1482 | 2368 | # The DOTFILE_DIRS tag can be used to specify one or more directories that |
1483 | # contain dot files that are included in the documentation (see the | |
1484 | # \dotfile command). | |
2369 | # contain dot files that are included in the documentation (see the \dotfile | |
2370 | # command). | |
2371 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1485 | 2372 | |
1486 | 2373 | DOTFILE_DIRS = |
1487 | 2374 | |
1488 | # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of | |
1489 | # nodes that will be shown in the graph. If the number of nodes in a graph | |
1490 | # becomes larger than this value, doxygen will truncate the graph, which is | |
1491 | # visualized by representing a node as a red box. Note that doxygen if the | |
1492 | # number of direct children of the root node in a graph is already larger than | |
1493 | # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note | |
1494 | # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. | |
2375 | # The MSCFILE_DIRS tag can be used to specify one or more directories that | |
2376 | # contain msc files that are included in the documentation (see the \mscfile | |
2377 | # command). | |
2378 | ||
2379 | MSCFILE_DIRS = | |
2380 | ||
2381 | # The DIAFILE_DIRS tag can be used to specify one or more directories that | |
2382 | # contain dia files that are included in the documentation (see the \diafile | |
2383 | # command). | |
2384 | ||
2385 | DIAFILE_DIRS = | |
2386 | ||
2387 | # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the | |
2388 | # path where java can find the plantuml.jar file. If left blank, it is assumed | |
2389 | # PlantUML is not used or called during a preprocessing step. Doxygen will | |
2390 | # generate a warning when it encounters a \startuml command in this case and | |
2391 | # will not generate output for the diagram. | |
2392 | ||
2393 | PLANTUML_JAR_PATH = | |
2394 | ||
2395 | # When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a | |
2396 | # configuration file for plantuml. | |
2397 | ||
2398 | PLANTUML_CFG_FILE = | |
2399 | ||
2400 | # When using plantuml, the specified paths are searched for files specified by | |
2401 | # the !include statement in a plantuml block. | |
2402 | ||
2403 | PLANTUML_INCLUDE_PATH = | |
2404 | ||
2405 | # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes | |
2406 | # that will be shown in the graph. If the number of nodes in a graph becomes | |
2407 | # larger than this value, doxygen will truncate the graph, which is visualized | |
2408 | # by representing a node as a red box. Note that doxygen if the number of direct | |
2409 | # children of the root node in a graph is already larger than | |
2410 | # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that | |
2411 | # the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. | |
2412 | # Minimum value: 0, maximum value: 10000, default value: 50. | |
2413 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1495 | 2414 | |
1496 | 2415 | DOT_GRAPH_MAX_NODES = 50 |
1497 | 2416 | |
1498 | # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the | |
1499 | # graphs generated by dot. A depth value of 3 means that only nodes reachable | |
1500 | # from the root by following a path via at most 3 edges will be shown. Nodes | |
1501 | # that lay further from the root node will be omitted. Note that setting this | |
1502 | # option to 1 or 2 may greatly reduce the computation time needed for large | |
1503 | # code bases. Also note that the size of a graph can be further restricted by | |
2417 | # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs | |
2418 | # generated by dot. A depth value of 3 means that only nodes reachable from the | |
2419 | # root by following a path via at most 3 edges will be shown. Nodes that lay | |
2420 | # further from the root node will be omitted. Note that setting this option to 1 | |
2421 | # or 2 may greatly reduce the computation time needed for large code bases. Also | |
2422 | # note that the size of a graph can be further restricted by | |
1504 | 2423 | # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. |
2424 | # Minimum value: 0, maximum value: 1000, default value: 0. | |
2425 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1505 | 2426 | |
1506 | 2427 | MAX_DOT_GRAPH_DEPTH = 1000 |
1507 | 2428 | |
1508 | 2429 | # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent |
1509 | # background. This is disabled by default, because dot on Windows does not | |
1510 | # seem to support this out of the box. Warning: Depending on the platform used, | |
1511 | # enabling this option may lead to badly anti-aliased labels on the edges of | |
1512 | # a graph (i.e. they become hard to read). | |
2430 | # background. This is disabled by default, because dot on Windows does not seem | |
2431 | # to support this out of the box. | |
2432 | # | |
2433 | # Warning: Depending on the platform used, enabling this option may lead to | |
2434 | # badly anti-aliased labels on the edges of a graph (i.e. they become hard to | |
2435 | # read). | |
2436 | # The default value is: NO. | |
2437 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1513 | 2438 | |
1514 | 2439 | DOT_TRANSPARENT = YES |
1515 | 2440 | |
1516 | # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output | |
2441 | # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output | |
1517 | 2442 | # files in one run (i.e. multiple -o and -T options on the command line). This |
1518 | # makes dot run faster, but since only newer versions of dot (>1.8.10) | |
1519 | # support this, this feature is disabled by default. | |
2443 | # makes dot run faster, but since only newer versions of dot (>1.8.10) support | |
2444 | # this, this feature is disabled by default. | |
2445 | # The default value is: NO. | |
2446 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1520 | 2447 | |
1521 | 2448 | DOT_MULTI_TARGETS = NO |
1522 | 2449 | |
1523 | # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will | |
1524 | # generate a legend page explaining the meaning of the various boxes and | |
1525 | # arrows in the dot generated graphs. | |
2450 | # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page | |
2451 | # explaining the meaning of the various boxes and arrows in the dot generated | |
2452 | # graphs. | |
2453 | # The default value is: YES. | |
2454 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1526 | 2455 | |
1527 | 2456 | GENERATE_LEGEND = YES |
1528 | 2457 | |
1529 | # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will | |
1530 | # remove the intermediate dot files that are used to generate | |
1531 | # the various graphs. | |
2458 | # If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot | |
2459 | # files that are used to generate the various graphs. | |
2460 | # The default value is: YES. | |
2461 | # This tag requires that the tag HAVE_DOT is set to YES. | |
1532 | 2462 | |
1533 | 2463 | DOT_CLEANUP = YES |
0 | Hello hackers! | |
1 | ||
2 | General remarks about contributing | |
3 | ---------------------------------- | |
4 | ||
5 | Contributions to the libnfc are welcome! | |
6 | Here are some directions to get you started: | |
7 | ||
8 | 1. Follow style conventions | |
9 | The source code of the library trend to follow some conventions so that it | |
10 | is consistent in style and thus easier to read. | |
11 | Look around and respect the same style. | |
12 | Don't use tabs. Increment unit is two spaces. | |
13 | Don't leave dandling spaces or tabs at EOL. | |
14 | Helper script to get some uniformity in the style: | |
15 | $ make style | |
16 | ||
17 | If you use vim see the "Vim: How to prevent trailing whitespaces" | |
18 | http://www.carbon-project.org/Vim__How_to_prevent_trailing_whitespaces.html | |
19 | ||
20 | 2. Chase warnings: no warning should be introduced by your changes | |
21 | Depending what you touch, you can check with: | |
22 | 2.1 When using autotools | |
23 | $ autoreconf -Wall -vis | |
24 | 2.2 When compiling | |
25 | 2.2.1 Using extra flags: | |
26 | $ export CFLAGS="-Wall -g -O2 -Wextra -pipe -funsigned-char -fstrict-aliasing \ | |
27 | -Wchar-subscripts -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wunused \ | |
28 | -Wuninitialized -Wpointer-arith -Wredundant-decls -Winline -Wformat \ | |
29 | -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs \ | |
30 | -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition \ | |
31 | -Wbad-function-cast -Wnested-externs -Wmissing-declarations" | |
32 | $ ./configure | |
33 | $ make clean | |
34 | $ make | |
35 | 2.2.2 Using clang: | |
36 | $ scan-build ./configure | |
37 | $ make clean | |
38 | $ scan-build make | |
39 | 2.2.3 Using cppcheck (v1.58 or higher): | |
40 | $ make cppcheck | |
41 | 2.3 When Debianizing | |
42 | $ lintian --info --display-info --display-experimental *deb | |
43 | or (shorter version) | |
44 | $ lintian -iIE *deb | |
45 | ||
46 | 3. Preserve cross-platform compatility | |
47 | The source code should remain compilable across various platforms, | |
48 | including some you probably cannot test alone so keep it in mind. | |
49 | Supported platforms: | |
50 | - Linux | |
51 | - FreeBSD | |
52 | - Mac OS X | |
53 | - Windows with Mingw |
0 | Hello hackers! | |
1 | ||
2 | General remarks about contributing | |
3 | ---------------------------------- | |
4 | ||
5 | Contributions to the libnfc are welcome! | |
6 | Here are some directions to get you started: | |
7 | ||
8 | 1. Follow style conventions | |
9 | The source code of the library trend to follow some conventions so that it | |
10 | is consistent in style and thus easier to read. | |
11 | Look around and respect the same style. | |
12 | Don't use tabs. Increment unit is two spaces. | |
13 | Don't leave dandling spaces or tabs at EOL. | |
14 | Helper script to get some uniformity in the style: | |
15 | $ make style | |
16 | ||
17 | If you use vim see the [Vim: How to prevent trailing whitespaces](http://www.carbon-project.org/Vim__How_to_prevent_trailing_whitespaces.html). | |
18 | ||
19 | 2. Chase warnings: no warning should be introduced by your changes | |
20 | Depending what you touch, you can check with: | |
21 | ||
22 | 2.1 When using autotools | |
23 | ||
24 | $ autoreconf -Wall -vis | |
25 | ||
26 | 2.2 When compiling | |
27 | ||
28 | 2.2.1 Using extra flags: | |
29 | ||
30 | $ export CFLAGS="-Wall -g -O2 -Wextra -pipe -funsigned-char -fstrict-aliasing \ | |
31 | -Wchar-subscripts -Wundef -Wshadow -Wcast-align -Wwrite-strings -Wunused \ | |
32 | -Wuninitialized -Wpointer-arith -Wredundant-decls -Winline -Wformat \ | |
33 | -Wformat-security -Wswitch-enum -Winit-self -Wmissing-include-dirs \ | |
34 | -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition \ | |
35 | -Wbad-function-cast -Wnested-externs -Wmissing-declarations" | |
36 | $ ./configure | |
37 | $ make clean | |
38 | $ make | |
39 | ||
40 | 2.2.2 Using clang: | |
41 | ||
42 | You can use same CFLAGS but also `-Wunreachable-code` | |
43 | ||
44 | $ scan-build ./configure | |
45 | $ make clean | |
46 | $ scan-build make | |
47 | ||
48 | 2.2.3 Using `cppcheck` (v1.58 or higher): | |
49 | ||
50 | $ make cppcheck | |
51 | ||
52 | 2.3 When Debianizing | |
53 | ||
54 | $ lintian --info --display-info --display-experimental *deb | |
55 | or (shorter version) | |
56 | $ lintian -iIE *deb | |
57 | ||
58 | 3. Preserve cross-platform compatibility | |
59 | ||
60 | The source code should remain compilable across various platforms, | |
61 | including some you probably cannot test alone so keep it in mind. | |
62 | Supported platforms: | |
63 | ||
64 | - Linux | |
65 | - FreeBSD | |
66 | - Mac OS X | |
67 | - Windows with MinGW |
9 | 9 | EXTRA_DIST = \ |
10 | 10 | CMakeLists.txt \ |
11 | 11 | Doxyfile \ |
12 | README-Windows.txt \ | |
13 | libnfc.conf.sample | |
12 | HACKING.md \ | |
13 | NEWS.md \ | |
14 | README.md \ | |
15 | README-Windows.md \ | |
16 | libnfc.conf.sample \ | |
17 | mingw-cross-compile.sh | |
14 | 18 | |
15 | 19 | CLEANFILES = Doxygen.log coverage.info libnfc.pc |
16 | 20 | |
33 | 37 | find . -name "*.[ch]" -exec astyle --formatted --mode=c --suffix=none \ |
34 | 38 | --indent=spaces=2 --indent-switches --indent-preprocessor \ |
35 | 39 | --keep-one-line-blocks --max-instatement-indent=60 \ |
36 | --brackets=linux --pad-oper --unpad-paren --pad-header \ | |
40 | --style=linux --pad-oper --unpad-paren --pad-header \ | |
37 | 41 | --align-pointer=name {} \; |
38 | 42 | |
39 | 43 | cppcheck: |
0 | New in 1.7.1: | |
1 | ||
2 | API Changes: | |
3 | ||
4 | * nfc_initiator_select_passive_target() provides defaults if pbtInitData=NULL | |
5 | * nfc_initiator_target_is_present() allow NULL pointer to tag | |
6 | ||
7 | New in 1.7.0: | |
8 | ||
9 | Drivers: | |
10 | ||
11 | * New PN532 over I2C driver, see contrib/libnfc/pn532_i2c_on_rpi.conf.sample | |
12 | ||
13 | API Changes: | |
14 | ||
15 | * New function iso14443b_crc_append() | |
16 | ||
17 | New in 1.7.0-rc7: | |
18 | ||
19 | Drivers: | |
20 | ||
21 | * New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample | |
22 | ||
23 | API Changes: | |
24 | ||
25 | * Functions | |
26 | - nfc_initiator_target_is_present() & str_nfc_target(): | |
27 | now take a pointer to nfc_target as argument | |
28 | - nfc_init(): upon malloc error, doesn't force exit() anymore | |
29 | so now you should test if context != NULL after nfc_init() call | |
30 | ||
31 | New in 1.7.0-rc5: | |
32 | ||
33 | API Changes: | |
34 | ||
35 | * Functions | |
36 | - New nfc_register_driver() function allowing to hook custom drivers. | |
37 | ||
38 | New in 1.7.0-rc3: | |
39 | ||
40 | API Changes: | |
41 | ||
42 | * Functions | |
43 | - Add timeout param to nfc_emulate_target() | |
44 | ||
45 | New in 1.7.0-rc2: | |
46 | ||
47 | Configuration: | |
48 | libnfc can now use a configuration file for special setups, or features | |
49 | activation. This file (/etc/nfc/libnfc.conf under GNU/Linux systems) | |
50 | supports already some keywords: | |
51 | - "allow_autoscan" to enable/disable device auto-detection feature; | |
52 | - "allow_intrusive_scan" to enable/disable intrusive auto-detection | |
53 | (ie. serial port probing); | |
54 | - "log_level" to select library verbosity; | |
55 | - "device.name" and "device.connstring" to define a user device, | |
56 | this is the recommended method if user has a not easily detectable | |
57 | device (ie. a serial one). | |
58 | It is also possible to define devices using dedicated configuration files and | |
59 | put them into device search directory (/etc/nfc/devices.d under GNU/Linux). | |
60 | Example for the OpenPCD2: create /etc/nfc/devices.d/openpcd2.conf with: | |
61 | name = "OpenPCD2" | |
62 | connstring = "pn532_uart:/dev/ttyACM0" | |
63 | optional = true | |
64 | The keyword "optional" does not mandate the device to be present always | |
65 | (it detects if the reader is indeed present before using it) | |
66 | ||
67 | API Changes: | |
68 | ||
69 | * Types | |
70 | - New NFC_ESOFT error to handle software errors (allocations, pipe | |
71 | creation, etc.) | |
72 | ||
73 | * Functions | |
74 | - Remove nfc_get_default_device() function: the default device is now the | |
75 | first in nfc_list_devices() or could be open using NULL connstring with | |
76 | nfc_open() function. | |
77 | - New enum-to-string converter functions str_nfc_modulation_type() and | |
78 | str_nfc_baud_rate() | |
79 | - New str_nfc_target() to convert nfc_target struct into allocated string | |
80 | - New nfc_device_get_information_about() function to retreive some device's | |
81 | information | |
82 | - No more in/out function parameter: nfc_initiator_transceive_*() now | |
83 | take a constant size for Rx buffer | |
84 | - New nfc_initiator_target_is_present() to test is the previously selected | |
85 | target is available in the field | |
86 | - nfc_initiator_transceive_bytes() returns NFC_EMFCAUTHFAIL when AUTH | |
87 | command failed on a Mifare Classic | |
88 | - New nfc_initiator_init_secure_element() to initiate a connection with | |
89 | secure element (Only supported with a PN532 with SAM equipped) | |
90 | ||
91 | New in 1.6.0-rc1: | |
92 | ||
93 | API Changes: | |
94 | ||
95 | * Types | |
96 | - '_t' suffix removed from all types (e.g. nfc_device_t is now nfc_device) | |
97 | - All errors removed in flavour of NFC_EIO, NFC_EINVARG, NFC_EDEVNOTSUPP, | |
98 | NFC_ENOTSUCHDEV, NFC_EOVFLOW, NFC_ETIMEOUT, NFC_EOPABORTED, NFC_ENOTIMPL, | |
99 | NFC_ETGRELEASED, NFC_ERFTRANS, NFC_ECHIP and NFC_SUCCESS | |
100 | - nfc_device_desc_t replaced by nfc_connstring: libnfc now uses connection | |
101 | strings to describe a device | |
102 | - byte_t typedef removed, libnfc now uses uint8_t from C99 | |
103 | - nfc_device is now an opaque type | |
104 | - nfc_properties replaces nfc_options | |
105 | ||
106 | * Functions | |
107 | - New nfc_get_default_device() function that allows to grab the connstring | |
108 | stored in LIBNFC_DEFAULT_DEVICE environnement variable or returns the | |
109 | first available device if not set | |
110 | - New nfc_device_get_connstring() accessor function to know the device | |
111 | connstring | |
112 | - New nfc_device_set_property_bool() function that replace nfc_configure() | |
113 | - New nfc_device_set_property_int() function to set integer property | |
114 | - nfc_device_name() renamed to nfc_device_get_name() for the sake of | |
115 | consistency | |
116 | - New nfc_device_get_last_error() function, an accessor to last error occured | |
117 | - Whole libnfc's functions now return 0 (NFC_SUCCESS) or positive value if | |
118 | appropriated on success and libnfc's error code on failure | |
119 | - nfc_connect(), nfc_disconnect() renamed to nfc_open(), nfc_close() | |
120 | respectively | |
121 | - Add 2 new functions: initialization and deinitialization functions: | |
122 | nfc_init() and nfc_exit() | |
123 | - New nfc_device_get_supported_modulation() and | |
124 | nfc_device_get_supported_baud_rate() functions | |
125 | ||
126 | * Dependencies | |
127 | - log4c is not anymore used for debugging facility. It was a bad choice, | |
128 | sorry for inconvenience. | |
129 | ||
130 | New in 1.5.1: | |
131 | ||
132 | API Changes | |
133 | ||
134 | * Types | |
135 | - Communication-level errors DEIO and DETIMEOUT are now know as ECOMIO, | |
136 | ECOMTIMEOUT respectively | |
137 | - Common device-level errors DEINVAL and DEABORT are now know as EINVALARG, | |
138 | EOPABORT respectively | |
139 | - New errors: EFRAACKMISMATCH, EFRAISERRFRAME, EDEVNOTSUP and ENOTIMPL | |
140 | ||
141 | * Functions | |
142 | - nfc_abort_command() returns a boolean | |
143 | - timeout (struct timeval) pointer added to | |
144 | nfc_initiator_transceive_bytes(), nfc_target_send_bytes() and | |
145 | nfc_target_receive_bytes() | |
146 | - timed functions nfc_initiator_transceive_bytes_timed() and | |
147 | nfc_initiator_transceive_bits_timed() now takes uint32_t as cycles | |
148 | pointer | |
149 | - nfc_initiator_poll_targets() renamed to nfc_initiator_poll_target() and | |
150 | only return one target | |
151 | ||
152 | New in 1.5.0: | |
153 | ||
154 | Installed files | |
155 | - nfc-message.h have been removed, internal macros are not part of API. | |
156 | - New nfc-emulation.h file offers a middle level API to handle emulation (see | |
157 | nfc-emulate-forum-tag4 example) | |
158 | ||
159 | API Changes | |
160 | ||
161 | * Types | |
162 | - New error: DEABORT raised when operation is aborted by user (using | |
163 | nfc_abort_command()) | |
164 | - nfc_chip_t type removed from public API (have been renamed to pn53x_type | |
165 | in chips/pn53x) | |
166 | - nfc_device_spec_t removed, each driver can use his own way to keep a | |
167 | connection pointer | |
168 | ||
169 | * Structures | |
170 | - nfc_device_t now have a nfc_driver_t struct pointer (named .driver) and | |
171 | void pointer (.driver_data) to handle device specific wrapping | |
172 | - nfc_device_t now have a void pointer (.chip_data) to keep some chip | |
173 | specific data | |
174 | - nfc_device_t now have an file descriptor array to manage to abort request | |
175 | - nfc_device_t does have .nc member (nfc_chip_t) anymore (different chips | |
176 | handling in now in chip level) | |
177 | - nfc_device_t does have .nds member (nfc_device_spec_t) anymore, each | |
178 | driver handle its communication using driver_data pointer | |
179 | - nfc_device_t does have .bActive member (bool) anymore, this variable was | |
180 | almost not used and was not efficient | |
181 | - nfc_device_t does have chip's register caches anymore, this is handle in | |
182 | chip level (using chip_data pointer) | |
183 | - driver_callbacks structure have been removed from public API | |
184 | - New nfc_emulator structure used by the new emulation API (see | |
185 | nfc_emulate_target()) | |
186 | - New nfc_emulation_state_machine structure used by the new emulation API, | |
187 | it handles an I/O function and data pointer to create a software based | |
188 | state-machine. | |
189 | ||
190 | * Functions | |
191 | - New nfc_abort_command() function to abort current running command. | |
192 | - New nfc_initiator_transceive_bits_timed() and | |
193 | nfc_initiator_transceive_bytes_timed() to transceive bits/bytes and | |
194 | measure the time to have a reply | |
195 | - New nfc_emulate_target() function to start a target emulation using an | |
196 | nfc_emulator structure (it contains a custom state-machine | |
197 | (nfc_emulation_state_machine struct) and a custom target (nfc_target_t) | |
198 | (see nfc-emulate-forum-tag4 to have a look on how-to use it) | |
199 | ||
200 | ||
201 | ||
202 | New in 1.4.1: | |
203 | ||
204 | API Changes | |
205 | ||
206 | * Types | |
207 | - New error: ETGUIDNOTSUP raised when UID is not 4 bytes long or does not | |
208 | start with 0x08 (Security restriction present in the NXP PN53x chips) | |
209 | ||
210 | ||
211 | ||
212 | New in 1.4.0: | |
213 | ||
214 | API Changes | |
215 | ||
216 | * Types | |
217 | - New nfc_device_option value (enum): NDO_FORCE_ISO14443_A to force the | |
218 | chip to switch in ISO14443-A | |
219 | - New nfc_dep_mode_t (enum) for DEP mode: | |
220 | NDM_UNDEFINED, NDM_PASSIVE, NDM_ACTIVE | |
221 | - New nfc_modulation_type_t (enum) that lists modulation types: | |
222 | NMT_ISO14443A, NMT_ISO14443B, NMT_FELICA, NMT_JEWEL, NMT_DEP | |
223 | - New nfc_baud_rate_t (enum): list of baud rates: | |
224 | NBR_UNDEFINED, NBR_106, NBR_212, NBR_424, NBR_847 | |
225 | - nfc_target_type_t have been removed from API (use nfc_modulation_t | |
226 | instead) | |
227 | ||
228 | * Structures | |
229 | - nfc_device_t now have a boolean bAutoIso14443_4 to keep the locally the | |
230 | state of NDO_AUTO_ISO14443_4 (should not be directly set, use | |
231 | nfc_configure() with NDO_AUTO_ISO14443_4) | |
232 | - nfc_device_t now have an uint8_t ui8Parameters to cache PN53x parameters | |
233 | - nfc_device_t now have a byte_t btSupportByte to cache supported | |
234 | modulations | |
235 | - nfc_dep_info_t have completely changed, please see API documentation | |
236 | - nfc_iso14443b_info_t have completely changed, please see API | |
237 | documentation | |
238 | - nfc_modulation_t have completely changed: it now contains a | |
239 | nfc_modulation_type_t and nfc_baud_rate_t couple. Initialization example: | |
240 | nfc_modulation_t nm = { | |
241 | .nmt = NMT_ISO14443A, | |
242 | .nbr = NBR_106, | |
243 | }; | |
244 | - nfc_target_t now contains new nfc_modulation_t instead of | |
245 | nfc_target_type_t. Initialization example: | |
246 | nfc_target_t nt = { | |
247 | .nm.nmt = NMT_ISO14443A, | |
248 | .nm.nbr = NBR_UNDEFINED, | |
249 | .nti.nai.abtAtqa = { 0x03, 0x44 }, | |
250 | .nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef }, | |
251 | .nti.nai.btSak = 0x20, | |
252 | .nti.nai.szUidLen = 4, | |
253 | .nti.nai.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, | |
254 | .nti.nai.szAtsLen = 5, | |
255 | }; | |
256 | ||
257 | * Functions | |
258 | - nfc_initiator_select_passive_target() now use new nfc_modulation_t and | |
259 | nfc_target_t instead of nfc_target_info_t | |
260 | - nfc_initiator_list_passive_targets() now use new nfc_modulation_t and | |
261 | nfc_target_t instead of nfc_target_info_t | |
262 | - nfc_initiator_poll_targets() use new nfc_modulation_t instead of | |
263 | nfc_target_type_t | |
264 | - nfc_initiator_select_dep_target() completely changed, use now | |
265 | nfc_dep_mode_t, nfc_baudrate_t, nfc_dep_info_t and nfc_target_t, please | |
266 | see API documentation | |
267 | - nfc_target_init() have an additional argument: nfc_target_t to describe | |
268 | the wanted target | |
269 | - append_iso14443a_crc() was renamed to iso14443a_crc_append() | |
270 | - New iso14443a_locate_historical_bytes() to locate historical bytes in ATS | |
271 | ||
272 | ||
273 | ||
274 | New in 1.3.9 (since 1.3.4): | |
275 | ||
276 | Installed files | |
277 | ||
278 | - mifaretag.h and mifareultag.h are removed, Mifare features are not a part | |
279 | of libnfc API anymore (these features are always available in examples/) | |
280 | ||
281 | API Changes | |
282 | ||
283 | * Types | |
284 | - New nfc_device_option_t value (enum): NDO_AUTO_14443_4, an option to | |
285 | enable/disable auto-switching to ISO/IEC 14443-4 if device is compliliant | |
286 | - New nfc_device_option_t value (enum): NDO_EASY_FRAMING, an option to | |
287 | enable/disable automatic frames encapsulation and chaining | |
288 | - New nfc_target_type_t (enum), with values like NTT_MIFARE, | |
289 | NTT_ISO14443B_106, NTT_DEP_ACTIVE_424, etc. | |
290 | - Mifare related types have been removed from API: mifare_cmd, | |
291 | mifare_param_auth, mifare_param_data, mifare_param_value, mifare_param | |
292 | ||
293 | * Structures | |
294 | - nfc_device_t now have boolean bEasyFraming to enable/disable "easy | |
295 | framing" feature (should not be directly set, use nfc_configure() with | |
296 | NDO_EASY_FRAMING) | |
297 | - nfc_device_t now have integer iLastError to handle last error | |
298 | - New chip_callbacks to handle error lookup per chip | |
299 | - driver_callbacks now have a pointer to chip_callbacks | |
300 | - New nfc_target_t that contains nfc_target_info_t and nfc_target_type_t | |
301 | ||
302 | * Functions | |
303 | - nfc_initiator_select_tag() became nfc_initiator_select_passive_target() | |
304 | - New nfc_initiator_list_passive_targets() returns a list of detected | |
305 | target on desired modulation | |
306 | - (experimental) New nfc_initiator_poll_targets() returns targets that are | |
307 | detected during hardware polling (available only with PN532) | |
308 | - nfc_initiator_transceive_dep_bytes(), nfc_target_receive_dep_bytes() and | |
309 | nfc_target_send_dep_bytes() have been removed from API, use | |
310 | NDO_EASY_FRAMING option to switch from raw mode to "easy framing" | |
311 | - nfc_initiator_mifare_cmd() have been removed: no more Mifare related | |
312 | stuff in libnfc's API | |
313 | - New nfc_strerror(), nfc_strerror_r() and nfc_perror() to report errors | |
314 | - New append_iso14443a_crc() to append iso14443a_crc() to a string | |
315 | ||
316 | ||
317 | New in 1.3.4 (since 1.2.1): | |
318 | ||
319 | Installed files | |
320 | ||
321 | - Headers are now installed in include/nfc instead of include/libnfc | |
322 | - libnfc.h have been renamed to nfc.h | |
323 | - defines.h and types.h have been merge into nfc-types.h | |
324 | - bitutils.h is not installed anymore, some functions are now in | |
325 | examples/nfc-utils.c | |
326 | - devices.h, dev_acr122.h, dev_arygon.h, dev_pn531.h, dev_pn533.h and rs232.h | |
327 | are not installed anymore | |
328 | - New header mifareultag.h, like mifaretag.h for Mifare UltraLight | |
329 | - New header nfc-messages.h with messages macros (DBG, ERR, INFO) | |
330 | ||
331 | API Changes | |
332 | ||
333 | * Types | |
334 | - uint32_t which was used as size now are size_t | |
335 | - chip_type became nfc_chip_t (enum) | |
336 | - init_modulation became nfc_modulation_t (enum), and now have | |
337 | NM_ACTIVE_DEP and NM_PASSIVE_DEP modulation values added | |
338 | ||
339 | * Structures | |
340 | - dev_info became nfc_device_t | |
341 | - dev_config_option became nfc_device_option_t | |
342 | - New nfc_device_desc_t to describe the way to access to a NFC device. | |
343 | Initialisation example: | |
344 | nfc_device_desc_t ndd = { | |
345 | ndd.pcDriver = "ARYGON"; | |
346 | ndd.pcPort = "/dev/ttyUSB0"; | |
347 | ndd.uiSpeed = 115200; | |
348 | }; | |
349 | - dev_callbacks became driver_callbacks and now have two function pointers | |
350 | more: pick_device() and list_devices() | |
351 | - New nfc_dep_info_t to handle DEP targets info | |
352 | - tag_info_iso14443a became nfc_iso14443a_info_t | |
353 | - tag_info_iso14443b became nfc_iso14443b_info_t | |
354 | - tag_info_felica became nfc_felica_info_t | |
355 | - tag_info_jewel became nfc_jewel_info_t | |
356 | - tag_info became nfc_target_info_t, and now have extended union to | |
357 | nfc_dep_info_t | |
358 | ||
359 | * Functions | |
360 | - nfc_connect() now takes 1 nfc_devive_desc_t argument (can be NULL) | |
361 | - New nfc_list_devices(), it find available NFC devices using all know | |
362 | drivers | |
363 | - (experimental) New nfc_initiator_select_dep(), it looks for DEP targets | |
364 | - (experimental) New nfc_initiator_transceive_dep_bytes(), like | |
365 | nfc_initiator_transceive_bytes() for DEP targets | |
366 | - (experimental) New nfc_target_receive_dep_bytes() and | |
367 | nfc_target_send_dep_bytes(), to receive/send bytes to DEP target | |
368 | (configured as initiator) while local NFC device is configured as target | |
369 | - New nfc_device_name() returns the device's name | |
370 | - New iso14443a_crc() computes CRC as described in ISO/IEC 14443 | |
371 | - New nfc_version() returns the actual version of libnfc (with SVN | |
372 | revision, if available) |
0 | New in 1.8.0: | |
1 | ||
2 | API Changes: | |
3 | - Restore nfc_modulation_type enum order to keep compatibility with libnfc 1.7.1 | |
4 | - Bump library version to 6.0.0 | |
5 | ||
6 | New in 1.7.2: | |
7 | ||
8 | Drivers: | |
9 | ||
10 | * New driver for pn71xx NXP's NFC Controllers through Linux Libnfc-nci (untested) | |
11 | * New driver for contactless PC/SC readers (only as initiator) | |
12 | ||
13 | API Changes: | |
14 | ||
15 | * nfc_device_get_supported_baud_rate() now takes also "mode" as argument | |
16 | * New nfc_device_get_supported_baud_rate_target_mode() | |
17 | * New NFC modulation type NMT_BARCODE and nfc_barcode_info struct to support Thinfilm NFC Barcode protocol | |
18 | * New NFC modulation type NMT_ISO14443BICLASS and NMT_ISO14443BICLASS struct to support HID iClass (Picopass) | |
19 | * pn53x_transceive() is now part of public API | |
20 | ||
21 | New in 1.7.1: | |
22 | ||
23 | API Changes: | |
24 | ||
25 | * nfc_initiator_select_passive_target() provides defaults if pbtInitData=NULL | |
26 | * nfc_initiator_target_is_present() allow NULL pointer to tag | |
27 | ||
28 | New in 1.7.0: | |
29 | ||
30 | Drivers: | |
31 | ||
32 | * New PN532 over I2C driver, see contrib/libnfc/pn532_i2c_on_rpi.conf.sample | |
33 | ||
34 | API Changes: | |
35 | ||
36 | * New function iso14443b_crc_append() | |
37 | ||
38 | New in 1.7.0-rc7: | |
39 | ||
40 | Drivers: | |
41 | ||
42 | * New PN532 over SPI driver, see contrib/libnfc/pn532_spi_on_rpi.conf.sample | |
43 | ||
44 | API Changes: | |
45 | ||
46 | * Functions | |
47 | - nfc_initiator_target_is_present() & str_nfc_target(): | |
48 | now take a pointer to nfc_target as argument | |
49 | - nfc_init(): upon malloc error, doesn't force exit() anymore | |
50 | so now you should test if context != NULL after nfc_init() call | |
51 | ||
52 | New in 1.7.0-rc5: | |
53 | ||
54 | API Changes: | |
55 | ||
56 | * Functions | |
57 | - New nfc_register_driver() function allowing to hook custom drivers. | |
58 | ||
59 | New in 1.7.0-rc3: | |
60 | ||
61 | API Changes: | |
62 | ||
63 | * Functions | |
64 | - Add timeout param to nfc_emulate_target() | |
65 | ||
66 | New in 1.7.0-rc2: | |
67 | ||
68 | Configuration: | |
69 | libnfc can now use a configuration file for special setups, or features | |
70 | activation. This file (/etc/nfc/libnfc.conf under GNU/Linux systems) | |
71 | supports already some keywords: | |
72 | - "allow_autoscan" to enable/disable device auto-detection feature; | |
73 | - "allow_intrusive_scan" to enable/disable intrusive auto-detection | |
74 | (ie. serial port probing); | |
75 | - "log_level" to select library verbosity; | |
76 | - "device.name" and "device.connstring" to define a user device, | |
77 | this is the recommended method if user has a not easily detectable | |
78 | device (ie. a serial one). | |
79 | It is also possible to define devices using dedicated configuration files and | |
80 | put them into device search directory (/etc/nfc/devices.d under GNU/Linux). | |
81 | Example for the OpenPCD2: create /etc/nfc/devices.d/openpcd2.conf with: | |
82 | name = "OpenPCD2" | |
83 | connstring = "pn532_uart:/dev/ttyACM0" | |
84 | optional = true | |
85 | The keyword "optional" does not mandate the device to be present always | |
86 | (it detects if the reader is indeed present before using it) | |
87 | ||
88 | API Changes: | |
89 | ||
90 | * Types | |
91 | - New NFC_ESOFT error to handle software errors (allocations, pipe | |
92 | creation, etc.) | |
93 | ||
94 | * Functions | |
95 | - Remove nfc_get_default_device() function: the default device is now the | |
96 | first in nfc_list_devices() or could be open using NULL connstring with | |
97 | nfc_open() function. | |
98 | - New enum-to-string converter functions str_nfc_modulation_type() and | |
99 | str_nfc_baud_rate() | |
100 | - New str_nfc_target() to convert nfc_target struct into allocated string | |
101 | - New nfc_device_get_information_about() function to retreive some device's | |
102 | information | |
103 | - No more in/out function parameter: nfc_initiator_transceive_*() now | |
104 | take a constant size for Rx buffer | |
105 | - New nfc_initiator_target_is_present() to test is the previously selected | |
106 | target is available in the field | |
107 | - nfc_initiator_transceive_bytes() returns NFC_EMFCAUTHFAIL when AUTH | |
108 | command failed on a Mifare Classic | |
109 | - New nfc_initiator_init_secure_element() to initiate a connection with | |
110 | secure element (Only supported with a PN532 with SAM equipped) | |
111 | ||
112 | New in 1.6.0-rc1: | |
113 | ||
114 | API Changes: | |
115 | ||
116 | * Types | |
117 | - '_t' suffix removed from all types (e.g. nfc_device_t is now nfc_device) | |
118 | - All errors removed in flavour of NFC_EIO, NFC_EINVARG, NFC_EDEVNOTSUPP, | |
119 | NFC_ENOTSUCHDEV, NFC_EOVFLOW, NFC_ETIMEOUT, NFC_EOPABORTED, NFC_ENOTIMPL, | |
120 | NFC_ETGRELEASED, NFC_ERFTRANS, NFC_ECHIP and NFC_SUCCESS | |
121 | - nfc_device_desc_t replaced by nfc_connstring: libnfc now uses connection | |
122 | strings to describe a device | |
123 | - byte_t typedef removed, libnfc now uses uint8_t from C99 | |
124 | - nfc_device is now an opaque type | |
125 | - nfc_properties replaces nfc_options | |
126 | ||
127 | * Functions | |
128 | - New nfc_get_default_device() function that allows to grab the connstring | |
129 | stored in LIBNFC_DEFAULT_DEVICE environnement variable or returns the | |
130 | first available device if not set | |
131 | - New nfc_device_get_connstring() accessor function to know the device | |
132 | connstring | |
133 | - New nfc_device_set_property_bool() function that replace nfc_configure() | |
134 | - New nfc_device_set_property_int() function to set integer property | |
135 | - nfc_device_name() renamed to nfc_device_get_name() for the sake of | |
136 | consistency | |
137 | - New nfc_device_get_last_error() function, an accessor to last error occured | |
138 | - Whole libnfc's functions now return 0 (NFC_SUCCESS) or positive value if | |
139 | appropriated on success and libnfc's error code on failure | |
140 | - nfc_connect(), nfc_disconnect() renamed to nfc_open(), nfc_close() | |
141 | respectively | |
142 | - Add 2 new functions: initialization and deinitialization functions: | |
143 | nfc_init() and nfc_exit() | |
144 | - New nfc_device_get_supported_modulation() and | |
145 | nfc_device_get_supported_baud_rate() functions | |
146 | ||
147 | * Dependencies | |
148 | - log4c is not anymore used for debugging facility. It was a bad choice, | |
149 | sorry for inconvenience. | |
150 | ||
151 | New in 1.5.1: | |
152 | ||
153 | API Changes | |
154 | ||
155 | * Types | |
156 | - Communication-level errors DEIO and DETIMEOUT are now know as ECOMIO, | |
157 | ECOMTIMEOUT respectively | |
158 | - Common device-level errors DEINVAL and DEABORT are now know as EINVALARG, | |
159 | EOPABORT respectively | |
160 | - New errors: EFRAACKMISMATCH, EFRAISERRFRAME, EDEVNOTSUP and ENOTIMPL | |
161 | ||
162 | * Functions | |
163 | - nfc_abort_command() returns a boolean | |
164 | - timeout (struct timeval) pointer added to | |
165 | nfc_initiator_transceive_bytes(), nfc_target_send_bytes() and | |
166 | nfc_target_receive_bytes() | |
167 | - timed functions nfc_initiator_transceive_bytes_timed() and | |
168 | nfc_initiator_transceive_bits_timed() now takes uint32_t as cycles | |
169 | pointer | |
170 | - nfc_initiator_poll_targets() renamed to nfc_initiator_poll_target() and | |
171 | only return one target | |
172 | ||
173 | New in 1.5.0: | |
174 | ||
175 | Installed files | |
176 | - nfc-message.h have been removed, internal macros are not part of API. | |
177 | - New nfc-emulation.h file offers a middle level API to handle emulation (see | |
178 | nfc-emulate-forum-tag4 example) | |
179 | ||
180 | API Changes | |
181 | ||
182 | * Types | |
183 | - New error: DEABORT raised when operation is aborted by user (using | |
184 | nfc_abort_command()) | |
185 | - nfc_chip_t type removed from public API (have been renamed to pn53x_type | |
186 | in chips/pn53x) | |
187 | - nfc_device_spec_t removed, each driver can use his own way to keep a | |
188 | connection pointer | |
189 | ||
190 | * Structures | |
191 | - nfc_device_t now have a nfc_driver_t struct pointer (named .driver) and | |
192 | void pointer (.driver_data) to handle device specific wrapping | |
193 | - nfc_device_t now have a void pointer (.chip_data) to keep some chip | |
194 | specific data | |
195 | - nfc_device_t now have an file descriptor array to manage to abort request | |
196 | - nfc_device_t does have .nc member (nfc_chip_t) anymore (different chips | |
197 | handling in now in chip level) | |
198 | - nfc_device_t does have .nds member (nfc_device_spec_t) anymore, each | |
199 | driver handle its communication using driver_data pointer | |
200 | - nfc_device_t does have .bActive member (bool) anymore, this variable was | |
201 | almost not used and was not efficient | |
202 | - nfc_device_t does have chip's register caches anymore, this is handle in | |
203 | chip level (using chip_data pointer) | |
204 | - driver_callbacks structure have been removed from public API | |
205 | - New nfc_emulator structure used by the new emulation API (see | |
206 | nfc_emulate_target()) | |
207 | - New nfc_emulation_state_machine structure used by the new emulation API, | |
208 | it handles an I/O function and data pointer to create a software based | |
209 | state-machine. | |
210 | ||
211 | * Functions | |
212 | - New nfc_abort_command() function to abort current running command. | |
213 | - New nfc_initiator_transceive_bits_timed() and | |
214 | nfc_initiator_transceive_bytes_timed() to transceive bits/bytes and | |
215 | measure the time to have a reply | |
216 | - New nfc_emulate_target() function to start a target emulation using an | |
217 | nfc_emulator structure (it contains a custom state-machine | |
218 | (nfc_emulation_state_machine struct) and a custom target (nfc_target_t) | |
219 | (see nfc-emulate-forum-tag4 to have a look on how-to use it) | |
220 | ||
221 | ||
222 | ||
223 | New in 1.4.1: | |
224 | ||
225 | API Changes | |
226 | ||
227 | * Types | |
228 | - New error: ETGUIDNOTSUP raised when UID is not 4 bytes long or does not | |
229 | start with 0x08 (Security restriction present in the NXP PN53x chips) | |
230 | ||
231 | ||
232 | ||
233 | New in 1.4.0: | |
234 | ||
235 | API Changes | |
236 | ||
237 | * Types | |
238 | - New nfc_device_option value (enum): NDO_FORCE_ISO14443_A to force the | |
239 | chip to switch in ISO14443-A | |
240 | - New nfc_dep_mode_t (enum) for DEP mode: | |
241 | NDM_UNDEFINED, NDM_PASSIVE, NDM_ACTIVE | |
242 | - New nfc_modulation_type_t (enum) that lists modulation types: | |
243 | NMT_ISO14443A, NMT_ISO14443B, NMT_FELICA, NMT_JEWEL, NMT_DEP | |
244 | - New nfc_baud_rate_t (enum): list of baud rates: | |
245 | NBR_UNDEFINED, NBR_106, NBR_212, NBR_424, NBR_847 | |
246 | - nfc_target_type_t have been removed from API (use nfc_modulation_t | |
247 | instead) | |
248 | ||
249 | * Structures | |
250 | - nfc_device_t now have a boolean bAutoIso14443_4 to keep the locally the | |
251 | state of NDO_AUTO_ISO14443_4 (should not be directly set, use | |
252 | nfc_configure() with NDO_AUTO_ISO14443_4) | |
253 | - nfc_device_t now have an uint8_t ui8Parameters to cache PN53x parameters | |
254 | - nfc_device_t now have a byte_t btSupportByte to cache supported | |
255 | modulations | |
256 | - nfc_dep_info_t have completely changed, please see API documentation | |
257 | - nfc_iso14443b_info_t have completely changed, please see API | |
258 | documentation | |
259 | - nfc_modulation_t have completely changed: it now contains a | |
260 | nfc_modulation_type_t and nfc_baud_rate_t couple. Initialization example: | |
261 | nfc_modulation_t nm = { | |
262 | .nmt = NMT_ISO14443A, | |
263 | .nbr = NBR_106, | |
264 | }; | |
265 | - nfc_target_t now contains new nfc_modulation_t instead of | |
266 | nfc_target_type_t. Initialization example: | |
267 | nfc_target_t nt = { | |
268 | .nm.nmt = NMT_ISO14443A, | |
269 | .nm.nbr = NBR_UNDEFINED, | |
270 | .nti.nai.abtAtqa = { 0x03, 0x44 }, | |
271 | .nti.nai.abtUid = { 0x08, 0xab, 0xcd, 0xef }, | |
272 | .nti.nai.btSak = 0x20, | |
273 | .nti.nai.szUidLen = 4, | |
274 | .nti.nai.abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, | |
275 | .nti.nai.szAtsLen = 5, | |
276 | }; | |
277 | ||
278 | * Functions | |
279 | - nfc_initiator_select_passive_target() now use new nfc_modulation_t and | |
280 | nfc_target_t instead of nfc_target_info_t | |
281 | - nfc_initiator_list_passive_targets() now use new nfc_modulation_t and | |
282 | nfc_target_t instead of nfc_target_info_t | |
283 | - nfc_initiator_poll_targets() use new nfc_modulation_t instead of | |
284 | nfc_target_type_t | |
285 | - nfc_initiator_select_dep_target() completely changed, use now | |
286 | nfc_dep_mode_t, nfc_baudrate_t, nfc_dep_info_t and nfc_target_t, please | |
287 | see API documentation | |
288 | - nfc_target_init() have an additional argument: nfc_target_t to describe | |
289 | the wanted target | |
290 | - append_iso14443a_crc() was renamed to iso14443a_crc_append() | |
291 | - New iso14443a_locate_historical_bytes() to locate historical bytes in ATS | |
292 | ||
293 | ||
294 | ||
295 | New in 1.3.9 (since 1.3.4): | |
296 | ||
297 | Installed files | |
298 | ||
299 | - mifaretag.h and mifareultag.h are removed, Mifare features are not a part | |
300 | of libnfc API anymore (these features are always available in examples/) | |
301 | ||
302 | API Changes | |
303 | ||
304 | * Types | |
305 | - New nfc_device_option_t value (enum): NDO_AUTO_14443_4, an option to | |
306 | enable/disable auto-switching to ISO/IEC 14443-4 if device is compliliant | |
307 | - New nfc_device_option_t value (enum): NDO_EASY_FRAMING, an option to | |
308 | enable/disable automatic frames encapsulation and chaining | |
309 | - New nfc_target_type_t (enum), with values like NTT_MIFARE, | |
310 | NTT_ISO14443B_106, NTT_DEP_ACTIVE_424, etc. | |
311 | - Mifare related types have been removed from API: mifare_cmd, | |
312 | mifare_param_auth, mifare_param_data, mifare_param_value, mifare_param | |
313 | ||
314 | * Structures | |
315 | - nfc_device_t now have boolean bEasyFraming to enable/disable "easy | |
316 | framing" feature (should not be directly set, use nfc_configure() with | |
317 | NDO_EASY_FRAMING) | |
318 | - nfc_device_t now have integer iLastError to handle last error | |
319 | - New chip_callbacks to handle error lookup per chip | |
320 | - driver_callbacks now have a pointer to chip_callbacks | |
321 | - New nfc_target_t that contains nfc_target_info_t and nfc_target_type_t | |
322 | ||
323 | * Functions | |
324 | - nfc_initiator_select_tag() became nfc_initiator_select_passive_target() | |
325 | - New nfc_initiator_list_passive_targets() returns a list of detected | |
326 | target on desired modulation | |
327 | - (experimental) New nfc_initiator_poll_targets() returns targets that are | |
328 | detected during hardware polling (available only with PN532) | |
329 | - nfc_initiator_transceive_dep_bytes(), nfc_target_receive_dep_bytes() and | |
330 | nfc_target_send_dep_bytes() have been removed from API, use | |
331 | NDO_EASY_FRAMING option to switch from raw mode to "easy framing" | |
332 | - nfc_initiator_mifare_cmd() have been removed: no more Mifare related | |
333 | stuff in libnfc's API | |
334 | - New nfc_strerror(), nfc_strerror_r() and nfc_perror() to report errors | |
335 | - New append_iso14443a_crc() to append iso14443a_crc() to a string | |
336 | ||
337 | ||
338 | New in 1.3.4 (since 1.2.1): | |
339 | ||
340 | Installed files | |
341 | ||
342 | - Headers are now installed in include/nfc instead of include/libnfc | |
343 | - libnfc.h have been renamed to nfc.h | |
344 | - defines.h and types.h have been merge into nfc-types.h | |
345 | - bitutils.h is not installed anymore, some functions are now in | |
346 | examples/nfc-utils.c | |
347 | - devices.h, dev_acr122.h, dev_arygon.h, dev_pn531.h, dev_pn533.h and rs232.h | |
348 | are not installed anymore | |
349 | - New header mifareultag.h, like mifaretag.h for Mifare UltraLight | |
350 | - New header nfc-messages.h with messages macros (DBG, ERR, INFO) | |
351 | ||
352 | API Changes | |
353 | ||
354 | * Types | |
355 | - uint32_t which was used as size now are size_t | |
356 | - chip_type became nfc_chip_t (enum) | |
357 | - init_modulation became nfc_modulation_t (enum), and now have | |
358 | NM_ACTIVE_DEP and NM_PASSIVE_DEP modulation values added | |
359 | ||
360 | * Structures | |
361 | - dev_info became nfc_device_t | |
362 | - dev_config_option became nfc_device_option_t | |
363 | - New nfc_device_desc_t to describe the way to access to a NFC device. | |
364 | Initialisation example: | |
365 | nfc_device_desc_t ndd = { | |
366 | ndd.pcDriver = "ARYGON"; | |
367 | ndd.pcPort = "/dev/ttyUSB0"; | |
368 | ndd.uiSpeed = 115200; | |
369 | }; | |
370 | - dev_callbacks became driver_callbacks and now have two function pointers | |
371 | more: pick_device() and list_devices() | |
372 | - New nfc_dep_info_t to handle DEP targets info | |
373 | - tag_info_iso14443a became nfc_iso14443a_info_t | |
374 | - tag_info_iso14443b became nfc_iso14443b_info_t | |
375 | - tag_info_felica became nfc_felica_info_t | |
376 | - tag_info_jewel became nfc_jewel_info_t | |
377 | - tag_info became nfc_target_info_t, and now have extended union to | |
378 | nfc_dep_info_t | |
379 | ||
380 | * Functions | |
381 | - nfc_connect() now takes 1 nfc_devive_desc_t argument (can be NULL) | |
382 | - New nfc_list_devices(), it find available NFC devices using all know | |
383 | drivers | |
384 | - (experimental) New nfc_initiator_select_dep(), it looks for DEP targets | |
385 | - (experimental) New nfc_initiator_transceive_dep_bytes(), like | |
386 | nfc_initiator_transceive_bytes() for DEP targets | |
387 | - (experimental) New nfc_target_receive_dep_bytes() and | |
388 | nfc_target_send_dep_bytes(), to receive/send bytes to DEP target | |
389 | (configured as initiator) while local NFC device is configured as target | |
390 | - New nfc_device_name() returns the device's name | |
391 | - New iso14443a_crc() computes CRC as described in ISO/IEC 14443 | |
392 | - New nfc_version() returns the actual version of libnfc (with SVN | |
393 | revision, if available) |
0 | *- | |
1 | * Free/Libre Near Field Communication (NFC) library | |
2 | * | |
3 | * Libnfc historical contributors: | |
4 | * Copyright (C) 2009 Roel Verdult | |
5 | * Copyright (C) 2009-2013 Romuald Conty | |
6 | * Copyright (C) 2010-2012 Romain Tartière | |
7 | * Copyright (C) 2010-2013 Philippe Teuwen | |
8 | * Copyright (C) 2012-2013 Ludovic Rousseau | |
9 | * Additional contributors: | |
10 | * See AUTHORS file | |
11 | -* | |
12 | ||
13 | General Information | |
14 | =================== | |
15 | ||
16 | libnfc is a library which allows userspace application access to NFC devices. | |
17 | ||
18 | The official web site is: | |
19 | http://www.nfc-tools.org/ | |
20 | ||
21 | The official forum site is: | |
22 | http://www.libnfc.org/community/ | |
23 | ||
24 | The official development site is: | |
25 | http://libnfc.googlecode.com/ | |
26 | ||
27 | Important note: this file covers POSIX systems, for Windows please read README-Windows.txt | |
28 | ||
29 | Requirements | |
30 | ============ | |
31 | ||
32 | Some NFC drivers depend on third party software: | |
33 | ||
34 | * pn53x_usb & acr122_usb: | |
35 | ||
36 | - libusb-0.1 http://libusb.sf.net | |
37 | ||
38 | * acr122_pcsc: | |
39 | ||
40 | - pcsc-lite http://pcsclite.alioth.debian.org/ | |
41 | ||
42 | The regression test suite depends on the cutter framework: | |
43 | http://cutter.sf.net | |
44 | ||
45 | Installation | |
46 | ============ | |
47 | ||
48 | See the file 'INSTALL' for configure, build and install details. | |
49 | ||
50 | Additionnally, you may need to grant permissions to your user to drive your device. | |
51 | Under GNU/Linux systems, if you use udev, you could use the provided udev rules. | |
52 | e.g. under Debian, Ubuntu, etc. | |
53 | sudo cp contrib/udev/42-pn53x.rules /lib/udev/rules.d/ | |
54 | ||
55 | Under FreeBSD, if you use devd, there is also a rules file: contrib/devd/pn53x.conf. | |
56 | ||
57 | How to report bugs | |
58 | ================== | |
59 | ||
60 | To report a bug, visit http://code.google.com/p/libnfc/issues/list and fill | |
61 | out a bug report form. | |
62 | ||
63 | If you have questions, remarks, we encourage you to post this in the developers | |
64 | community: | |
65 | http://www.libnfc.org/community | |
66 | ||
67 | Please make sure to include: | |
68 | ||
69 | * The version of libnfc | |
70 | ||
71 | * Information about your system. For instance: | |
72 | ||
73 | - What operating system and version | |
74 | - For Linux, what version of the C library | |
75 | ||
76 | And anything else you think is relevant. | |
77 | ||
78 | * A trace with debug activated. | |
79 | ||
80 | Reproduce the bug with debug, e.g. if it was: | |
81 | $ nfc-list -v | |
82 | run it as: | |
83 | $ LIBNFC_LOG_LEVEL=3 nfc-list -v | |
84 | ||
85 | * How to reproduce the bug. | |
86 | ||
87 | Please include a short test program that exhibits the behavior. | |
88 | As a last resort, you can also provide a pointer to a larger piece | |
89 | of software that can be downloaded. | |
90 | ||
91 | * If the bug was a crash, the exact text that was printed out | |
92 | when the crash occured. | |
93 | ||
94 | * Further information such as stack traces may be useful, but | |
95 | is not necessary. | |
96 | ||
97 | Patches | |
98 | ======= | |
99 | ||
100 | Patches can be posted to http://code.google.com/p/libnfc/issues/list or | |
101 | can be sent directly to libnfc's developers: | |
102 | http://nfc-tools.org/index.php?title=Contact | |
103 | ||
104 | If the patch fixes a bug, it is usually a good idea to include | |
105 | all the information described in "How to Report Bugs". | |
106 | ||
107 | Building | |
108 | ======== | |
109 | ||
110 | It should be as simple as running these two commands: | |
111 | ||
112 | ./configure | |
113 | make | |
114 | ||
115 | Troubleshooting | |
116 | =============== | |
117 | ||
118 | Touchatag/ACR122: | |
119 | ----------------- | |
120 | If your Touchatag or ACR122 device fails being detected by libnfc, make sure | |
121 | that PCSC-lite daemon (pcscd) is installed and is running. | |
122 | ||
123 | If your Touchatag or ACR122 device fails being detected by PCSC-lite daemon | |
124 | (pcsc_scan doesn't see anything) then try removing the bogus firmware detection | |
125 | of libccid: edit libccid_Info.plist configuration file (usually | |
126 | /etc/libccid_Info.plist) and locate "<key>ifdDriverOptions</key>", turn | |
127 | "<string>0x0000</string>" value into 0x0004 to allow bogus devices and restart | |
128 | pcscd daemon. | |
129 | ||
130 | ACR122: | |
131 | ------- | |
132 | Using an ACR122 device with libnfc and without tag (e.g. to use NFCIP modes or | |
133 | card emulation) needs yet another PCSC-lite tweak: You need to allow usage of | |
134 | CCID Exchange command. To do this, edit libccid_Info.plist configuration file | |
135 | (usually /etc/libccid_Info.plist) and locate "<key>ifdDriverOptions</key>", | |
136 | turn "<string>0x0000</string>" value into 0x0001 to allow CCID exchange or | |
137 | 0x0005 to allow CCID exchange and bogus devices (cf previous remark) and | |
138 | restart pcscd daemon. | |
139 | ||
140 | Warning: if you use ACS CCID drivers (acsccid), configuration file is located | |
141 | in something like: /usr/lib/pcsc/drivers/ifd-acsccid.bundle/Contents/Info.plist | |
142 | ||
143 | SCL3711: | |
144 | -------- | |
145 | Libnfc cannot be used concurrently with the PCSC proprietary driver of SCL3711. | |
146 | Two possible solutions: | |
147 | * Either you don't install SCL3711 driver at all | |
148 | * Or you stop the PCSC daemon when you want to use libnfc-based tools | |
149 | ||
150 | PN533 USB device on Linux >= 3.1: | |
151 | --------------------------------- | |
152 | Since Linux kernel version 3.1, two kernel-modules must not be loaded in order | |
153 | to use libnfc : "nfc" and "pn533". | |
154 | To prevent kernel from loading automatically these modules, you can blacklist | |
155 | them in a modprobe conf file. This file is provided within libnfc archive: | |
156 | sudo cp contrib/linux/blacklist-libnfc.conf /etc/modprobe.d/blacklist-libnfc.conf | |
157 | ||
158 | Proprietary Notes | |
159 | ================= | |
160 | ||
161 | FeliCa is s registered trademark of the Sony Corporation. | |
162 | MIFARE is a trademark of NXP Semiconductors. | |
163 | Jewel Topaz is a trademark of Innovision Research & Technology. | |
164 | All other trademarks are the property of their respective owners. | |
165 |
0 | *- | |
1 | * Free/Libre Near Field Communication (NFC) library | |
2 | * | |
3 | * Libnfc historical contributors: | |
4 | * Copyright (C) 2009 Roel Verdult | |
5 | * Copyright (C) 2009-2013 Romuald Conty | |
6 | * Copyright (C) 2010-2012 Romain Tartière | |
7 | * Copyright (C) 2010-2013 Philippe Teuwen | |
8 | * Copyright (C) 2012-2013 Ludovic Rousseau | |
9 | * Additional contributors of Windows-specific parts: | |
10 | * Copyright (C) 2010 Glenn Ergeerts | |
11 | * Copyright (C) 2013 Alex Lian | |
12 | -* | |
13 | ||
14 | Requirements | |
15 | ============ | |
16 | ||
17 | - MinGW-w64 compiler toolchain [1] | |
18 | - LibUsb-Win32 1.2.5.0 (or greater) [2] | |
19 | - CMake 2.8 [3] | |
20 | ||
21 | This was tested on Windows 7 64 bit, but should work on Windows Vista and | |
22 | Windows XP and 32 bit as well. | |
23 | Only the ACS ACR122 and the ASK Logo readers are tested at the moment, so any feedback about other devices is very welcome. | |
24 | ||
25 | Community forum: http://www.libnfc.org/community/ | |
26 | ||
27 | Building | |
28 | ======== | |
29 | ||
30 | To build the distribution the MinGW Makefiles generator of CMake was used. Here | |
31 | is an example of how to generate a distribution with the above mentioned | |
32 | requirements fulfilled (it is assumed the CMake binaries are in the system | |
33 | path, this is optional during installation of CMake): | |
34 | ||
35 | - Add the following directories to your PATH: | |
36 | ||
37 | c:\MinGW64\bin;c:\MinGW64\x86_64-w64-mingw32\lib32;c:\MinGW64\x86_64-w64-mingw32\include | |
38 | ||
39 | - Now it is possible to run CMake and mingw32-make: | |
40 | ||
41 | C:\dev\libnfc-read-only> mkdir ..\libnfc-build | |
42 | C:\dev\libnfc-read-only> cd ..\libnfc-build | |
43 | C:\dev\libnfc-build> cmake-gui . | |
44 | ||
45 | Now you can configure the build. Press "Configure", specify "MinGW32 Makefiles" | |
46 | and then you have the opportunity to set some configuration variables. If you | |
47 | don't want a Debug build change the variable CMAKE_BUILD_TYPE to "Release". | |
48 | ||
49 | If a non-GUI solution is preferred one can use: | |
50 | ||
51 | C:\dev\libnfc-build> cmake -G "MinGW Makefiles" | |
52 | -DCMAKE_BUILD_TYPE=Release ..\libnfc-read-only | |
53 | ||
54 | Now run mingw32-make to build: | |
55 | ||
56 | C:\dev\libnfc-read-only\bin> mingw32-make | |
57 | ||
58 | The build will create a shared library for Windows (nfc.dll) to link your applications against. It will compile | |
59 | the tools against this shared library. | |
60 | ||
61 | References | |
62 | ========== | |
63 | [1] the easiest way is to use the TDM-GCC installer. | |
64 | Make sure to select MinGW-w64 in the installer, the regular MinGW does not contain headers for PCSC. | |
65 | http://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/tdm64-gcc-4.5.1.exe/download | |
66 | ||
67 | [2] http://sourceforge.net/projects/libusb-win32/files/ | |
68 | ||
69 | [3] http://www.cmake.org |
0 | *- | |
1 | * Free/Libre Near Field Communication (NFC) library | |
2 | * | |
3 | * Libnfc historical contributors: | |
4 | * Copyright (C) 2009 Roel Verdult | |
5 | * Copyright (C) 2009-2013 Romuald Conty | |
6 | * Copyright (C) 2010-2012 Romain Tartière | |
7 | * Copyright (C) 2010-2013 Philippe Teuwen | |
8 | * Copyright (C) 2012-2013 Ludovic Rousseau | |
9 | * Additional contributors of Windows-specific parts: | |
10 | * Copyright (C) 2010 Glenn Ergeerts | |
11 | * Copyright (C) 2013 Alex Lian | |
12 | -* | |
13 | ||
14 | Requirements | |
15 | ============ | |
16 | ||
17 | - MinGW-w64 compiler toolchain [1] | |
18 | - LibUsb-Win32 1.2.5.0 (or greater) [2] | |
19 | - CMake 2.8 [3] | |
20 | - PCRE for Windows [4] | |
21 | ||
22 | This was tested on Windows 7 64 bit, but should work on Windows Vista and | |
23 | Windows XP and 32 bit as well. | |
24 | Only the ACS ACR122 and the ASK Logo readers are tested at the moment, so any feedback about other devices is very welcome. | |
25 | ||
26 | Community forum: http://www.libnfc.org/community/ | |
27 | ||
28 | Building | |
29 | ======== | |
30 | ||
31 | To build the distribution the MinGW Makefiles generator of CMake was used. Here | |
32 | is an example of how to generate a distribution with the above mentioned | |
33 | requirements fulfilled (it is assumed the CMake binaries are in the system | |
34 | path, this is optional during installation of CMake): | |
35 | ||
36 | - Add the following directories to your PATH : c:\MinGW64\bin;c:\MinGW64\x86_64-w64-mingw32\lib32;c:\MinGW64\x86_64-w64-mingw32\include | |
37 | ||
38 | - Now it is possible to run CMake and mingw32-make: | |
39 | ||
40 | C:\dev\libnfc-read-only> mkdir ..\libnfc-build | |
41 | C:\dev\libnfc-read-only> cd ..\libnfc-build | |
42 | C:\dev\libnfc-build> cmake-gui . | |
43 | ||
44 | Now you can configure the build. Press "Configure", specify "MinGW32 Makefiles" | |
45 | and then you have the opportunity to set some configuration variables. If you | |
46 | don't want a Debug build change the variable CMAKE_BUILD_TYPE to "Release". | |
47 | ||
48 | If a non-GUI solution is preferred one can use: | |
49 | ||
50 | C:\dev\libnfc-build> cmake -G "MinGW Makefiles" | |
51 | -DCMAKE_BUILD_TYPE=Release ..\libnfc-read-only | |
52 | ||
53 | Now run mingw32-make to build: | |
54 | ||
55 | C:\dev\libnfc-read-only\bin> mingw32-make | |
56 | ||
57 | The build will create a shared library for Windows (nfc.dll) to link your applications against. It will compile | |
58 | the tools against this shared library. | |
59 | ||
60 | References | |
61 | ========== | |
62 | [1] the easiest way is to use the TDM-GCC installer. | |
63 | Make sure to select MinGW-w64 in the installer, the regular MinGW does not contain headers for PCSC. | |
64 | http://sourceforge.net/projects/tdm-gcc/files/TDM-GCC%20Installer/tdm64-gcc-4.5.1.exe/download | |
65 | [2] http://sourceforge.net/projects/libusb-win32/files/ | |
66 | [3] http://www.cmake.org | |
67 | [4] http://gnuwin32.sourceforge.net/packages/pcre.htm⏎ |
0 | ``` | |
1 | *- | |
2 | * Free/Libre Near Field Communication (NFC) library | |
3 | * | |
4 | * Libnfc historical contributors: | |
5 | * Copyright (C) 2009 Roel Verdult | |
6 | * Copyright (C) 2009-2015 Romuald Conty | |
7 | * Copyright (C) 2010-2012 Romain Tartière | |
8 | * Copyright (C) 2010-2013 Philippe Teuwen | |
9 | * Copyright (C) 2012-2013 Ludovic Rousseau | |
10 | * Additional contributors: | |
11 | * See AUTHORS file | |
12 | -* | |
13 | ``` | |
14 | ||
15 | General Information | |
16 | =================== | |
17 | ||
18 | libnfc is a library which allows userspace application access to NFC devices. | |
19 | ||
20 | The official web site is: | |
21 | http://www.nfc-tools.org/ | |
22 | ||
23 | The official forum site is: | |
24 | http://www.libnfc.org/community/ | |
25 | ||
26 | The official development site is: | |
27 | https://github.com/nfc-tools/libnfc | |
28 | ||
29 | Important note: this file covers POSIX systems, for Windows please read README-Windows.md | |
30 | ||
31 | Requirements | |
32 | ============ | |
33 | ||
34 | Some NFC drivers depend on third party software: | |
35 | ||
36 | * pn53x_usb & acr122_usb: | |
37 | ||
38 | - libusb-0.1 http://libusb.sf.net | |
39 | ||
40 | * acr122_pcsc: | |
41 | ||
42 | - pcsc-lite http://pcsclite.alioth.debian.org/ | |
43 | - pcsc: | |
44 | ||
45 | - Support build with pcsc driver, which can be using all compatible readers, Feitian R502 and bR500 already passed the test. | |
46 | ||
47 | The regression test suite depends on the cutter framework: | |
48 | http://cutter.sf.net | |
49 | ||
50 | Installation | |
51 | ============ | |
52 | ||
53 | See the file `INSTALL` for configure, build and install details. | |
54 | ||
55 | Additionnally, you may need to grant permissions to your user to drive your device. | |
56 | Under GNU/Linux systems, if you use udev, you could use the provided udev rules. | |
57 | e.g. under Debian, Ubuntu, etc. | |
58 | ||
59 | sudo cp contrib/udev/93-pn53x.rules /lib/udev/rules.d/ | |
60 | ||
61 | Under FreeBSD, if you use devd, there is also a rules file: contrib/devd/pn53x.conf. | |
62 | ||
63 | Configuration | |
64 | ============= | |
65 | ||
66 | In order to change the default behavior of the library, the libnfc uses a | |
67 | configuration file located in sysconfdir (as provided to ./configure). | |
68 | ||
69 | A sample commented file is available in sources: libnfc.conf.sample | |
70 | ||
71 | If you have compiled using: | |
72 | ||
73 | ./configure --prefix=/usr --sysconfdir=/etc | |
74 | ||
75 | you can make configuration directory and copy the sample file: | |
76 | ||
77 | sudo mkdir /etc/nfc | |
78 | sudo cp libnfc.conf.sample /etc/nfc/libnfc.conf | |
79 | ||
80 | To configure multiple devices, you can either modify libnfc.conf or create a | |
81 | file per device in a nfc/devices.d directory: | |
82 | ||
83 | sudo mkdir -p /etc/nfc/devices.d | |
84 | printf 'name = "My first device"\nconnstring = "pn532_uart:/dev/ttyACM0"\n' | sudo tee /etc/nfc/devices.d/first.conf | |
85 | printf 'name = "My second device"\nconnstring = "pn532_uart:/dev/ttyACM1"\n' | sudo tee /etc/nfc/devices.d/second.conf | |
86 | ||
87 | How to report bugs | |
88 | ================== | |
89 | ||
90 | To report a bug, visit https://github.com/nfc-tools/libnfc/issues and fill | |
91 | out a bug report form. | |
92 | ||
93 | If you have questions, remarks, we encourage you to post this in the developers | |
94 | community: | |
95 | http://www.libnfc.org/community | |
96 | ||
97 | Please make sure to include: | |
98 | ||
99 | * The version of libnfc | |
100 | ||
101 | * Information about your system. For instance: | |
102 | ||
103 | - What operating system and version | |
104 | - For Linux, what version of the C library | |
105 | ||
106 | And anything else you think is relevant. | |
107 | ||
108 | * A trace with debug activated. | |
109 | ||
110 | Reproduce the bug with debug, e.g. if it was: | |
111 | ||
112 | $ nfc-list -v | |
113 | ||
114 | run it as: | |
115 | ||
116 | $ LIBNFC_LOG_LEVEL=3 nfc-list -v | |
117 | ||
118 | * How to reproduce the bug. | |
119 | ||
120 | Please include a short test program that exhibits the behavior. | |
121 | ||
122 | As a last resort, you can also provide a pointer to a larger piece | |
123 | ||
124 | of software that can be downloaded. | |
125 | ||
126 | * If the bug was a crash, the exact text that was printed out | |
127 | ||
128 | when the crash occured. | |
129 | ||
130 | * Further information such as stack traces may be useful, but | |
131 | ||
132 | is not necessary. | |
133 | ||
134 | Patches | |
135 | ======= | |
136 | ||
137 | Patches can be posted to https://github.com/nfc-tools/libnfc/issues | |
138 | ||
139 | If the patch fixes a bug, it is usually a good idea to include | |
140 | all the information described in "How to Report Bugs". | |
141 | ||
142 | Building | |
143 | ======== | |
144 | ||
145 | It should be as simple as running these two commands: | |
146 | ||
147 | ./configure | |
148 | make | |
149 | ||
150 | To build with specific driver(s), see option `--with-drivers=...` detailed in `./configure --help`. | |
151 | ||
152 | Note: if you're using directly the development repository and not the release sources, you will have to execute firstly `autoreconf -vis`. | |
153 | ||
154 | Troubleshooting | |
155 | =============== | |
156 | ||
157 | Touchatag/ACR122: | |
158 | ----------------- | |
159 | ||
160 | If your Touchatag or ACR122 device fails being detected by libnfc, make sure | |
161 | that PCSC-lite daemon (`pcscd`) is installed and is running. | |
162 | ||
163 | If your Touchatag or ACR122 device fails being detected by PCSC-lite daemon | |
164 | (`pcsc_scan` doesn't see anything) then try removing the bogus firmware detection | |
165 | of libccid: edit libccid_Info.plist configuration file (usually | |
166 | `/etc/libccid_Info.plist`) and locate `<key>ifdDriverOptions</key>`, turn | |
167 | `<string>0x0000</string>` value into `0x0004` to allow bogus devices and restart | |
168 | pcscd daemon. | |
169 | ||
170 | ACR122: | |
171 | ------- | |
172 | ||
173 | Using an ACR122 device with libnfc and without tag (e.g. to use NFCIP modes or | |
174 | card emulation) needs yet another PCSC-lite tweak: You need to allow usage of | |
175 | CCID Exchange command. To do this, edit `libccid_Info.plist` configuration file | |
176 | (usually `/etc/libccid_Info.plist`) and locate `<key>ifdDriverOptions</key>`, | |
177 | turn `<string>0x0000</string>` value into `0x0001` to allow CCID exchange or | |
178 | `0x0005` to allow CCID exchange and bogus devices (cf previous remark) and | |
179 | restart pcscd daemon. | |
180 | ||
181 | Warning: if you use ACS CCID drivers (acsccid), configuration file is located | |
182 | in something like: `/usr/lib/pcsc/drivers/ifd-acsccid.bundle/Contents/Info.plist` | |
183 | ||
184 | SCL3711: | |
185 | -------- | |
186 | ||
187 | Libnfc cannot be used concurrently with the PCSC proprietary driver of SCL3711. | |
188 | Two possible solutions: | |
189 | ||
190 | * Either you don't install SCL3711 driver at all | |
191 | * Or you stop the PCSC daemon when you want to use libnfc-based tools | |
192 | ||
193 | PN533 USB device on Linux >= 3.1: | |
194 | --------------------------------- | |
195 | ||
196 | Since Linux kernel version 3.1, a few kernel-modules must not be loaded in order | |
197 | to use libnfc : "nfc", "pn533" and "pn533_usb". | |
198 | To prevent kernel from loading automatically these modules, you can blacklist | |
199 | them in a modprobe conf file. This file is provided within libnfc archive: | |
200 | ||
201 | sudo cp contrib/linux/blacklist-libnfc.conf /etc/modprobe.d/blacklist-libnfc.conf | |
202 | ||
203 | FEITIAN bR500 and R502: | |
204 | ----------------------- | |
205 | ||
206 | Libnfc can work with PCSC proprietary driver of bR500 and R502, which is already available on most Linux setups. | |
207 | To activate the PCSC support: `./configure --with-drivers=pcsc`. | |
208 | Readers known to work: | |
209 | ||
210 | - Feitian bR500 | |
211 | - Feitian R502 Dual interface reader | |
212 | - Feitian R502 CL(Contactless) reader | |
213 | ||
214 | These readers are support by CCID since v1.4.25, make sure your CCID driver version higher or equal to 1.4.25. | |
215 | ||
216 | 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) | |
217 | ||
218 | ``` | |
219 | grep -A 1 CFBundleShortVersionString /usr/local/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist | |
220 | ``` | |
221 | ||
222 | 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/) | |
223 | ||
224 | ``` | |
225 | grep -A 1 CFBundleShortVersionString /usr/lib/pcsc/drivers/ifd-ccid.bundle/Contents/Info.plist | |
226 | ``` | |
227 | ||
228 | Proprietary Notes | |
229 | ================= | |
230 | FeliCa is a registered trademark of the Sony Corporation. | |
231 | MIFARE is a trademark of NXP Semiconductors. | |
232 | Jewel Topaz is a trademark of Innovision Research & Technology. | |
233 | All other trademarks are the property of their respective owners. |
5 | 5 | # set other_libs to a list of additional libs that cannot be reached by dependency analysis |
6 | 6 | SET(other_libs "") |
7 | 7 | |
8 | SET(dirs "@LIBUSB_LIBRARY_DIR@" "@PCRE_BIN_DIRS@") | |
8 | SET(dirs "@LIBUSB_LIBRARY_DIR@") | |
9 | 9 | |
10 | 10 | fixup_bundle("${bundle}" "${other_libs}" "${dirs}") |
0 | # -*- cmake -*- | |
1 | ||
2 | ||
3 | # Use the following variables to compile and link against LibNFC: | |
4 | # LIBNFC_FOUND - True if LibNFC was found on your system | |
5 | # LIBNFC_USE_FILE - The file making LibNFC usable | |
6 | # LIBNFC_DEFINITIONS - Definitions needed to build with LibNFC | |
7 | # LIBNFC_INCLUDE_DIR - Directory where nfc/nfc.h can be found | |
8 | # LIBNFC_INCLUDE_DIRS - List of directories of LibNFC and it's dependencies | |
9 | # LIBNFC_LIBRARY - LibNFC library location | |
10 | # LIBNFC_LIBRARIES - List of libraries to link against LibNFC library | |
11 | # LIBNFC_LIBRARY_DIRS - List of directories containing LibNFC' libraries | |
12 | # LIBNFC_ROOT_DIR - The base directory of LibNFC | |
13 | # LIBNFC_VERSION_STRING - A human-readable string containing the version | |
14 | # LIBNFC_VERSION_MAJOR - The major version of LibNFC | |
15 | # LIBNFC_VERSION_MINOR - The minor version of LibNFC | |
16 | # LIBNFC_VERSION_PATCH - The patch version of LibNFC | |
17 | ||
18 | set ( LIBNFC_FOUND 1 ) | |
19 | set ( LIBNFC_USE_FILE "@LIBNFC_USE_FILE@" ) | |
20 | ||
21 | set ( LIBNFC_DEFINITIONS "@LIBNFC_DEFINITIONS@" ) | |
22 | set ( LIBNFC_INCLUDE_DIR "@LIBNFC_INCLUDE_DIR@" ) | |
23 | set ( LIBNFC_INCLUDE_DIRS "@LIBNFC_INCLUDE_DIRS@" ) | |
24 | set ( LIBNFC_LIBRARY "@LIBNFC_LIBRARY@" ) | |
25 | set ( LIBNFC_LIBRARIES "@LIBNFC_LIBRARIES@" ) | |
26 | set ( LIBNFC_LIBRARY_DIRS "@LIBNFC_LIBRARY_DIRS@" ) | |
27 | set ( LIBNFC_ROOT_DIR "@LIBNFC_ROOT_DIR@" ) | |
28 | ||
29 | set ( LIBNFC_VERSION_STRING "@LIBNFC_VERSION_STRING@" ) | |
30 | set ( LIBNFC_VERSION_MAJOR "@LIBNFC_VERSION_MAJOR@" ) | |
31 | set ( LIBNFC_VERSION_MINOR "@LIBNFC_VERSION_MINOR@" ) | |
32 | set ( LIBNFC_VERSION_PATCH "@LIBNFC_VERSION_PATCH@" ) | |
33 |
0 | # This is a basic version file for the Config-mode of find_package(). | |
1 | # It is used by write_basic_package_version_file() as input file for configure_file() | |
2 | # to create a version-file which can be installed along a config.cmake file. | |
3 | # | |
4 | # The created file sets PACKAGE_VERSION_EXACT if the current version string and | |
5 | # the requested version string are exactly the same and it sets | |
6 | # PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version. | |
7 | # The variable CVF_VERSION must be set before calling configure_file(). | |
8 | ||
9 | set(PACKAGE_VERSION "@LIBNFC_VERSION_STRING@") | |
10 | ||
11 | if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}" ) | |
12 | set(PACKAGE_VERSION_COMPATIBLE FALSE) | |
13 | else() | |
14 | set(PACKAGE_VERSION_COMPATIBLE TRUE) | |
15 | if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") | |
16 | set(PACKAGE_VERSION_EXACT TRUE) | |
17 | endif() | |
18 | endif() | |
19 | ||
20 | # if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: | |
21 | if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") | |
22 | return() | |
23 | endif() | |
24 | ||
25 | # check that the installed version has the same 32/64bit-ness as the one which is currently searching: | |
26 | if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "8") | |
27 | math(EXPR installedBits "8 * 8") | |
28 | set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") | |
29 | set(PACKAGE_VERSION_UNSUITABLE TRUE) | |
30 | endif() |
2 | 2 | EXTRA_DIST = \ |
3 | 3 | FixBundle.cmake.in \ |
4 | 4 | config_posix.h.cmake \ |
5 | config_windows.h.cmake | |
5 | config_windows.h.cmake \ | |
6 | LibNFCConfig.cmake.in \ | |
7 | LibNFCConfigVersion.cmake.in \ | |
8 | UseLibNFC.cmake |
0 | # -*- cmake -*- | |
1 | ||
2 | add_definitions ( ${LIBNFC_DEFINITIONS} ) | |
3 | include_directories ( ${LIBNFC_INCLUDE_DIRS} ) | |
4 | link_directories ( ${LIBNFC_LIBRARY_DIRS} ) |
0 | # This CMake script wants to use pcre functionality needed for windows | |
1 | # compilation. However, since PCRE isn't really a default install location | |
2 | # there isn't much to search. | |
3 | # | |
4 | # Operating Systems Supported: | |
5 | # - Windows (requires MinGW) | |
6 | # Tested with Windows XP/Windows 7 | |
7 | # | |
8 | # This should work for both 32 bit and 64 bit systems. | |
9 | # | |
10 | # Author: A. Lian <alex.lian@gmail.com> | |
11 | # | |
12 | ||
13 | IF(WIN32) | |
14 | IF(NOT PCRE_FOUND) | |
15 | FIND_PATH(PCRE_INCLUDE_DIRS regex.h) | |
16 | FIND_LIBRARY(PCRE_LIBRARIES NAMES PCRE pcre) | |
17 | FIND_PATH(PCRE_BIN_DIRS pcre3.dll) | |
18 | ||
19 | IF(PCRE_INCLUDE_DIRS AND PCRE_LIBRARIES AND PCRE_BIN_DIRS) | |
20 | SET(PCRE_FOUND TRUE) | |
21 | ENDIF(PCRE_INCLUDE_DIRS AND PCRE_LIBRARIES AND PCRE_BIN_DIRS) | |
22 | ENDIF(NOT PCRE_FOUND) | |
23 | ||
24 | IF(PCRE_FOUND) | |
25 | IF(NOT PCRE_FIND_QUIETLY) | |
26 | MESSAGE(STATUS "Found PCRE: ${PCRE_LIBRARIES} ${PCRE_INCLUDE_DIRS} ${PCRE_BIN_DIRS}") | |
27 | ENDIF (NOT PCRE_FIND_QUIETLY) | |
28 | ELSE(PCRE_FOUND) | |
29 | IF(PCRE_FIND_REQUIRED) | |
30 | MESSAGE(FATAL_ERROR "Could not find PCRE") | |
31 | ENDIF(PCRE_FIND_REQUIRED) | |
32 | ENDIF(PCRE_FOUND) | |
33 | ||
34 | INCLUDE(FindPackageHandleStandardArgs) | |
35 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG | |
36 | PCRE_LIBRARIES | |
37 | PCRE_INCLUDE_DIRS | |
38 | PCRE_BIN_DIRS | |
39 | ) | |
40 | ||
41 | ENDIF(WIN32) |
0 | SET(LIBNFC_DRIVER_PCSC OFF CACHE BOOL "Enable PC/SC reader support (Depends on PC/SC)") | |
0 | 1 | SET(LIBNFC_DRIVER_ACR122_PCSC OFF CACHE BOOL "Enable ACR122 support (Depends on PC/SC)") |
1 | 2 | SET(LIBNFC_DRIVER_ACR122_USB ON CACHE BOOL "Enable ACR122 support (Direct USB connection)") |
2 | 3 | SET(LIBNFC_DRIVER_ACR122S ON CACHE BOOL "Enable ACR122S support (Use serial port)") |
10 | 11 | ENDIF(WIN32) |
11 | 12 | SET(LIBNFC_DRIVER_PN532_UART ON CACHE BOOL "Enable PN532 UART support (Use serial port)") |
12 | 13 | SET(LIBNFC_DRIVER_PN53X_USB ON CACHE BOOL "Enable PN531 and PN531 USB support (Depends on libusb)") |
14 | ||
15 | IF(LIBNFC_DRIVER_PCSC) | |
16 | FIND_PACKAGE(PCSC REQUIRED) | |
17 | ADD_DEFINITIONS("-DDRIVER_PCSC_ENABLED") | |
18 | SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pcsc") | |
19 | ENDIF(LIBNFC_DRIVER_PCSC) | |
13 | 20 | |
14 | 21 | IF(LIBNFC_DRIVER_ACR122_PCSC) |
15 | 22 | FIND_PACKAGE(PCSC REQUIRED) |
60 | 67 | SET(USB_REQUIRED TRUE) |
61 | 68 | ENDIF(LIBNFC_DRIVER_PN53X_USB) |
62 | 69 | |
63 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/drivers) | |
70 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/libnfc/drivers) |
1 | 1 | COPYING-CMAKE-SCRIPTS \ |
2 | 2 | FindLIBUSB.cmake \ |
3 | 3 | FindPCSC.cmake \ |
4 | FindPCRE.cmake \ | |
5 | 4 | UseDoxygen.cmake \ |
6 | 5 | LibnfcDrivers.cmake |
90 | 90 | |
91 | 91 | configure_file(${DOXYFILE_IN} Doxyfile ESCAPE_QUOTES IMMEDIATE @ONLY) |
92 | 92 | |
93 | get_target_property(DOC_TARGET doc TYPE) | |
94 | if(NOT DOC_TARGET) | |
93 | if(NOT TARGET doc) | |
95 | 94 | add_custom_target(doc) |
96 | 95 | endif() |
97 | 96 |
0 | 0 | # General init |
1 | 1 | |
2 | 2 | # /!\ Don't forget to update 'CMakeLists.txt' too /!\ |
3 | AC_INIT([libnfc],[1.7.1],[nfc-tools@googlegroups.com]) | |
3 | AC_INIT([libnfc],[1.8.0],[nfc-tools@googlegroups.com]) | |
4 | 4 | |
5 | 5 | AC_CONFIG_MACRO_DIR([m4]) |
6 | 6 | |
12 | 12 | AC_DEFINE_UNQUOTED([GIT_REVISION], ["$GIT_REVISION"], [GIT revision]) |
13 | 13 | fi |
14 | 14 | |
15 | AM_INIT_AUTOMAKE(subdir-objects dist-bzip2 no-dist-gzip) | |
15 | AM_INIT_AUTOMAKE(subdir-objects dist-bzip2 no-dist-gzip foreign) | |
16 | 16 | m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) |
17 | 17 | |
18 | 18 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) |
46 | 46 | 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]) |
47 | 47 | AC_CHECK_HEADERS([linux/spi/spidev.h], [spi_available="yes"]) |
48 | 48 | AC_CHECK_HEADERS([linux/i2c-dev.h], [i2c_available="yes"]) |
49 | AC_CHECK_HEADERS([linux_nfc_api.h], [nfc_nci_available="yes"]) | |
49 | 50 | AC_CHECK_FUNCS([memmove memset select strdup strerror strstr strtol usleep], |
50 | 51 | [AC_DEFINE([_XOPEN_SOURCE], [600], [Enable POSIX extensions if present])]) |
51 | 52 | |
124 | 125 | |
125 | 126 | # Enable I2C if |
126 | 127 | AM_CONDITIONAL(I2C_ENABLED, [test x"$i2c_required" = x"yes"]) |
128 | if test x"$i2c_required" = x"yes" | |
129 | then | |
130 | AC_SEARCH_LIBS([clock_gettime], [rt]) | |
131 | fi | |
132 | ||
133 | # Enable Libnfc-NCI if required | |
134 | if test x"$nfc_nci_required" = x"yes" | |
135 | then | |
136 | PKG_CHECK_MODULES([LIBNFC_NCI], [libnfc-nci], | |
137 | [AC_MSG_NOTICE([libnfc-nci present])], | |
138 | [AC_MSG_ERROR([libnfc-nci not present but required for some drivers configuration])] | |
139 | ) | |
140 | CFLAGS="$CFLAGS $LIBNFC_NCI_CFLAGS" | |
141 | fi | |
127 | 142 | |
128 | 143 | # Documentation (default: no) |
129 | 144 | AC_ARG_ENABLE([doc],AS_HELP_STRING([--enable-doc],[Enable documentation generation.]),[enable_doc=$enableval],[enable_doc="no"]) |
0 | 0 | EXTRA_DIST = \ |
1 | pn532_via_uart2usb.conf.sample \ | |
2 | arygon.conf.sample \ | |
3 | pn532_uart_on_rpi.conf.sample | |
1 | arygon.conf.sample \ | |
2 | pn532_i2c_on_rpi.conf.sample \ | |
3 | pn532_spi_on_rpi.conf.sample \ | |
4 | pn532_uart_on_rpi_3.conf.sample \ | |
5 | pn532_uart_on_rpi.conf.sample \ | |
6 | pn532_via_uart2usb.conf.sample |
0 | ## Typical configuration file for PN532 device on R-Pi 3 connected using miniUART | |
1 | ## Note: Changes have been made to R-Pi 3 with the addition of Bluetooth LE | |
2 | ## The UART is now being used by the BLE module. Instead of disabling it, you can | |
3 | ## use the PN532 device with the "mini UART", which is still hijacked by the linux kernel | |
4 | ## as a serial console | |
5 | ## | |
6 | ## Tested recipe with PN532 breakout from Adafruit | |
7 | ## | |
8 | ## To enable uart on GPIO, add this line to bottom of /boot/config.txt | |
9 | ## enable_uart=1 | |
10 | ## | |
11 | ## Stop and disable serial console: | |
12 | ## $ sudo systemctl stop serial-getty@ttyS0.service | |
13 | ## $ sudo systemctl disable serial-getty@ttyS0.service | |
14 | ## | |
15 | ## Remove console from /boot/cmdline.txt by removing: | |
16 | ## console=serial0,115200 Save and reboot for changes to take effect. | |
17 | ## | |
18 | name = "PN532 board via UART" | |
19 | connstring = pn532_uart:/dev/ttyS0 | |
20 | allow_intrusive_scan = true | |
21 |
0 | # udev rules file for PN531 and PN533 devices (for udev 0.98 version) | |
1 | # to be installed in /etc/udev/rules.d | |
2 | ||
3 | SUBSYSTEM!="usb|usb_device", GOTO="pn53x_rules_end" | |
4 | ACTION!="add", GOTO="pn53x_rules_end" | |
5 | ||
6 | # PN531 | |
7 | ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="0531", MODE="0664", GROUP="plugdev" | |
8 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0193", MODE="0664", GROUP="plugdev" | |
9 | ||
10 | # PN533 | |
11 | ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="2533", MODE="0664", GROUP="plugdev" | |
12 | ATTRS{idVendor}=="04e6", ATTRS{idProduct}=="5591", MODE="0664", GROUP="plugdev" | |
13 | ATTRS{idVendor}=="1fd3", ATTRS{idProduct}=="0608", MODE="0664", GROUP="plugdev" | |
14 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="02e1", MODE="0664", GROUP="plugdev" | |
15 | ||
16 | # ACR122 / Touchatag | |
17 | ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2200", MODE="0664", GROUP="plugdev" | |
18 | ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90cc", MODE="0664", GROUP="plugdev" | |
19 | ||
20 | LABEL="pn53x_rules_end" |
0 | # udev rules file for PN531 and PN533 devices (for udev 0.98 version) | |
1 | # to be installed in /etc/udev/rules.d | |
2 | ||
3 | SUBSYSTEM!="usb|usb_device", GOTO="pn53x_rules_end" | |
4 | ACTION!="add", GOTO="pn53x_rules_end" | |
5 | ||
6 | # PN531 | |
7 | ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="0531", MODE="0664", GROUP="plugdev" | |
8 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0193", MODE="0664", GROUP="plugdev" | |
9 | ||
10 | # PN533 | |
11 | ATTRS{idVendor}=="04cc", ATTRS{idProduct}=="2533", MODE="0664", GROUP="plugdev" | |
12 | ATTRS{idVendor}=="04e6", ATTRS{idProduct}=="5591", MODE="0664", GROUP="plugdev" | |
13 | ATTRS{idVendor}=="04e6", ATTRS{idProduct}=="5594", MODE="0664", GROUP="plugdev" | |
14 | ATTRS{idVendor}=="1fd3", ATTRS{idProduct}=="0608", MODE="0664", GROUP="plugdev" | |
15 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="02e1", MODE="0664", GROUP="plugdev" | |
16 | ||
17 | # ACR122 / Touchatag | |
18 | ATTRS{idVendor}=="072f", ATTRS{idProduct}=="2200", MODE="0664", GROUP="plugdev" | |
19 | ATTRS{idVendor}=="072f", ATTRS{idProduct}=="90cc", MODE="0664", GROUP="plugdev" | |
20 | ||
21 | LABEL="pn53x_rules_end" |
122 | 122 | { |
123 | 123 | struct serial_port_windows *spw; |
124 | 124 | |
125 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed); | |
125 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d baud.", uiPortSpeed); | |
126 | 126 | // Set port speed (Input and Output) |
127 | 127 | switch (uiPortSpeed) { |
128 | 128 | case 9600: |
134 | 134 | case 460800: |
135 | 135 | break; |
136 | 136 | default: |
137 | 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); | |
137 | 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); | |
138 | 138 | return; |
139 | 139 | }; |
140 | 140 | spw = (struct serial_port_windows *) sp; |
3 | 3 | EXPORTS |
4 | 4 | nfc_init |
5 | 5 | nfc_exit |
6 | nfc_register_driver | |
6 | 7 | nfc_open |
7 | 8 | nfc_close |
8 | nfc_abbort_command | |
9 | nfc_abort_command | |
9 | 10 | nfc_list_devices |
10 | 11 | nfc_idle |
11 | 12 | nfc_initiator_init |
16 | 17 | nfc_initiator_select_dep_target |
17 | 18 | nfc_initiator_poll_dep_target |
18 | 19 | nfc_initiator_deselect_target |
19 | nfc_initiator_poll_targets | |
20 | 20 | nfc_initiator_transceive_bytes |
21 | 21 | nfc_initiator_transceive_bits |
22 | 22 | nfc_initiator_transceive_bytes_timed |
35 | 35 | nfc_device_get_connstring |
36 | 36 | nfc_device_get_supported_modulation |
37 | 37 | nfc_device_get_supported_baud_rate |
38 | nfc_device_get_supported_baud_rate_target_mode | |
38 | 39 | nfc_device_set_property_int |
39 | 40 | nfc_device_set_property_bool |
40 | 41 | iso14443a_crc |
41 | 42 | iso14443a_crc_append |
43 | iso14443b_crc | |
44 | iso14443b_crc_append | |
42 | 45 | iso14443a_locate_historical_bytes |
46 | nfc_free | |
43 | 47 | nfc_version |
44 | 48 | nfc_device_get_information_about |
45 | 49 | str_nfc_modulation_type |
33 | 33 | // Handle platform specific includes |
34 | 34 | #include "contrib/windows.h" |
35 | 35 | |
36 | //There is no setenv()and unsetenv() in windows,but we can use putenv() instead. | |
36 | 37 | int setenv(const char *name, const char *value, int overwrite) |
37 | 38 | { |
38 | int exists = GetEnvironmentVariableA(name, NULL, 0); | |
39 | if ((exists && overwrite) || (!exists)) { | |
40 | if (!SetEnvironmentVariableA(name, value)) { | |
41 | // Set errno here correctly | |
42 | return -1; | |
43 | } | |
44 | return 0; | |
39 | char *env = getenv(name); | |
40 | if ((env && overwrite) || (!env)) { | |
41 | char *str[32]; | |
42 | strcpy(str, name); | |
43 | strcat(str, "="); | |
44 | strcat(str, value); | |
45 | return putenv(str); | |
45 | 46 | } |
46 | // Exists and overwrite is 0. | |
47 | 47 | return -1; |
48 | 48 | } |
49 | 49 | |
50 | 50 | void unsetenv(const char *name) |
51 | 51 | { |
52 | SetEnvironmentVariableA(name, NULL); | |
52 | char *str[32]; | |
53 | strcpy(str, name); | |
54 | strcat(str, "="); | |
55 | putenv(str); | |
53 | 56 | } |
7 | 7 | nfc-mfsetuid |
8 | 8 | nfc-poll |
9 | 9 | nfc-relay |
10 | pn53x-diagnose | |
11 | pn53x-sam | |
12 | pn53x-tamashell | |
10 | 13 | ) |
11 | 14 | |
12 | 15 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libnfc) |
73 | 73 | pn53x_tamashell_SOURCES = pn53x-tamashell.c |
74 | 74 | pn53x_tamashell_LDADD = $(top_builddir)/libnfc/libnfc.la \ |
75 | 75 | $(top_builddir)/utils/libnfcutils.la |
76 | pn53x_tamashell_CFLAGS = @READLINE_INCLUDES@ -I$(top_srcdir) | |
76 | 77 | pn53x_tamashell_LDFLAGS = @READLINE_LIBS@ |
77 | 78 | |
78 | 79 | quick_start_example1_SOURCES = doc/quick_start_example1.c |
22 | 22 | .B libnfc |
23 | 23 | issue tracker at: |
24 | 24 | .br |
25 | .BR http://code.google.com/p/libnfc/issues | |
25 | .BR https://github.com/nfc-tools/libnfc/issues | |
26 | 26 | .SH LICENCE |
27 | 27 | .B libnfc |
28 | 28 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
17 | 17 | .B libnfc |
18 | 18 | issue tracker at: |
19 | 19 | .br |
20 | .BR http://code.google.com/p/libnfc/issues | |
20 | .BR https://github.com/nfc-tools/libnfc/issues | |
21 | 21 | .SH LICENCE |
22 | 22 | .B libnfc |
23 | 23 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
17 | 17 | .B libnfc |
18 | 18 | issue tracker at: |
19 | 19 | .br |
20 | .BR http://code.google.com/p/libnfc/issues | |
20 | .BR https://github.com/nfc-tools/libnfc/issues | |
21 | 21 | .SH LICENCE |
22 | 22 | .B libnfc |
23 | 23 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
34 | 34 | Please report any bugs on the |
35 | 35 | .Em libnfc |
36 | 36 | issue tracker at: |
37 | .Em http://code.google.com/p/libnfc/issues | |
37 | .Em https://github.com/nfc-tools/libnfc/issues | |
38 | 38 | .Sh LICENCE |
39 | 39 | .Em libnfc |
40 | 40 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
38 | 38 | .B libnfc |
39 | 39 | issue tracker at: |
40 | 40 | .br |
41 | .BR http://code.google.com/p/libnfc/issues | |
41 | .BR https://github.com/nfc-tools/libnfc/issues | |
42 | 42 | .SH LICENCE |
43 | 43 | .B libnfc |
44 | 44 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
265 | 265 | }, |
266 | 266 | .nti = { |
267 | 267 | .nai = { |
268 | abtAtqa = { 0x03, 0x44 }, | |
269 | abtUid = { 0x08, 0xab, 0xcd, 0xef }, | |
270 | btSak = 0x20, | |
268 | .abtAtqa = { 0x03, 0x44 }, | |
269 | .abtUid = { 0x08, 0xab, 0xcd, 0xef }, | |
270 | .btSak = 0x20, | |
271 | 271 | .szUidLen = 4, |
272 | 272 | .abtAts = { 0x75, 0x77, 0x81, 0x02, 0x80 }, |
273 | 273 | .szAtsLen = 5, |
13 | 13 | The nfc-emulate-uid tool demonstrates that this can still be done using |
14 | 14 | transmission of raw frames, and the desired UID can be optionally specified. |
15 | 15 | |
16 | This makes it a serious thread for security systems that rely only on the | |
16 | This makes it a serious threat for security systems that rely only on the | |
17 | 17 | uniqueness of the UID. |
18 | 18 | |
19 | 19 | Unfortunately, this example can't directly start in fully customisable |
53 | 53 | .B libnfc |
54 | 54 | issue tracker at: |
55 | 55 | .br |
56 | .BR http://code.google.com/p/libnfc/issues | |
56 | .BR https://github.com/nfc-tools/libnfc/issues | |
57 | 57 | .SH LICENCE |
58 | 58 | .B libnfc |
59 | 59 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
78 | 78 | if (pnd != NULL) { |
79 | 79 | printf("\nAborting current command...\n"); |
80 | 80 | nfc_abort_command(pnd); |
81 | } | |
81 | nfc_close(pnd); | |
82 | } | |
83 | nfc_exit(context); | |
84 | exit(EXIT_SUCCESS); | |
82 | 85 | } |
83 | 86 | |
84 | 87 | static void |
236 | 239 | } |
237 | 240 | } |
238 | 241 | } |
239 | nfc_close(pnd); | |
240 | nfc_exit(context); | |
241 | exit(EXIT_SUCCESS); | |
242 | 242 | } |
23 | 23 | .B libnfc |
24 | 24 | issue tracker at: |
25 | 25 | .br |
26 | .BR http://code.google.com/p/libnfc/issues | |
26 | .BR https://github.com/nfc-tools/libnfc/issues | |
27 | 27 | .SH LICENCE |
28 | 28 | .B libnfc |
29 | 29 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | 11 | * Copyright (C) 2011 Adam Laurie |
12 | * Copyright (C) 2014 Dario Carluccio | |
12 | 13 | * |
13 | 14 | * Redistribution and use in source and binary forms, with or without |
14 | 15 | * modification, are permitted provided that the following conditions are met: |
139 | 140 | static void |
140 | 141 | print_usage(char *argv[]) |
141 | 142 | { |
142 | printf("Usage: %s [OPTIONS] [UID]\n", argv[0]); | |
143 | printf("Usage: %s [OPTIONS] [UID|BLOCK0]\n", argv[0]); | |
143 | 144 | printf("Options:\n"); |
144 | 145 | printf("\t-h\tHelp. Print this message.\n"); |
145 | 146 | printf("\t-f\tFormat. Delete all data (set to 0xFF) and reset ACLs to default.\n"); |
146 | 147 | printf("\t-q\tQuiet mode. Suppress output of READER and CARD data (improves timing).\n"); |
147 | 148 | printf("\n\tSpecify UID (4 HEX bytes) to set UID, or leave blank for default '01234567'.\n"); |
149 | printf("\n\tSpecify BLOCK0 (16 HEX bytes) to set content of Block0. CRC (Byte 4) is recalculated an overwritten'.\n"); | |
148 | 150 | printf("\tThis utility can be used to recover cards that have been damaged by writing bad\n"); |
149 | 151 | printf("\tdata (e.g. wrong BCC), thus making them non-selectable by most tools/readers.\n"); |
150 | 152 | printf("\n\t*** Note: this utility only works with special Mifare 1K cards (Chinese clones).\n\n"); |
176 | 178 | } |
177 | 179 | abtData[4] = abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3]; |
178 | 180 | iso14443a_crc_append(abtData, 16); |
181 | } else if (strlen(argv[arg]) == 32) { | |
182 | for (i = 0 ; i < 16 ; ++i) { | |
183 | memcpy(tmp, argv[arg] + i * 2, 2); | |
184 | sscanf(tmp, "%02x", &c); | |
185 | abtData[i] = (char) c; | |
186 | } | |
187 | abtData[4] = abtData[0] ^ abtData[1] ^ abtData[2] ^ abtData[3]; | |
188 | iso14443a_crc_append(abtData, 16); | |
179 | 189 | } else { |
180 | 190 | ERR("%s is not supported option.", argv[arg]); |
181 | 191 | print_usage(argv); |
354 | 364 | // now reset UID |
355 | 365 | iso14443a_crc_append(abtHalt, 2); |
356 | 366 | transmit_bytes(abtHalt, 4); |
357 | transmit_bits(abtUnlock1, 7); | |
358 | if (format) { | |
359 | transmit_bytes(abtWipe, 1); | |
360 | transmit_bytes(abtHalt, 4); | |
361 | transmit_bits(abtUnlock1, 7); | |
362 | } | |
363 | transmit_bytes(abtUnlock2, 1); | |
367 | ||
368 | if (!transmit_bits(abtUnlock1, 7)) { | |
369 | printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n"); | |
370 | } else { | |
371 | if (format) { | |
372 | transmit_bytes(abtWipe, 1); | |
373 | transmit_bytes(abtHalt, 4); | |
374 | transmit_bits(abtUnlock1, 7); | |
375 | } | |
376 | ||
377 | if (transmit_bytes(abtUnlock2, 1)) { | |
378 | printf("Card unlocked\n"); | |
379 | } else { | |
380 | printf("Warning: Unlock command [2/2]: failed / not acknowledged.\n"); | |
381 | } | |
382 | } | |
383 | ||
364 | 384 | transmit_bytes(abtWrite, 4); |
365 | 385 | transmit_bytes(abtData, 18); |
366 | 386 | if (format) { |
41 | 41 | .B libnfc |
42 | 42 | issue tracker at: |
43 | 43 | .br |
44 | .BR http://code.google.com/p/libnfc/issues | |
44 | .BR https://github.com/nfc-tools/libnfc/issues | |
45 | 45 | .SH LICENCE |
46 | 46 | .B libnfc |
47 | 47 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * Redistribution and use in source and binary forms, with or without |
13 | 14 | * modification, are permitted provided that the following conditions are met: |
100 | 101 | |
101 | 102 | const uint8_t uiPollNr = 20; |
102 | 103 | const uint8_t uiPeriod = 2; |
103 | const nfc_modulation nmModulations[5] = { | |
104 | const nfc_modulation nmModulations[6] = { | |
104 | 105 | { .nmt = NMT_ISO14443A, .nbr = NBR_106 }, |
105 | 106 | { .nmt = NMT_ISO14443B, .nbr = NBR_106 }, |
106 | 107 | { .nmt = NMT_FELICA, .nbr = NBR_212 }, |
107 | 108 | { .nmt = NMT_FELICA, .nbr = NBR_424 }, |
108 | 109 | { .nmt = NMT_JEWEL, .nbr = NBR_106 }, |
110 | { .nmt = NMT_ISO14443BICLASS, .nbr = NBR_106 }, | |
109 | 111 | }; |
110 | const size_t szModulations = 5; | |
112 | const size_t szModulations = 6; | |
111 | 113 | |
112 | 114 | nfc_target nt; |
113 | 115 | int res = 0; |
144 | 146 | |
145 | 147 | if (res > 0) { |
146 | 148 | print_nfc_target(&nt, verbose); |
149 | printf("Waiting for card removing..."); | |
150 | fflush(stdout); | |
151 | while (0 == nfc_initiator_target_is_present(pnd, NULL)) {} | |
152 | nfc_perror(pnd, "nfc_initiator_target_is_present"); | |
153 | printf("done.\n"); | |
147 | 154 | } else { |
148 | 155 | printf("No target found.\n"); |
149 | 156 | } |
150 | ||
151 | printf("Waiting for card removing..."); | |
152 | while (0 == nfc_initiator_target_is_present(pnd, NULL)) {} | |
153 | nfc_perror(pnd, "nfc_initiator_target_is_present"); | |
154 | printf("done.\n"); | |
155 | 157 | |
156 | 158 | nfc_close(pnd); |
157 | 159 | nfc_exit(context); |
21 | 21 | .B libnfc |
22 | 22 | issue tracker at: |
23 | 23 | .br |
24 | .BR http://code.google.com/p/libnfc/issues | |
24 | .BR https://github.com/nfc-tools/libnfc/issues | |
25 | 25 | .SH LICENCE |
26 | 26 | .B libnfc |
27 | 27 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
12 | 12 | .B libnfc |
13 | 13 | issue tracker at: |
14 | 14 | .br |
15 | .BR http://code.google.com/p/libnfc/issues | |
15 | .BR https://github.com/nfc-tools/libnfc/issues | |
16 | 16 | .SH LICENCE |
17 | 17 | .B libnfc |
18 | 18 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
18 | 18 | .B libnfc |
19 | 19 | issue tracker at: |
20 | 20 | .br |
21 | .BR http://code.google.com/p/libnfc/issues | |
21 | .BR https://github.com/nfc-tools/libnfc/issues | |
22 | 22 | .SH LICENCE |
23 | 23 | .B libnfc |
24 | 24 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
0 | 0 | #!/bin/sh |
1 | ||
2 | #DEBUG='//;' | |
1 | 3 | |
2 | 4 | cat << EOF | \ |
3 | 5 | pn53x-tamashell |\ |
4 | awk '\ | |
6 | awk $DEBUG'\ | |
5 | 7 | /^> #.*:/{ |
6 | 8 | sub(/^> #/,"") |
7 | 9 | n=$0 |
20 | 22 | # Select one typeB target |
21 | 23 | 4A010300 |
22 | 24 | |
25 | # SELECT AID "1TIC.ICA" | |
26 | 4001 00a4 0400 08 315449432e494341 | |
27 | ||
23 | 28 | # Select ICC file |
24 | 4001 80a4 0800 04 3f00 0002 | |
29 | 4001 00a4 0000 02 3f00 | |
30 | 4001 00a4 0000 02 0002 | |
25 | 31 | #ICC: |
26 | 4001 80b2 0104 1d | |
32 | 4001 00b2 0104 1d | |
27 | 33 | |
28 | 34 | # Select Holder file |
29 | 4001 80a4 0800 04 3f00 3f1c | |
35 | 4001 00a4 0000 02 3f1c | |
30 | 36 | #Holder1: |
31 | 4001 80b2 0104 1d | |
37 | 4001 00b2 0104 1d | |
32 | 38 | #Holder2: |
33 | 4001 80b2 0204 1d | |
39 | 4001 00b2 0204 1d | |
34 | 40 | |
35 | 41 | # Select EnvHol file |
36 | 4001 00a4 0800 04 2000 2001 | |
42 | 4001 00a4 0000 00 | |
43 | 4001 00a4 0000 02 2000 | |
44 | 4001 00a4 0000 02 2001 | |
37 | 45 | #EnvHol1: |
38 | 46 | 4001 00b2 0104 1d |
39 | 47 | #EnvHol2: |
40 | 48 | 4001 00b2 0204 1d |
41 | 49 | |
42 | 50 | # Select EvLog file |
43 | 4001 00a4 0800 04 2000 2010 | |
51 | 4001 00a4 0000 02 2010 | |
44 | 52 | #EvLog1: |
45 | 53 | 4001 00b2 0104 1d |
46 | 54 | #EvLog2: |
49 | 57 | 4001 00b2 0304 1d |
50 | 58 | |
51 | 59 | # Select ConList file |
52 | 4001 00a4 0800 04 2000 2050 | |
60 | 4001 00a4 0000 02 2050 | |
53 | 61 | #ConList: |
54 | 62 | 4001 00b2 0104 1d |
55 | 63 | |
56 | 64 | # Select Contra file |
57 | 4001 00a4 0800 04 2000 2020 | |
65 | 4001 00a4 0000 02 2020 | |
58 | 66 | #Contra1: |
59 | 67 | 4001 00b2 0104 1d |
60 | 68 | #Contra2: |
81 | 89 | 4001 00b2 0c04 1d |
82 | 90 | |
83 | 91 | # Select Counter file |
84 | 4001 00a4 0800 04 2000 2069 | |
92 | 4001 00a4 0000 02 2069 | |
85 | 93 | #Counter: |
86 | 94 | 4001 00b2 0104 1d |
87 | 95 | |
88 | 96 | # Select LoadLog file |
89 | 4001 00a4 0800 04 1000 1014 | |
97 | 4001 00a4 0000 00 | |
98 | 4001 00a4 0000 02 1000 | |
99 | 4001 00a4 0000 02 1014 | |
90 | 100 | #LoadLog: |
91 | 101 | 4001 00b2 0104 1d |
92 | 102 | |
93 | 103 | # Select Purcha file |
94 | 4001 00a4 08 0004 1000 1015 | |
104 | 4001 00a4 0000 02 1015 | |
95 | 105 | #Purcha1: |
96 | 106 | 4001 00b2 0104 1d |
97 | 107 | #Purcha2: |
100 | 110 | 4001 00b2 0304 1d |
101 | 111 | |
102 | 112 | # Select SpecEv file |
103 | 4001 00a4 08 0004 2000 2040 | |
113 | 4001 00a4 0000 00 | |
114 | 4001 00a4 0000 02 2000 | |
115 | 4001 00a4 0000 02 2040 | |
104 | 116 | #SpecEv1: |
105 | 117 | 4001 00b2 0104 1d |
106 | 118 | #SpecEv2: |
67 | 67 | .B libnfc |
68 | 68 | issue tracker at: |
69 | 69 | .br |
70 | .BR http://code.google.com/p/libnfc/issues | |
70 | .BR https://github.com/nfc-tools/libnfc/issues | |
71 | 71 | .SH LICENCE |
72 | 72 | .B libnfc |
73 | 73 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * This program is free software: you can redistribute it and/or modify it |
13 | 14 | * under the terms of the GNU Lesser General Public License as published by the |
234 | 235 | } nfc_iso14443bi_info; |
235 | 236 | |
236 | 237 | /** |
238 | * @struct nfc_iso14443biclass_info | |
239 | * @brief NFC ISO14443BiClass tag information | |
240 | */ | |
241 | typedef struct { | |
242 | uint8_t abtUID[8]; | |
243 | } nfc_iso14443biclass_info; | |
244 | ||
245 | /** | |
237 | 246 | * @struct nfc_iso14443b2sr_info |
238 | 247 | * @brief NFC ISO14443-2B ST SRx tag information |
239 | 248 | */ |
259 | 268 | uint8_t btSensRes[2]; |
260 | 269 | uint8_t btId[4]; |
261 | 270 | } nfc_jewel_info; |
271 | ||
272 | /** | |
273 | * @struct nfc_barcode_info | |
274 | * @brief Thinfilm NFC Barcode information | |
275 | */ | |
276 | typedef struct { | |
277 | size_t szDataLen; | |
278 | uint8_t abtData[32]; | |
279 | } nfc_barcode_info; | |
262 | 280 | |
263 | 281 | /** |
264 | 282 | * @union nfc_target_info |
273 | 291 | nfc_iso14443b2ct_info nci; |
274 | 292 | nfc_jewel_info nji; |
275 | 293 | nfc_dep_info ndi; |
294 | nfc_barcode_info nti; // "t" for Thinfilm, "b" already used | |
295 | nfc_iso14443biclass_info nhi; // hid iclass / picopass - nii already used | |
276 | 296 | } nfc_target_info; |
277 | 297 | |
278 | 298 | /** |
300 | 320 | NMT_ISO14443B2CT, // ISO14443-2B ASK CTx |
301 | 321 | NMT_FELICA, |
302 | 322 | NMT_DEP, |
323 | NMT_BARCODE, // Thinfilm NFC Barcode | |
324 | NMT_ISO14443BICLASS, // HID iClass 14443B mode | |
325 | NMT_END_ENUM = NMT_ISO14443BICLASS, // dummy for sizing - always should alias last | |
303 | 326 | } nfc_modulation_type; |
304 | 327 | |
305 | 328 | /** |
27 | 27 | * @file nfc.h |
28 | 28 | * @brief libnfc interface |
29 | 29 | * |
30 | * Provide all usefull functions (API) to handle NFC devices. | |
30 | * Provide all useful functions (API) to handle NFC devices. | |
31 | 31 | */ |
32 | 32 | |
33 | 33 | #ifndef _LIBNFC_H_ |
34 | 34 | # define _LIBNFC_H_ |
35 | ||
36 | # include <sys/time.h> | |
37 | 35 | |
38 | 36 | # include <stdint.h> |
39 | 37 | # include <stdbool.h> |
126 | 124 | NFC_EXPORT const char *nfc_device_get_connstring(nfc_device *pnd); |
127 | 125 | NFC_EXPORT int nfc_device_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); |
128 | 126 | NFC_EXPORT int nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); |
127 | 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); | |
129 | 128 | |
130 | 129 | /* Properties accessors */ |
131 | 130 | NFC_EXPORT int nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value); |
46 | 46 | |
47 | 47 | INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses) |
48 | 48 | |
49 | IF(WIN32) | |
50 | # Windows now requires regex, so we utilize PCRE | |
51 | # since Windows doesn't get the benefit of finding in CMake | |
52 | # it has to be added manually | |
53 | IF(PCRE_FOUND) | |
54 | INCLUDE_DIRECTORIES(${PCRE_INCLUDE_DIRS}) | |
55 | LINK_DIRECTORIES(${PCRE_LIBRARY_DIRS}) | |
56 | ENDIF(PCRE_FOUND) | |
57 | ENDIF(WIN32) | |
58 | ||
59 | 49 | IF(PCSC_FOUND) |
60 | 50 | INCLUDE_DIRECTORIES(${PCSC_INCLUDE_DIRS}) |
61 | 51 | LINK_DIRECTORIES(${PCSC_LIBRARY_DIRS}) |
88 | 78 | TARGET_LINK_LIBRARIES(nfc ${LIBUSB_LIBRARIES}) |
89 | 79 | ENDIF(LIBUSB_FOUND) |
90 | 80 | |
91 | SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 0) | |
81 | IF(LIBRT_FOUND) | |
82 | TARGET_LINK_LIBRARIES(nfc ${LIBRT_LIBRARIES}) | |
83 | ENDIF(LIBRT_FOUND) | |
84 | ||
85 | SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 6 VERSION 6.0.0) | |
92 | 86 | |
93 | 87 | IF(WIN32) |
94 | 88 | # Libraries that are windows specific |
95 | 89 | TARGET_LINK_LIBRARIES(nfc wsock32) |
96 | IF(PCRE_FOUND) | |
97 | TARGET_LINK_LIBRARIES(nfc ${PCRE_LIBRARIES}) | |
98 | ENDIF(PCRE_FOUND) | |
99 | 90 | |
100 | 91 | ADD_CUSTOM_COMMAND( |
101 | 92 | OUTPUT libnfc.lib |
102 | COMMAND dlltool -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll | |
93 | COMMAND ${DLLTOOL} -d ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def -l ${CMAKE_CURRENT_BINARY_DIR}/libnfc.lib ${CMAKE_CURRENT_BINARY_DIR}/libnfc.dll | |
103 | 94 | DEPENDS nfc ${CMAKE_CURRENT_SOURCE_DIR}/../contrib/win32/nfc.def |
104 | 95 | ) |
105 | 96 | ADD_CUSTOM_TARGET(win32lib ALL DEPENDS libnfc.lib) |
21 | 21 | nfc-internal.h \ |
22 | 22 | target-subr.h |
23 | 23 | |
24 | libnfc_la_LDFLAGS = -no-undefined -version-info 5:1:0 -export-symbols-regex '^nfc_|^iso14443a_|^str_nfc_|pn53x_transceive|pn532_SAMConfiguration|pn53x_read_register|pn53x_write_register' | |
24 | 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' | |
25 | 25 | libnfc_la_CFLAGS = @DRIVERS_CFLAGS@ |
26 | 26 | libnfc_la_LIBADD = \ |
27 | 27 | $(top_builddir)/libnfc/chips/libnfcchips.la \ |
43 | 43 | endif |
44 | 44 | |
45 | 45 | EXTRA_DIST = \ |
46 | CMakeLists.txt | |
46 | CMakeLists.txt \ | |
47 | additional-pages.dox |
134 | 134 | |
135 | 135 | if (recCount < 0) { |
136 | 136 | res = NFC_EIO; |
137 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, | |
138 | "Error: read only %d bytes (%d expected) (%s).", (int)recCount, (int) szRx, strerror(errno)); | |
137 | 139 | } else { |
138 | 140 | if (recCount < (ssize_t)szRx) { |
139 | 141 | res = NFC_EINVARG; |
166 | 168 | return NFC_SUCCESS; |
167 | 169 | } else { |
168 | 170 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, |
169 | "Error: wrote only %d bytes (%d expected).", (int)writeCount, (int) szTx); | |
171 | "Error: wrote only %d bytes (%d expected) (%s).", (int)writeCount, (int) szTx, strerror(errno)); | |
170 | 172 | return NFC_EIO; |
171 | 173 | } |
172 | 174 | } |
188 | 190 | size_t szRes = 1; |
189 | 191 | |
190 | 192 | res[0] = NULL; |
191 | DIR *dir; | |
192 | if ((dir = opendir("/dev")) == NULL) { | |
193 | DIR *pdDir; | |
194 | if ((pdDir = opendir("/dev")) == NULL) { | |
193 | 195 | perror("opendir error: /dev"); |
194 | 196 | return res; |
195 | 197 | } |
196 | struct dirent entry; | |
197 | struct dirent *result; | |
198 | ||
199 | while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) { | |
198 | struct dirent *pdDirEnt; | |
199 | while ((pdDirEnt = readdir(pdDir)) != NULL) { | |
200 | 200 | const char **p = i2c_ports_device_radix; |
201 | 201 | while (*p) { |
202 | if (!strncmp(entry.d_name, *p, strlen(*p))) { | |
202 | if (!strncmp(pdDirEnt->d_name, *p, strlen(*p))) { | |
203 | 203 | char **res2 = realloc(res, (szRes + 1) * sizeof(char *)); |
204 | 204 | if (!res2) { |
205 | 205 | perror("malloc"); |
206 | 206 | goto oom; |
207 | 207 | } |
208 | 208 | res = res2; |
209 | if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) { | |
209 | if (!(res[szRes - 1] = malloc(6 + strlen(pdDirEnt->d_name)))) { | |
210 | 210 | perror("malloc"); |
211 | 211 | goto oom; |
212 | 212 | } |
213 | sprintf(res[szRes - 1], "/dev/%s", entry.d_name); | |
213 | sprintf(res[szRes - 1], "/dev/%s", pdDirEnt->d_name); | |
214 | 214 | |
215 | 215 | szRes++; |
216 | 216 | res[szRes - 1] = NULL; |
219 | 219 | } |
220 | 220 | } |
221 | 221 | oom: |
222 | closedir(dir); | |
222 | closedir(pdDir); | |
223 | 223 | |
224 | 224 | return res; |
225 | 225 | } |
195 | 195 | struct spi_ioc_transfer tr_send = { |
196 | 196 | .tx_buf = (unsigned long) pbtTx, |
197 | 197 | .rx_buf = 0, |
198 | .len = szTx , | |
198 | .len = szTx, | |
199 | 199 | .delay_usecs = 0, |
200 | 200 | .speed_hz = 0, |
201 | 201 | .bits_per_word = 0, |
282 | 282 | |
283 | 283 | DIR *pdDir = opendir("/dev"); |
284 | 284 | struct dirent *pdDirEnt; |
285 | struct dirent entry; | |
286 | struct dirent *result; | |
287 | while ((readdir_r(pdDir, &entry, &result) == 0) && (result != NULL)) { | |
288 | pdDirEnt = &entry; | |
285 | while ((pdDirEnt = readdir(pdDir)) != NULL) { | |
289 | 286 | #if !defined(__APPLE__) |
290 | 287 | if (!isdigit(pdDirEnt->d_name[strlen(pdDirEnt->d_name) - 1])) |
291 | 288 | continue; |
73 | 73 | #endif |
74 | 74 | |
75 | 75 | # if defined(__APPLE__) |
76 | const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial-", NULL }; | |
76 | const char *serial_ports_device_radix[] = { "tty.SLAB_USBtoUART", "tty.usbserial", "tty.usbmodem", NULL }; | |
77 | 77 | # elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined(__FreeBSD_kernel__) |
78 | 78 | const char *serial_ports_device_radix[] = { "cuaU", "cuau", NULL }; |
79 | # elif defined (__linux__) | |
79 | # elif defined (__NetBSD__) | |
80 | const char *serial_ports_device_radix[] = { "tty0", "ttyC", "ttyS", "ttyU", "ttyY", NULL }; | |
81 | # elif defined (__linux__) || defined (__CYGWIN__) | |
80 | 82 | const char *serial_ports_device_radix[] = { "ttyUSB", "ttyS", "ttyACM", "ttyAMA", "ttyO", NULL }; |
81 | 83 | # else |
82 | 84 | # error "Can't determine serial string for your system" |
83 | 85 | # endif |
86 | ||
87 | // As of 2015/Feb/22, Cygwin does not handle FIONREAD on physical serial devices. | |
88 | // We'll use TIOCINQ instead which is pretty much the same. | |
89 | #ifdef __CYGWIN__ | |
90 | # include <sys/termios.h> | |
91 | # define FIONREAD TIOCINQ | |
92 | #endif | |
84 | 93 | |
85 | 94 | // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct |
86 | 95 | # define CCLAIMED 0x80000000 |
178 | 187 | void |
179 | 188 | uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) |
180 | 189 | { |
181 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d bauds.", uiPortSpeed); | |
190 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Serial port speed requested to be set to %d baud.", uiPortSpeed); | |
182 | 191 | |
183 | 192 | // Portability note: on some systems, B9600 != 9600 so we have to do |
184 | 193 | // uint32_t <=> speed_t associations by hand. |
214 | 223 | break; |
215 | 224 | # endif |
216 | 225 | default: |
217 | 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).", | |
226 | 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).", | |
218 | 227 | uiPortSpeed); |
219 | 228 | return; |
220 | 229 | }; |
384 | 393 | size_t szRes = 1; |
385 | 394 | |
386 | 395 | res[0] = NULL; |
387 | DIR *dir; | |
388 | if ((dir = opendir("/dev")) == NULL) { | |
396 | DIR *pdDir; | |
397 | if ((pdDir = opendir("/dev")) == NULL) { | |
389 | 398 | perror("opendir error: /dev"); |
390 | 399 | return res; |
391 | 400 | } |
392 | struct dirent entry; | |
393 | struct dirent *result; | |
394 | while ((readdir_r(dir, &entry, &result) == 0) && (result != NULL)) { | |
401 | struct dirent *pdDirEnt; | |
402 | while ((pdDirEnt = readdir(pdDir)) != NULL) { | |
395 | 403 | #if !defined(__APPLE__) |
396 | if (!isdigit(entry.d_name[strlen(entry.d_name) - 1])) | |
404 | if (!isdigit(pdDirEnt->d_name[strlen(pdDirEnt->d_name) - 1])) | |
397 | 405 | continue; |
398 | 406 | #endif |
399 | 407 | const char **p = serial_ports_device_radix; |
400 | 408 | while (*p) { |
401 | if (!strncmp(entry.d_name, *p, strlen(*p))) { | |
409 | if (!strncmp(pdDirEnt->d_name, *p, strlen(*p))) { | |
402 | 410 | char **res2 = realloc(res, (szRes + 1) * sizeof(char *)); |
403 | 411 | if (!res2) { |
404 | 412 | perror("malloc"); |
405 | 413 | goto oom; |
406 | 414 | } |
407 | 415 | res = res2; |
408 | if (!(res[szRes - 1] = malloc(6 + strlen(entry.d_name)))) { | |
416 | if (!(res[szRes - 1] = malloc(6 + strlen(pdDirEnt->d_name)))) { | |
409 | 417 | perror("malloc"); |
410 | 418 | goto oom; |
411 | 419 | } |
412 | sprintf(res[szRes - 1], "/dev/%s", entry.d_name); | |
420 | sprintf(res[szRes - 1], "/dev/%s", pdDirEnt->d_name); | |
413 | 421 | |
414 | 422 | szRes++; |
415 | 423 | res[szRes - 1] = NULL; |
418 | 426 | } |
419 | 427 | } |
420 | 428 | oom: |
421 | closedir(dir); | |
429 | closedir(pdDir); | |
422 | 430 | |
423 | 431 | return res; |
424 | 432 | } |
34 | 34 | |
35 | 35 | #ifndef _WIN32 |
36 | 36 | // Under POSIX system, we use libusb (>= 0.1.12) |
37 | #include <stdint.h> | |
37 | 38 | #include <usb.h> |
38 | 39 | #define USB_TIMEDOUT ETIMEDOUT |
39 | 40 | #define _usb_strerror( X ) strerror(-X) |
80 | 80 | #define TgGetTargetStatus 0x8A |
81 | 81 | |
82 | 82 | /** @note PN53x's normal frame: |
83 | * | |
84 | * .-- Start | |
85 | * | .-- Packet length | |
86 | * | | .-- Length checksum | |
87 | * | | | .-- Direction (D4 Host to PN, D5 PN to Host) | |
88 | * | | | | .-- Code | |
89 | * | | | | | .-- Packet checksum | |
90 | * | | | | | | .-- Postamble | |
91 | * V | | | | | | | |
92 | * ----- V V V V V V | |
93 | * 00 FF 02 FE D4 02 2A 00 | |
83 | * See the PN532 (firmware) user manual, section 6.2.1.1: Normal information | |
84 | * frame, figure 13. Normal information frame, page 28 rev. 02 - 2007-11-07. | |
85 | * | |
86 | * .-- Preamble | |
87 | * | .-- Start | |
88 | * | | .-- Packet length | |
89 | * | | | .-- Length checksum | |
90 | * | | | | .-- Direction (D4 Host to PN, D5 PN to Host) | |
91 | * | | | | | .-- Code | |
92 | * | | | | | | .-- Packet checksum | |
93 | * | | | | | | | .-- Postamble | |
94 | * | V | | | | | | | |
95 | * V ----- V V V V V V | |
96 | * 00 00 FF 02 FE D4 02 2A 00 | |
94 | 97 | */ |
95 | 98 | |
96 | 99 | /** @note PN53x's extended frame: |
97 | * | |
98 | * .-- Start | |
99 | * | .-- Fixed to FF to enable extended frame | |
100 | * | | .-- Packet length | |
101 | * | | | .-- Length checksum | |
102 | * | | | | .-- Direction (D4 Host to PN, D5 PN to Host) | |
103 | * | | | | | .-- Code | |
104 | * | | | | | | .-- Packet checksum | |
105 | * | | | | | | | .-- Postamble | |
106 | * V V V | | | | | | |
107 | * ----- ----- ----- V V V V V | |
108 | * 00 FF FF FF 00 02 FE D4 02 2A 00 | |
100 | * See the PN532 (firmware) user manual, section 6.2.1.2: Extended information | |
101 | * frame, figure 14. Normal information frame, page 29 rev. 02 - 2007-11-07. | |
102 | * | |
103 | * .-- Preamble | |
104 | * | .-- Start | |
105 | * | | .-- Fixed to FF to enable extended frame | |
106 | * | | | .-- Packet length | |
107 | * | | | | .-- Length checksum | |
108 | * | | | | | .-- Direction (D4 Host to PN, D5 PN to Host) | |
109 | * | | | | | | .-- Code | |
110 | * | | | | | | | .-- Packet checksum | |
111 | * | | | | | | | | .-- Postamble | |
112 | * | V V V | | | | | | |
113 | * V ----- ----- ----- V V V V V | |
114 | * 00 00 FF FF FF 00 02 FE D4 02 2A 00 | |
109 | 115 | */ |
110 | 116 | |
111 | 117 | /** |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * This program is free software: you can redistribute it and/or modify it |
13 | 14 | * under the terms of the GNU Lesser General Public License as published by the |
51 | 52 | const uint8_t pn53x_ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 }; |
52 | 53 | const uint8_t pn53x_nack_frame[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 }; |
53 | 54 | static const uint8_t pn53x_error_frame[] = { 0x00, 0x00, 0xff, 0x01, 0xff, 0x7f, 0x81, 0x00 }; |
54 | const nfc_baud_rate pn53x_iso14443a_supported_baud_rates[] = { NBR_106, 0 }; | |
55 | const nfc_baud_rate pn532_iso14443a_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; | |
56 | const nfc_baud_rate pn533_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; | |
55 | 57 | const nfc_baud_rate pn53x_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 }; |
56 | 58 | const nfc_baud_rate pn53x_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; |
57 | 59 | const nfc_baud_rate pn53x_jewel_supported_baud_rates[] = { NBR_106, 0 }; |
60 | const nfc_baud_rate pn53x_barcode_supported_baud_rates[] = { NBR_106, 0 }; | |
58 | 61 | const nfc_baud_rate pn532_iso14443b_supported_baud_rates[] = { NBR_106, 0 }; |
59 | 62 | const nfc_baud_rate pn533_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; |
60 | 63 | const nfc_modulation_type pn53x_supported_modulation_as_target[] = {NMT_ISO14443A, NMT_FELICA, NMT_DEP, 0}; |
82 | 85 | } |
83 | 86 | |
84 | 87 | if (!CHIP_DATA(pnd)->supported_modulation_as_initiator) { |
85 | CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * 9); | |
88 | CHIP_DATA(pnd)->supported_modulation_as_initiator = malloc(sizeof(nfc_modulation_type) * (NMT_END_ENUM + 1)); | |
86 | 89 | if (! CHIP_DATA(pnd)->supported_modulation_as_initiator) |
87 | 90 | return NFC_ESOFT; |
88 | 91 | int nbSupportedModulation = 0; |
95 | 98 | if (pnd->btSupportByte & SUPPORT_ISO14443B) { |
96 | 99 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B; |
97 | 100 | nbSupportedModulation++; |
101 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443BI; | |
102 | nbSupportedModulation++; | |
103 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B2SR; | |
104 | nbSupportedModulation++; | |
105 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443B2CT; | |
106 | nbSupportedModulation++; | |
107 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_ISO14443BICLASS; | |
108 | nbSupportedModulation++; | |
98 | 109 | } |
99 | 110 | if (CHIP_DATA(pnd)->type != PN531) { |
100 | 111 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_JEWEL; |
112 | nbSupportedModulation++; | |
113 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_BARCODE; | |
101 | 114 | nbSupportedModulation++; |
102 | 115 | } |
103 | 116 | CHIP_DATA(pnd)->supported_modulation_as_initiator[nbSupportedModulation] = NMT_DEP; |
363 | 376 | pn53x_wrap_frame(const uint8_t *pbtTx, const size_t szTxBits, const uint8_t *pbtTxPar, |
364 | 377 | uint8_t *pbtFrame) |
365 | 378 | { |
366 | uint8_t btFrame; | |
367 | 379 | uint8_t btData; |
368 | 380 | uint32_t uiBitPos; |
369 | 381 | uint32_t uiDataPos = 0; |
390 | 402 | // air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + .. |
391 | 403 | while (true) { |
392 | 404 | // Reset the temporary frame byte; |
393 | btFrame = 0; | |
405 | uint8_t btFrame = 0; | |
394 | 406 | |
395 | 407 | for (uiBitPos = 0; uiBitPos < 8; uiBitPos++) { |
396 | 408 | // Copy as much data that fits in the frame byte |
565 | 577 | memcpy(pnti->nsi.abtUID, pbtRawData, 8); |
566 | 578 | break; |
567 | 579 | |
580 | case NMT_ISO14443BICLASS: | |
581 | // Store the UID | |
582 | for (uint8_t i = 0 ; i < 8 ; ++i) | |
583 | pnti->nhi.abtUID[7 - i] = pbtRawData[i]; | |
584 | break; | |
585 | ||
568 | 586 | case NMT_ISO14443B2CT: |
569 | 587 | // Store UID LSB |
570 | 588 | memcpy(pnti->nci.abtUID, pbtRawData, 2); |
603 | 621 | pbtRawData += 2; |
604 | 622 | memcpy(pnti->nji.btId, pbtRawData, 4); |
605 | 623 | break; |
606 | // Should not happend... | |
624 | case NMT_BARCODE: | |
625 | pnti->nti.szDataLen = szRawData; | |
626 | memcpy(pnti->nti.abtData, pbtRawData, szRawData); | |
627 | break; | |
628 | // Should not happend... | |
607 | 629 | case NMT_DEP: |
608 | 630 | return NFC_ECHIP; |
609 | break; | |
610 | 631 | } |
611 | 632 | return NFC_SUCCESS; |
612 | 633 | } |
819 | 840 | case NP_TIMEOUT_ATR: |
820 | 841 | CHIP_DATA(pnd)->timeout_atr = value; |
821 | 842 | return pn53x_RFConfiguration__Various_timings(pnd, pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_atr), pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_communication)); |
822 | break; | |
823 | 843 | case NP_TIMEOUT_COM: |
824 | 844 | CHIP_DATA(pnd)->timeout_communication = value; |
825 | 845 | return pn53x_RFConfiguration__Various_timings(pnd, pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_atr), pn53x_int_to_timeout(CHIP_DATA(pnd)->timeout_communication)); |
826 | break; | |
827 | // Following properties are invalid (not integer) | |
846 | // Following properties are invalid (not integer) | |
828 | 847 | case NP_HANDLE_CRC: |
829 | 848 | case NP_HANDLE_PARITY: |
830 | 849 | case NP_ACTIVATE_FIELD: |
862 | 881 | return res; |
863 | 882 | pnd->bCrc = bEnable; |
864 | 883 | return NFC_SUCCESS; |
865 | break; | |
866 | 884 | |
867 | 885 | case NP_HANDLE_PARITY: |
868 | 886 | // Handle parity bit by PN53X chip or parse it as data bit |
874 | 892 | return res; |
875 | 893 | pnd->bPar = bEnable; |
876 | 894 | return NFC_SUCCESS; |
877 | break; | |
878 | 895 | |
879 | 896 | case NP_EASY_FRAMING: |
880 | 897 | pnd->bEasyFraming = bEnable; |
881 | 898 | return NFC_SUCCESS; |
882 | break; | |
883 | 899 | |
884 | 900 | case NP_ACTIVATE_FIELD: |
885 | 901 | return pn53x_RFConfiguration__RF_field(pnd, bEnable); |
886 | break; | |
887 | 902 | |
888 | 903 | case NP_ACTIVATE_CRYPTO1: |
889 | 904 | btValue = (bEnable) ? SYMBOL_MF_CRYPTO1_ON : 0x00; |
890 | 905 | return pn53x_write_register(pnd, PN53X_REG_CIU_Status2, SYMBOL_MF_CRYPTO1_ON, btValue); |
891 | break; | |
892 | 906 | |
893 | 907 | case NP_INFINITE_SELECT: |
894 | 908 | // TODO Made some research around this point: |
900 | 914 | (bEnable) ? 0xff : 0x01, // MxRtyPSL, default: 0x01 |
901 | 915 | (bEnable) ? 0xff : 0x02 // MxRtyPassiveActivation, default: 0xff (0x00 leads to problems with PN531) |
902 | 916 | ); |
903 | break; | |
904 | 917 | |
905 | 918 | case NP_ACCEPT_INVALID_FRAMES: |
906 | 919 | btValue = (bEnable) ? SYMBOL_RX_NO_ERROR : 0x00; |
907 | 920 | return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_NO_ERROR, btValue); |
908 | break; | |
909 | 921 | |
910 | 922 | case NP_ACCEPT_MULTIPLE_FRAMES: |
911 | 923 | btValue = (bEnable) ? SYMBOL_RX_MULTIPLE : 0x00; |
912 | 924 | return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_MULTIPLE, btValue); |
913 | break; | |
914 | 925 | |
915 | 926 | case NP_AUTO_ISO14443_4: |
916 | 927 | if (bEnable == pnd->bAutoIso14443_4) |
918 | 929 | return NFC_SUCCESS; |
919 | 930 | pnd->bAutoIso14443_4 = bEnable; |
920 | 931 | return pn53x_set_parameters(pnd, PARAM_AUTO_RATS, bEnable); |
921 | break; | |
922 | 932 | |
923 | 933 | case NP_FORCE_ISO14443_A: |
924 | 934 | if (!bEnable) { |
934 | 944 | } |
935 | 945 | // Set the PN53X to force 100% ASK Modified miller decoding (default for 14443A cards) |
936 | 946 | return pn53x_write_register(pnd, PN53X_REG_CIU_TxAuto, SYMBOL_FORCE_100_ASK, 0x40); |
937 | break; | |
938 | 947 | |
939 | 948 | case NP_FORCE_ISO14443_B: |
940 | 949 | if (!bEnable) { |
946 | 955 | return res; |
947 | 956 | } |
948 | 957 | return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_FRAMING, 0x03); |
949 | break; | |
950 | 958 | |
951 | 959 | case NP_FORCE_SPEED_106: |
952 | 960 | if (!bEnable) { |
958 | 966 | return res; |
959 | 967 | } |
960 | 968 | return pn53x_write_register(pnd, PN53X_REG_CIU_RxMode, SYMBOL_RX_SPEED, 0x00); |
961 | break; | |
962 | // Following properties are invalid (not boolean) | |
969 | // Following properties are invalid (not boolean) | |
963 | 970 | case NP_TIMEOUT_COMMAND: |
964 | 971 | case NP_TIMEOUT_ATR: |
965 | 972 | case NP_TIMEOUT_COM: |
966 | 973 | return NFC_EINVARG; |
967 | break; | |
968 | 974 | } |
969 | 975 | |
970 | 976 | return NFC_EINVARG; |
1050 | 1056 | return NFC_SUCCESS; |
1051 | 1057 | } |
1052 | 1058 | |
1059 | // iclass requires special modulation settings | |
1060 | void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd) | |
1061 | { | |
1062 | // send a bunch of low level commands reverse engineered from a working iClass reader | |
1063 | // original device was using a PN512 | |
1064 | // | |
1065 | // // TxModeReg - Defines the data rate and framing during transmission. | |
1066 | //// set bit 4 for target mode? - RxWaitRF Set to logic 1, the counter for RxWait starts only if an external RF field is detected in Target mode for NFCIP-1 or in Card Communication mode | |
1067 | //pn512_write_register(0x12, "\x03", 1, false); | |
1068 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_TxMode, 0x03); | |
1069 | // | |
1070 | // // RxModeReg - Defines the data rate and framing during reception. | |
1071 | //pn512_write_register(0x13, "\x03", 1, false); | |
1072 | // addy changed to set bit 3 - RxNoErr (put data in fifo before flagging read end) | |
1073 | //pn512_write_register(0x13, "\x0B", 1, false); | |
1074 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_RxMode, 0x0B); | |
1075 | ||
1076 | // ManualRCVReg - Allows manual fine tuning of the internal receiver. | |
1077 | //pn512_write_register(0x1d, "\x10", 1, false); | |
1078 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_ManualRCV, 0x10); | |
1079 | ||
1080 | // RFCfgReg - Configures the receiver gain and RF level detector sensitivity. | |
1081 | //pn512_write_register(0x26, "\x70", 1, false); | |
1082 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_RFCfg, 0x70); | |
1083 | ||
1084 | // GsNOffReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched off. | |
1085 | //pn512_write_register(0x23, "\x88", 1, false); | |
1086 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOFF, 0x88); | |
1087 | ||
1088 | // GsNOnReg - Selects the conductance for the N-driver of the antenna driver pins TX1 and TX2 when the driver is switched on. | |
1089 | //pn512_write_register(0x27, "\xf8", 1, false); | |
1090 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_GsNOn, 0xf8); | |
1091 | ||
1092 | // CWGsPReg - Defines the conductance of the P-driver during times of no modulation. | |
1093 | //pn512_write_register(0x28, "\x3f", 1, false); | |
1094 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_CWGsP, 0x3f); | |
1095 | ||
1096 | // ModGsPReg - Defines the driver P-output conductance during modulation. | |
1097 | //pn512_write_register(0x29, "\x10", 1, false); | |
1098 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_ModGsP, 0x10); | |
1099 | ||
1100 | // TReloadReg (MSB) - Describes the MSB of the 16-bit long timer reload value. | |
1101 | //pn512_write_register(0x2c, "\x69", 1, false); | |
1102 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_hi, 0x69); | |
1103 | ||
1104 | // TReloadReg (LSB) - Describes the LSB of the 16-bit long timer reload value. | |
1105 | //pn512_write_register(0x2d, "\xf0", 1, false); | |
1106 | pn53x_WriteRegister(pnd, PN53X_REG_CIU_TReloadVal_lo, 0xf0); | |
1107 | } | |
1108 | ||
1053 | 1109 | int |
1054 | 1110 | pn532_initiator_init_secure_element(struct nfc_device *pnd) |
1055 | 1111 | { |
1067 | 1123 | size_t szTargetsData = sizeof(abtTargetsData); |
1068 | 1124 | int res = 0; |
1069 | 1125 | nfc_target nttmp; |
1070 | ||
1071 | if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT) { | |
1126 | memset(&nttmp, 0x00, sizeof(nfc_target)); | |
1127 | ||
1128 | if (nm.nmt == NMT_ISO14443BI || nm.nmt == NMT_ISO14443B2SR || nm.nmt == NMT_ISO14443B2CT || nm.nmt == NMT_ISO14443BICLASS) { | |
1072 | 1129 | if (CHIP_DATA(pnd)->type == RCS360) { |
1073 | 1130 | // TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select |
1074 | 1131 | pnd->last_error = NFC_ENOTIMPL; |
1095 | 1152 | size_t szInitiateLen = 2; |
1096 | 1153 | uint8_t abtSelect[] = { 0x0e, 0x00 }; |
1097 | 1154 | uint8_t abtRx[1]; |
1155 | uint8_t *pbtInitData = (uint8_t *) "\x0b"; | |
1156 | size_t szInitData = 1; | |
1098 | 1157 | // Getting random Chip_ID |
1099 | 1158 | if ((res = pn53x_initiator_transceive_bytes(pnd, abtInitiate, szInitiateLen, abtRx, sizeof(abtRx), timeout)) < 0) { |
1100 | 1159 | if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout |
1107 | 1166 | return res; |
1108 | 1167 | } |
1109 | 1168 | szTargetsData = (size_t)res; |
1169 | if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { | |
1170 | if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout | |
1171 | continue; | |
1172 | } else | |
1173 | return res; | |
1174 | } | |
1175 | szTargetsData = (size_t)res; | |
1110 | 1176 | } else if (nm.nmt == NMT_ISO14443B2CT) { |
1111 | 1177 | // Some work to do before getting the UID... |
1112 | 1178 | const uint8_t abtReqt[] = { 0x10 }; |
1179 | uint8_t *pbtInitData = (uint8_t *) "\x9F\xFF\xFF"; | |
1180 | size_t szInitData = 3; | |
1113 | 1181 | // Getting product code / fab code & store it in output buffer after the serial nr we'll obtain later |
1114 | 1182 | if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), abtTargetsData + 2, sizeof(abtTargetsData) - 2, timeout)) < 0) { |
1115 | 1183 | if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout |
1118 | 1186 | return res; |
1119 | 1187 | } |
1120 | 1188 | szTargetsData = (size_t)res; |
1121 | } | |
1122 | ||
1123 | if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { | |
1124 | if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout | |
1125 | continue; | |
1126 | } else | |
1127 | return res; | |
1128 | } | |
1129 | szTargetsData = (size_t)res; | |
1130 | if (nm.nmt == NMT_ISO14443B2CT) { | |
1189 | if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { | |
1190 | if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout | |
1191 | continue; | |
1192 | } else | |
1193 | return res; | |
1194 | } | |
1195 | szTargetsData = (size_t)res; | |
1131 | 1196 | if (szTargetsData != 2) |
1132 | 1197 | return 0; // Target is not ISO14443B2CT |
1133 | 1198 | uint8_t abtRead[] = { 0xC4 }; // Reading UID_MSB (Read address 4) |
1135 | 1200 | return res; |
1136 | 1201 | } |
1137 | 1202 | szTargetsData = 6; // u16 UID_LSB, u8 prod code, u8 fab code, u16 UID_MSB |
1138 | } | |
1203 | } else if (nm.nmt == NMT_ISO14443BICLASS) { | |
1204 | pn53x_initiator_init_iclass_modulation(pnd); | |
1205 | // | |
1206 | // Some work to do before getting the UID... | |
1207 | // send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response | |
1208 | uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL | |
1209 | uint8_t abtAnticol[11]; | |
1210 | if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout)) < 0) { | |
1211 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all"); | |
1212 | //if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout | |
1213 | // continue; | |
1214 | //} else | |
1215 | // return res; | |
1216 | } | |
1217 | // do select - returned anticol contains 'handle' for tag if present | |
1218 | abtReqt[0] = 0x0c; // iClass SELECT | |
1219 | abtAnticol[0] = 0x81; // iClass ANTICOL | |
1220 | if ((res = pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout)) < 0) { | |
1221 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol"); | |
1222 | return res; | |
1223 | } | |
1224 | // write back anticol handle to get UID | |
1225 | if ((res = pn53x_initiator_transceive_bytes(pnd, abtAnticol, 9, abtTargetsData, 10, timeout)) < 0) { | |
1226 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass get UID"); | |
1227 | return res; | |
1228 | } | |
1229 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "iClass raw UID: %02x %02x %02x %02x %02x %02x %02x %02x", abtTargetsData[0], abtTargetsData[1], abtTargetsData[2], abtTargetsData[3], abtTargetsData[4], abtTargetsData[5], abtTargetsData[6], abtTargetsData[7]); | |
1230 | szTargetsData = 8; | |
1231 | nttmp.nm = nm; | |
1232 | if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { | |
1233 | return res; | |
1234 | } | |
1235 | } else { | |
1236 | ||
1237 | if ((res = pn53x_initiator_transceive_bytes(pnd, pbtInitData, szInitData, abtTargetsData, sizeof(abtTargetsData), timeout)) < 0) { | |
1238 | if ((res == NFC_ERFTRANS) && (CHIP_DATA(pnd)->last_status_byte == 0x01)) { // Chip timeout | |
1239 | continue; | |
1240 | } else | |
1241 | return res; | |
1242 | } | |
1243 | szTargetsData = (size_t)res; | |
1244 | } | |
1245 | ||
1139 | 1246 | nttmp.nm = nm; |
1140 | 1247 | if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { |
1141 | 1248 | return res; |
1155 | 1262 | } while (pnd->bInfiniteSelect); |
1156 | 1263 | if (! found) |
1157 | 1264 | return 0; |
1265 | } else if (nm.nmt == NMT_BARCODE) { | |
1266 | if (CHIP_DATA(pnd)->type == RCS360) { | |
1267 | // TODO add support for RC-S360, at the moment it refuses to send raw frames without a first select | |
1268 | pnd->last_error = NFC_ENOTIMPL; | |
1269 | return pnd->last_error; | |
1270 | } | |
1271 | // No native support in InListPassiveTarget so we do discovery by hand | |
1272 | ||
1273 | // We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO | |
1274 | if ((! CHIP_DATA(pnd)->progressive_field) && (res = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { | |
1275 | return res; | |
1276 | } | |
1277 | if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0) { | |
1278 | return res; | |
1279 | } | |
1280 | if ((res = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0) { | |
1281 | return res; | |
1282 | } | |
1283 | ||
1284 | bool found = false; | |
1285 | do { | |
1286 | uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; | |
1287 | uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; | |
1288 | if ((res = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 0) { | |
1289 | if ((res == NFC_ERFTRANS) || (res == NFC_ECHIP)) { // Broken reception | |
1290 | continue; | |
1291 | } else { | |
1292 | nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); | |
1293 | nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); | |
1294 | return res; | |
1295 | } | |
1296 | } | |
1297 | ||
1298 | // Shuffle bits to produce NFC Barcode bitstream | |
1299 | uint8_t uRemainder; | |
1300 | size_t szPos; | |
1301 | size_t szBytes = res / 8; | |
1302 | size_t off = 0; | |
1303 | uint8_t i; | |
1304 | memset(abtTargetsData, 0x00, sizeof(abtTargetsData)); | |
1305 | // Reinject S bit | |
1306 | abtTargetsData[off / 8] |= 1 << (7 - (off % 8)); | |
1307 | off++; | |
1308 | ||
1309 | for (szPos = 0; szPos < szBytes; szPos++) { | |
1310 | for (i = 0; i < 8; i++) { | |
1311 | abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8)); | |
1312 | off++; | |
1313 | } | |
1314 | abtTargetsData[off / 8] |= abtRxPar[szPos] << (7 - (off % 8)); | |
1315 | off++; | |
1316 | } | |
1317 | uRemainder = res % 8; | |
1318 | for (i = 0; i < uRemainder; i++) { | |
1319 | abtTargetsData[off / 8] |= ((abtRx[szPos] >> i) & 1) << (7 - (off % 8)); | |
1320 | off++; | |
1321 | } | |
1322 | ||
1323 | if (off % 128 != 0) { | |
1324 | // NFC Barcode seems incomplete | |
1325 | continue; | |
1326 | } | |
1327 | ||
1328 | szTargetsData = (size_t)off / 8; | |
1329 | ||
1330 | // validate CRC | |
1331 | uint8_t pbtCrc[2]; | |
1332 | iso14443a_crc(abtTargetsData, szTargetsData - 2, pbtCrc); | |
1333 | if ((pbtCrc[1] != abtTargetsData[szTargetsData - 2]) || (pbtCrc[0] != abtTargetsData[szTargetsData - 1])) { | |
1334 | continue; | |
1335 | } | |
1336 | nttmp.nm = nm; | |
1337 | if ((res = pn53x_decode_target_data(abtTargetsData, szTargetsData, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { | |
1338 | return res; | |
1339 | } | |
1340 | found = true; | |
1341 | break; | |
1342 | } while (pnd->bInfiniteSelect); | |
1343 | if (! found) { | |
1344 | return 0; | |
1345 | } | |
1158 | 1346 | } else { |
1159 | ||
1160 | 1347 | const pn53x_modulation pm = pn53x_nm_to_pm(nm); |
1161 | if (PM_UNDEFINED == pm) { | |
1348 | if ((PM_UNDEFINED == pm) || (NBR_UNDEFINED == nm.nbr)) { | |
1162 | 1349 | pnd->last_error = NFC_EINVARG; |
1163 | 1350 | return pnd->last_error; |
1164 | 1351 | } |
1172 | 1359 | nttmp.nm = nm; |
1173 | 1360 | if ((res = pn53x_decode_target_data(abtTargetsData + 1, szTargetsData - 1, CHIP_DATA(pnd)->type, nm.nmt, &(nttmp.nti))) < 0) { |
1174 | 1361 | return res; |
1362 | } | |
1363 | if ((nm.nmt == NMT_ISO14443A) && (nm.nbr != NBR_106)) { | |
1364 | uint8_t pncmd_inpsl[4] = { InPSL, 0x01 }; | |
1365 | pncmd_inpsl[2] = nm.nbr - 1; | |
1366 | pncmd_inpsl[3] = nm.nbr - 1; | |
1367 | if ((res = pn53x_transceive(pnd, pncmd_inpsl, sizeof(pncmd_inpsl), NULL, 0, 0)) < 0) { | |
1368 | return res; | |
1369 | } | |
1175 | 1370 | } |
1176 | 1371 | } |
1177 | 1372 | if (pn53x_current_target_new(pnd, &nttmp) == NULL) { |
1191 | 1386 | const uint8_t *pbtInitData, const size_t szInitData, |
1192 | 1387 | nfc_target *pnt) |
1193 | 1388 | { |
1194 | return pn53x_initiator_select_passive_target_ext(pnd, nm, pbtInitData, szInitData, pnt, 0); | |
1389 | return pn53x_initiator_select_passive_target_ext(pnd, nm, pbtInitData, szInitData, pnt, 300); | |
1195 | 1390 | } |
1196 | 1391 | |
1197 | 1392 | int |
1221 | 1416 | szTargetTypes++; |
1222 | 1417 | } |
1223 | 1418 | nfc_target ntTargets[2]; |
1419 | memset(ntTargets, 0x00, sizeof(nfc_target) * 2); | |
1420 | ||
1224 | 1421 | if ((res = pn53x_InAutoPoll(pnd, apttTargetTypes, szTargetTypes, uiPollNr, uiPeriod, ntTargets, 0)) < 0) |
1225 | 1422 | return res; |
1226 | 1423 | switch (res) { |
1424 | case 0: | |
1425 | return pnd->last_error = NFC_SUCCESS; | |
1426 | break; | |
1227 | 1427 | case 1: |
1228 | 1428 | *pnt = ntTargets[0]; |
1229 | 1429 | if (pn53x_current_target_new(pnd, pnt) == NULL) { |
1230 | 1430 | return pnd->last_error = NFC_ESOFT; |
1231 | 1431 | } |
1232 | 1432 | return res; |
1233 | break; | |
1234 | 1433 | case 2: |
1235 | 1434 | *pnt = ntTargets[1]; // We keep the selected one |
1236 | 1435 | if (pn53x_current_target_new(pnd, pnt) == NULL) { |
1237 | 1436 | return pnd->last_error = NFC_ESOFT; |
1238 | 1437 | } |
1239 | 1438 | return res; |
1240 | break; | |
1241 | 1439 | default: |
1242 | 1440 | return NFC_ECHIP; |
1243 | break; | |
1244 | 1441 | } |
1245 | 1442 | } else { |
1246 | 1443 | bool bInfiniteSelect = pnd->bInfiniteSelect; |
1302 | 1499 | case NBR_847: |
1303 | 1500 | case NBR_UNDEFINED: |
1304 | 1501 | return NFC_EINVARG; |
1305 | break; | |
1306 | 1502 | } |
1307 | 1503 | |
1308 | 1504 | pn53x_current_target_free(pnd); |
1333 | 1529 | uint8_t abtCmd[PN53x_EXTENDED_FRAME__DATA_MAX_LEN] = { InCommunicateThru }; |
1334 | 1530 | |
1335 | 1531 | // Check if we should prepare the parity bits ourself |
1336 | if (!pnd->bPar) { | |
1532 | if ((!pnd->bPar) && (szTxBits > 0)) { | |
1337 | 1533 | // Convert data with parity to a frame |
1338 | 1534 | if ((res = pn53x_wrap_frame(pbtTx, szTxBits, pbtTxPar, abtCmd + 1)) < 0) |
1339 | 1535 | return res; |
1465 | 1661 | |
1466 | 1662 | static uint32_t __pn53x_get_timer(struct nfc_device *pnd, const uint8_t last_cmd_byte) |
1467 | 1663 | { |
1468 | uint8_t parity; | |
1469 | 1664 | uint8_t counter_hi, counter_lo; |
1470 | uint16_t counter, u16cycles; | |
1665 | uint16_t counter; | |
1471 | 1666 | uint32_t u32cycles; |
1472 | 1667 | size_t off = 0; |
1473 | 1668 | if (CHIP_DATA(pnd)->type == PN533) { |
1495 | 1690 | // counter saturated |
1496 | 1691 | u32cycles = 0xFFFFFFFF; |
1497 | 1692 | } else { |
1693 | uint8_t parity; | |
1694 | uint16_t u16cycles; | |
1498 | 1695 | u16cycles = 0xFFFF - counter; |
1499 | 1696 | u32cycles = u16cycles; |
1500 | 1697 | u32cycles *= (CHIP_DATA(pnd)->timer_prescaler * 2 + 1); |
1732 | 1929 | if (pnd->bCrc) { |
1733 | 1930 | // We've to compute CRC ourselves to know last byte actually sent |
1734 | 1931 | uint8_t *pbtTxRaw; |
1735 | pbtTxRaw = (uint8_t *) malloc(szTx + 2); | |
1932 | pbtTxRaw = (uint8_t *) calloc(szTx + 2, 1); | |
1736 | 1933 | if (!pbtTxRaw) |
1737 | 1934 | return NFC_ESOFT; |
1738 | 1935 | memcpy(pbtTxRaw, pbtTx, szTx); |
1843 | 2040 | } |
1844 | 2041 | } |
1845 | 2042 | return ret; |
2043 | } | |
2044 | ||
2045 | static int pn53x_ISO14443A_Barcode_is_present(struct nfc_device *pnd) | |
2046 | { | |
2047 | int ret; | |
2048 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping Barcode"); | |
2049 | ||
2050 | // We turn RF field off first for a better detection rate but this doesn't work well with ASK LoGO | |
2051 | if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { | |
2052 | return ret; | |
2053 | } | |
2054 | if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false)) < 0) | |
2055 | return ret; | |
2056 | if ((ret = nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, false)) < 0) | |
2057 | return ret; | |
2058 | ||
2059 | int failures = 0; | |
2060 | while (failures < 3) { | |
2061 | if ((! CHIP_DATA(pnd)->progressive_field) && (ret = nfc_device_set_property_bool(pnd, NP_ACTIVATE_FIELD, false)) < 0) { | |
2062 | return ret; | |
2063 | } | |
2064 | uint8_t abtRx[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; | |
2065 | uint8_t abtRxPar[PN53x_EXTENDED_FRAME__DATA_MAX_LEN]; | |
2066 | if ((ret = nfc_initiator_transceive_bits(pnd, NULL, 0, NULL, abtRx, sizeof(abtRx), abtRxPar)) < 1) { | |
2067 | failures++; | |
2068 | } else { | |
2069 | nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); | |
2070 | nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); | |
2071 | return NFC_SUCCESS; | |
2072 | } | |
2073 | } | |
2074 | nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true); | |
2075 | nfc_device_set_property_bool(pnd, NP_HANDLE_PARITY, true); | |
2076 | return NFC_ETGRELEASED; | |
1846 | 2077 | } |
1847 | 2078 | |
1848 | 2079 | static int pn53x_ISO14443A_MFUL_is_present(struct nfc_device *pnd) |
2015 | 2246 | return ret; |
2016 | 2247 | } |
2017 | 2248 | |
2249 | static int pn53x_ISO14443B_ICLASS_is_present(struct nfc_device *pnd) | |
2250 | { | |
2251 | int timeout = 300; | |
2252 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): Ping B iClass"); | |
2253 | pn53x_initiator_init_iclass_modulation(pnd); | |
2254 | // | |
2255 | // Some work to do before getting the UID... | |
2256 | // send ICLASS_ACTIVATE_ALL command - will get timeout as we don't expect response | |
2257 | uint8_t abtReqt[] = { 0x0a }; // iClass ACTIVATE_ALL | |
2258 | uint8_t abtAnticol[11]; | |
2259 | if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), NULL, 0, timeout) < 0) { | |
2260 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "got expected timeout on iClass activate all"); | |
2261 | } | |
2262 | // do select - returned anticol contains 'handle' for tag if present | |
2263 | abtReqt[0] = 0x0c; // iClass SELECT | |
2264 | abtAnticol[0] = 0x81; // iClass ANTICOL | |
2265 | if (pn53x_initiator_transceive_bytes(pnd, abtReqt, sizeof(abtReqt), &abtAnticol[1], sizeof(abtAnticol) - 1, timeout) < 0) { | |
2266 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "timeout on iClass anticol"); | |
2267 | return NFC_ETGRELEASED;; | |
2268 | } | |
2269 | return NFC_SUCCESS; | |
2270 | } | |
2271 | ||
2018 | 2272 | static int pn53x_ISO14443B_CT_is_present(struct nfc_device *pnd) |
2019 | 2273 | { |
2020 | 2274 | int ret; |
2055 | 2309 | } |
2056 | 2310 | |
2057 | 2311 | // Ping target |
2058 | int ret; | |
2312 | int ret = NFC_EDEVNOTSUPP; | |
2059 | 2313 | switch (CHIP_DATA(pnd)->current_target->nm.nmt) { |
2060 | 2314 | case NMT_ISO14443A: |
2061 | 2315 | if (CHIP_DATA(pnd)->current_target->nti.nai.btSak & 0x20) { |
2080 | 2334 | case NMT_JEWEL: |
2081 | 2335 | ret = pn53x_ISO14443A_Jewel_is_present(pnd); |
2082 | 2336 | break; |
2337 | case NMT_BARCODE: | |
2338 | ret = pn53x_ISO14443A_Barcode_is_present(pnd); | |
2339 | break; | |
2083 | 2340 | case NMT_ISO14443B: |
2084 | 2341 | ret = pn53x_ISO14443B_4_is_present(pnd); |
2085 | 2342 | break; |
2092 | 2349 | case NMT_ISO14443B2CT: |
2093 | 2350 | ret = pn53x_ISO14443B_CT_is_present(pnd); |
2094 | 2351 | break; |
2095 | default: | |
2096 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "target_is_present(): card type not supported"); | |
2097 | ret = NFC_EDEVNOTSUPP; | |
2352 | case NMT_ISO14443BICLASS: | |
2353 | ret = pn53x_ISO14443B_ICLASS_is_present(pnd); | |
2098 | 2354 | break; |
2099 | 2355 | } |
2100 | 2356 | if (ret == NFC_ETGRELEASED) |
2146 | 2402 | case NMT_ISO14443BI: |
2147 | 2403 | case NMT_ISO14443B2SR: |
2148 | 2404 | case NMT_ISO14443B2CT: |
2405 | case NMT_ISO14443BICLASS: | |
2149 | 2406 | case NMT_JEWEL: |
2407 | case NMT_BARCODE: | |
2150 | 2408 | pnd->last_error = NFC_EDEVNOTSUPP; |
2151 | 2409 | return pnd->last_error; |
2152 | break; | |
2153 | 2410 | } |
2154 | 2411 | |
2155 | 2412 | // Let the PN53X be activated by the RF level detector from power down mode |
2248 | 2505 | case NMT_ISO14443BI: |
2249 | 2506 | case NMT_ISO14443B2SR: |
2250 | 2507 | case NMT_ISO14443B2CT: |
2508 | case NMT_ISO14443BICLASS: | |
2251 | 2509 | case NMT_JEWEL: |
2510 | case NMT_BARCODE: | |
2252 | 2511 | pnd->last_error = NFC_EDEVNOTSUPP; |
2253 | 2512 | return pnd->last_error; |
2254 | break; | |
2255 | 2513 | } |
2256 | 2514 | |
2257 | 2515 | bool targetActivated = false; |
2396 | 2654 | return pnd->last_error; |
2397 | 2655 | } |
2398 | 2656 | } |
2399 | // NO BREAK | |
2657 | abtCmd[0] = TgGetInitiatorCommand; | |
2658 | break; | |
2400 | 2659 | case NMT_JEWEL: |
2660 | case NMT_BARCODE: | |
2401 | 2661 | case NMT_ISO14443B: |
2402 | 2662 | case NMT_ISO14443BI: |
2403 | 2663 | case NMT_ISO14443B2SR: |
2404 | 2664 | case NMT_ISO14443B2CT: |
2665 | case NMT_ISO14443BICLASS: | |
2405 | 2666 | case NMT_FELICA: |
2406 | 2667 | abtCmd[0] = TgGetInitiatorCommand; |
2407 | 2668 | break; |
2501 | 2762 | return pnd->last_error; |
2502 | 2763 | } |
2503 | 2764 | } |
2504 | // NO BREAK | |
2765 | abtCmd[0] = TgResponseToInitiator; | |
2766 | break; | |
2505 | 2767 | case NMT_JEWEL: |
2768 | case NMT_BARCODE: | |
2506 | 2769 | case NMT_ISO14443B: |
2507 | 2770 | case NMT_ISO14443BI: |
2508 | 2771 | case NMT_ISO14443B2SR: |
2509 | 2772 | case NMT_ISO14443B2CT: |
2773 | case NMT_ISO14443BICLASS: | |
2510 | 2774 | case NMT_FELICA: |
2511 | 2775 | abtCmd[0] = TgResponseToInitiator; |
2512 | 2776 | break; |
2719 | 2983 | } |
2720 | 2984 | break; |
2721 | 2985 | case PM_JEWEL_106: |
2986 | case PM_BARCODE_106: | |
2722 | 2987 | if (CHIP_DATA(pnd)->type == PN531) { |
2723 | 2988 | // These modulations are not supported by pn531 |
2724 | 2989 | pnd->last_error = NFC_EDEVNOTSUPP; |
2910 | 3175 | case NBR_UNDEFINED: |
2911 | 3176 | pnd->last_error = NFC_EINVARG; |
2912 | 3177 | return pnd->last_error; |
2913 | break; | |
2914 | 3178 | } |
2915 | 3179 | |
2916 | 3180 | if (pbtNFCID3i) { |
3127 | 3391 | switch (nm.nmt) { |
3128 | 3392 | case NMT_ISO14443A: |
3129 | 3393 | return PM_ISO14443A_106; |
3130 | break; | |
3131 | 3394 | |
3132 | 3395 | case NMT_ISO14443B: |
3396 | case NMT_ISO14443BICLASS: | |
3133 | 3397 | switch (nm.nbr) { |
3134 | 3398 | case NBR_106: |
3135 | 3399 | return PM_ISO14443B_106; |
3136 | break; | |
3137 | 3400 | case NBR_212: |
3138 | 3401 | return PM_ISO14443B_212; |
3139 | break; | |
3140 | 3402 | case NBR_424: |
3141 | 3403 | return PM_ISO14443B_424; |
3142 | break; | |
3143 | 3404 | case NBR_847: |
3144 | 3405 | return PM_ISO14443B_847; |
3145 | break; | |
3146 | 3406 | case NBR_UNDEFINED: |
3147 | 3407 | // Nothing to do... |
3148 | 3408 | break; |
3151 | 3411 | |
3152 | 3412 | case NMT_JEWEL: |
3153 | 3413 | return PM_JEWEL_106; |
3154 | break; | |
3414 | ||
3415 | case NMT_BARCODE: | |
3416 | return PM_BARCODE_106; | |
3155 | 3417 | |
3156 | 3418 | case NMT_FELICA: |
3157 | 3419 | switch (nm.nbr) { |
3158 | 3420 | case NBR_212: |
3159 | 3421 | return PM_FELICA_212; |
3160 | break; | |
3161 | 3422 | case NBR_424: |
3162 | 3423 | return PM_FELICA_424; |
3163 | break; | |
3164 | 3424 | case NBR_106: |
3165 | 3425 | case NBR_847: |
3166 | 3426 | case NBR_UNDEFINED: |
3193 | 3453 | case PTT_MIFARE: |
3194 | 3454 | case PTT_ISO14443_4A_106: |
3195 | 3455 | return (const nfc_modulation) { .nmt = NMT_ISO14443A, .nbr = NBR_106 }; |
3196 | break; | |
3197 | 3456 | |
3198 | 3457 | case PTT_ISO14443_4B_106: |
3199 | 3458 | case PTT_ISO14443_4B_TCL_106: |
3200 | 3459 | return (const nfc_modulation) { .nmt = NMT_ISO14443B, .nbr = NBR_106 }; |
3201 | break; | |
3202 | 3460 | |
3203 | 3461 | case PTT_JEWEL_106: |
3204 | 3462 | return (const nfc_modulation) { .nmt = NMT_JEWEL, .nbr = NBR_106 }; |
3205 | break; | |
3206 | 3463 | |
3207 | 3464 | case PTT_FELICA_212: |
3208 | 3465 | return (const nfc_modulation) { .nmt = NMT_FELICA, .nbr = NBR_212 }; |
3209 | break; | |
3466 | ||
3210 | 3467 | case PTT_FELICA_424: |
3211 | 3468 | return (const nfc_modulation) { .nmt = NMT_FELICA, .nbr = NBR_424 }; |
3212 | break; | |
3213 | 3469 | |
3214 | 3470 | case PTT_DEP_PASSIVE_106: |
3215 | 3471 | case PTT_DEP_ACTIVE_106: |
3216 | 3472 | return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_106 }; |
3217 | break; | |
3473 | ||
3218 | 3474 | case PTT_DEP_PASSIVE_212: |
3219 | 3475 | case PTT_DEP_ACTIVE_212: |
3220 | 3476 | return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_212 }; |
3221 | break; | |
3477 | ||
3222 | 3478 | case PTT_DEP_PASSIVE_424: |
3223 | 3479 | case PTT_DEP_ACTIVE_424: |
3224 | 3480 | return (const nfc_modulation) { .nmt = NMT_DEP, .nbr = NBR_424 }; |
3225 | break; | |
3226 | 3481 | } |
3227 | 3482 | // We should never be here, this line silent compilation warning |
3228 | 3483 | return (const nfc_modulation) { .nmt = NMT_ISO14443A, .nbr = NBR_106 }; |
3234 | 3489 | switch (nm.nmt) { |
3235 | 3490 | case NMT_ISO14443A: |
3236 | 3491 | return PTT_MIFARE; |
3237 | // return PTT_ISO14443_4A_106; | |
3238 | break; | |
3492 | // return PTT_ISO14443_4A_106; | |
3239 | 3493 | |
3240 | 3494 | case NMT_ISO14443B: |
3495 | case NMT_ISO14443BICLASS: | |
3241 | 3496 | switch (nm.nbr) { |
3242 | 3497 | case NBR_106: |
3243 | 3498 | return PTT_ISO14443_4B_106; |
3244 | break; | |
3499 | ||
3245 | 3500 | case NBR_UNDEFINED: |
3246 | 3501 | case NBR_212: |
3247 | 3502 | case NBR_424: |
3253 | 3508 | |
3254 | 3509 | case NMT_JEWEL: |
3255 | 3510 | return PTT_JEWEL_106; |
3256 | break; | |
3257 | 3511 | |
3258 | 3512 | case NMT_FELICA: |
3259 | 3513 | switch (nm.nbr) { |
3260 | 3514 | case NBR_212: |
3261 | 3515 | return PTT_FELICA_212; |
3262 | break; | |
3516 | ||
3263 | 3517 | case NBR_424: |
3264 | 3518 | return PTT_FELICA_424; |
3265 | break; | |
3519 | ||
3266 | 3520 | case NBR_UNDEFINED: |
3267 | 3521 | case NBR_106: |
3268 | 3522 | case NBR_847: |
3274 | 3528 | case NMT_ISO14443BI: |
3275 | 3529 | case NMT_ISO14443B2SR: |
3276 | 3530 | case NMT_ISO14443B2CT: |
3531 | case NMT_BARCODE: | |
3277 | 3532 | case NMT_DEP: |
3278 | 3533 | // Nothing to do... |
3279 | 3534 | break; |
3298 | 3553 | } |
3299 | 3554 | |
3300 | 3555 | int |
3301 | pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) | |
3556 | pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) | |
3302 | 3557 | { |
3303 | 3558 | switch (nmt) { |
3304 | 3559 | case NMT_FELICA: |
3305 | 3560 | *supported_br = (nfc_baud_rate *)pn53x_felica_supported_baud_rates; |
3306 | 3561 | break; |
3307 | case NMT_ISO14443A: | |
3308 | *supported_br = (nfc_baud_rate *)pn53x_iso14443a_supported_baud_rates; | |
3309 | break; | |
3310 | case NMT_ISO14443B: | |
3311 | case NMT_ISO14443BI: | |
3312 | case NMT_ISO14443B2SR: | |
3313 | case NMT_ISO14443B2CT: { | |
3562 | case NMT_ISO14443A: { | |
3563 | if ((CHIP_DATA(pnd)->type != PN533) || (mode == N_TARGET)) { | |
3564 | *supported_br = (nfc_baud_rate *)pn532_iso14443a_supported_baud_rates; | |
3565 | } else { | |
3566 | *supported_br = (nfc_baud_rate *)pn533_iso14443a_supported_baud_rates; | |
3567 | } | |
3568 | } | |
3569 | break; | |
3570 | case NMT_ISO14443B: { | |
3314 | 3571 | if ((CHIP_DATA(pnd)->type != PN533)) { |
3315 | 3572 | *supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates; |
3316 | 3573 | } else { |
3318 | 3575 | } |
3319 | 3576 | } |
3320 | 3577 | break; |
3578 | case NMT_ISO14443BI: | |
3579 | case NMT_ISO14443B2SR: | |
3580 | case NMT_ISO14443B2CT: | |
3581 | case NMT_ISO14443BICLASS: | |
3582 | *supported_br = (nfc_baud_rate *)pn532_iso14443b_supported_baud_rates; | |
3583 | break; | |
3321 | 3584 | case NMT_JEWEL: |
3322 | 3585 | *supported_br = (nfc_baud_rate *)pn53x_jewel_supported_baud_rates; |
3586 | break; | |
3587 | case NMT_BARCODE: | |
3588 | *supported_br = (nfc_baud_rate *)pn53x_barcode_supported_baud_rates; | |
3323 | 3589 | break; |
3324 | 3590 | case NMT_DEP: |
3325 | 3591 | *supported_br = (nfc_baud_rate *)pn53x_dep_supported_baud_rates; |
3433 | 3699 | free(*pbuf); |
3434 | 3700 | return res; |
3435 | 3701 | } |
3436 | ||
3437 | 3702 | for (int i = 0; nmt[i]; i++) { |
3438 | 3703 | if ((res = snprintf(buf, buflen, "%s%s (", (i == 0) ? "" : ", ", str_nfc_modulation_type(nmt[i]))) < 0) { |
3439 | 3704 | free(*pbuf); |
3446 | 3711 | } |
3447 | 3712 | buflen -= res; |
3448 | 3713 | const nfc_baud_rate *nbr; |
3449 | if ((res = nfc_device_get_supported_baud_rate(pnd, nmt[i], &nbr)) < 0) { | |
3714 | if ((res = nfc_device_get_supported_baud_rate_target_mode(pnd, nmt[i], &nbr)) < 0) { | |
3450 | 3715 | free(*pbuf); |
3451 | 3716 | return res; |
3452 | 3717 | } |
3575 | 3840 | |
3576 | 3841 | CHIP_DATA(pnd)->supported_modulation_as_target = NULL; |
3577 | 3842 | |
3843 | // Set default progressive field flag | |
3844 | CHIP_DATA(pnd)->progressive_field = false; | |
3845 | ||
3578 | 3846 | return pnd->chip_data; |
3579 | 3847 | } |
3580 | 3848 |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * This program is free software: you can redistribute it and/or modify it |
13 | 14 | * under the terms of the GNU Lesser General Public License as published by the |
209 | 210 | /** Supported modulation type */ |
210 | 211 | nfc_modulation_type *supported_modulation_as_initiator; |
211 | 212 | nfc_modulation_type *supported_modulation_as_target; |
213 | bool progressive_field; | |
212 | 214 | }; |
213 | 215 | |
214 | 216 | #define CHIP_DATA(pnd) ((struct pn53x_data*)(pnd->chip_data)) |
230 | 232 | PM_ISO14443B_106 = 0x03, |
231 | 233 | /** Jewel Topaz (Innovision Research & Development) (Not supported by PN531) */ |
232 | 234 | PM_JEWEL_106 = 0x04, |
235 | /** Thinfilm NFC Barcode (Not supported by PN531) */ | |
236 | PM_BARCODE_106 = 0x05, | |
233 | 237 | /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ |
234 | 238 | PM_ISO14443B_212 = 0x06, |
235 | 239 | /** ISO14443-B http://en.wikipedia.org/wiki/ISO/IEC_14443 (Not supported by PN531 nor PN532) */ |
318 | 322 | |
319 | 323 | // NFC device as Initiator functions |
320 | 324 | int pn53x_initiator_init(struct nfc_device *pnd); |
325 | void pn53x_initiator_init_iclass_modulation(struct nfc_device *pnd); | |
321 | 326 | int pn532_initiator_init_secure_element(struct nfc_device *pnd); |
322 | 327 | int pn53x_initiator_select_passive_target(struct nfc_device *pnd, |
323 | 328 | const nfc_modulation nm, |
391 | 396 | int pn53x_check_error_frame(struct nfc_device *pnd, const uint8_t *pbtRxFrame, const size_t szRxFrameLen); |
392 | 397 | int pn53x_build_frame(uint8_t *pbtFrame, size_t *pszFrame, const uint8_t *pbtData, const size_t szData); |
393 | 398 | int pn53x_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); |
394 | int pn53x_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); | |
399 | 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); | |
395 | 400 | int pn53x_get_information_about(nfc_device *pnd, char **pbuf); |
396 | 401 | |
397 | 402 | void *pn53x_data_new(struct nfc_device *pnd, const struct pn53x_io *io); |
32 | 32 | #ifdef CONFFILES |
33 | 33 | #include <stdio.h> |
34 | 34 | #include <stdlib.h> |
35 | #include <ctype.h> | |
35 | 36 | #include <dirent.h> |
36 | 37 | #include <string.h> |
37 | #include <regex.h> | |
38 | 38 | #include <sys/stat.h> |
39 | 39 | |
40 | 40 | #include <nfc/nfc.h> |
55 | 55 | #define LIBNFC_CONFFILE LIBNFC_SYSCONFDIR"/libnfc.conf" |
56 | 56 | #define LIBNFC_DEVICECONFDIR LIBNFC_SYSCONFDIR"/devices.d" |
57 | 57 | |
58 | static bool | |
59 | conf_parse_file(const char *filename, void (*conf_keyvalue)(void *data, const char *key, const char *value), void *data) | |
58 | static int | |
59 | escaped_value(const char line[BUFSIZ], int i, char **value) | |
60 | { | |
61 | if (line[i] != '"') | |
62 | goto FAIL; | |
63 | i++; | |
64 | if (line[i] == 0 || line[i] == '\n') | |
65 | goto FAIL; | |
66 | int c = 0; | |
67 | while (line[i] && line[i] != '"') { | |
68 | i++; | |
69 | c++; | |
70 | } | |
71 | if (line[i] != '"') | |
72 | goto FAIL; | |
73 | *value = malloc(c + 1); | |
74 | if (!*value) | |
75 | goto FAIL; | |
76 | memset(*value, 0, c + 1); | |
77 | memcpy(*value, &line[i - c], c); | |
78 | i++; | |
79 | while (line[i] && isspace(line[i])) | |
80 | i++; | |
81 | if (line[i] != 0 && line[i] != '\n') | |
82 | goto FAIL; | |
83 | return 0; | |
84 | ||
85 | FAIL: | |
86 | free(*value); | |
87 | *value = NULL; | |
88 | return -1; | |
89 | } | |
90 | ||
91 | static int | |
92 | non_escaped_value(const char line[BUFSIZ], int i, char **value) | |
93 | { | |
94 | int c = 0; | |
95 | while (line[i] && !isspace(line[i])) { | |
96 | i++; | |
97 | c++; | |
98 | } | |
99 | *value = malloc(c + 1); | |
100 | if (!*value) | |
101 | goto FAIL; | |
102 | memset(*value, 0, c + 1); | |
103 | memcpy(*value, &line[i - c], c); | |
104 | i++; | |
105 | while (line[i] && isspace(line[i])) | |
106 | i++; | |
107 | if (line[i] != 0) | |
108 | goto FAIL; | |
109 | return 0; | |
110 | ||
111 | FAIL: | |
112 | free(*value); | |
113 | *value = NULL; | |
114 | return -1; | |
115 | } | |
116 | ||
117 | static int | |
118 | parse_line(const char line[BUFSIZ], char **key, char **value) | |
119 | { | |
120 | *key = NULL; | |
121 | *value = NULL; | |
122 | int i = 0; | |
123 | int c = 0; | |
124 | ||
125 | // optional initial spaces | |
126 | while (isspace(line[i])) | |
127 | i++; | |
128 | if (line[i] == 0 || line[i] == '\n') | |
129 | return -1; | |
130 | ||
131 | // key | |
132 | while (isalnum(line[i]) || line[i] == '_' || line[i] == '.') { | |
133 | i++; | |
134 | c++; | |
135 | } | |
136 | if (c == 0 || line[i] == 0 || line[i] == '\n') // key is empty | |
137 | return -1; | |
138 | *key = malloc(c + 1); | |
139 | if (!*key) | |
140 | return -1; | |
141 | memset(*key, 0, c + 1); | |
142 | memcpy(*key, &line[i - c], c); | |
143 | ||
144 | // space before '=' | |
145 | while (isspace(line[i])) | |
146 | i++; | |
147 | if (line[i] != '=') | |
148 | return -1; | |
149 | i++; | |
150 | if (line[i] == 0 || line[i] == '\n') | |
151 | return -1; | |
152 | // space after '=' | |
153 | while (isspace(line[i])) | |
154 | i++; | |
155 | if (line[i] == 0 || line[i] == '\n') | |
156 | return -1; | |
157 | if (escaped_value(line, i, value) == 0) | |
158 | return 0; | |
159 | else if (non_escaped_value(line, i, value) == 0) | |
160 | return 0; | |
161 | ||
162 | // Extracting key or value failed | |
163 | free(*key); | |
164 | *key = NULL; | |
165 | free(*value); | |
166 | *value = NULL; | |
167 | return -1; | |
168 | } | |
169 | ||
170 | static void | |
171 | conf_parse_file(const char *filename, | |
172 | void (*conf_keyvalue)(void *data, const char *key, const char *value), | |
173 | void *data) | |
60 | 174 | { |
61 | 175 | FILE *f = fopen(filename, "r"); |
62 | 176 | if (!f) { |
63 | 177 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Unable to open file: %s", filename); |
64 | return false; | |
178 | return; | |
65 | 179 | } |
66 | 180 | char line[BUFSIZ]; |
67 | const char *str_regex = "^[[:space:]]*([[:alnum:]_.]+)[[:space:]]*=[[:space:]]*(\"(.+)\"|([^[:space:]]+))[[:space:]]*$"; | |
68 | regex_t preg; | |
69 | if (regcomp(&preg, str_regex, REG_EXTENDED | REG_NOTEOL) != 0) { | |
70 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Regular expression used for configuration file parsing is not valid."); | |
71 | fclose(f); | |
72 | return false; | |
73 | } | |
74 | size_t nmatch = preg.re_nsub + 1; | |
75 | regmatch_t *pmatch = malloc(sizeof(*pmatch) * nmatch); | |
76 | if (!pmatch) { | |
77 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Not enough memory: malloc failed."); | |
78 | regfree(&preg); | |
79 | fclose(f); | |
80 | return false; | |
81 | } | |
82 | 181 | |
83 | 182 | int lineno = 0; |
84 | 183 | while (fgets(line, BUFSIZ, f) != NULL) { |
88 | 187 | case '\n': |
89 | 188 | break; |
90 | 189 | default: { |
91 | int match; | |
92 | if ((match = regexec(&preg, line, nmatch, pmatch, 0)) == 0) { | |
93 | const size_t key_size = pmatch[1].rm_eo - pmatch[1].rm_so; | |
94 | const off_t value_pmatch = pmatch[3].rm_eo != -1 ? 3 : 4; | |
95 | const size_t value_size = pmatch[value_pmatch].rm_eo - pmatch[value_pmatch].rm_so; | |
96 | char key[key_size + 1]; | |
97 | char value[value_size + 1]; | |
98 | strncpy(key, line + (pmatch[1].rm_so), key_size); | |
99 | key[key_size] = '\0'; | |
100 | strncpy(value, line + (pmatch[value_pmatch].rm_so), value_size); | |
101 | value[value_size] = '\0'; | |
190 | char *key; | |
191 | char *value; | |
192 | if (parse_line(line, &key, &value) == 0) { | |
102 | 193 | conf_keyvalue(data, key, value); |
194 | free(key); | |
195 | free(value); | |
103 | 196 | } else { |
104 | 197 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Parse error on line #%d: %s", lineno, line); |
105 | 198 | } |
106 | 199 | } |
107 | break; | |
108 | } | |
109 | } | |
110 | ||
111 | free(pmatch); | |
112 | regfree(&preg); | |
200 | } | |
201 | } | |
113 | 202 | fclose(f); |
114 | return false; | |
203 | return; | |
115 | 204 | } |
116 | 205 | |
117 | 206 | static void |
176 | 265 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open directory: %s", dirname); |
177 | 266 | } else { |
178 | 267 | struct dirent *de; |
179 | #ifdef WIN32 | |
180 | 268 | while ((de = readdir(d)) != NULL) { |
181 | #else | |
182 | struct dirent entry; | |
183 | struct dirent *result; | |
184 | while ((readdir_r(d, &entry, &result) == 0) && (result != NULL)) { | |
185 | de = &entry; | |
186 | #endif | |
269 | // FIXME add a way to sort devices | |
187 | 270 | if (de->d_name[0] != '.') { |
188 | 271 | const size_t filename_len = strlen(de->d_name); |
189 | 272 | const size_t extension_len = strlen(".conf"); |
5 | 5 | libnfcdrivers_la_SOURCES = |
6 | 6 | libnfcdrivers_la_CFLAGS = @DRIVERS_CFLAGS@ -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses |
7 | 7 | libnfcdrivers_la_LIBADD = |
8 | ||
9 | if DRIVER_PCSC_ENABLED | |
10 | libnfcdrivers_la_SOURCES += pcsc.c pcsc.h | |
11 | endif | |
8 | 12 | |
9 | 13 | if DRIVER_ACR122_PCSC_ENABLED |
10 | 14 | libnfcdrivers_la_SOURCES += acr122_pcsc.c acr122_pcsc.h |
38 | 42 | libnfcdrivers_la_SOURCES += pn532_i2c.c pn532_i2c.h |
39 | 43 | endif |
40 | 44 | |
45 | if DRIVER_PN71XX_ENABLED | |
46 | libnfcdrivers_la_LIBADD += @LIBNFC_NCI_LIBS@ | |
47 | libnfcdrivers_la_SOURCES += pn71xx.c pn71xx.h | |
48 | endif | |
49 | ||
41 | 50 | if PCSC_ENABLED |
42 | 51 | libnfcdrivers_la_CFLAGS += @libpcsclite_CFLAGS@ |
43 | 52 | libnfcdrivers_la_LIBADD += @libpcsclite_LIBS@ |
58 | 58 | # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500) |
59 | 59 | #elif defined(__APPLE__) |
60 | 60 | # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2)) |
61 | #elif defined (__FreeBSD__) || defined (__OpenBSD__) | |
61 | #elif defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) | |
62 | 62 | # define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2)) |
63 | 63 | #elif defined (__linux__) |
64 | 64 | # include <reader.h> |
92 | 92 | // Prototypes |
93 | 93 | char *acr122_pcsc_firmware(nfc_device *pnd); |
94 | 94 | |
95 | const char *supported_devices[] = { | |
95 | static const char *supported_devices[] = { | |
96 | 96 | "ACS ACR122", // ACR122U & Touchatag, last version |
97 | 97 | "ACS ACR 38U-CCID", // Touchatag, early version |
98 | 98 | "ACS ACR38U-CCID", // Touchatag, early version, under MacOSX |
399 | 399 | { |
400 | 400 | // FIXME: timeout is not handled |
401 | 401 | (void) timeout; |
402 | ||
403 | 402 | int len; |
404 | uint8_t abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 }; | |
405 | 403 | |
406 | 404 | if (DRIVER_DATA(pnd)->ioCard.dwProtocol == SCARD_PROTOCOL_T0) { |
407 | 405 | /* |
408 | 406 | * Retrieve the PN532 response. |
409 | 407 | */ |
410 | 408 | DWORD dwRxLen = sizeof(DRIVER_DATA(pnd)->abtRx); |
409 | uint8_t abtRxCmd[5] = { 0xFF, 0xC0, 0x00, 0x00 }; | |
411 | 410 | abtRxCmd[4] = DRIVER_DATA(pnd)->abtRx[1]; |
412 | 411 | if (SCardTransmit(DRIVER_DATA(pnd)->hCard, &(DRIVER_DATA(pnd)->ioCard), abtRxCmd, sizeof(abtRxCmd), NULL, DRIVER_DATA(pnd)->abtRx, &dwRxLen) != SCARD_S_SUCCESS) { |
413 | 412 | pnd->last_error = NFC_EIO; |
261 | 261 | const struct acr122_usb_supported_device acr122_usb_supported_devices[] = { |
262 | 262 | { 0x072F, 0x2200, "ACS ACR122" }, |
263 | 263 | { 0x072F, 0x90CC, "Touchatag" }, |
264 | { 0x072F, 0x2214, "ACS ACR1222" }, | |
264 | 265 | }; |
265 | 266 | |
266 | 267 | // Find transfer endpoints for bulk transfers |
329 | 330 | // acr122_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice)); |
330 | 331 | 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); |
331 | 332 | usb_close(udev); |
332 | snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename); | |
333 | if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", ACR122_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) { | |
334 | // truncation occurred, skipping that one | |
335 | continue; | |
336 | } | |
333 | 337 | device_found++; |
334 | 338 | // Test if we reach the maximum "wanted" devices |
335 | 339 | if (device_found == connstrings_len) { |
425 | 429 | goto free_mem; |
426 | 430 | } |
427 | 431 | |
428 | res = usb_set_altinterface(data.pudh, 0); | |
429 | if (res < 0) { | |
430 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set alternate setting on USB interface (%s)", _usb_strerror(res)); | |
431 | usb_close(data.pudh); | |
432 | // we failed to use the specified device | |
433 | goto free_mem; | |
432 | // Check if there are more than 0 alternative interfaces and claim the first one | |
433 | if (dev->config->interface->altsetting->bAlternateSetting > 0) { | |
434 | res = usb_set_altinterface(data.pudh, 0); | |
435 | if (res < 0) { | |
436 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Unable to set alternate setting on USB interface (%s)", _usb_strerror(res)); | |
437 | usb_close(data.pudh); | |
438 | // we failed to use the specified device | |
439 | goto free_mem; | |
440 | } | |
434 | 441 | } |
435 | 442 | |
436 | 443 | // Allocate memory for the device info and specification, fill it and return the info |
421 | 421 | |
422 | 422 | while ((acPort = acPorts[iDevice++])) { |
423 | 423 | sp = uart_open(acPort); |
424 | 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); | |
424 | 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); | |
425 | 425 | |
426 | 426 | if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { |
427 | 427 | // We need to flush input to be sure first reply does not comes from older byte transceive |
561 | 561 | } |
562 | 562 | |
563 | 563 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, |
564 | "Attempt to connect to: %s at %d bauds.", ndd.port, ndd.speed); | |
564 | "Attempt to connect to: %s at %d baud.", ndd.port, ndd.speed); | |
565 | 565 | |
566 | 566 | sp = uart_open(ndd.port); |
567 | 567 | if (sp == INVALID_SERIAL_PORT) { |
90 | 90 | |
91 | 91 | // ARYGON frames |
92 | 92 | static const uint8_t arygon_error_none[] = "FF000000\x0d\x0a"; |
93 | static const uint8_t arygon_error_incomplete_command[] = "FF0C0000\x0d\x0a"; | |
94 | 93 | static const uint8_t arygon_error_unknown_mode[] = "FF060000\x0d\x0a"; |
95 | 94 | |
96 | 95 | // Prototypes |
108 | 107 | |
109 | 108 | while ((acPort = acPorts[iDevice++])) { |
110 | 109 | sp = uart_open(acPort); |
111 | 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); | |
110 | 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); | |
112 | 111 | |
113 | 112 | if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { |
114 | 113 | // We need to flush input to be sure first reply does not comes from older byte transceive |
252 | 251 | serial_port sp; |
253 | 252 | nfc_device *pnd = NULL; |
254 | 253 | |
255 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d bauds.", ndd.port, ndd.speed); | |
254 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d baud.", ndd.port, ndd.speed); | |
256 | 255 | sp = uart_open(ndd.port); |
257 | 256 | |
258 | 257 | if (sp == INVALID_SERIAL_PORT) |
0 | /*- | |
1 | * Free/Libre Near Field Communication (NFC) library | |
2 | * | |
3 | * Libnfc historical contributors: | |
4 | * Copyright (C) 2019 Frank Morgner | |
5 | * See AUTHORS file for a more comprehensive list of contributors. | |
6 | * Additional contributors of this file: | |
7 | * | |
8 | * This program is free software: you can redistribute it and/or modify it | |
9 | * under the terms of the GNU Lesser General Public License as published by the | |
10 | * Free Software Foundation, either version 3 of the License, or (at your | |
11 | * option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 | * more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public License | |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/> | |
20 | */ | |
21 | ||
22 | /** | |
23 | * @file pcsc.c | |
24 | * @brief Driver for non-ACR122 devices behind PC/SC | |
25 | */ | |
26 | ||
27 | #ifdef HAVE_CONFIG_H | |
28 | # include "config.h" | |
29 | #endif // HAVE_CONFIG_H | |
30 | ||
31 | #include <inttypes.h> | |
32 | #include <stdio.h> | |
33 | #include <stdlib.h> | |
34 | #include <stddef.h> | |
35 | #include <string.h> | |
36 | ||
37 | #include <nfc/nfc.h> | |
38 | ||
39 | #include "drivers/pcsc.h" | |
40 | #include "nfc-internal.h" | |
41 | ||
42 | // Bus | |
43 | #ifdef __APPLE__ | |
44 | #include <PCSC/winscard.h> | |
45 | #include <PCSC/wintypes.h> | |
46 | // define from pcsclite for apple | |
47 | #define SCARD_AUTOALLOCATE (DWORD)(-1) | |
48 | ||
49 | #define SCARD_ATTR_VALUE(Class, Tag) ((((ULONG)(Class)) << 16) | ((ULONG)(Tag))) | |
50 | ||
51 | #define SCARD_CLASS_VENDOR_INFO 1 /**< Vendor information definitions */ | |
52 | #define SCARD_CLASS_COMMUNICATIONS 2 /**< Communication definitions */ | |
53 | #define SCARD_CLASS_PROTOCOL 3 /**< Protocol definitions */ | |
54 | #define SCARD_CLASS_POWER_MGMT 4 /**< Power Management definitions */ | |
55 | #define SCARD_CLASS_SECURITY 5 /**< Security Assurance definitions */ | |
56 | #define SCARD_CLASS_MECHANICAL 6 /**< Mechanical characteristic definitions */ | |
57 | #define SCARD_CLASS_VENDOR_DEFINED 7 /**< Vendor specific definitions */ | |
58 | #define SCARD_CLASS_IFD_PROTOCOL 8 /**< Interface Device Protocol options */ | |
59 | #define SCARD_CLASS_ICC_STATE 9 /**< ICC State specific definitions */ | |
60 | #define SCARD_CLASS_SYSTEM 0x7fff /**< System-specific definitions */ | |
61 | ||
62 | #define SCARD_ATTR_VENDOR_NAME SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0100) /**< Vendor name. */ | |
63 | #define SCARD_ATTR_VENDOR_IFD_TYPE SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0101) /**< Vendor-supplied interface device type (model designation of reader). */ | |
64 | #define SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0102) /**< Vendor-supplied interface device version (DWORD in the form 0xMMmmbbbb where MM = major version, mm = minor version, and bbbb = build number). */ | |
65 | #define SCARD_ATTR_VENDOR_IFD_SERIAL_NO SCARD_ATTR_VALUE(SCARD_CLASS_VENDOR_INFO, 0x0103) /**< Vendor-supplied interface device serial number. */ | |
66 | #define SCARD_ATTR_ICC_TYPE_PER_ATR SCARD_ATTR_VALUE(SCARD_CLASS_ICC_STATE, 0x0304) /**< Single byte indicating smart card type */ | |
67 | #else | |
68 | #ifndef _Win32 | |
69 | #include <reader.h> | |
70 | #endif | |
71 | #include <winscard.h> | |
72 | #endif | |
73 | ||
74 | #define PCSC_DRIVER_NAME "pcsc" | |
75 | ||
76 | #include <nfc/nfc.h> | |
77 | ||
78 | #define LOG_GROUP NFC_LOG_GROUP_DRIVER | |
79 | #define LOG_CATEGORY "libnfc.driver.pcsc" | |
80 | ||
81 | static const char *supported_devices[] = { | |
82 | "ACS ACR122", // ACR122U & Touchatag, last version | |
83 | "ACS ACR 38U-CCID", // Touchatag, early version | |
84 | "ACS ACR38U-CCID", // Touchatag, early version, under MacOSX | |
85 | "ACS AET65", // Touchatag using CCID driver version >= 1.4.6 | |
86 | " CCID USB", // ?? | |
87 | NULL | |
88 | }; | |
89 | ||
90 | struct pcsc_data { | |
91 | SCARDHANDLE hCard; | |
92 | SCARD_IO_REQUEST ioCard; | |
93 | DWORD dwShareMode; | |
94 | DWORD last_error; | |
95 | }; | |
96 | ||
97 | #define DRIVER_DATA(pnd) ((struct pcsc_data*)(pnd->driver_data)) | |
98 | ||
99 | static SCARDCONTEXT _SCardContext; | |
100 | static int _iSCardContextRefCount = 0; | |
101 | ||
102 | const nfc_baud_rate pcsc_supported_brs[] = {NBR_106, NBR_424, 0}; | |
103 | const nfc_modulation_type pcsc_supported_mts[] = {NMT_ISO14443A, NMT_ISO14443B, 0}; | |
104 | ||
105 | static SCARDCONTEXT * | |
106 | pcsc_get_scardcontext(void) | |
107 | { | |
108 | if (_iSCardContextRefCount == 0) { | |
109 | if (SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &_SCardContext) != SCARD_S_SUCCESS) | |
110 | return NULL; | |
111 | } | |
112 | _iSCardContextRefCount++; | |
113 | ||
114 | return &_SCardContext; | |
115 | } | |
116 | ||
117 | static void | |
118 | pcsc_free_scardcontext(void) | |
119 | { | |
120 | if (_iSCardContextRefCount) { | |
121 | _iSCardContextRefCount--; | |
122 | if (!_iSCardContextRefCount) { | |
123 | SCardReleaseContext(_SCardContext); | |
124 | } | |
125 | } | |
126 | } | |
127 | ||
128 | #define ICC_TYPE_UNKNOWN 0 | |
129 | #define ICC_TYPE_14443A 5 | |
130 | #define ICC_TYPE_14443B 6 | |
131 | ||
132 | bool is_pcsc_reader_vendor_feitian(const struct nfc_device *pnd); | |
133 | ||
134 | static int pcsc_transmit(struct nfc_device *pnd, const uint8_t *tx, const size_t tx_len, uint8_t *rx, size_t *rx_len) | |
135 | { | |
136 | struct pcsc_data *data = pnd->driver_data; | |
137 | DWORD dw_rx_len = *rx_len; | |
138 | //in libfreefare, tx_len = 1, and it leads to 0x80100008 error, with PC/SC reader, the input tx_len at least two bytes for the SW value | |
139 | //so if found the reader is Feitian reader, we set to 2 | |
140 | if (dw_rx_len == 1 && is_pcsc_reader_vendor_feitian(pnd)) { | |
141 | dw_rx_len = 2; | |
142 | } | |
143 | ||
144 | LOG_HEX(NFC_LOG_GROUP_COM, "TX", tx, tx_len); | |
145 | ||
146 | data->last_error = SCardTransmit(data->hCard, &data->ioCard, tx, tx_len, | |
147 | NULL, rx, &dw_rx_len); | |
148 | if (data->last_error != SCARD_S_SUCCESS) { | |
149 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC transmit failed"); | |
150 | return NFC_EIO; | |
151 | } | |
152 | *rx_len = dw_rx_len; | |
153 | ||
154 | LOG_HEX(NFC_LOG_GROUP_COM, "RX", rx, *rx_len); | |
155 | ||
156 | return NFC_SUCCESS; | |
157 | } | |
158 | ||
159 | static int pcsc_get_status(struct nfc_device *pnd, int *target_present, uint8_t *atr, size_t *atr_len) | |
160 | { | |
161 | struct pcsc_data *data = pnd->driver_data; | |
162 | DWORD dw_atr_len = *atr_len, reader_len, state, protocol; | |
163 | ||
164 | data->last_error = SCardStatus(data->hCard, NULL, &reader_len, &state, &protocol, atr, &dw_atr_len); | |
165 | if (data->last_error != SCARD_S_SUCCESS | |
166 | && data->last_error != SCARD_W_RESET_CARD) { | |
167 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Get status failed"); | |
168 | return NFC_EIO; | |
169 | } | |
170 | ||
171 | *target_present = state & SCARD_PRESENT; | |
172 | *atr_len = dw_atr_len; | |
173 | ||
174 | return NFC_SUCCESS; | |
175 | } | |
176 | ||
177 | static int pcsc_reconnect(struct nfc_device *pnd, DWORD share_mode, DWORD protocol, DWORD disposition) | |
178 | { | |
179 | struct pcsc_data *data = pnd->driver_data; | |
180 | ||
181 | data->last_error = SCardReconnect(data->hCard, share_mode, protocol, disposition, &data->ioCard.dwProtocol); | |
182 | if (data->last_error != SCARD_S_SUCCESS | |
183 | && data->last_error != SCARD_W_RESET_CARD) { | |
184 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reconnect failed"); | |
185 | return NFC_EIO; | |
186 | } | |
187 | ||
188 | data->dwShareMode = share_mode; | |
189 | ||
190 | return NFC_SUCCESS; | |
191 | } | |
192 | ||
193 | static uint8_t pcsc_get_icc_type(const struct nfc_device *pnd) | |
194 | { | |
195 | struct pcsc_data *data = pnd->driver_data; | |
196 | uint8_t it = 0; | |
197 | DWORD dwItLen = sizeof it; | |
198 | data->last_error = SCardGetAttrib(data->hCard, SCARD_ATTR_ICC_TYPE_PER_ATR, &it, &dwItLen); | |
199 | return it; | |
200 | } | |
201 | ||
202 | static bool is_pcsc_reader_vendor(const struct nfc_device *pnd, const char *target_vendor_name) | |
203 | { | |
204 | bool isTarget = false; | |
205 | if (pnd == NULL || strlen(pnd->name) == 0) { | |
206 | return isTarget; | |
207 | } | |
208 | ||
209 | return isTarget = (strstr(pnd->name, target_vendor_name)) ? true : false; | |
210 | } | |
211 | ||
212 | bool is_pcsc_reader_vendor_feitian(const struct nfc_device *pnd) | |
213 | { | |
214 | return is_pcsc_reader_vendor(pnd, "Feitian") || is_pcsc_reader_vendor(pnd, "FeiTian") || is_pcsc_reader_vendor(pnd, "feitian") || is_pcsc_reader_vendor(pnd, "FEITIAN"); | |
215 | } | |
216 | ||
217 | //get atqa by send apdu | |
218 | static int pcsc_get_atqa(struct nfc_device *pnd, uint8_t *atqa, size_t atqa_len) | |
219 | { | |
220 | const uint8_t get_data[] = {0xFF, 0xCA, 0x03, 0x00, 0x00}; | |
221 | uint8_t resp[256 + 2]; | |
222 | size_t resp_len = sizeof resp; | |
223 | ||
224 | pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len); | |
225 | if (pnd->last_error != NFC_SUCCESS) | |
226 | return pnd->last_error; | |
227 | ||
228 | if (resp_len < 2) { | |
229 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for ATQA"); | |
230 | pnd->last_error = NFC_EDEVNOTSUPP; | |
231 | return pnd->last_error; | |
232 | } | |
233 | if (atqa_len < resp_len - 2) { | |
234 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ATQA length is wrong"); | |
235 | pnd->last_error = NFC_ESOFT; | |
236 | return pnd->last_error; | |
237 | } | |
238 | ||
239 | memcpy(atqa, resp, resp_len - 2); | |
240 | return resp_len - 2; | |
241 | } | |
242 | ||
243 | //get ats by send apdu | |
244 | static int pcsc_get_ats(struct nfc_device *pnd, uint8_t *ats, size_t ats_len) | |
245 | { | |
246 | const uint8_t get_data[] = {0xFF, 0xCA, 0x01, 0x00, 0x00}; | |
247 | uint8_t resp[256 + 2]; | |
248 | size_t resp_len = sizeof resp; | |
249 | ||
250 | pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len); | |
251 | if (pnd->last_error != NFC_SUCCESS) | |
252 | return pnd->last_error; | |
253 | ||
254 | if (resp_len < 2) { | |
255 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for ATS"); | |
256 | pnd->last_error = NFC_EDEVNOTSUPP; | |
257 | return pnd->last_error; | |
258 | } | |
259 | if (ats_len < resp_len - 2) { | |
260 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "ATS length is wrong"); | |
261 | pnd->last_error = NFC_ESOFT; | |
262 | return pnd->last_error; | |
263 | } | |
264 | ||
265 | //memcpy(ats, resp + 1, resp_len - 2 - 1); | |
266 | memcpy(ats, resp + 1, resp[0] - 1); | |
267 | return resp_len - 2 - 1; | |
268 | } | |
269 | ||
270 | //get sak by send apdu | |
271 | static int pcsc_get_sak(struct nfc_device *pnd, uint8_t *sak, size_t sak_len) | |
272 | { | |
273 | const uint8_t get_data[] = {0xFF, 0xCA, 0x02, 0x00, 0x00}; | |
274 | uint8_t resp[256 + 2]; | |
275 | size_t resp_len = sizeof resp; | |
276 | ||
277 | pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len); | |
278 | if (pnd->last_error != NFC_SUCCESS) | |
279 | return pnd->last_error; | |
280 | ||
281 | if (resp_len < 2) { | |
282 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for SAK"); | |
283 | pnd->last_error = NFC_EDEVNOTSUPP; | |
284 | return pnd->last_error; | |
285 | } | |
286 | if (sak_len < resp_len - 2) { | |
287 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "SAK length is wrong"); | |
288 | pnd->last_error = NFC_ESOFT; | |
289 | return pnd->last_error; | |
290 | } | |
291 | ||
292 | memcpy(sak, resp, resp_len - 2); | |
293 | return resp_len - 2; | |
294 | } | |
295 | ||
296 | static int pcsc_get_uid(struct nfc_device *pnd, uint8_t *uid, size_t uid_len) | |
297 | { | |
298 | const uint8_t get_data[] = {0xFF, 0xCA, 0x00, 0x00, 0x00}; | |
299 | uint8_t resp[256 + 2]; | |
300 | size_t resp_len = sizeof resp; | |
301 | ||
302 | pnd->last_error = pcsc_transmit(pnd, get_data, sizeof get_data, resp, &resp_len); | |
303 | if (pnd->last_error != NFC_SUCCESS) | |
304 | return pnd->last_error; | |
305 | ||
306 | if (resp_len < 2) { | |
307 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Reader doesn't support request for UID"); | |
308 | pnd->last_error = NFC_EDEVNOTSUPP; | |
309 | return pnd->last_error; | |
310 | } | |
311 | if (uid_len < resp_len - 2) { | |
312 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "UID too big"); | |
313 | pnd->last_error = NFC_ESOFT; | |
314 | return pnd->last_error; | |
315 | } | |
316 | ||
317 | memcpy(uid, resp, resp_len - 2); | |
318 | return resp_len - 2; | |
319 | } | |
320 | ||
321 | static int pcsc_props_to_target(struct nfc_device *pnd, uint8_t it, const uint8_t *patr, size_t szatr, const uint8_t *puid, int szuid, const nfc_modulation_type nmt, nfc_target *pnt) | |
322 | { | |
323 | if (NULL != pnt) { | |
324 | switch (nmt) { | |
325 | case NMT_ISO14443A: | |
326 | if ((it == ICC_TYPE_UNKNOWN || it == ICC_TYPE_14443A) | |
327 | && (szuid <= 0 || szuid == 4 || szuid == 7 || szuid == 10) | |
328 | && NULL != patr && szatr >= 5 | |
329 | && patr[0] == 0x3B | |
330 | && patr[1] == (0x80 | ((uint8_t)(szatr - 5))) | |
331 | && patr[2] == 0x80 | |
332 | && patr[3] == 0x01) { | |
333 | memset(pnt, 0, sizeof * pnt); | |
334 | pnt->nm.nmt = NMT_ISO14443A; | |
335 | pnt->nm.nbr = pcsc_supported_brs[0]; | |
336 | if (szuid > 0) { | |
337 | memcpy(pnt->nti.nai.abtUid, puid, szuid); | |
338 | pnt->nti.nai.szUidLen = szuid; | |
339 | } | |
340 | if (is_pcsc_reader_vendor_feitian(pnd)) { | |
341 | uint8_t atqa[2]; | |
342 | pcsc_get_atqa(pnd, atqa, sizeof(atqa)); | |
343 | //memcpy(pnt->nti.nai.abtAtqa,atqa,2); | |
344 | pnt->nti.nai.abtAtqa[0] = atqa[1]; | |
345 | pnt->nti.nai.abtAtqa[1] = atqa[0]; | |
346 | uint8_t sak[1]; | |
347 | pcsc_get_sak(pnd, sak, sizeof(sak)); | |
348 | pnt->nti.nai.btSak = sak[0]; | |
349 | uint8_t ats[256]; | |
350 | int ats_len = pcsc_get_ats(pnd, ats, sizeof(ats)); | |
351 | memcpy(pnt->nti.nai.abtAts, ats, ats_len); | |
352 | //memcpy(pnt->nti.nai.abtAts + ats_len, patr + 4, (uint8_t)(szatr - 5)); | |
353 | pnt->nti.nai.szAtsLen = ats_len;// + szatr - 5; | |
354 | } else { | |
355 | /* SAK_ISO14443_4_COMPLIANT */ | |
356 | pnt->nti.nai.btSak = 0x20; | |
357 | /* Choose TL, TA, TB, TC according to Mifare DESFire */ | |
358 | memcpy(pnt->nti.nai.abtAts, "\x75\x77\x81\x02", 4); | |
359 | /* copy historical bytes */ | |
360 | memcpy(pnt->nti.nai.abtAts + 4, patr + 4, (uint8_t)(szatr - 5)); | |
361 | pnt->nti.nai.szAtsLen = 4 + (uint8_t)(szatr - 5); | |
362 | } | |
363 | ||
364 | return NFC_SUCCESS; | |
365 | } | |
366 | break; | |
367 | case NMT_ISO14443B: | |
368 | if ((ICC_TYPE_UNKNOWN == 0 || ICC_TYPE_14443B == 6) | |
369 | && (szuid <= 0 || szuid == 8) | |
370 | && NULL != patr && szatr == 5 + 8 | |
371 | && patr[0] == 0x3B | |
372 | && patr[1] == (0x80 | 0x08) | |
373 | && patr[2] == 0x80 | |
374 | && patr[3] == 0x01) { | |
375 | memset(pnt, 0, sizeof * pnt); | |
376 | pnt->nm.nmt = NMT_ISO14443B; | |
377 | pnt->nm.nbr = pcsc_supported_brs[0]; | |
378 | memcpy(pnt->nti.nbi.abtApplicationData, patr + 4, 4); | |
379 | memcpy(pnt->nti.nbi.abtProtocolInfo, patr + 8, 3); | |
380 | /* PI_ISO14443_4_SUPPORTED */ | |
381 | pnt->nti.nbi.abtProtocolInfo[1] = 0x01; | |
382 | return NFC_SUCCESS; | |
383 | } | |
384 | break; | |
385 | default: | |
386 | break; | |
387 | } | |
388 | } | |
389 | return NFC_EINVARG; | |
390 | } | |
391 | ||
392 | #define PCSC_MAX_DEVICES 16 | |
393 | /** | |
394 | * @brief List opened devices | |
395 | * | |
396 | * Probe PCSC to find any reader but the ACR122 devices (ACR122U and Touchatag/Tikitag). | |
397 | * | |
398 | * @param connstring array of nfc_connstring where found device's connection strings will be stored. | |
399 | * @param connstrings_len size of connstrings array. | |
400 | * @return number of devices found. | |
401 | */ | |
402 | static size_t | |
403 | pcsc_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) | |
404 | { | |
405 | (void) context; | |
406 | size_t szPos = 0; | |
407 | char acDeviceNames[256 + 64 * PCSC_MAX_DEVICES]; | |
408 | size_t szDeviceNamesLen = sizeof(acDeviceNames); | |
409 | SCARDCONTEXT *pscc; | |
410 | int i; | |
411 | ||
412 | // Clear the reader list | |
413 | memset(acDeviceNames, '\0', szDeviceNamesLen); | |
414 | ||
415 | // Test if context succeeded | |
416 | if (!(pscc = pcsc_get_scardcontext())) { | |
417 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: %s", "PCSC context not found (make sure PCSC daemon is running)."); | |
418 | return 0; | |
419 | } | |
420 | // Retrieve the string array of all available pcsc readers | |
421 | DWORD dwDeviceNamesLen = szDeviceNamesLen; | |
422 | if (SCardListReaders(*pscc, NULL, acDeviceNames, &dwDeviceNamesLen) != SCARD_S_SUCCESS) | |
423 | return 0; | |
424 | ||
425 | size_t device_found = 0; | |
426 | while ((acDeviceNames[szPos] != '\0') && (device_found < connstrings_len)) { | |
427 | bool bSupported = false; | |
428 | for (i = 0; supported_devices[i] && !bSupported; i++) { | |
429 | int l = strlen(supported_devices[i]); | |
430 | bSupported = 0 == !strncmp(supported_devices[i], acDeviceNames + szPos, l); | |
431 | } | |
432 | ||
433 | if (bSupported) { | |
434 | // Supported non-ACR122 device found | |
435 | snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s", PCSC_DRIVER_NAME, acDeviceNames + szPos); | |
436 | device_found++; | |
437 | } else { | |
438 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Skipping PCSC device [%s] as it is supported by acr122_pcsc driver.", acDeviceNames + szPos); | |
439 | } | |
440 | ||
441 | // Find next device name position | |
442 | while (acDeviceNames[szPos++] != '\0'); | |
443 | } | |
444 | pcsc_free_scardcontext(); | |
445 | ||
446 | return device_found; | |
447 | } | |
448 | ||
449 | struct pcsc_descriptor { | |
450 | char *pcsc_device_name; | |
451 | }; | |
452 | ||
453 | static nfc_device * | |
454 | pcsc_open(const nfc_context *context, const nfc_connstring connstring) | |
455 | { | |
456 | struct pcsc_descriptor ndd; | |
457 | int connstring_decode_level = connstring_decode(connstring, PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); | |
458 | ||
459 | if (connstring_decode_level < 1) { | |
460 | return NULL; | |
461 | } | |
462 | ||
463 | nfc_connstring fullconnstring; | |
464 | if (connstring_decode_level == 1) { | |
465 | // Device was not specified, take the first one we can find | |
466 | size_t szDeviceFound = pcsc_scan(context, &fullconnstring, 1); | |
467 | if (szDeviceFound < 1) | |
468 | return NULL; | |
469 | connstring_decode_level = connstring_decode(fullconnstring, PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); | |
470 | if (connstring_decode_level < 2) { | |
471 | return NULL; | |
472 | } | |
473 | } else { | |
474 | memcpy(fullconnstring, connstring, sizeof(nfc_connstring)); | |
475 | } | |
476 | if (strlen(ndd.pcsc_device_name) < 5) { // We can assume it's a reader ID as pcsc_name always ends with "NN NN" | |
477 | // Device was not specified, only ID, retrieve it | |
478 | size_t index; | |
479 | if (sscanf(ndd.pcsc_device_name, "%4" SCNuPTR, &index) != 1) { | |
480 | free(ndd.pcsc_device_name); | |
481 | return NULL; | |
482 | } | |
483 | nfc_connstring *ncs = malloc(sizeof(nfc_connstring) * (index + 1)); | |
484 | if (!ncs) { | |
485 | perror("malloc"); | |
486 | free(ndd.pcsc_device_name); | |
487 | return NULL; | |
488 | } | |
489 | size_t szDeviceFound = pcsc_scan(context, ncs, index + 1); | |
490 | if (szDeviceFound < index + 1) { | |
491 | free(ncs); | |
492 | free(ndd.pcsc_device_name); | |
493 | return NULL; | |
494 | } | |
495 | strncpy(fullconnstring, ncs[index], sizeof(nfc_connstring)); | |
496 | fullconnstring[sizeof(nfc_connstring) - 1] = '\0'; | |
497 | free(ncs); | |
498 | connstring_decode_level = connstring_decode(fullconnstring, PCSC_DRIVER_NAME, "pcsc", &ndd.pcsc_device_name, NULL); | |
499 | ||
500 | if (connstring_decode_level < 2) { | |
501 | free(ndd.pcsc_device_name); | |
502 | return NULL; | |
503 | } | |
504 | } | |
505 | ||
506 | nfc_device *pnd = nfc_device_new(context, fullconnstring); | |
507 | if (!pnd) { | |
508 | perror("malloc"); | |
509 | goto error; | |
510 | } | |
511 | pnd->driver_data = malloc(sizeof(struct pcsc_data)); | |
512 | if (!pnd->driver_data) { | |
513 | perror("malloc"); | |
514 | goto error; | |
515 | } | |
516 | ||
517 | SCARDCONTEXT *pscc; | |
518 | ||
519 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open %s", ndd.pcsc_device_name); | |
520 | // Test if context succeeded | |
521 | if (!(pscc = pcsc_get_scardcontext())) | |
522 | goto error; | |
523 | DRIVER_DATA(pnd)->last_error = SCardConnect(*pscc, ndd.pcsc_device_name, SCARD_SHARE_DIRECT, 0, &(DRIVER_DATA(pnd)->hCard), (void *) & (DRIVER_DATA(pnd)->ioCard.dwProtocol)); | |
524 | if (DRIVER_DATA(pnd)->last_error != SCARD_S_SUCCESS) { | |
525 | // We can not connect to this device. | |
526 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s", "PCSC connect failed"); | |
527 | goto error; | |
528 | } | |
529 | // Configure I/O settings for card communication | |
530 | DRIVER_DATA(pnd)->ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST); | |
531 | DRIVER_DATA(pnd)->dwShareMode = SCARD_SHARE_DIRECT; | |
532 | ||
533 | // Done, we found the reader we are looking for | |
534 | snprintf(pnd->name, sizeof(pnd->name), "%s", ndd.pcsc_device_name); | |
535 | ||
536 | pnd->driver = &pcsc_driver; | |
537 | ||
538 | free(ndd.pcsc_device_name); | |
539 | return pnd; | |
540 | ||
541 | error: | |
542 | free(ndd.pcsc_device_name); | |
543 | nfc_device_free(pnd); | |
544 | return NULL; | |
545 | } | |
546 | ||
547 | static void | |
548 | pcsc_close(nfc_device *pnd) | |
549 | { | |
550 | SCardDisconnect(DRIVER_DATA(pnd)->hCard, SCARD_LEAVE_CARD); | |
551 | pcsc_free_scardcontext(); | |
552 | ||
553 | nfc_device_free(pnd); | |
554 | } | |
555 | ||
556 | static const char *stringify_error(const LONG pcscError) | |
557 | { | |
558 | static char strError[75]; | |
559 | const char *msg = NULL; | |
560 | ||
561 | switch (pcscError) { | |
562 | case SCARD_S_SUCCESS: | |
563 | msg = "Command successful."; | |
564 | break; | |
565 | case SCARD_F_INTERNAL_ERROR: | |
566 | msg = "Internal error."; | |
567 | break; | |
568 | case SCARD_E_CANCELLED: | |
569 | msg = "Command cancelled."; | |
570 | break; | |
571 | case SCARD_E_INVALID_HANDLE: | |
572 | msg = "Invalid handle."; | |
573 | break; | |
574 | case SCARD_E_INVALID_PARAMETER: | |
575 | msg = "Invalid parameter given."; | |
576 | break; | |
577 | case SCARD_E_INVALID_TARGET: | |
578 | msg = "Invalid target given."; | |
579 | break; | |
580 | case SCARD_E_NO_MEMORY: | |
581 | msg = "Not enough memory."; | |
582 | break; | |
583 | case SCARD_F_WAITED_TOO_LONG: | |
584 | msg = "Waited too long."; | |
585 | break; | |
586 | case SCARD_E_INSUFFICIENT_BUFFER: | |
587 | msg = "Insufficient buffer."; | |
588 | break; | |
589 | case SCARD_E_UNKNOWN_READER: | |
590 | msg = "Unknown reader specified."; | |
591 | break; | |
592 | case SCARD_E_TIMEOUT: | |
593 | msg = "Command timeout."; | |
594 | break; | |
595 | case SCARD_E_SHARING_VIOLATION: | |
596 | msg = "Sharing violation."; | |
597 | break; | |
598 | case SCARD_E_NO_SMARTCARD: | |
599 | msg = "No smart card inserted."; | |
600 | break; | |
601 | case SCARD_E_UNKNOWN_CARD: | |
602 | msg = "Unknown card."; | |
603 | break; | |
604 | case SCARD_E_CANT_DISPOSE: | |
605 | msg = "Cannot dispose handle."; | |
606 | break; | |
607 | case SCARD_E_PROTO_MISMATCH: | |
608 | msg = "Card protocol mismatch."; | |
609 | break; | |
610 | case SCARD_E_NOT_READY: | |
611 | msg = "Subsystem not ready."; | |
612 | break; | |
613 | case SCARD_E_INVALID_VALUE: | |
614 | msg = "Invalid value given."; | |
615 | break; | |
616 | case SCARD_E_SYSTEM_CANCELLED: | |
617 | msg = "System cancelled."; | |
618 | break; | |
619 | case SCARD_F_COMM_ERROR: | |
620 | msg = "RPC transport error."; | |
621 | break; | |
622 | case SCARD_F_UNKNOWN_ERROR: | |
623 | msg = "Unknown error."; | |
624 | break; | |
625 | case SCARD_E_INVALID_ATR: | |
626 | msg = "Invalid ATR."; | |
627 | break; | |
628 | case SCARD_E_NOT_TRANSACTED: | |
629 | msg = "Transaction failed."; | |
630 | break; | |
631 | case SCARD_E_READER_UNAVAILABLE: | |
632 | msg = "Reader is unavailable."; | |
633 | break; | |
634 | /* case SCARD_P_SHUTDOWN: */ | |
635 | case SCARD_E_PCI_TOO_SMALL: | |
636 | msg = "PCI struct too small."; | |
637 | break; | |
638 | case SCARD_E_READER_UNSUPPORTED: | |
639 | msg = "Reader is unsupported."; | |
640 | break; | |
641 | case SCARD_E_DUPLICATE_READER: | |
642 | msg = "Reader already exists."; | |
643 | break; | |
644 | case SCARD_E_CARD_UNSUPPORTED: | |
645 | msg = "Card is unsupported."; | |
646 | break; | |
647 | case SCARD_E_NO_SERVICE: | |
648 | msg = "Service not available."; | |
649 | break; | |
650 | case SCARD_E_SERVICE_STOPPED: | |
651 | msg = "Service was stopped."; | |
652 | break; | |
653 | /* case SCARD_E_UNEXPECTED: */ | |
654 | /* case SCARD_E_ICC_CREATEORDER: */ | |
655 | /* case SCARD_E_UNSUPPORTED_FEATURE: */ | |
656 | /* case SCARD_E_DIR_NOT_FOUND: */ | |
657 | /* case SCARD_E_NO_DIR: */ | |
658 | /* case SCARD_E_NO_FILE: */ | |
659 | /* case SCARD_E_NO_ACCESS: */ | |
660 | /* case SCARD_E_WRITE_TOO_MANY: */ | |
661 | /* case SCARD_E_BAD_SEEK: */ | |
662 | /* case SCARD_E_INVALID_CHV: */ | |
663 | /* case SCARD_E_UNKNOWN_RES_MNG: */ | |
664 | /* case SCARD_E_NO_SUCH_CERTIFICATE: */ | |
665 | /* case SCARD_E_CERTIFICATE_UNAVAILABLE: */ | |
666 | case SCARD_E_NO_READERS_AVAILABLE: | |
667 | msg = "Cannot find a smart card reader."; | |
668 | break; | |
669 | /* case SCARD_E_COMM_DATA_LOST: */ | |
670 | /* case SCARD_E_NO_KEY_CONTAINER: */ | |
671 | /* case SCARD_E_SERVER_TOO_BUSY: */ | |
672 | case SCARD_W_UNSUPPORTED_CARD: | |
673 | msg = "Card is not supported."; | |
674 | break; | |
675 | case SCARD_W_UNRESPONSIVE_CARD: | |
676 | msg = "Card is unresponsive."; | |
677 | break; | |
678 | case SCARD_W_UNPOWERED_CARD: | |
679 | msg = "Card is unpowered."; | |
680 | break; | |
681 | case SCARD_W_RESET_CARD: | |
682 | msg = "Card was reset."; | |
683 | break; | |
684 | case SCARD_W_REMOVED_CARD: | |
685 | msg = "Card was removed."; | |
686 | break; | |
687 | /* case SCARD_W_SECURITY_VIOLATION: */ | |
688 | /* case SCARD_W_WRONG_CHV: */ | |
689 | /* case SCARD_W_CHV_BLOCKED: */ | |
690 | /* case SCARD_W_EOF: */ | |
691 | /* case SCARD_W_CANCELLED_BY_USER: */ | |
692 | /* case SCARD_W_CARD_NOT_AUTHENTICATED: */ | |
693 | ||
694 | case SCARD_E_UNSUPPORTED_FEATURE: | |
695 | msg = "Feature not supported."; | |
696 | break; | |
697 | default: | |
698 | (void)snprintf(strError, sizeof(strError) - 1, "Unknown error: 0x%08lX", | |
699 | pcscError); | |
700 | }; | |
701 | ||
702 | if (msg) | |
703 | (void)strncpy(strError, msg, sizeof(strError)); | |
704 | else | |
705 | (void)snprintf(strError, sizeof(strError) - 1, "Unknown error: 0x%08lX", | |
706 | pcscError); | |
707 | ||
708 | /* add a null byte */ | |
709 | strError[sizeof(strError) - 1] = '\0'; | |
710 | ||
711 | return strError; | |
712 | } | |
713 | ||
714 | static const char * | |
715 | pcsc_strerror(const struct nfc_device *pnd) | |
716 | { | |
717 | return stringify_error(DRIVER_DATA(pnd)->last_error); | |
718 | } | |
719 | ||
720 | static int pcsc_initiator_init(struct nfc_device *pnd) | |
721 | { | |
722 | (void) pnd; | |
723 | return NFC_SUCCESS; | |
724 | } | |
725 | ||
726 | static int pcsc_initiator_select_passive_target(struct nfc_device *pnd, const nfc_modulation nm, const uint8_t *pbtInitData, const size_t szInitData, nfc_target *pnt) | |
727 | { | |
728 | uint8_t atr[MAX_ATR_SIZE]; | |
729 | uint8_t uid[10]; | |
730 | int target_present; | |
731 | size_t atr_len = sizeof atr; | |
732 | ||
733 | (void) pbtInitData; | |
734 | (void) szInitData; | |
735 | ||
736 | if (nm.nbr != pcsc_supported_brs[0] && nm.nbr != pcsc_supported_brs[1]) | |
737 | return NFC_EINVARG; | |
738 | ||
739 | pnd->last_error = pcsc_get_status(pnd, &target_present, atr, &atr_len); | |
740 | if (pnd->last_error != NFC_SUCCESS) | |
741 | return pnd->last_error; | |
742 | ||
743 | if (!target_present) { | |
744 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "No target present"); | |
745 | return NFC_ENOTSUCHDEV; | |
746 | } | |
747 | ||
748 | uint8_t icc_type = pcsc_get_icc_type(pnd); | |
749 | int uid_len = pcsc_get_uid(pnd, uid, sizeof uid); | |
750 | if (pcsc_props_to_target(pnd, icc_type, atr, atr_len, uid, uid_len, nm.nmt, pnt) != NFC_SUCCESS) { | |
751 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Type of target not supported"); | |
752 | return NFC_EDEVNOTSUPP; | |
753 | } | |
754 | ||
755 | pnd->last_error = pcsc_reconnect(pnd, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_LEAVE_CARD); | |
756 | if (pnd->last_error != NFC_SUCCESS) | |
757 | return pnd->last_error; | |
758 | ||
759 | return 1; | |
760 | } | |
761 | ||
762 | #if 0 | |
763 | static int pcsc_initiator_deselect_target(struct nfc_device *pnd) | |
764 | { | |
765 | pnd->last_error = pcsc_reconnect(pnd, SCARD_SHARE_DIRECT, 0, SCARD_LEAVE_CARD); | |
766 | return pnd->last_error; | |
767 | } | |
768 | #endif | |
769 | ||
770 | static int pcsc_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, const size_t szRx, int timeout) | |
771 | { | |
772 | size_t resp_len = szRx; | |
773 | ||
774 | // FIXME: timeout is not handled | |
775 | (void) timeout; | |
776 | ||
777 | if (is_pcsc_reader_vendor_feitian(pnd)) { | |
778 | LOG_HEX(NFC_LOG_GROUP_COM, "not feitian reader pcsc apdu send", pbtTx, szTx); | |
779 | ||
780 | uint8_t apdu_data[256]; | |
781 | uint8_t resp[256 + 2]; | |
782 | size_t send_size = 0; | |
783 | if (pbtTx[0] == 0x30) {//read data | |
784 | apdu_data[0] = 0xFF; | |
785 | apdu_data[1] = 0xB0; | |
786 | apdu_data[2] = 0x00; | |
787 | apdu_data[3] = pbtTx[1]; | |
788 | apdu_data[4] = 0x10; | |
789 | send_size = 5; | |
790 | } else if (pbtTx[0] == 0xA0 || pbtTx[0] == 0xA2) {//write data | |
791 | apdu_data[0] = 0xFF; | |
792 | apdu_data[1] = 0xD6; | |
793 | apdu_data[2] = 0x00; | |
794 | apdu_data[3] = pbtTx[1]; | |
795 | apdu_data[4] = szTx - 2; | |
796 | memcpy(apdu_data + 5, pbtTx + 2, szTx - 2); | |
797 | send_size = 5 + szTx - 2; | |
798 | } else if (pbtTx[0] == 0x60 || pbtTx[0] == 0x61 || pbtTx[0] == 0x1A) { //Auth command | |
799 | apdu_data[0] = 0xFF; | |
800 | apdu_data[1] = 0x86; | |
801 | apdu_data[2] = 0x00; | |
802 | apdu_data[3] = 0x00; | |
803 | apdu_data[4] = 0x05; | |
804 | apdu_data[5] = 0x01; | |
805 | apdu_data[6] = 0x00; | |
806 | apdu_data[7] = pbtTx[1];//block index | |
807 | apdu_data[8] = pbtTx[0];//type a or type b | |
808 | apdu_data[9] = 0x01; | |
809 | send_size = 10; | |
810 | } else if (pbtTx[0] == 0xC0) { //DECREMENT cmd | |
811 | apdu_data[0] = 0xFF; | |
812 | apdu_data[1] = 0xD7; | |
813 | apdu_data[2] = 0x00; | |
814 | apdu_data[3] = pbtTx[1];//block index | |
815 | apdu_data[4] = 0x05; | |
816 | memcpy(apdu_data + 5, pbtTx + 2, szTx - 2); | |
817 | send_size = 5 + szTx - 2; | |
818 | } else if (pbtTx[0] == 0xC1) { //INCREMENT cmd | |
819 | apdu_data[0] = 0xFF; | |
820 | apdu_data[1] = 0xD7; | |
821 | apdu_data[2] = 0x00; | |
822 | apdu_data[3] = pbtTx[1];//block index | |
823 | apdu_data[4] = 0x05; | |
824 | memcpy(apdu_data + 5, pbtTx + 2, szTx - 2); | |
825 | send_size = 5 + szTx - 2; | |
826 | } else if (pbtTx[0] == 0xC2) { //STORE cmd | |
827 | apdu_data[0] = 0xFF; | |
828 | apdu_data[1] = 0xD8; | |
829 | apdu_data[2] = 0x00; | |
830 | apdu_data[3] = pbtTx[1]; | |
831 | apdu_data[4] = szTx - 2; | |
832 | memcpy(apdu_data + 5, pbtTx + 2, szTx - 2); | |
833 | send_size = 5 + szTx - 2; | |
834 | } else {//other cmd | |
835 | memcpy(apdu_data, pbtTx, szTx); | |
836 | send_size = szTx; | |
837 | } | |
838 | LOG_HEX(NFC_LOG_GROUP_COM, "feitian reader pcsc apdu send:", apdu_data, send_size); | |
839 | pnd->last_error = pcsc_transmit(pnd, apdu_data, send_size, resp, &resp_len); | |
840 | LOG_HEX(NFC_LOG_GROUP_COM, "feitian reader pcsc apdu received:", resp, resp_len); | |
841 | ||
842 | memcpy(pbtRx, resp, resp_len); | |
843 | } else { | |
844 | pnd->last_error = pcsc_transmit(pnd, pbtTx, szTx, pbtRx, &resp_len); | |
845 | } | |
846 | if (pnd->last_error != NFC_SUCCESS) | |
847 | return pnd->last_error; | |
848 | ||
849 | return resp_len; | |
850 | } | |
851 | ||
852 | static int pcsc_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) | |
853 | { | |
854 | uint8_t atr[MAX_ATR_SIZE]; | |
855 | int target_present; | |
856 | size_t atr_len = sizeof atr; | |
857 | nfc_target nt; | |
858 | ||
859 | pnd->last_error = pcsc_get_status(pnd, &target_present, atr, &atr_len); | |
860 | if (pnd->last_error != NFC_SUCCESS) | |
861 | return pnd->last_error; | |
862 | ||
863 | if (!target_present) { | |
864 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "No target present"); | |
865 | return NFC_ENOTSUCHDEV; | |
866 | } | |
867 | ||
868 | if (pnt) { | |
869 | if (pcsc_props_to_target(pnd, ICC_TYPE_UNKNOWN, atr, atr_len, NULL, 0, pnt->nm.nmt, &nt) != NFC_SUCCESS | |
870 | || pnt->nm.nmt != nt.nm.nmt || pnt->nm.nbr != nt.nm.nbr) { | |
871 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Target doesn't meet requirements"); | |
872 | return NFC_ENOTSUCHDEV; | |
873 | } | |
874 | } | |
875 | return NFC_SUCCESS; | |
876 | } | |
877 | ||
878 | static int pcsc_device_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable) | |
879 | { | |
880 | (void) pnd; | |
881 | switch (property) { | |
882 | case NP_INFINITE_SELECT: | |
883 | // ignore | |
884 | return NFC_SUCCESS; | |
885 | case NP_AUTO_ISO14443_4: | |
886 | case NP_EASY_FRAMING: | |
887 | if ((bEnable == true) || (is_pcsc_reader_vendor_feitian(pnd))) | |
888 | return NFC_SUCCESS; | |
889 | break; | |
890 | case NP_FORCE_ISO14443_A: | |
891 | case NP_HANDLE_CRC: | |
892 | case NP_HANDLE_PARITY: | |
893 | case NP_FORCE_SPEED_106: | |
894 | if (bEnable == true) | |
895 | return NFC_SUCCESS; | |
896 | break; | |
897 | case NP_ACCEPT_INVALID_FRAMES: | |
898 | case NP_ACCEPT_MULTIPLE_FRAMES: | |
899 | if (bEnable == false) | |
900 | return NFC_SUCCESS; | |
901 | break; | |
902 | case NP_ACTIVATE_FIELD: | |
903 | if (bEnable == false) { | |
904 | struct pcsc_data *data = pnd->driver_data; | |
905 | pcsc_reconnect(pnd, data->dwShareMode, data->ioCard.dwProtocol, SCARD_RESET_CARD); | |
906 | } | |
907 | return NFC_SUCCESS; | |
908 | default: | |
909 | break; | |
910 | } | |
911 | return NFC_EDEVNOTSUPP; | |
912 | } | |
913 | ||
914 | static int pcsc_get_supported_modulation(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) | |
915 | { | |
916 | (void) pnd; | |
917 | if (mode == N_TARGET || NULL == supported_mt) | |
918 | return NFC_EINVARG; | |
919 | *supported_mt = pcsc_supported_mts; | |
920 | return NFC_SUCCESS; | |
921 | } | |
922 | ||
923 | static int pcsc_get_supported_baud_rate(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) | |
924 | { | |
925 | (void) pnd; | |
926 | (void) nmt; | |
927 | if (mode == N_TARGET || NULL == supported_br) | |
928 | return NFC_EINVARG; | |
929 | *supported_br = pcsc_supported_brs; | |
930 | return NFC_SUCCESS; | |
931 | } | |
932 | ||
933 | static int | |
934 | pcsc_get_information_about(nfc_device *pnd, char **pbuf) | |
935 | { | |
936 | struct pcsc_data *data = pnd->driver_data; | |
937 | LPBYTE name = NULL, version = NULL, type = NULL, serial = NULL; | |
938 | DWORD name_len = SCARD_AUTOALLOCATE, version_len = SCARD_AUTOALLOCATE, | |
939 | type_len = SCARD_AUTOALLOCATE, serial_len = SCARD_AUTOALLOCATE; | |
940 | int res = NFC_SUCCESS; | |
941 | SCARDCONTEXT *pscc; | |
942 | ||
943 | if (!(pscc = pcsc_get_scardcontext())) { | |
944 | pnd->last_error = NFC_ESOFT; | |
945 | return pnd->last_error; | |
946 | } | |
947 | ||
948 | SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_NAME, (LPBYTE)&name, &name_len); | |
949 | SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_IFD_TYPE, (LPBYTE)&type, &type_len); | |
950 | SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_IFD_VERSION, (LPBYTE)&version, &version_len); | |
951 | SCardGetAttrib(data->hCard, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, (LPBYTE)&serial, &serial_len); | |
952 | ||
953 | *pbuf = malloc(name_len + type_len + version_len + serial_len + 30); | |
954 | if (! *pbuf) { | |
955 | res = NFC_ESOFT; | |
956 | goto error; | |
957 | } | |
958 | sprintf((char *) *pbuf, | |
959 | "%s" // model | |
960 | "%s%s" // version | |
961 | " (%s)" // vendor | |
962 | "%s%s\n" // serial | |
963 | , | |
964 | name && name_len > 0 && name[0] != '\0' | |
965 | ? (char *)name : "unknown model", | |
966 | version && version_len > 0 && version[0] != '\0' | |
967 | ? " " : "", version_len > 0 ? (char *)version : "", | |
968 | type && type_len > 0 && type[0] != '\0' | |
969 | ? (char *)type : "unknown vendor", | |
970 | serial && serial_len > 0 && serial[0] != '\0' | |
971 | ? "\nserial: " : "", serial_len > 0 ? (char *)serial : ""); | |
972 | ||
973 | error: | |
974 | #ifdef __APPLE__ | |
975 | if (pscc != NULL) { | |
976 | SCardReleaseContext(*pscc); | |
977 | } | |
978 | if (name != NULL) { | |
979 | free(name); | |
980 | name = NULL; | |
981 | } | |
982 | if (type != NULL) { | |
983 | free(type); | |
984 | type = NULL; | |
985 | } | |
986 | if (version != NULL) { | |
987 | free(version); | |
988 | version = NULL; | |
989 | } | |
990 | if (serial != NULL) { | |
991 | free(serial); | |
992 | serial = NULL; | |
993 | } | |
994 | #else | |
995 | SCardFreeMemory(*pscc, name); | |
996 | SCardFreeMemory(*pscc, type); | |
997 | SCardFreeMemory(*pscc, version); | |
998 | SCardFreeMemory(*pscc, serial); | |
999 | #endif | |
1000 | ||
1001 | pnd->last_error = res; | |
1002 | return pnd->last_error; | |
1003 | } | |
1004 | ||
1005 | const struct nfc_driver pcsc_driver = { | |
1006 | .name = PCSC_DRIVER_NAME, | |
1007 | .scan = pcsc_scan, | |
1008 | .open = pcsc_open, | |
1009 | .close = pcsc_close, | |
1010 | .strerror = pcsc_strerror, | |
1011 | ||
1012 | .initiator_init = pcsc_initiator_init, | |
1013 | .initiator_init_secure_element = NULL, // No secure-element support | |
1014 | .initiator_select_passive_target = pcsc_initiator_select_passive_target, | |
1015 | .initiator_poll_target = NULL, | |
1016 | .initiator_select_dep_target = NULL, | |
1017 | .initiator_deselect_target = NULL, | |
1018 | .initiator_transceive_bytes = pcsc_initiator_transceive_bytes, | |
1019 | .initiator_transceive_bits = NULL, | |
1020 | .initiator_transceive_bytes_timed = NULL, | |
1021 | .initiator_transceive_bits_timed = NULL, | |
1022 | .initiator_target_is_present = pcsc_initiator_target_is_present, | |
1023 | ||
1024 | .target_init = NULL, | |
1025 | .target_send_bytes = NULL, | |
1026 | .target_receive_bytes = NULL, | |
1027 | .target_send_bits = NULL, | |
1028 | .target_receive_bits = NULL, | |
1029 | ||
1030 | .device_set_property_bool = pcsc_device_set_property_bool, | |
1031 | .device_set_property_int = NULL, | |
1032 | .get_supported_modulation = pcsc_get_supported_modulation, | |
1033 | .get_supported_baud_rate = pcsc_get_supported_baud_rate, | |
1034 | .device_get_information_about = pcsc_get_information_about, | |
1035 | ||
1036 | .abort_command = NULL, // Abort is not supported in this driver | |
1037 | .idle = NULL, | |
1038 | .powerdown = NULL, | |
1039 | }; |
0 | /*- | |
1 | * Free/Libre Near Field Communication (NFC) library | |
2 | * | |
3 | * Libnfc historical contributors: | |
4 | * Copyright (C) 2019 Frank Morgner | |
5 | * See AUTHORS file for a more comprehensive list of contributors. | |
6 | * Additional contributors of this file: | |
7 | * | |
8 | * This program is free software: you can redistribute it and/or modify it | |
9 | * under the terms of the GNU Lesser General Public License as published by the | |
10 | * Free Software Foundation, either version 3 of the License, or (at your | |
11 | * option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 | * more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public License | |
19 | * along with this program. If not, see <http://www.gnu.org/licenses/> | |
20 | */ | |
21 | ||
22 | /** | |
23 | * @file pcsc.h | |
24 | * @brief Driver for non-ACR122 devices (behind PC/SC daemon) | |
25 | */ | |
26 | ||
27 | #ifndef __NFC_DRIVER_PCSC_H__ | |
28 | #define __NFC_DRIVER_PCSC_H__ | |
29 | ||
30 | #include <nfc/nfc-types.h> | |
31 | ||
32 | extern const struct nfc_driver pcsc_driver; | |
33 | ||
34 | #endif // ! __NFC_DRIVER_PCSC_H__ |
58 | 58 | // I2C address of the PN532 chip. |
59 | 59 | #define PN532_I2C_ADDR 0x24 |
60 | 60 | |
61 | /* | |
62 | * When sending lots of data, the pn532 occasionally fails to respond in time. | |
63 | * Since it happens so rarely, lets try to fix it by re-sending the data. This | |
64 | * define allows for fine tuning the number of retries. | |
65 | */ | |
66 | #define PN532_SEND_RETRIES 3 | |
67 | ||
61 | 68 | // Internal data structs |
62 | 69 | const struct pn53x_io pn532_i2c_io; |
63 | 70 | |
66 | 73 | volatile bool abort_flag; |
67 | 74 | }; |
68 | 75 | |
69 | /* Delay for the loop waiting for READY frame (in ms) */ | |
70 | #define PN532_RDY_LOOP_DELAY 90 | |
71 | ||
72 | const struct timespec rdyDelay = { | |
73 | .tv_sec = 0, | |
74 | .tv_nsec = PN532_RDY_LOOP_DELAY * 1000 * 1000 | |
75 | }; | |
76 | /* preamble and start bytes, see pn532-internal.h for details */ | |
77 | const uint8_t pn53x_preamble_and_start[] = { 0x00, 0x00, 0xff }; | |
78 | #define PN53X_PREAMBLE_AND_START_LEN (sizeof(pn53x_preamble_and_start) / sizeof(pn53x_preamble_and_start[0])) | |
76 | 79 | |
77 | 80 | /* Private Functions Prototypes */ |
78 | 81 | |
94 | 97 | |
95 | 98 | |
96 | 99 | #define DRIVER_DATA(pnd) ((struct pn532_i2c_data*)(pnd->driver_data)) |
100 | ||
101 | /* | |
102 | * Bus free time (in ms) between a STOP condition and START condition. See | |
103 | * tBuf in the PN532 data sheet, section 12.25: Timing for the I2C interface, | |
104 | * table 320. I2C timing specification, page 211, rev. 3.2 - 2007-12-07. | |
105 | */ | |
106 | #define PN532_BUS_FREE_TIME 5 | |
107 | static struct timespec __transaction_stop; | |
108 | ||
109 | /** | |
110 | * @brief Wrapper around i2c_read to ensure proper timing by respecting the | |
111 | * minimal free bus time between a STOP condition and a START condition. | |
112 | * | |
113 | * @note This is not thread safe, but since libnfc is single threaded | |
114 | * this should be okay. | |
115 | * | |
116 | * @param id I2C device | |
117 | * @param buf pointer on buffer used to store data | |
118 | * @param len length of the buffer | |
119 | * @return length (in bytes) of read data, or driver error code (negative value) | |
120 | */ | |
121 | static ssize_t pn532_i2c_read(const i2c_device id, | |
122 | uint8_t *buf, const size_t len) | |
123 | { | |
124 | struct timespec transaction_start, bus_free_time = { 0, 0 }; | |
125 | ssize_t ret; | |
126 | ||
127 | clock_gettime(CLOCK_MONOTONIC, &transaction_start); | |
128 | bus_free_time.tv_nsec = (PN532_BUS_FREE_TIME * 1000 * 1000) - | |
129 | (transaction_start.tv_nsec - __transaction_stop.tv_nsec); | |
130 | nanosleep(&bus_free_time, NULL); | |
131 | ||
132 | ret = i2c_read(id, buf, len); | |
133 | clock_gettime(CLOCK_MONOTONIC, &__transaction_stop); | |
134 | return ret; | |
135 | } | |
136 | ||
137 | /** | |
138 | * @brief Wrapper around i2c_write to ensure proper timing by respecting the | |
139 | * minimal free bus time between a STOP condition and a START condition. | |
140 | * | |
141 | * @note This is not thread safe, but since libnfc is single threaded | |
142 | * this should be okay. | |
143 | * | |
144 | * @param id I2C device | |
145 | * @param buf pointer on buffer containing data | |
146 | * @param len length of the buffer | |
147 | * @return NFC_SUCCESS on success, otherwise driver error code | |
148 | */ | |
149 | static ssize_t pn532_i2c_write(const i2c_device id, | |
150 | const uint8_t *buf, const size_t len) | |
151 | { | |
152 | struct timespec transaction_start, bus_free_time = { 0, 0 }; | |
153 | ssize_t ret; | |
154 | ||
155 | clock_gettime(CLOCK_MONOTONIC, &transaction_start); | |
156 | bus_free_time.tv_nsec = (PN532_BUS_FREE_TIME * 1000 * 1000) - | |
157 | (transaction_start.tv_nsec - __transaction_stop.tv_nsec); | |
158 | nanosleep(&bus_free_time, NULL); | |
159 | ||
160 | ret = i2c_write(id, buf, len); | |
161 | clock_gettime(CLOCK_MONOTONIC, &__transaction_stop); | |
162 | return ret; | |
163 | } | |
97 | 164 | |
98 | 165 | /** |
99 | 166 | * @brief Scan all available I2C buses to find PN532 devices. |
307 | 374 | pn532_i2c_send(nfc_device *pnd, const uint8_t *pbtData, const size_t szData, int timeout) |
308 | 375 | { |
309 | 376 | int res = 0; |
377 | uint8_t retries; | |
310 | 378 | |
311 | 379 | // Discard any existing data ? |
312 | 380 | |
333 | 401 | break; |
334 | 402 | }; |
335 | 403 | |
336 | uint8_t abtFrame[PN532_BUFFER_LEN] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff" | |
404 | uint8_t abtFrame[PN532_BUFFER_LEN]; | |
337 | 405 | size_t szFrame = 0; |
338 | 406 | |
407 | memcpy(abtFrame, pn53x_preamble_and_start, PN53X_PREAMBLE_AND_START_LEN); // Every packet must start with the preamble and start bytes. | |
339 | 408 | if ((res = pn53x_build_frame(abtFrame, &szFrame, pbtData, szData)) < 0) { |
340 | 409 | pnd->last_error = res; |
341 | 410 | return pnd->last_error; |
342 | 411 | } |
343 | 412 | |
344 | res = i2c_write(DRIVER_DATA(pnd)->dev, abtFrame, szFrame); | |
413 | for (retries = PN532_SEND_RETRIES; retries > 0; retries--) { | |
414 | res = pn532_i2c_write(DRIVER_DATA(pnd)->dev, abtFrame, szFrame); | |
415 | if (res >= 0) | |
416 | break; | |
417 | ||
418 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "Failed to transmit data. Retries left: %d.", retries - 1); | |
419 | } | |
345 | 420 | |
346 | 421 | if (res < 0) { |
347 | 422 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Unable to transmit data. (TX)"); |
399 | 474 | } |
400 | 475 | |
401 | 476 | do { |
402 | // Wait a little bit before reading | |
403 | nanosleep(&rdyDelay, (struct timespec *) NULL); | |
404 | ||
405 | int recCount = i2c_read(DRIVER_DATA(pnd)->dev, i2cRx, szDataLen + 1); | |
477 | int recCount = pn532_i2c_read(DRIVER_DATA(pnd)->dev, i2cRx, szDataLen + 1); | |
406 | 478 | |
407 | 479 | if (DRIVER_DATA(pnd)->abort_flag) { |
408 | 480 | // Reset abort flag |
476 | 548 | goto error; |
477 | 549 | } |
478 | 550 | |
479 | const uint8_t pn53x_preamble[3] = { 0x00, 0x00, 0xff }; | |
480 | ||
481 | if (0 != (memcmp(frameBuf, pn53x_preamble, 3))) { | |
551 | if (0 != (memcmp(frameBuf, pn53x_preamble_and_start, PN53X_PREAMBLE_AND_START_LEN))) { | |
482 | 552 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_ERROR, "%s", "Frame preamble+start code mismatch"); |
483 | 553 | pnd->last_error = NFC_EIO; |
484 | 554 | goto error; |
571 | 641 | int |
572 | 642 | pn532_i2c_ack(nfc_device *pnd) |
573 | 643 | { |
574 | return i2c_write(DRIVER_DATA(pnd)->dev, pn53x_ack_frame, sizeof(pn53x_ack_frame)); | |
644 | return pn532_i2c_write(DRIVER_DATA(pnd)->dev, pn53x_ack_frame, sizeof(pn53x_ack_frame)); | |
575 | 645 | } |
576 | 646 | |
577 | 647 | /** |
432 | 432 | goto error; |
433 | 433 | } |
434 | 434 | |
435 | pnd->last_error = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf , 4, true); | |
435 | pnd->last_error = spi_send_receive(DRIVER_DATA(pnd)->port, &pn532_spi_cmd_dataread, 1, abtRxBuf, 4, true); | |
436 | 436 | |
437 | 437 | if (pnd->last_error < 0) { |
438 | 438 | goto error; |
81 | 81 | |
82 | 82 | while ((acPort = acPorts[iDevice++])) { |
83 | 83 | sp = uart_open(acPort); |
84 | 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); | |
84 | 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); | |
85 | 85 | |
86 | 86 | if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) { |
87 | 87 | // We need to flush input to be sure first reply does not comes from older byte transceive |
224 | 224 | serial_port sp; |
225 | 225 | nfc_device *pnd = NULL; |
226 | 226 | |
227 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d bauds.", ndd.port, ndd.speed); | |
227 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Attempt to open: %s at %d baud.", ndd.port, ndd.speed); | |
228 | 228 | sp = uart_open(ndd.port); |
229 | 229 | |
230 | 230 | if (sp == INVALID_SERIAL_PORT) |
4 | 4 | * Copyright (C) 2009 Roel Verdult |
5 | 5 | * Copyright (C) 2009-2013 Romuald Conty |
6 | 6 | * Copyright (C) 2010-2012 Romain Tartière |
7 | * Copyright (C) 2010-2013 Philippe Teuwen | |
7 | * Copyright (C) 2010-2017 Philippe Teuwen | |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
59 | 59 | |
60 | 60 | #define DRIVER_DATA(pnd) ((struct pn53x_usb_data*)(pnd->driver_data)) |
61 | 61 | |
62 | const nfc_modulation_type no_target_support[] = {0}; | |
63 | ||
62 | 64 | typedef enum { |
63 | 65 | UNKNOWN, |
64 | 66 | NXP_PN531, |
66 | 68 | NXP_PN533, |
67 | 69 | ASK_LOGO, |
68 | 70 | SCM_SCL3711, |
71 | SCM_SCL3712, | |
69 | 72 | SONY_RCS360 |
70 | 73 | } pn53x_usb_model; |
71 | 74 | |
77 | 80 | uint32_t uiEndPointOut; |
78 | 81 | uint32_t uiMaxPacketSize; |
79 | 82 | volatile bool abort_flag; |
83 | bool possibly_corrupted_usbdesc; | |
80 | 84 | }; |
81 | 85 | |
82 | 86 | // Internal io struct |
120 | 124 | uint16_t product_id; |
121 | 125 | pn53x_usb_model model; |
122 | 126 | const char *name; |
127 | /* hardcoded known values for buggy hardware whose configuration vanishes */ | |
128 | uint32_t uiEndPointIn; | |
129 | uint32_t uiEndPointOut; | |
130 | uint32_t uiMaxPacketSize; | |
123 | 131 | }; |
124 | 132 | |
125 | 133 | const struct pn53x_usb_supported_device pn53x_usb_supported_devices[] = { |
126 | { 0x04CC, 0x0531, NXP_PN531, "Philips / PN531" }, | |
127 | { 0x04CC, 0x2533, NXP_PN533, "NXP / PN533" }, | |
128 | { 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW" }, | |
129 | { 0x054c, 0x0193, SONY_PN531, "Sony / PN531" }, | |
130 | { 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO" }, | |
131 | { 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]" } | |
134 | { 0x04CC, 0x0531, NXP_PN531, "Philips / PN531", 0x84, 0x04, 0x40 }, | |
135 | { 0x04CC, 0x2533, NXP_PN533, "NXP / PN533", 0x84, 0x04, 0x40 }, | |
136 | { 0x04E6, 0x5591, SCM_SCL3711, "SCM Micro / SCL3711-NFC&RW", 0x84, 0x04, 0x40 }, | |
137 | { 0x04E6, 0x5594, SCM_SCL3712, "SCM Micro / SCL3712-NFC&RW", 0, 0, 0 }, // to check on real device | |
138 | { 0x054c, 0x0193, SONY_PN531, "Sony / PN531", 0x84, 0x04, 0x40 }, | |
139 | { 0x1FD3, 0x0608, ASK_LOGO, "ASK / LoGO", 0x84, 0x04, 0x40 }, | |
140 | { 0x054C, 0x02E1, SONY_RCS360, "Sony / FeliCa S360 [PaSoRi]", 0x84, 0x04, 0x40 } | |
132 | 141 | }; |
142 | ||
143 | // PN533 USB descriptors backup buffers | |
144 | ||
145 | const uint8_t btXramUsbDesc_scl3711[] = { | |
146 | 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, | |
147 | 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, | |
148 | 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x1e, 0x03, 0x53, 0x00, | |
149 | 0x43, 0x00, 0x4c, 0x00, 0x33, 0x00, 0x37, 0x00, 0x31, 0x00, 0x31, 0x00, | |
150 | 0x2d, 0x00, 0x4e, 0x00, 0x46, 0x00, 0x43, 0x00, 0x26, 0x00, 0x52, 0x00, | |
151 | 0x57, | |
152 | }; | |
153 | const uint8_t btXramUsbDesc_nxppn533[] = { | |
154 | 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x32, 0x09, 0x04, 0x00, | |
155 | 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, | |
156 | 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0c, 0x03, 0x50, 0x00, | |
157 | 0x4e, 0x00, 0x35, 0x00, 0x33, 0x00, 0x33, 0x00, 0x04, 0x03, 0x09, 0x04, | |
158 | 0x08, 0x03, 0x4e, 0x00, 0x58, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, | |
159 | 0x00, | |
160 | }; | |
161 | const uint8_t btXramUsbDesc_asklogo[] = { | |
162 | 0x09, 0x02, 0x20, 0x00, 0x01, 0x01, 0x00, 0x80, 0x96, 0x09, 0x04, 0x00, | |
163 | 0x00, 0x02, 0xff, 0xff, 0xff, 0x00, 0x07, 0x05, 0x04, 0x02, 0x40, 0x00, | |
164 | 0x04, 0x07, 0x05, 0x84, 0x02, 0x40, 0x00, 0x04, 0x0a, 0x03, 0x4c, 0x00, | |
165 | 0x6f, 0x00, 0x47, 0x00, 0x4f, 0x00, 0x04, 0x03, 0x09, 0x04, 0x08, 0x03, | |
166 | 0x41, 0x00, 0x53, 0x00, 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
167 | 0x00, | |
168 | }; | |
169 | ||
170 | static void pn533_fix_usbdesc(nfc_device *pnd) | |
171 | { | |
172 | // PN533 USB descriptors may have been corrupted by large commands/responses | |
173 | // so they need to be restored before closing usb connection. | |
174 | // cf PN5331B3HNC270 Release Note | |
175 | uint32_t szXramUsbDesc = 0; | |
176 | uint8_t *btXramUsbDesc = NULL; | |
177 | if (DRIVER_DATA(pnd)->model == NXP_PN533) { | |
178 | btXramUsbDesc = (uint8_t *)btXramUsbDesc_nxppn533; | |
179 | szXramUsbDesc = sizeof(btXramUsbDesc_nxppn533); | |
180 | } else if (DRIVER_DATA(pnd)->model == SCM_SCL3711) { | |
181 | btXramUsbDesc = (uint8_t *)btXramUsbDesc_scl3711; | |
182 | szXramUsbDesc = sizeof(btXramUsbDesc_scl3711); | |
183 | } else if (DRIVER_DATA(pnd)->model == ASK_LOGO) { | |
184 | btXramUsbDesc = (uint8_t *)btXramUsbDesc_asklogo; | |
185 | szXramUsbDesc = sizeof(btXramUsbDesc_asklogo); | |
186 | } | |
187 | #define MAXSZXRAMUSBDESC 61 | |
188 | if ((szXramUsbDesc == 0) || (MAXSZXRAMUSBDESC > 61)) | |
189 | return; | |
190 | #if 0 | |
191 | // Debug routine to check if corruption occurred: | |
192 | // Don't read more regs at once or it will trigger the bug and corrupt what we're busy reading! | |
193 | uint8_t abtCmdRR[] = { ReadRegister, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
194 | uint8_t nRRreg = ((sizeof(abtCmdRR) - 1) / 2); | |
195 | uint8_t abtRxRR[1 + nRRreg]; | |
196 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Checking USB descriptors corruption in XRAM"); | |
197 | for (uint8_t i = 0x19, j = 0; i < 0x19 + szXramUsbDesc;) { | |
198 | for (uint8_t k = 0; k < nRRreg; k++) { | |
199 | abtCmdRR[(2 * k) + 2] = i++; | |
200 | } | |
201 | if (pn53x_transceive(pnd, abtCmdRR, sizeof(abtCmdRR), abtRxRR, sizeof(abtRxRR), -1) < 0) { | |
202 | return; // void | |
203 | } | |
204 | for (int k = 0; (k < nRRreg) && (j < szXramUsbDesc); k++) { | |
205 | //printf("0x%02x, ", abtRxRR[1 + k]); | |
206 | if (btXramUsbDesc[j] != abtRxRR[1 + k]) | |
207 | 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]); | |
208 | j++; | |
209 | } | |
210 | } | |
211 | #endif | |
212 | // Abuse the overflow bug to restore USB descriptors in one go | |
213 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "%s", "Fixing USB descriptors corruption"); | |
214 | uint8_t abtCmdWR[19 + MAXSZXRAMUSBDESC] = { GetFirmwareVersion }; | |
215 | for (uint8_t i = 0; i < szXramUsbDesc; i++) { | |
216 | abtCmdWR[i + 19] = btXramUsbDesc[i]; | |
217 | } | |
218 | size_t szCmdWR = sizeof(abtCmdWR); | |
219 | uint8_t abtRxWR[4]; | |
220 | if (pn53x_transceive(pnd, abtCmdWR, szCmdWR, abtRxWR, sizeof(abtRxWR), -1) < 0) { | |
221 | return; // void | |
222 | } | |
223 | DRIVER_DATA(pnd)->possibly_corrupted_usbdesc = false; | |
224 | } | |
133 | 225 | |
134 | 226 | static pn53x_usb_model |
135 | 227 | pn53x_usb_get_device_model(uint16_t vendor_id, uint16_t product_id) |
141 | 233 | } |
142 | 234 | |
143 | 235 | return UNKNOWN; |
236 | } | |
237 | ||
238 | static bool | |
239 | pn53x_usb_get_end_points_default(struct usb_device *dev, struct pn53x_usb_data *data) | |
240 | { | |
241 | for (size_t n = 0; n < sizeof(pn53x_usb_supported_devices) / sizeof(struct pn53x_usb_supported_device); n++) { | |
242 | if ((dev->descriptor.idVendor == pn53x_usb_supported_devices[n].vendor_id) && | |
243 | (dev->descriptor.idProduct == pn53x_usb_supported_devices[n].product_id)) { | |
244 | if (pn53x_usb_supported_devices[n].uiMaxPacketSize != 0) { | |
245 | data->uiEndPointIn = pn53x_usb_supported_devices[n].uiEndPointIn; | |
246 | data->uiEndPointOut = pn53x_usb_supported_devices[n].uiEndPointOut; | |
247 | data->uiMaxPacketSize = pn53x_usb_supported_devices[n].uiMaxPacketSize; | |
248 | ||
249 | return true; | |
250 | } | |
251 | } | |
252 | } | |
253 | ||
254 | return false; | |
144 | 255 | } |
145 | 256 | |
146 | 257 | int pn53x_usb_ack(nfc_device *pnd); |
193 | 304 | if ((pn53x_usb_supported_devices[n].vendor_id == dev->descriptor.idVendor) && |
194 | 305 | (pn53x_usb_supported_devices[n].product_id == dev->descriptor.idProduct)) { |
195 | 306 | // Make sure there are 2 endpoints available |
196 | // with libusb-win32 we got some null pointers so be robust before looking at endpoints: | |
197 | if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL) { | |
198 | // Nope, we maybe want the next one, let's try to find another | |
199 | continue; | |
200 | } | |
201 | if (dev->config->interface->altsetting->bNumEndpoints < 2) { | |
202 | // Nope, we maybe want the next one, let's try to find another | |
203 | continue; | |
307 | // libusb-win32 may return a NULL dev->config, | |
308 | // or the descriptors may be corrupted, hence | |
309 | // let us assume we will use hardcoded defaults | |
310 | // from pn53x_usb_supported_devices if available. | |
311 | // otherwise get data from the descriptors. | |
312 | if (pn53x_usb_supported_devices[n].uiMaxPacketSize == 0) { | |
313 | if (dev->config->interface == NULL || dev->config->interface->altsetting == NULL) { | |
314 | // Nope, we maybe want the next one, let's try to find another | |
315 | continue; | |
316 | } | |
317 | if (dev->config->interface->altsetting->bNumEndpoints < 2) { | |
318 | // Nope, we maybe want the next one, let's try to find another | |
319 | continue; | |
320 | } | |
204 | 321 | } |
205 | 322 | |
206 | 323 | usb_dev_handle *udev = usb_open(dev); |
219 | 336 | // pn53x_usb_get_usb_device_name (dev, udev, pnddDevices[device_found].acDevice, sizeof (pnddDevices[device_found].acDevice)); |
220 | 337 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "device found: Bus %s Device %s", bus->dirname, dev->filename); |
221 | 338 | usb_close(udev); |
222 | snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename); | |
339 | if (snprintf(connstrings[device_found], sizeof(nfc_connstring), "%s:%s:%s", PN53X_USB_DRIVER_NAME, bus->dirname, dev->filename) >= (int)sizeof(nfc_connstring)) { | |
340 | // truncation occurred, skipping that one | |
341 | continue; | |
342 | } | |
223 | 343 | device_found++; |
224 | 344 | // Test if we reach the maximum "wanted" devices |
225 | 345 | if (device_found == connstrings_len) { |
281 | 401 | .pudh = NULL, |
282 | 402 | .uiEndPointIn = 0, |
283 | 403 | .uiEndPointOut = 0, |
404 | .possibly_corrupted_usbdesc = false, | |
284 | 405 | }; |
285 | 406 | struct usb_bus *bus; |
286 | 407 | struct usb_device *dev; |
302 | 423 | // Open the USB device |
303 | 424 | if ((data.pudh = usb_open(dev)) == NULL) |
304 | 425 | continue; |
305 | // Retrieve end points | |
306 | pn53x_usb_get_end_points(dev, &data); | |
426 | ||
427 | //To retrieve real USB endpoints configuration: | |
428 | //pn53x_usb_get_end_points(dev, &data); | |
429 | //printf("DEBUG ENDPOINTS In:0x%x Out:0x%x Size:0x%x\n", data.uiEndPointIn, data.uiEndPointOut, data.uiMaxPacketSize); | |
430 | ||
431 | // Retrieve end points, using hardcoded defaults if available | |
432 | // or using the descriptors otherwise. | |
433 | if (pn53x_usb_get_end_points_default(dev, &data) == false) { | |
434 | pn53x_usb_get_end_points(dev, &data); | |
435 | } | |
307 | 436 | // Set configuration |
308 | 437 | int res = usb_set_configuration(data.pudh, 1); |
309 | 438 | if (res < 0) { |
346 | 475 | } |
347 | 476 | |
348 | 477 | switch (DRIVER_DATA(pnd)->model) { |
349 | // empirical tuning | |
478 | // empirical tuning | |
350 | 479 | case ASK_LOGO: |
351 | 480 | CHIP_DATA(pnd)->timer_correction = 50; |
481 | CHIP_DATA(pnd)->progressive_field = true; | |
352 | 482 | break; |
353 | 483 | case SCM_SCL3711: |
484 | case SCM_SCL3712: | |
354 | 485 | case NXP_PN533: |
355 | 486 | CHIP_DATA(pnd)->timer_correction = 46; |
356 | 487 | break; |
404 | 535 | pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P32) | _BV(P33) | _BV(P35)); |
405 | 536 | } |
406 | 537 | |
538 | if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) | |
539 | pn533_fix_usbdesc(pnd); | |
540 | ||
407 | 541 | pn53x_idle(pnd); |
408 | 542 | |
409 | 543 | int res; |
432 | 566 | return pnd->last_error; |
433 | 567 | } |
434 | 568 | |
569 | DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= szData > 17; | |
435 | 570 | if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), abtFrame, szFrame, timeout)) < 0) { |
436 | 571 | pnd->last_error = res; |
437 | 572 | return pnd->last_error; |
451 | 586 | // For some reasons (eg. send another command while a previous one is |
452 | 587 | // running), the PN533 sometimes directly replies the response packet |
453 | 588 | // instead of ACK frame, so we send a NACK frame to force PN533 to resend |
454 | // response packet. With this hack, the nextly executed function (ie. | |
455 | // pn53x_usb_receive()) will be able to retreive the correct response | |
589 | // response packet. With this hack, the next executed function (ie. | |
590 | // pn53x_usb_receive()) will be able to retrieve the correct response | |
456 | 591 | // packet. |
457 | 592 | // FIXME Sony reader is also affected by this bug but NACK is not supported |
458 | 593 | if ((res = pn53x_usb_bulk_write(DRIVER_DATA(pnd), (uint8_t *)pn53x_nack_frame, sizeof(pn53x_nack_frame), timeout)) < 0) { |
462 | 597 | return pnd->last_error; |
463 | 598 | } |
464 | 599 | } |
465 | ||
466 | 600 | return NFC_SUCCESS; |
467 | 601 | } |
468 | 602 | |
600 | 734 | } |
601 | 735 | // The PN53x command is done and we successfully received the reply |
602 | 736 | pnd->last_error = 0; |
737 | DRIVER_DATA(pnd)->possibly_corrupted_usbdesc |= len > 16; | |
603 | 738 | return len; |
604 | 739 | } |
605 | 740 | |
663 | 798 | /* ie. Switch LED1 on and turn off progressive field */ |
664 | 799 | pn53x_write_register(pnd, PN53X_SFR_P3, 0xFF, _BV(P30) | _BV(P31) | _BV(P33) | _BV(P35)); |
665 | 800 | } |
801 | if (DRIVER_DATA(pnd)->possibly_corrupted_usbdesc) | |
802 | pn533_fix_usbdesc(pnd); | |
666 | 803 | |
667 | 804 | return NFC_SUCCESS; |
668 | 805 | } |
684 | 821 | } |
685 | 822 | break; |
686 | 823 | case SCM_SCL3711: |
824 | if (NP_ACTIVATE_FIELD == property) { | |
825 | // Switch on/off LED according to ACTIVATE_FIELD option | |
826 | if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0) | |
827 | return res; | |
828 | } | |
829 | break; | |
830 | case SCM_SCL3712: | |
687 | 831 | if (NP_ACTIVATE_FIELD == property) { |
688 | 832 | // Switch on/off LED according to ACTIVATE_FIELD option |
689 | 833 | if ((res = pn53x_write_register(pnd, PN53X_SFR_P3, _BV(P32), bEnable ? 0 : _BV(P32))) < 0) |
705 | 849 | pn53x_usb_abort_command(nfc_device *pnd) |
706 | 850 | { |
707 | 851 | DRIVER_DATA(pnd)->abort_flag = true; |
852 | return NFC_SUCCESS; | |
853 | } | |
854 | ||
855 | static int | |
856 | pn53x_usb_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) | |
857 | { | |
858 | if ((DRIVER_DATA(pnd)->model != ASK_LOGO) || (mode != N_TARGET)) | |
859 | return pn53x_get_supported_modulation(pnd, mode, supported_mt); | |
860 | else // ASK_LOGO has no N_TARGET support | |
861 | *supported_mt = no_target_support; | |
708 | 862 | return NFC_SUCCESS; |
709 | 863 | } |
710 | 864 | |
741 | 895 | |
742 | 896 | .device_set_property_bool = pn53x_usb_set_property_bool, |
743 | 897 | .device_set_property_int = pn53x_set_property_int, |
744 | .get_supported_modulation = pn53x_get_supported_modulation, | |
898 | .get_supported_modulation = pn53x_usb_get_supported_modulation, | |
745 | 899 | .get_supported_baud_rate = pn53x_get_supported_baud_rate, |
746 | 900 | .device_get_information_about = pn53x_get_information_about, |
747 | 901 |
0 | ||
1 | /** | |
2 | * @file pn71xx.h | |
3 | * @brief Driver for PN71XX using libnfc-nci library | |
4 | */ | |
5 | ||
6 | #ifdef HAVE_CONFIG_H | |
7 | # include "config.h" | |
8 | #endif // HAVE_CONFIG_H | |
9 | ||
10 | #include "pn71xx.h" | |
11 | ||
12 | #include <stdio.h> | |
13 | #include <inttypes.h> | |
14 | #include <string.h> | |
15 | #include <unistd.h> | |
16 | #include <stdlib.h> | |
17 | #include <time.h> | |
18 | ||
19 | #include <nfc/nfc.h> | |
20 | ||
21 | #include "drivers.h" | |
22 | #include "nfc-internal.h" | |
23 | ||
24 | #include "linux_nfc_api.h" | |
25 | ||
26 | #define PN71XX_DRIVER_NAME "pn71xx" | |
27 | ||
28 | #define LOG_CATEGORY "libnfc.driver.pn71xx" | |
29 | #define LOG_GROUP NFC_LOG_GROUP_DRIVER | |
30 | ||
31 | 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}; | |
32 | 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}; | |
33 | ||
34 | const nfc_baud_rate pn71xx_iso14443a_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; | |
35 | const nfc_baud_rate pn71xx_felica_supported_baud_rates[] = { NBR_424, NBR_212, 0 }; | |
36 | const nfc_baud_rate pn71xx_dep_supported_baud_rates[] = { NBR_424, NBR_212, NBR_106, 0 }; | |
37 | const nfc_baud_rate pn71xx_jewel_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; | |
38 | const nfc_baud_rate pn71xx_iso14443b_supported_baud_rates[] = { NBR_847, NBR_424, NBR_212, NBR_106, 0 }; | |
39 | ||
40 | static nfcTagCallback_t TagCB; | |
41 | static nfc_tag_info_t *TagInfo = NULL; | |
42 | ||
43 | static void onTagArrival(nfc_tag_info_t *pTagInfo); | |
44 | static void onTagDeparture(void); | |
45 | ||
46 | /** ------------------------------------------------------------------------ */ | |
47 | /** ------------------------------------------------------------------------ */ | |
48 | /** | |
49 | * @brief Initialize libnfc_nci library to verify presence of PN71xx device. | |
50 | * | |
51 | * @param context NFC context. | |
52 | * @param connstrings array of 'nfc_connstring' buffer (allocated by caller). It is used to store the | |
53 | * connection info strings of devices found. | |
54 | * @param connstrings_len length of the connstrings array. | |
55 | * @return number of devices found. | |
56 | */ | |
57 | static size_t | |
58 | pn71xx_scan(const nfc_context *context, nfc_connstring connstrings[], const size_t connstrings_len) | |
59 | { | |
60 | size_t device_found = 0; | |
61 | ||
62 | if ((context == NULL) || (connstrings_len == 0)) return 0; | |
63 | ||
64 | if (nfcManager_doInitialize() == 0) { | |
65 | nfc_connstring connstring = "pn71xx"; | |
66 | memcpy(connstrings[device_found++], connstring, sizeof(nfc_connstring)); | |
67 | } | |
68 | ||
69 | return device_found; | |
70 | } | |
71 | ||
72 | /** | |
73 | * @brief Close connection to PN71xx by stopping the discovery loop and deinitializing the libnfc_nci library. | |
74 | * | |
75 | * @param pnd pointer on the device to close. | |
76 | */ | |
77 | static void | |
78 | pn71xx_close(nfc_device *pnd) | |
79 | { | |
80 | nfcManager_disableDiscovery(); | |
81 | nfcManager_deregisterTagCallback(); | |
82 | nfcManager_doDeinitialize(); | |
83 | nfc_device_free(pnd); | |
84 | pnd = NULL; | |
85 | } | |
86 | ||
87 | /** | |
88 | * @brief Open a connection to PN71xx, starting the discovery loop for tag detection. | |
89 | * | |
90 | * @param context NFC context. | |
91 | * @param connstring connection info to the device | |
92 | * @return pointer to the device, or NULL in case of error. | |
93 | */ | |
94 | static nfc_device * | |
95 | pn71xx_open(const nfc_context *context, const nfc_connstring connstring) | |
96 | { | |
97 | nfc_device *pnd; | |
98 | ||
99 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "open: %s", connstring); | |
100 | ||
101 | pnd = nfc_device_new(context, connstring); | |
102 | if (!pnd) { | |
103 | perror("malloc"); | |
104 | return NULL; | |
105 | } | |
106 | ||
107 | pnd->driver = &pn71xx_driver; | |
108 | strcpy(pnd->name, "pn71xx-device"); | |
109 | strcpy(pnd->connstring, connstring); | |
110 | ||
111 | TagCB.onTagArrival = onTagArrival; | |
112 | TagCB.onTagDeparture = onTagDeparture; | |
113 | nfcManager_registerTagCallback(&TagCB); | |
114 | ||
115 | nfcManager_enableDiscovery(DEFAULT_NFA_TECH_MASK, 1, 0, 0); | |
116 | ||
117 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "wait 1 seconds for polling"); | |
118 | sleep(1); | |
119 | ||
120 | return pnd; | |
121 | } | |
122 | ||
123 | /** ------------------------------------------------------------------------ */ | |
124 | /** ------------------------------------------------------------------------ */ | |
125 | static bool IsTechnology(nfc_tag_info_t *TagInfo, nfc_modulation_type nmt) | |
126 | { | |
127 | switch (nmt) { | |
128 | case NMT_ISO14443A: | |
129 | if (TagInfo->technology == TARGET_TYPE_ISO14443_4 | |
130 | || TagInfo->technology == TARGET_TYPE_ISO14443_3A | |
131 | || TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC | |
132 | || TagInfo->technology == TARGET_TYPE_MIFARE_UL) | |
133 | return true; | |
134 | break; | |
135 | ||
136 | case NMT_ISO14443B: | |
137 | case NMT_ISO14443BI: | |
138 | case NMT_ISO14443B2SR: | |
139 | case NMT_ISO14443B2CT: | |
140 | if (TagInfo->technology == TARGET_TYPE_ISO14443_3B) | |
141 | return true; | |
142 | break; | |
143 | ||
144 | case NMT_FELICA: | |
145 | if (TagInfo->technology == TARGET_TYPE_FELICA) | |
146 | return true; | |
147 | break; | |
148 | ||
149 | case NMT_JEWEL: | |
150 | if (TagInfo->technology == TARGET_TYPE_ISO14443_3A | |
151 | && TagInfo->protocol == NFA_PROTOCOL_T1T) | |
152 | return true; | |
153 | break; | |
154 | ||
155 | default: | |
156 | return false; | |
157 | } | |
158 | return false; | |
159 | } | |
160 | ||
161 | static void BufferPrintBytes(char *buffer, unsigned int buflen, const uint8_t *data, unsigned int datalen) | |
162 | { | |
163 | int cx = 0; | |
164 | for (unsigned int i = 0x00; i < datalen; i++) { | |
165 | cx += snprintf(buffer + cx, buflen - cx, "%02X ", data[i]); | |
166 | } | |
167 | } | |
168 | ||
169 | static void PrintTagInfo(nfc_tag_info_t *TagInfo) | |
170 | { | |
171 | switch (TagInfo->technology) { | |
172 | case TARGET_TYPE_UNKNOWN: { | |
173 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Unknown'"); | |
174 | } | |
175 | break; | |
176 | case TARGET_TYPE_ISO14443_3A: { | |
177 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3A'"); | |
178 | } | |
179 | break; | |
180 | case TARGET_TYPE_ISO14443_3B: { | |
181 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 3B'"); | |
182 | } | |
183 | break; | |
184 | case TARGET_TYPE_ISO14443_4: { | |
185 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type 4A'"); | |
186 | } | |
187 | break; | |
188 | case TARGET_TYPE_FELICA: { | |
189 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type F'"); | |
190 | } | |
191 | break; | |
192 | case TARGET_TYPE_ISO15693: { | |
193 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type V'"); | |
194 | } | |
195 | break; | |
196 | case TARGET_TYPE_NDEF: { | |
197 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type NDEF'"); | |
198 | } | |
199 | break; | |
200 | case TARGET_TYPE_NDEF_FORMATABLE: { | |
201 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type Formatable'"); | |
202 | } | |
203 | break; | |
204 | case TARGET_TYPE_MIFARE_CLASSIC: { | |
205 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Classic'"); | |
206 | } | |
207 | break; | |
208 | case TARGET_TYPE_MIFARE_UL: { | |
209 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Mifare Ul'"); | |
210 | } | |
211 | break; | |
212 | case TARGET_TYPE_KOVIO_BARCODE: { | |
213 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A - Kovio Barcode'"); | |
214 | } | |
215 | break; | |
216 | case TARGET_TYPE_ISO14443_3A_3B: { | |
217 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type A/B'"); | |
218 | } | |
219 | break; | |
220 | default: { | |
221 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "'Type %d (Unknown or not supported)'\n", TagInfo->technology); | |
222 | } | |
223 | break; | |
224 | } | |
225 | /*32 is max UID len (Kovio tags)*/ | |
226 | if ((0x00 != TagInfo->uid_length) && (32 >= TagInfo->uid_length)) { | |
227 | char buffer [100]; | |
228 | int cx = 0; | |
229 | ||
230 | if (4 == TagInfo->uid_length || 7 == TagInfo->uid_length || 10 == TagInfo->uid_length) { | |
231 | cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID1 : \t'"); | |
232 | } else if (8 == TagInfo->uid_length) { | |
233 | cx += snprintf(buffer + cx, sizeof(buffer) - cx, "NFCID2 : \t'"); | |
234 | } else { | |
235 | cx += snprintf(buffer + cx, sizeof(buffer) - cx, "UID : \t'"); | |
236 | } | |
237 | ||
238 | BufferPrintBytes(buffer + cx, sizeof(buffer) - cx, (unsigned char *) TagInfo->uid, TagInfo->uid_length); | |
239 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "%s'", buffer); | |
240 | } | |
241 | } | |
242 | ||
243 | /** ------------------------------------------------------------------------ */ | |
244 | /** ------------------------------------------------------------------------ */ | |
245 | ||
246 | static void onTagArrival(nfc_tag_info_t *pTagInfo) | |
247 | { | |
248 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag found"); | |
249 | ||
250 | TagInfo = malloc(sizeof(nfc_tag_info_t)); | |
251 | memcpy(TagInfo, pTagInfo, sizeof(nfc_tag_info_t)); | |
252 | ||
253 | PrintTagInfo(TagInfo); | |
254 | } | |
255 | ||
256 | static void onTagDeparture(void) | |
257 | { | |
258 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "tag lost"); | |
259 | ||
260 | free(TagInfo); | |
261 | TagInfo = NULL; | |
262 | } | |
263 | ||
264 | static int | |
265 | pn71xx_initiator_init(struct nfc_device *pnd) | |
266 | { | |
267 | if (pnd == NULL) return NFC_EIO; | |
268 | return NFC_SUCCESS; | |
269 | } | |
270 | ||
271 | static int | |
272 | pn71xx_initiator_select_passive_target(struct nfc_device *pnd, | |
273 | const nfc_modulation nm, | |
274 | const uint8_t *pbtInitData, const size_t szInitData, | |
275 | nfc_target *pnt) | |
276 | { | |
277 | if (pnd == NULL) return NFC_EIO; | |
278 | ||
279 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "select_passive_target"); | |
280 | ||
281 | if (TagInfo) { | |
282 | ||
283 | nfc_target nttmp; | |
284 | memset(&nttmp, 0x00, sizeof(nfc_target)); | |
285 | nttmp.nm = nm; | |
286 | ||
287 | void *uidPtr = NULL; | |
288 | unsigned int maxLen = 0; | |
289 | ||
290 | switch (nm.nmt) { | |
291 | case NMT_ISO14443A: | |
292 | if (IsTechnology(TagInfo, nm.nmt)) { | |
293 | maxLen = 10; | |
294 | uidPtr = nttmp.nti.nai.abtUid; | |
295 | ||
296 | if (TagInfo->technology == TARGET_TYPE_MIFARE_CLASSIC) { | |
297 | nttmp.nti.nai.btSak = 0x08; | |
298 | } else { | |
299 | // make hardcoded desfire for freefare lib check | |
300 | nttmp.nti.nai.btSak = 0x20; | |
301 | nttmp.nti.nai.szAtsLen = 5; | |
302 | memcpy(nttmp.nti.nai.abtAts, "\x75\x77\x81\x02", 4); | |
303 | } | |
304 | } | |
305 | break; | |
306 | ||
307 | case NMT_ISO14443B: | |
308 | if (IsTechnology(TagInfo, nm.nmt)) { | |
309 | maxLen = 4; | |
310 | uidPtr = nttmp.nti.nbi.abtPupi; | |
311 | } | |
312 | break; | |
313 | ||
314 | case NMT_ISO14443BI: | |
315 | if (IsTechnology(TagInfo, nm.nmt)) { | |
316 | maxLen = 4; | |
317 | uidPtr = nttmp.nti.nii.abtDIV; | |
318 | } | |
319 | break; | |
320 | ||
321 | case NMT_ISO14443B2SR: | |
322 | if (IsTechnology(TagInfo, nm.nmt)) { | |
323 | maxLen = 8; | |
324 | uidPtr = nttmp.nti.nsi.abtUID; | |
325 | } | |
326 | break; | |
327 | ||
328 | case NMT_ISO14443B2CT: | |
329 | if (IsTechnology(TagInfo, nm.nmt)) { | |
330 | maxLen = 4; | |
331 | uidPtr = nttmp.nti.nci.abtUID; | |
332 | } | |
333 | break; | |
334 | ||
335 | case NMT_FELICA: | |
336 | if (IsTechnology(TagInfo, nm.nmt)) { | |
337 | maxLen = 8; | |
338 | uidPtr = nttmp.nti.nfi.abtId; | |
339 | } | |
340 | break; | |
341 | ||
342 | case NMT_JEWEL: | |
343 | if (IsTechnology(TagInfo, nm.nmt)) { | |
344 | maxLen = 4; | |
345 | uidPtr = nttmp.nti.nji.btId; | |
346 | } | |
347 | break; | |
348 | ||
349 | default: | |
350 | return 0; | |
351 | } | |
352 | ||
353 | if (uidPtr && TagInfo->uid_length) { | |
354 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "target found"); | |
355 | int len = TagInfo->uid_length > maxLen ? maxLen : TagInfo->uid_length; | |
356 | memcpy(uidPtr, TagInfo->uid, len); | |
357 | if (nm.nmt == NMT_ISO14443A) | |
358 | nttmp.nti.nai.szUidLen = len; | |
359 | ||
360 | // Is a tag info struct available | |
361 | if (pnt) { | |
362 | memcpy(pnt, &nttmp, sizeof(nfc_target)); | |
363 | } | |
364 | return 1; | |
365 | } | |
366 | } | |
367 | ||
368 | return 0; | |
369 | } | |
370 | ||
371 | static int | |
372 | pn71xx_initiator_deselect_target(struct nfc_device *pnd) | |
373 | { | |
374 | if (pnd == NULL) return NFC_EIO; | |
375 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "deselect_passive_target"); | |
376 | return NFC_SUCCESS; | |
377 | } | |
378 | ||
379 | ||
380 | static int | |
381 | pn71xx_initiator_transceive_bytes(struct nfc_device *pnd, const uint8_t *pbtTx, const size_t szTx, uint8_t *pbtRx, | |
382 | const size_t szRx, int timeout) | |
383 | { | |
384 | if (pnd == NULL) return NFC_EIO; | |
385 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "transceive_bytes timeout=%d", timeout); | |
386 | ||
387 | if (!TagInfo) return NFC_EINVARG; | |
388 | ||
389 | char buffer[500]; | |
390 | BufferPrintBytes(buffer, sizeof(buffer), pbtTx, szTx); | |
391 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "===> %s", buffer); | |
392 | ||
393 | int received = nfcTag_transceive(TagInfo->handle, (uint8_t *) pbtTx, szTx, pbtRx, szRx, 500); | |
394 | if (received <= 0) | |
395 | return NFC_EIO; | |
396 | ||
397 | BufferPrintBytes(buffer, sizeof(buffer), pbtRx, received); | |
398 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "<=== %s", buffer); | |
399 | ||
400 | return received; | |
401 | } | |
402 | ||
403 | static int | |
404 | pn71xx_initiator_poll_target(struct nfc_device *pnd, | |
405 | const nfc_modulation *pnmModulations, const size_t szModulations, | |
406 | const uint8_t uiPollNr, const uint8_t uiPeriod, | |
407 | nfc_target *pnt) | |
408 | { | |
409 | static int periodFactor = 150000; | |
410 | int period = uiPeriod * periodFactor; | |
411 | ||
412 | if (pnd == NULL) return 0; | |
413 | ||
414 | for (int j = 0; j < uiPollNr; j++) { | |
415 | for (unsigned int i = 0; i < szModulations; i++) { | |
416 | const nfc_modulation nm = pnmModulations[i]; | |
417 | ||
418 | nfc_target nt; | |
419 | int res = pn71xx_initiator_select_passive_target(pnd, nm, 0, 0, &nt); | |
420 | if (res > 0 && pnt) { | |
421 | memcpy(pnt, &nt, sizeof(nfc_target)); | |
422 | return res; | |
423 | } | |
424 | } | |
425 | usleep(period); | |
426 | } | |
427 | ||
428 | return 0; | |
429 | } | |
430 | ||
431 | static int | |
432 | pn71xx_initiator_target_is_present(struct nfc_device *pnd, const nfc_target *pnt) | |
433 | { | |
434 | if ((pnd == NULL) || (pnt == NULL)) return 1; | |
435 | return !TagInfo; | |
436 | } | |
437 | ||
438 | ||
439 | /** ------------------------------------------------------------------------ */ | |
440 | /** ------------------------------------------------------------------------ */ | |
441 | static int | |
442 | pn71xx_get_supported_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt) | |
443 | { | |
444 | if (pnd == NULL) return NFC_EIO; | |
445 | ||
446 | switch (mode) { | |
447 | case N_TARGET: | |
448 | *supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_target; | |
449 | break; | |
450 | case N_INITIATOR: | |
451 | *supported_mt = (nfc_modulation_type *)pn71xx_supported_modulation_as_initiator; | |
452 | break; | |
453 | default: | |
454 | return NFC_EINVARG; | |
455 | } | |
456 | return NFC_SUCCESS; | |
457 | } | |
458 | ||
459 | static int | |
460 | pn71xx_get_supported_baud_rate(nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) | |
461 | { | |
462 | if (pnd == NULL) return NFC_EIO; | |
463 | if (mode) {} | |
464 | ||
465 | switch (nmt) { | |
466 | case NMT_FELICA: | |
467 | *supported_br = (nfc_baud_rate *)pn71xx_felica_supported_baud_rates; | |
468 | break; | |
469 | case NMT_ISO14443A: | |
470 | *supported_br = (nfc_baud_rate *)pn71xx_iso14443a_supported_baud_rates; | |
471 | break; | |
472 | case NMT_ISO14443B: | |
473 | case NMT_ISO14443BI: | |
474 | case NMT_ISO14443B2SR: | |
475 | case NMT_ISO14443B2CT: | |
476 | *supported_br = (nfc_baud_rate *)pn71xx_iso14443b_supported_baud_rates; | |
477 | break; | |
478 | case NMT_JEWEL: | |
479 | *supported_br = (nfc_baud_rate *)pn71xx_jewel_supported_baud_rates; | |
480 | break; | |
481 | case NMT_DEP: | |
482 | *supported_br = (nfc_baud_rate *)pn71xx_dep_supported_baud_rates; | |
483 | break; | |
484 | default: | |
485 | return NFC_EINVARG; | |
486 | } | |
487 | return NFC_SUCCESS; | |
488 | } | |
489 | ||
490 | /** ------------------------------------------------------------------------ */ | |
491 | /** ------------------------------------------------------------------------ */ | |
492 | ||
493 | static int | |
494 | pn71xx_set_property_bool(struct nfc_device *pnd, const nfc_property property, const bool bEnable) | |
495 | { | |
496 | if (pnd == NULL) return NFC_EIO; | |
497 | return NFC_SUCCESS; | |
498 | } | |
499 | ||
500 | static int | |
501 | pn71xx_set_property_int(struct nfc_device *pnd, const nfc_property property, const int value) | |
502 | { | |
503 | if (pnd == NULL) return NFC_EIO; | |
504 | return NFC_SUCCESS; | |
505 | } | |
506 | ||
507 | static int | |
508 | pn71xx_get_information_about(nfc_device *pnd, char **pbuf) | |
509 | { | |
510 | static const char *info = "PN71XX nfc driver using libnfc-nci userspace library"; | |
511 | size_t buflen = strlen(info) + 1; | |
512 | ||
513 | if (pnd == NULL) return NFC_EIO; | |
514 | ||
515 | *pbuf = malloc(buflen); | |
516 | memcpy(*pbuf, info, buflen); | |
517 | ||
518 | return buflen; | |
519 | } | |
520 | /** | |
521 | * @brief Abort any pending operation | |
522 | * | |
523 | * @param pnd pointer on the NFC device. | |
524 | * @return NFC_SUCCESS | |
525 | */ | |
526 | static int | |
527 | pn71xx_abort_command(nfc_device *pnd) | |
528 | { | |
529 | if (pnd == NULL) return NFC_EIO; | |
530 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "abort_command"); | |
531 | return NFC_SUCCESS; | |
532 | } | |
533 | ||
534 | static int | |
535 | pn71xx_idle(struct nfc_device *pnd) | |
536 | { | |
537 | if (pnd == NULL) return NFC_EIO; | |
538 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "idle"); | |
539 | return NFC_SUCCESS; | |
540 | } | |
541 | ||
542 | static int | |
543 | pn71xx_PowerDown(struct nfc_device *pnd) | |
544 | { | |
545 | if (pnd == NULL) return NFC_EIO; | |
546 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "PowerDown"); | |
547 | return NFC_SUCCESS; | |
548 | } | |
549 | ||
550 | /** ------------------------------------------------------------------------ */ | |
551 | /** ------------------------------------------------------------------------ */ | |
552 | const struct nfc_driver pn71xx_driver = { | |
553 | .name = PN71XX_DRIVER_NAME, | |
554 | .scan_type = NOT_INTRUSIVE, | |
555 | .scan = pn71xx_scan, | |
556 | .open = pn71xx_open, | |
557 | .close = pn71xx_close, | |
558 | .strerror = NULL, | |
559 | ||
560 | .initiator_init = pn71xx_initiator_init, | |
561 | .initiator_init_secure_element = NULL, | |
562 | .initiator_select_passive_target = pn71xx_initiator_select_passive_target, | |
563 | .initiator_poll_target = pn71xx_initiator_poll_target, | |
564 | .initiator_select_dep_target = NULL, | |
565 | .initiator_deselect_target = pn71xx_initiator_deselect_target, | |
566 | .initiator_transceive_bytes = pn71xx_initiator_transceive_bytes, | |
567 | .initiator_transceive_bits = NULL, | |
568 | .initiator_transceive_bytes_timed = NULL, | |
569 | .initiator_transceive_bits_timed = NULL, | |
570 | .initiator_target_is_present = pn71xx_initiator_target_is_present, | |
571 | ||
572 | .target_init = NULL, | |
573 | .target_send_bytes = NULL, | |
574 | .target_receive_bytes = NULL, | |
575 | .target_send_bits = NULL, | |
576 | .target_receive_bits = NULL, | |
577 | ||
578 | .device_set_property_bool = pn71xx_set_property_bool, | |
579 | .device_set_property_int = pn71xx_set_property_int, | |
580 | .get_supported_modulation = pn71xx_get_supported_modulation, | |
581 | .get_supported_baud_rate = pn71xx_get_supported_baud_rate, | |
582 | .device_get_information_about = pn71xx_get_information_about, | |
583 | ||
584 | .abort_command = pn71xx_abort_command, | |
585 | .idle = pn71xx_idle, | |
586 | .powerdown = pn71xx_PowerDown, | |
587 | }; | |
588 |
0 | /** | |
1 | * @file pn71xx.h | |
2 | * @brief Driver for PN71XX using libnfc-nci library | |
3 | */ | |
4 | ||
5 | #ifndef __NFC_DRIVER_PN71XX_H__ | |
6 | #define __NFC_DRIVER_PN71XX_H__ | |
7 | ||
8 | #include <nfc/nfc-types.h> | |
9 | ||
10 | /* Reference to the driver structure */ | |
11 | extern const struct nfc_driver pn71xx_driver; | |
12 | ||
13 | #endif // ! __NFC_DRIVER_7120_H__ |
46 | 46 | void |
47 | 47 | iso14443a_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) |
48 | 48 | { |
49 | uint8_t bt; | |
50 | 49 | uint32_t wCrc = 0x6363; |
51 | 50 | |
52 | 51 | do { |
52 | uint8_t bt; | |
53 | 53 | bt = *pbtData++; |
54 | 54 | bt = (bt ^ (uint8_t)(wCrc & 0x00FF)); |
55 | 55 | bt = (bt ^ (bt << 4)); |
77 | 77 | void |
78 | 78 | iso14443b_crc(uint8_t *pbtData, size_t szLen, uint8_t *pbtCrc) |
79 | 79 | { |
80 | uint8_t bt; | |
81 | 80 | uint32_t wCrc = 0xFFFF; |
82 | 81 | |
83 | 82 | do { |
83 | uint8_t bt; | |
84 | 84 | bt = *pbtData++; |
85 | 85 | bt = (bt ^ (uint8_t)(wCrc & 0x00FF)); |
86 | 86 | bt = (bt ^ (bt << 4)); |
38 | 38 | uint8_t mirror(uint8_t bt); |
39 | 39 | uint32_t mirror32(uint32_t ui32Bits); |
40 | 40 | uint64_t mirror64(uint64_t ui64Bits); |
41 | void mirror_uint8_ts(uint8_t *pbts, size_t szLen); | |
42 | 41 | |
43 | 42 | #endif // _LIBNFC_MIRROR_SUBR_H_ |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * This program is free software: you can redistribute it and/or modify it |
13 | 14 | * under the terms of the GNU Lesser General Public License as published by the |
168 | 169 | prepare_initiator_data(const nfc_modulation nm, uint8_t **ppbtInitiatorData, size_t *pszInitiatorData) |
169 | 170 | { |
170 | 171 | switch (nm.nmt) { |
171 | case NMT_ISO14443B: { | |
172 | case NMT_ISO14443B: | |
172 | 173 | // Application Family Identifier (AFI) must equals 0x00 in order to wakeup all ISO14443-B PICCs (see ISO/IEC 14443-3) |
173 | 174 | *ppbtInitiatorData = (uint8_t *) "\x00"; |
174 | 175 | *pszInitiatorData = 1; |
175 | } | |
176 | break; | |
177 | case NMT_ISO14443BI: { | |
176 | break; | |
177 | case NMT_ISO14443BI: | |
178 | 178 | // APGEN |
179 | 179 | *ppbtInitiatorData = (uint8_t *) "\x01\x0b\x3f\x80"; |
180 | 180 | *pszInitiatorData = 4; |
181 | } | |
182 | break; | |
183 | case NMT_ISO14443B2SR: { | |
184 | // Get_UID | |
185 | *ppbtInitiatorData = (uint8_t *) "\x0b"; | |
186 | *pszInitiatorData = 1; | |
187 | } | |
188 | break; | |
189 | case NMT_ISO14443B2CT: { | |
190 | // SELECT-ALL | |
191 | *ppbtInitiatorData = (uint8_t *) "\x9F\xFF\xFF"; | |
192 | *pszInitiatorData = 3; | |
193 | } | |
194 | break; | |
195 | case NMT_FELICA: { | |
181 | break; | |
182 | case NMT_FELICA: | |
196 | 183 | // polling payload must be present (see ISO/IEC 18092 11.2.2.5) |
197 | 184 | *ppbtInitiatorData = (uint8_t *) "\x00\xff\xff\x01\x00"; |
198 | 185 | *pszInitiatorData = 5; |
199 | } | |
200 | break; | |
186 | break; | |
201 | 187 | case NMT_ISO14443A: |
188 | case NMT_ISO14443B2CT: | |
189 | case NMT_ISO14443B2SR: | |
190 | case NMT_ISO14443BICLASS: | |
202 | 191 | case NMT_JEWEL: |
192 | case NMT_BARCODE: | |
203 | 193 | case NMT_DEP: |
204 | 194 | *ppbtInitiatorData = NULL; |
205 | 195 | *pszInitiatorData = 0; |
241 | 231 | int res = sscanf(connstring, format, param0, param1, param2); |
242 | 232 | |
243 | 233 | if (res < 1 || ((0 != strcmp(param0, driver_name)) && |
244 | (bus_name != NULL) && | |
245 | 234 | (0 != strcmp(param0, bus_name)))) { |
246 | 235 | // Driver name does not match. |
247 | 236 | res = 0; |
147 | 147 | int (*device_set_property_bool)(struct nfc_device *pnd, const nfc_property property, const bool bEnable); |
148 | 148 | int (*device_set_property_int)(struct nfc_device *pnd, const nfc_property property, const int value); |
149 | 149 | int (*get_supported_modulation)(struct nfc_device *pnd, const nfc_mode mode, const nfc_modulation_type **const supported_mt); |
150 | int (*get_supported_baud_rate)(struct nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br); | |
150 | 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); | |
151 | 151 | int (*device_get_information_about)(struct nfc_device *pnd, char **buf); |
152 | 152 | |
153 | 153 | int (*abort_command)(struct nfc_device *pnd); |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * This program is free software: you can redistribute it and/or modify it |
13 | 14 | * under the terms of the GNU Lesser General Public License as published by the |
78 | 79 | #include <stdlib.h> |
79 | 80 | #include <stddef.h> |
80 | 81 | #include <string.h> |
82 | #include <assert.h> | |
81 | 83 | |
82 | 84 | #include <nfc/nfc.h> |
83 | 85 | |
85 | 87 | #include "target-subr.h" |
86 | 88 | #include "drivers.h" |
87 | 89 | |
90 | #if defined (DRIVER_PCSC_ENABLED) | |
91 | # include "drivers/pcsc.h" | |
92 | #endif /* DRIVER_PCSC_ENABLED */ | |
93 | ||
88 | 94 | #if defined (DRIVER_ACR122_PCSC_ENABLED) |
89 | 95 | # include "drivers/acr122_pcsc.h" |
90 | 96 | #endif /* DRIVER_ACR122_PCSC_ENABLED */ |
116 | 122 | #if defined (DRIVER_PN532_I2C_ENABLED) |
117 | 123 | # include "drivers/pn532_i2c.h" |
118 | 124 | #endif /* DRIVER_PN532_I2C_ENABLED */ |
125 | ||
126 | #if defined (DRIVER_PN71XX_ENABLED) | |
127 | # include "drivers/pn71xx.h" | |
128 | #endif /* DRIVER_PN71XX_ENABLED */ | |
119 | 129 | |
120 | 130 | |
121 | 131 | #define LOG_CATEGORY "libnfc.general" |
128 | 138 | |
129 | 139 | const struct nfc_driver_list *nfc_drivers = NULL; |
130 | 140 | |
141 | // descritions for debugging | |
142 | const char *nfc_property_name[] = { | |
143 | "NP_TIMEOUT_COMMAND", | |
144 | "NP_TIMEOUT_ATR", | |
145 | "NP_TIMEOUT_COM", | |
146 | "NP_HANDLE_CRC", | |
147 | "NP_HANDLE_PARITY", | |
148 | "NP_ACTIVATE_FIELD", | |
149 | "NP_ACTIVATE_CRYPTO1", | |
150 | "NP_INFINITE_SELECT", | |
151 | "NP_ACCEPT_INVALID_FRAMES", | |
152 | "NP_ACCEPT_MULTIPLE_FRAMES", | |
153 | "NP_AUTO_ISO14443_4", | |
154 | "NP_EASY_FRAMING", | |
155 | "NP_FORCE_ISO14443_A", | |
156 | "NP_FORCE_ISO14443_B", | |
157 | "NP_FORCE_SPEED_106" | |
158 | }; | |
159 | ||
131 | 160 | static void |
132 | 161 | nfc_drivers_init(void) |
133 | 162 | { |
134 | 163 | #if defined (DRIVER_PN53X_USB_ENABLED) |
135 | 164 | nfc_register_driver(&pn53x_usb_driver); |
136 | 165 | #endif /* DRIVER_PN53X_USB_ENABLED */ |
166 | #if defined (DRIVER_PCSC_ENABLED) | |
167 | nfc_register_driver(&pcsc_driver); | |
168 | #endif /* DRIVER_ACR122_PCSC_ENABLED */ | |
137 | 169 | #if defined (DRIVER_ACR122_PCSC_ENABLED) |
138 | 170 | nfc_register_driver(&acr122_pcsc_driver); |
139 | 171 | #endif /* DRIVER_ACR122_PCSC_ENABLED */ |
155 | 187 | #if defined (DRIVER_ARYGON_ENABLED) |
156 | 188 | nfc_register_driver(&arygon_driver); |
157 | 189 | #endif /* DRIVER_ARYGON_ENABLED */ |
158 | } | |
159 | ||
190 | #if defined (DRIVER_PN71XX_ENABLED) | |
191 | nfc_register_driver(&pn71xx_driver); | |
192 | #endif /* DRIVER_PN71XX_ENABLED */ | |
193 | } | |
194 | ||
195 | static int | |
196 | nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation *nm); | |
160 | 197 | |
161 | 198 | /** @ingroup lib |
162 | 199 | * @brief Register an NFC device driver with libnfc. |
168 | 205 | int |
169 | 206 | nfc_register_driver(const struct nfc_driver *ndr) |
170 | 207 | { |
171 | if (!ndr) | |
208 | if (!ndr) { | |
209 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_register_driver returning NFC_EINVARG"); | |
172 | 210 | return NFC_EINVARG; |
211 | } | |
173 | 212 | |
174 | 213 | struct nfc_driver_list *pndl = (struct nfc_driver_list *)malloc(sizeof(struct nfc_driver_list)); |
175 | 214 | if (!pndl) |
273 | 312 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "Unable to open \"%s\".", ncs); |
274 | 313 | return NULL; |
275 | 314 | } |
276 | for (uint32_t i = 0; i > context->user_defined_device_count; i++) { | |
315 | for (uint32_t i = 0; i < context->user_defined_device_count; i++) { | |
277 | 316 | if (strcmp(ncs, context->user_defined_devices[i].connstring) == 0) { |
278 | 317 | // This is a device sets by user, we use the device name given by user |
279 | 318 | strcpy(pnd->name, context->user_defined_devices[i].name); |
385 | 424 | pndl = pndl->next; |
386 | 425 | } |
387 | 426 | } else if (context->user_defined_device_count == 0) { |
388 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: %s" , "user must specify device(s) manually when autoscan is disabled"); | |
427 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_INFO, "Warning: %s", "user must specify device(s) manually when autoscan is disabled"); | |
389 | 428 | } |
390 | 429 | |
391 | 430 | return device_found; |
405 | 444 | int |
406 | 445 | nfc_device_set_property_int(nfc_device *pnd, const nfc_property property, const int value) |
407 | 446 | { |
447 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_int %s %s", nfc_property_name[property], value ? "True" : "False"); | |
408 | 448 | HAL(device_set_property_int, pnd, property, value); |
409 | 449 | } |
410 | 450 | |
424 | 464 | int |
425 | 465 | nfc_device_set_property_bool(nfc_device *pnd, const nfc_property property, const bool bEnable) |
426 | 466 | { |
467 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "set_property_bool %s %s", nfc_property_name[property], bEnable ? "True" : "False"); | |
427 | 468 | HAL(device_set_property_bool, pnd, property, bEnable); |
428 | 469 | } |
429 | 470 | |
479 | 520 | } |
480 | 521 | |
481 | 522 | /** @ingroup initiator |
482 | * @brief Initialize NFC device as initiator with its secure element initiator (reader) | |
523 | * @brief Initialize NFC device as initiator with its secure element as target (reader) | |
483 | 524 | * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) |
484 | 525 | * @param pnd \a nfc_device struct pointer that represent currently used device |
485 | 526 | * |
486 | 527 | * The NFC device is configured to function as secure element reader. |
487 | 528 | * After initialization it can be used to communicate with the secure element. |
488 | * @note RF field is desactvated in order to some power | |
529 | * @note RF field is deactivated in order to save some power | |
489 | 530 | */ |
490 | 531 | int |
491 | 532 | nfc_initiator_init_secure_element(nfc_device *pnd) |
525 | 566 | uint8_t *abtInit = NULL; |
526 | 567 | uint8_t abtTmpInit[MAX(12, szInitData)]; |
527 | 568 | size_t szInit = 0; |
569 | int res; | |
570 | if ((res = nfc_device_validate_modulation(pnd, N_INITIATOR, &nm)) != NFC_SUCCESS) | |
571 | return res; | |
528 | 572 | if (szInitData == 0) { |
529 | 573 | // Provide default values, if any |
530 | 574 | prepare_initiator_data(nm, &abtInit, &szInit); |
595 | 639 | break; |
596 | 640 | } |
597 | 641 | nfc_initiator_deselect_target(pnd); |
598 | // deselect has no effect on FeliCa and Jewel cards so we'll stop after one... | |
642 | // deselect has no effect on FeliCa, Jewel and Thinfilm cards so we'll stop after one... | |
599 | 643 | // ISO/IEC 14443 B' cards are polled at 100% probability so it's not possible to detect correctly two cards at the same time |
600 | if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) { | |
644 | if ((nm.nmt == NMT_FELICA) || (nm.nmt == NMT_JEWEL) || (nm.nmt == NMT_BARCODE) || | |
645 | (nm.nmt == NMT_ISO14443BI) || (nm.nmt == NMT_ISO14443B2SR) || (nm.nmt == NMT_ISO14443B2CT)) { | |
601 | 646 | break; |
602 | 647 | } |
603 | 648 | } |
639 | 684 | * @param pnd \a nfc_device struct pointer that represent currently used device |
640 | 685 | * @param ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode) |
641 | 686 | * @param nbr desired baud rate |
642 | * @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) | |
687 | * @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) | |
643 | 688 | * @param[out] pnt is a \a nfc_target struct pointer where target information will be put. |
644 | 689 | * @param timeout in milliseconds |
645 | 690 | * |
667 | 712 | * @param pnd \a nfc_device struct pointer that represent currently used device |
668 | 713 | * @param ndm desired D.E.P. mode (\a NDM_ACTIVE or \a NDM_PASSIVE for active, respectively passive mode) |
669 | 714 | * @param nbr desired baud rate |
670 | * @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) | |
715 | * @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) | |
671 | 716 | * @param[out] pnt is a \a nfc_target struct pointer where target information will be put. |
672 | 717 | * @param timeout in milliseconds |
673 | 718 | * |
966 | 1011 | * @param pnd \a nfc_device struct pointer that represent currently used device |
967 | 1012 | * |
968 | 1013 | * This function switch the device in idle mode. |
969 | * In initiator mode, the RF field is turned off and the device is set to low power mode (if avaible); | |
1014 | * In initiator mode, the RF field is turned off and the device is set to low power mode (if available); | |
970 | 1015 | * In target mode, the emulation is stoped (no target available from external initiator) and the device is set to low power mode (if avaible). |
971 | 1016 | */ |
972 | 1017 | int |
1192 | 1237 | } |
1193 | 1238 | |
1194 | 1239 | /** @ingroup data |
1195 | * @brief Get supported baud rates. | |
1240 | * @brief Get supported baud rates (initiator mode). | |
1196 | 1241 | * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) |
1197 | 1242 | * @param pnd \a nfc_device struct pointer that represent currently used device |
1198 | 1243 | * @param nmt \a nfc_modulation_type. |
1202 | 1247 | int |
1203 | 1248 | nfc_device_get_supported_baud_rate(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) |
1204 | 1249 | { |
1205 | HAL(get_supported_baud_rate, pnd, nmt, supported_br); | |
1250 | HAL(get_supported_baud_rate, pnd, N_INITIATOR, nmt, supported_br); | |
1251 | } | |
1252 | ||
1253 | /** @ingroup data | |
1254 | * @brief Get supported baud rates for target mode. | |
1255 | * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) | |
1256 | * @param pnd \a nfc_device struct pointer that represent currently used device | |
1257 | * @param nmt \a nfc_modulation_type. | |
1258 | * @param supported_br pointer of \a nfc_baud_rate array. | |
1259 | * | |
1260 | */ | |
1261 | int | |
1262 | nfc_device_get_supported_baud_rate_target_mode(nfc_device *pnd, const nfc_modulation_type nmt, const nfc_baud_rate **const supported_br) | |
1263 | { | |
1264 | HAL(get_supported_baud_rate, pnd, N_TARGET, nmt, supported_br); | |
1265 | } | |
1266 | ||
1267 | /** @ingroup data | |
1268 | * @brief Validate combination of modulation and baud rate on the currently used device. | |
1269 | * @return Returns 0 on success, otherwise returns libnfc's error code (negative value) | |
1270 | * @param pnd \a nfc_device struct pointer that represent currently used device | |
1271 | * @param mode \a nfc_mode. | |
1272 | * @param nm \a nfc_modulation. | |
1273 | * | |
1274 | */ | |
1275 | static int | |
1276 | nfc_device_validate_modulation(nfc_device *pnd, const nfc_mode mode, const nfc_modulation *nm) | |
1277 | { | |
1278 | int res; | |
1279 | const nfc_modulation_type *nmt = NULL; | |
1280 | if ((res = nfc_device_get_supported_modulation(pnd, mode, &nmt)) < 0) { | |
1281 | return res; | |
1282 | } | |
1283 | assert(nmt != NULL); | |
1284 | for (int i = 0; nmt[i]; i++) { | |
1285 | if (nmt[i] == nm->nmt) { | |
1286 | const nfc_baud_rate *nbr = NULL; | |
1287 | if (mode == N_INITIATOR) { | |
1288 | if ((res = nfc_device_get_supported_baud_rate(pnd, nmt[i], &nbr)) < 0) { | |
1289 | return res; | |
1290 | } | |
1291 | } else { | |
1292 | if ((res = nfc_device_get_supported_baud_rate_target_mode(pnd, nmt[i], &nbr)) < 0) { | |
1293 | return res; | |
1294 | } | |
1295 | } | |
1296 | assert(nbr != NULL); | |
1297 | for (int j = 0; nbr[j]; j++) { | |
1298 | if (nbr[j] == nm->nbr) | |
1299 | return NFC_SUCCESS; | |
1300 | } | |
1301 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG"); | |
1302 | return NFC_EINVARG; | |
1303 | } | |
1304 | } | |
1305 | log_put(LOG_GROUP, LOG_CATEGORY, NFC_LOG_PRIORITY_DEBUG, "nfc_device_validate_modulation returning NFC_EINVARG"); | |
1306 | return NFC_EINVARG; | |
1206 | 1307 | } |
1207 | 1308 | |
1208 | 1309 | /* Misc. functions */ |
1251 | 1352 | /** @ingroup string-converter |
1252 | 1353 | * @brief Convert \a nfc_baud_rate value to string |
1253 | 1354 | * @return Returns nfc baud rate |
1254 | * @param \a nfc_baud_rate to convert | |
1355 | * @param nbr \a nfc_baud_rate to convert | |
1255 | 1356 | */ |
1256 | 1357 | const char * |
1257 | 1358 | str_nfc_baud_rate(const nfc_baud_rate nbr) |
1259 | 1360 | switch (nbr) { |
1260 | 1361 | case NBR_UNDEFINED: |
1261 | 1362 | return "undefined baud rate"; |
1262 | break; | |
1263 | 1363 | case NBR_106: |
1264 | 1364 | return "106 kbps"; |
1265 | break; | |
1266 | 1365 | case NBR_212: |
1267 | 1366 | return "212 kbps"; |
1268 | break; | |
1269 | 1367 | case NBR_424: |
1270 | 1368 | return "424 kbps"; |
1271 | break; | |
1272 | 1369 | case NBR_847: |
1273 | 1370 | return "847 kbps"; |
1274 | break; | |
1275 | } | |
1276 | // Should never go there.. | |
1277 | return ""; | |
1371 | } | |
1372 | ||
1373 | return "???"; | |
1278 | 1374 | } |
1279 | 1375 | |
1280 | 1376 | /** @ingroup string-converter |
1281 | 1377 | * @brief Convert \a nfc_modulation_type value to string |
1282 | 1378 | * @return Returns nfc modulation type |
1283 | * @param \a nfc_modulation_type to convert | |
1379 | * @param nmt \a nfc_modulation_type to convert | |
1284 | 1380 | */ |
1285 | 1381 | const char * |
1286 | 1382 | str_nfc_modulation_type(const nfc_modulation_type nmt) |
1288 | 1384 | switch (nmt) { |
1289 | 1385 | case NMT_ISO14443A: |
1290 | 1386 | return "ISO/IEC 14443A"; |
1291 | break; | |
1292 | 1387 | case NMT_ISO14443B: |
1293 | 1388 | return "ISO/IEC 14443-4B"; |
1294 | break; | |
1295 | 1389 | case NMT_ISO14443BI: |
1296 | 1390 | return "ISO/IEC 14443-4B'"; |
1297 | break; | |
1391 | case NMT_ISO14443BICLASS: | |
1392 | return "ISO/IEC 14443-2B-3B iClass (Picopass)"; | |
1298 | 1393 | case NMT_ISO14443B2CT: |
1299 | 1394 | return "ISO/IEC 14443-2B ASK CTx"; |
1300 | break; | |
1301 | 1395 | case NMT_ISO14443B2SR: |
1302 | 1396 | return "ISO/IEC 14443-2B ST SRx"; |
1303 | break; | |
1304 | 1397 | case NMT_FELICA: |
1305 | 1398 | return "FeliCa"; |
1306 | break; | |
1307 | 1399 | case NMT_JEWEL: |
1308 | 1400 | return "Innovision Jewel"; |
1309 | break; | |
1401 | case NMT_BARCODE: | |
1402 | return "Thinfilm NFC Barcode"; | |
1310 | 1403 | case NMT_DEP: |
1311 | 1404 | return "D.E.P."; |
1312 | break; | |
1313 | } | |
1314 | // Should never go there.. | |
1315 | return ""; | |
1405 | } | |
1406 | ||
1407 | return "???"; | |
1316 | 1408 | } |
1317 | 1409 | |
1318 | 1410 | /** @ingroup string-converter |
1319 | * @brief Convert \a nfc_modulation_type value to string | |
1411 | * @brief Convert \a nfc_target content to string | |
1320 | 1412 | * @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) |
1321 | * @param nt \a nfc_target struct to print | |
1413 | * @param pnt \a nfc_target struct pointer to print | |
1322 | 1414 | * @param buf pointer where string will be allocated, then nfc target information printed |
1415 | * @param verbose false for essential, true for detailed, human-readable, information | |
1323 | 1416 | * |
1324 | 1417 | * @warning *buf must be freed using nfc_free() |
1325 | 1418 | */ |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * This program is free software: you can redistribute it and/or modify it |
13 | 14 | * under the terms of the GNU Lesser General Public License as published by the |
497 | 498 | snprint_hex(dst + off, size - off, pnji->btId, 4); |
498 | 499 | } |
499 | 500 | |
501 | void | |
502 | snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, bool verbose) | |
503 | { | |
504 | (void) verbose; | |
505 | int off = 0; | |
506 | off += snprintf(dst + off, size - off, " Size (bits): %lu\n", (unsigned long)(pnti->szDataLen * 8)); | |
507 | off += snprintf(dst + off, size - off, " Content: "); | |
508 | for (uint8_t i = 0; i < pnti->szDataLen; i++) { | |
509 | off += snprintf(dst + off, size - off, "%02X", pnti->abtData[i]); | |
510 | if ((i % 8 == 7) && (i < (pnti->szDataLen - 1))) { | |
511 | off += snprintf(dst + off, size - off, "\n "); | |
512 | } | |
513 | } | |
514 | snprintf(dst + off, size - off, "\n"); | |
515 | } | |
516 | ||
500 | 517 | #define PI_ISO14443_4_SUPPORTED 0x01 |
501 | 518 | #define PI_NAD_SUPPORTED 0x01 |
502 | 519 | #define PI_CID_SUPPORTED 0x02 |
593 | 610 | } |
594 | 611 | |
595 | 612 | void |
613 | snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose) | |
614 | { | |
615 | (void) verbose; | |
616 | int off = 0; | |
617 | off += snprintf(dst + off, size - off, " UID: "); | |
618 | snprint_hex(dst + off, size - off, pnic->abtUID, 8); | |
619 | } | |
620 | ||
621 | void | |
596 | 622 | snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose) |
597 | 623 | { |
598 | 624 | (void) verbose; |
636 | 662 | case NMT_JEWEL: |
637 | 663 | snprint_nfc_jewel_info(dst + off, size - off, &pnt->nti.nji, verbose); |
638 | 664 | break; |
665 | case NMT_BARCODE: | |
666 | snprint_nfc_barcode_info(dst + off, size - off, &pnt->nti.nti, verbose); | |
667 | break; | |
639 | 668 | case NMT_FELICA: |
640 | 669 | snprint_nfc_felica_info(dst + off, size - off, &pnt->nti.nfi, verbose); |
641 | 670 | break; |
648 | 677 | case NMT_ISO14443B2SR: |
649 | 678 | snprint_nfc_iso14443b2sr_info(dst + off, size - off, &pnt->nti.nsi, verbose); |
650 | 679 | break; |
680 | case NMT_ISO14443BICLASS: | |
681 | snprint_nfc_iso14443biclass_info(dst + off, size - off, &pnt->nti.nhi, verbose); | |
682 | break; | |
651 | 683 | case NMT_ISO14443B2CT: |
652 | 684 | snprint_nfc_iso14443b2ct_info(dst + off, size - off, &pnt->nti.nci, verbose); |
653 | 685 | break; |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * This program is free software: you can redistribute it and/or modify it |
13 | 14 | * under the terms of the GNU Lesser General Public License as published by the |
36 | 37 | void snprint_nfc_iso14443b_info(char *dst, size_t size, const nfc_iso14443b_info *pnbi, bool verbose); |
37 | 38 | void snprint_nfc_iso14443bi_info(char *dst, size_t size, const nfc_iso14443bi_info *pnii, bool verbose); |
38 | 39 | void snprint_nfc_iso14443b2sr_info(char *dst, size_t size, const nfc_iso14443b2sr_info *pnsi, bool verbose); |
40 | void snprint_nfc_iso14443biclass_info(char *dst, size_t size, const nfc_iso14443biclass_info *pnic, bool verbose); | |
39 | 41 | void snprint_nfc_iso14443b2ct_info(char *dst, size_t size, const nfc_iso14443b2ct_info *pnci, bool verbose); |
40 | 42 | void snprint_nfc_felica_info(char *dst, size_t size, const nfc_felica_info *pnfi, bool verbose); |
41 | 43 | void snprint_nfc_jewel_info(char *dst, size_t size, const nfc_jewel_info *pnji, bool verbose); |
44 | void snprint_nfc_barcode_info(char *dst, size_t size, const nfc_barcode_info *pnti, bool verbose); | |
42 | 45 | void snprint_nfc_dep_info(char *dst, size_t size, const nfc_dep_info *pndi, bool verbose); |
43 | 46 | void snprint_nfc_target(char *dst, size_t size, const nfc_target *pnt, bool verbose); |
44 | 47 |
3 | 3 | [ |
4 | 4 | AC_MSG_CHECKING(which drivers to build) |
5 | 5 | AC_ARG_WITH(drivers, |
6 | 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.]), | |
6 | 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.]), | |
7 | ||
7 | 8 | [ case "${withval}" in |
8 | 9 | yes | no) |
9 | 10 | dnl ignore calls without any arguments |
35 | 36 | fi |
36 | 37 | ;; |
37 | 38 | all) |
38 | DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart" | |
39 | DRIVER_BUILD_LIST="acr122_pcsc acr122_usb acr122s arygon pn53x_usb pn532_uart pcsc" | |
40 | ||
39 | 41 | if test x"$spi_available" = x"yes" |
40 | 42 | then |
41 | 43 | DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_spi" |
44 | 46 | then |
45 | 47 | DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn532_i2c" |
46 | 48 | fi |
49 | if test x"$nfc_nci_available" = x"yes" | |
50 | then | |
51 | DRIVER_BUILD_LIST="$DRIVER_BUILD_LIST pn71xx" | |
52 | fi | |
47 | 53 | ;; |
48 | 54 | esac |
49 | 55 | |
50 | 56 | DRIVERS_CFLAGS="" |
51 | 57 | |
58 | driver_pcsc_enabled="no" | |
52 | 59 | driver_acr122_pcsc_enabled="no" |
53 | 60 | driver_acr122_usb_enabled="no" |
54 | 61 | driver_acr122s_enabled="no" |
57 | 64 | driver_pn532_uart_enabled="no" |
58 | 65 | driver_pn532_spi_enabled="no" |
59 | 66 | driver_pn532_i2c_enabled="no" |
67 | driver_pn71xx_enabled="no" | |
60 | 68 | |
61 | 69 | for driver in ${DRIVER_BUILD_LIST} |
62 | 70 | do |
63 | 71 | case "${driver}" in |
72 | pcsc) | |
73 | pcsc_required="yes" | |
74 | driver_pcsc_enabled="yes" | |
75 | DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PCSC_ENABLED" | |
76 | ;; | |
64 | 77 | acr122_pcsc) |
65 | 78 | pcsc_required="yes" |
66 | 79 | driver_acr122_pcsc_enabled="yes" |
101 | 114 | driver_pn532_i2c_enabled="yes" |
102 | 115 | DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN532_I2C_ENABLED" |
103 | 116 | ;; |
117 | pn71xx) | |
118 | nfc_nci_required="yes" | |
119 | driver_pn71xx_enabled="yes" | |
120 | DRIVERS_CFLAGS="$DRIVERS_CFLAGS -DDRIVER_PN71XX_ENABLED" | |
121 | ;; | |
104 | 122 | *) |
105 | 123 | AC_MSG_ERROR([Unknow driver: $driver]) |
106 | 124 | ;; |
108 | 126 | done |
109 | 127 | AC_SUBST(DRIVERS_CFLAGS) |
110 | 128 | AM_CONDITIONAL(DRIVER_ACR122_PCSC_ENABLED, [test x"$driver_acr122_pcsc_enabled" = xyes]) |
129 | AM_CONDITIONAL(DRIVER_PCSC_ENABLED, [test x"$driver_pcsc_enabled" = xyes]) | |
111 | 130 | AM_CONDITIONAL(DRIVER_ACR122_USB_ENABLED, [test x"$driver_acr122_usb_enabled" = xyes]) |
112 | 131 | AM_CONDITIONAL(DRIVER_ACR122S_ENABLED, [test x"$driver_acr122s_enabled" = xyes]) |
113 | 132 | AM_CONDITIONAL(DRIVER_PN53X_USB_ENABLED, [test x"$driver_pn53x_usb_enabled" = xyes]) |
115 | 134 | AM_CONDITIONAL(DRIVER_PN532_UART_ENABLED, [test x"$driver_pn532_uart_enabled" = xyes]) |
116 | 135 | AM_CONDITIONAL(DRIVER_PN532_SPI_ENABLED, [test x"$driver_pn532_spi_enabled" = xyes]) |
117 | 136 | AM_CONDITIONAL(DRIVER_PN532_I2C_ENABLED, [test x"$driver_pn532_i2c_enabled" = xyes]) |
137 | AM_CONDITIONAL(DRIVER_PN71XX_ENABLED, [test x"$driver_pn71xx_enabled" = xyes]) | |
118 | 138 | ]) |
119 | 139 | |
120 | 140 | AC_DEFUN([LIBNFC_DRIVERS_SUMMARY],[ |
121 | 141 | echo |
122 | 142 | echo "Selected drivers:" |
143 | echo " pcsc............. $driver_pcsc_enabled" | |
123 | 144 | echo " acr122_pcsc...... $driver_acr122_pcsc_enabled" |
124 | 145 | echo " acr122_usb....... $driver_acr122_usb_enabled" |
125 | 146 | echo " acr122s.......... $driver_acr122s_enabled" |
128 | 149 | echo " pn532_uart....... $driver_pn532_uart_enabled" |
129 | 150 | echo " pn532_spi....... $driver_pn532_spi_enabled" |
130 | 151 | echo " pn532_i2c........ $driver_pn532_i2c_enabled" |
152 | echo " pn71xx........... $driver_pn71xx_enabled" | |
131 | 153 | ]) |
0 | #!/bin/sh | |
1 | PROJECT_DIR=$(readlink -e $(dirname $0)) | |
2 | cd "$PROJECT_DIR" | |
3 | ||
4 | WITH_USB=1 | |
5 | ||
6 | LIBUSB_WIN32_BIN_VERSION="1.2.6.0" | |
7 | LIBUSB_WIN32_BIN_ARCHIVE="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION.zip" | |
8 | LIBUSB_WIN32_BIN_URL="http://freefr.dl.sourceforge.net/project/libusb-win32/libusb-win32-releases/$LIBUSB_WIN32_BIN_VERSION/$LIBUSB_WIN32_BIN_ARCHIVE" | |
9 | LIBUSB_WIN32_BIN_DIR="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION" | |
10 | ||
11 | if [ "$WITH_USB" = "1" ]; then | |
12 | if [ ! -d $LIBUSB_WIN32_BIN_DIR ]; then | |
13 | wget -c $LIBUSB_WIN32_BIN_URL | |
14 | unzip $LIBUSB_WIN32_BIN_ARCHIVE | |
15 | fi | |
16 | fi | |
17 | ||
18 | ||
19 | rm -rf build | |
20 | mkdir build | |
21 | cd build | |
22 | ||
23 | ||
24 | case $1 in | |
25 | 32*) | |
26 | 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' | |
27 | mingw32-make;; | |
28 | 64*) | |
29 | 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' | |
30 | mingw64-make;; | |
31 | *) | |
32 | echo "specify whether to build 32-bit or 64-bit version by supplying 32 or 64 as parameter";; | |
33 | esac |
0 | #!/bin/sh | |
1 | ||
2 | WITH_USB=1 | |
3 | ||
4 | LIBUSB_WIN32_BIN_VERSION="1.2.6.0" | |
5 | LIBUSB_WIN32_BIN_ARCHIVE="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION.zip" | |
6 | LIBUSB_WIN32_BIN_URL="http://freefr.dl.sourceforge.net/project/libusb-win32/libusb-win32-releases/$LIBUSB_WIN32_BIN_VERSION/$LIBUSB_WIN32_BIN_ARCHIVE" | |
7 | LIBUSB_WIN32_BIN_DIR="libusb-win32-bin-$LIBUSB_WIN32_BIN_VERSION" | |
8 | ||
9 | if [ "$WITH_USB" = "1" ]; then | |
10 | if [ ! -d $LIBUSB_WIN32_BIN_DIR ]; then | |
11 | wget -c $LIBUSB_WIN32_BIN_URL | |
12 | unzip $LIBUSB_WIN32_BIN_ARCHIVE | |
13 | fi | |
14 | fi | |
15 | ||
16 | MINGW="${MINGW:=i686-w64-mingw32}" | |
17 | MINGW_DIR="/usr/$MINGW" | |
18 | ||
19 | # Use MinGW binaries before others | |
20 | #export PATH=$MINGW_DIR/bin:$PATH | |
21 | ||
22 | # Set CPATH to MinGW include files | |
23 | export CPATH=$MINGW_DIR/include | |
24 | export LD_LIBRARY_PATH=$MINGW_DIR/lib | |
25 | export LD_RUN_PATH=$MINGW_DIR/lib | |
26 | ||
27 | # Force pkg-config to search in cross environement directory | |
28 | export PKG_CONFIG_LIBDIR=$MINGW_DIR/lib/pkgconfig | |
29 | ||
30 | # Stop compilation on first error | |
31 | export CFLAGS="-Wfatal-errors" | |
32 | ||
33 | # Include default MinGW include directory, and libnfc's win32 files | |
34 | export CFLAGS="$CFLAGS -I$MINGW_DIR/include -I$PWD/contrib/win32" | |
35 | ||
36 | if [ "$MINGW" = "i686-w64-mingw32" ]; then | |
37 | # mingw-64 includes winscard.a and winscard.h | |
38 | # | |
39 | # It is not enough to set libpcsclite_LIBS to "-lwinscard", because it is | |
40 | # forgotten when libnfc is created with libtool. That's why we are setting | |
41 | # LIBS. | |
42 | export LIBS="-lwinscard" | |
43 | ||
44 | echo "MinGW-w64 ships all requirements libnfc." | |
45 | echo "Unfortunately the MinGW-w64 header are currently" | |
46 | echo "buggy. Also, Libtool doesn't support MinGW-w64" | |
47 | echo "very well." | |
48 | echo "" | |
49 | echo "Warning ________________________________________" | |
50 | echo "You will only be able to compile libnfc.dll, but" | |
51 | echo "none of the executables (see utils and examples)." | |
52 | echo "" | |
53 | # You can fix winbase.h by adding the following lines: | |
54 | # #include <basetsd.h> | |
55 | # #include <windef.h> | |
56 | # But the problem with Libtool remains. | |
57 | else | |
58 | if [ -z "$libpcsclite_LIBS$libpcsclite_CFLAGS" ]; then | |
59 | echo "Error __________________________________________" | |
60 | echo "You need to get the PC/SC library from a Windows" | |
61 | echo "machine and the appropriate header files. Then" | |
62 | echo "specify libpcsclite_LIBS=.../WinScard.dll and" | |
63 | echo "libpcsclite_CFLAGS=-I..." | |
64 | fi | |
65 | exit 1 | |
66 | fi | |
67 | ||
68 | ## Configure to cross-compile using mingw32msvc | |
69 | if [ "$WITH_USB" = "1" ]; then | |
70 | # with direct-USB drivers (use libusb-win32) | |
71 | DRIVERS="all" | |
72 | else | |
73 | # with UART divers only (can be tested under wine) | |
74 | DRIVERS="pn532_uart,arygon" | |
75 | fi | |
76 | ||
77 | if [ ! -x configure ]; then | |
78 | autoreconf -is | |
79 | fi | |
80 | ||
81 | ./configure --target=$MINGW --host=$MINGW \ | |
82 | --with-drivers=$DRIVERS \ | |
83 | --with-libusb-win32=$PWD/$LIBUSB_WIN32_BIN_DIR \ | |
84 | $* | |
85 | ||
86 | if [ "$MINGW" = "i686-w64-mingw32" ]; then | |
87 | # due to the buggy headers from MINGW-64 we always add "contrib/windows.h", | |
88 | # otherwise some windows types won't be available. | |
89 | echo "#include \"contrib/windows.h\"" >> config.h | |
90 | fi |
44 | 44 | echo-cutter: |
45 | 45 | @echo $(CUTTER) |
46 | 46 | |
47 | EXTRA_DIST = run-test.sh | |
48 | 47 | CLEANFILES = *.gcno |
49 | 48 | |
50 | 49 | endif |
50 | EXTRA_DIST = run-test.sh |
44 | 44 | .nbr = NBR_106, |
45 | 45 | }; |
46 | 46 | res = nfc_initiator_list_passive_targets(device, nm, ant, MAX_TARGET_COUNT); |
47 | cut_assert_operator_int(res, >= , 0, cut_message("nfc_initiator_list_passive_targets")); | |
47 | cut_assert_operator_int(res, >=, 0, cut_message("nfc_initiator_list_passive_targets")); | |
48 | 48 | |
49 | 49 | nfc_close(device); |
50 | 50 | } |
85 | 85 | |
86 | 86 | uint8_t abtRx[1024]; |
87 | 87 | int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 0); |
88 | cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
88 | cut_assert_operator_int(res, >, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
89 | 89 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
90 | 90 | |
91 | 91 | res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); |
92 | cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
92 | cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
93 | 93 | const uint8_t abtAttRx[] = "Hello DEP target!"; |
94 | 94 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); |
95 | 95 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
96 | 96 | |
97 | 97 | const uint8_t abtTx[] = "Hello DEP initiator!"; |
98 | 98 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); |
99 | cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
99 | cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
100 | 100 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
101 | 101 | |
102 | 102 | return (void *) thread_res; |
124 | 124 | // Active mode |
125 | 125 | printf("=========== INITIATOR %s (Active mode / %s Kbps) =========\n", nfc_device_get_name(device), str_nfc_baud_rate(nbr)); |
126 | 126 | res = nfc_initiator_select_dep_target(device, NDM_ACTIVE, nbr, NULL, &nt, 1000); |
127 | cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
127 | cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
128 | 128 | cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); |
129 | 129 | cut_assert_equal_int(nbr, nt.nm.nbr, cut_message("Invalid target baud rate")); |
130 | 130 | 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")); |
135 | 135 | const uint8_t abtTx[] = "Hello DEP target!"; |
136 | 136 | uint8_t abtRx[1024]; |
137 | 137 | res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); |
138 | cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
138 | cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
139 | 139 | |
140 | 140 | const uint8_t abtAttRx[] = "Hello DEP initiator!"; |
141 | 141 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data (as initiator)")); |
142 | 142 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
143 | 143 | res = nfc_initiator_deselect_target(device); |
144 | cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
144 | cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
145 | 145 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
146 | 146 | |
147 | 147 | return (void *) thread_res; |
85 | 85 | uint8_t abtRx[1024]; |
86 | 86 | size_t szRx = sizeof(abtRx); |
87 | 87 | int res = nfc_target_init(device, &nt, abtRx, szRx, 0); |
88 | cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
88 | cut_assert_operator_int(res, >, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
89 | 89 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
90 | 90 | |
91 | 91 | // First pass |
92 | 92 | res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); |
93 | cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
93 | cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
94 | 94 | |
95 | 95 | const uint8_t abtAttRx[] = "Hello DEP target!"; |
96 | 96 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); |
98 | 98 | |
99 | 99 | const uint8_t abtTx[] = "Hello DEP initiator!"; |
100 | 100 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); |
101 | cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
101 | cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
102 | 102 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
103 | 103 | |
104 | 104 | // Second pass |
105 | 105 | res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); |
106 | cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
107 | ||
108 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
109 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } | |
110 | ||
111 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); | |
112 | cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
106 | cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
107 | ||
108 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
109 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } | |
110 | ||
111 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); | |
112 | cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
113 | 113 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
114 | 114 | |
115 | 115 | // Third pass |
116 | 116 | res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); |
117 | cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
118 | ||
119 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
120 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } | |
121 | ||
122 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); | |
123 | cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
117 | cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
118 | ||
119 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
120 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } | |
121 | ||
122 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); | |
123 | cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
124 | 124 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
125 | 125 | |
126 | 126 | // Fourth pass |
127 | 127 | res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); |
128 | cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
129 | ||
130 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
131 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } | |
132 | ||
133 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); | |
134 | cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
128 | cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
129 | ||
130 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
131 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } | |
132 | ||
133 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); | |
134 | cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
135 | 135 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
136 | 136 | |
137 | 137 | return (void *) thread_res; |
159 | 159 | // Passive mode / 106Kbps |
160 | 160 | printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device)); |
161 | 161 | res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt, 5000); |
162 | cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
162 | cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
163 | 163 | cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); |
164 | 164 | cut_assert_equal_int(NBR_106, nt.nm.nbr, cut_message("Invalid target baud rate")); |
165 | 165 | 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")); |
170 | 170 | const uint8_t abtTx[] = "Hello DEP target!"; |
171 | 171 | uint8_t abtRx[1024]; |
172 | 172 | res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500); |
173 | cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
173 | cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
174 | 174 | |
175 | 175 | const uint8_t abtAttRx[] = "Hello DEP initiator!"; |
176 | 176 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); |
177 | 177 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
178 | 178 | |
179 | 179 | res = nfc_initiator_deselect_target(device); |
180 | cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
180 | cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
181 | 181 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
182 | 182 | |
183 | 183 | // Passive mode / 212Kbps (second pass) |
184 | 184 | printf("=========== INITIATOR %s (Passive mode / 212Kbps) =========\n", nfc_device_get_name(device)); |
185 | 185 | res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000); |
186 | cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
186 | cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
187 | 187 | cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); |
188 | 188 | cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate")); |
189 | 189 | 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")); |
192 | 192 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
193 | 193 | |
194 | 194 | res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 1000); |
195 | cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
196 | ||
197 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
198 | if (res < 0) { thread_res = -1; return (void *) thread_res; } | |
199 | ||
200 | res = nfc_initiator_deselect_target(device); | |
201 | cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
195 | cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
196 | ||
197 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
198 | if (res < 0) { thread_res = -1; return (void *) thread_res; } | |
199 | ||
200 | res = nfc_initiator_deselect_target(device); | |
201 | cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
202 | 202 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
203 | 203 | |
204 | 204 | // Passive mode / 212Kbps |
205 | 205 | printf("=========== INITIATOR %s (Passive mode / 212Kbps, second pass) =========\n", nfc_device_get_name(device)); |
206 | 206 | res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_212, NULL, &nt, 1000); |
207 | cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
207 | cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
208 | 208 | cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); |
209 | 209 | cut_assert_equal_int(NBR_212, nt.nm.nbr, cut_message("Invalid target baud rate")); |
210 | 210 | 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")); |
213 | 213 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
214 | 214 | |
215 | 215 | res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); |
216 | cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
217 | ||
218 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
219 | if (res < 0) { thread_res = -1; return (void *) thread_res; } | |
220 | ||
221 | res = nfc_initiator_deselect_target(device); | |
222 | cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
216 | cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
217 | ||
218 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
219 | if (res < 0) { thread_res = -1; return (void *) thread_res; } | |
220 | ||
221 | res = nfc_initiator_deselect_target(device); | |
222 | cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
223 | 223 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
224 | 224 | |
225 | 225 | // Passive mode / 424Kbps |
226 | 226 | printf("=========== INITIATOR %s (Passive mode / 424Kbps) =========\n", nfc_device_get_name(device)); |
227 | 227 | res = nfc_initiator_select_dep_target(device, NDM_PASSIVE, NBR_424, NULL, &nt, 1000); |
228 | cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
228 | cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
229 | 229 | cut_assert_equal_int(NMT_DEP, nt.nm.nmt, cut_message("Invalid target modulation")); |
230 | 230 | cut_assert_equal_int(NBR_424, nt.nm.nbr, cut_message("Invalid target baud rate")); |
231 | 231 | 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")); |
234 | 234 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
235 | 235 | |
236 | 236 | res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 5000); |
237 | cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
238 | ||
239 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
240 | if (res < 0) { thread_res = -1; return (void *) thread_res; } | |
241 | ||
242 | res = nfc_initiator_deselect_target(device); | |
243 | cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
237 | cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
238 | ||
239 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); | |
240 | if (res < 0) { thread_res = -1; return (void *) thread_res; } | |
241 | ||
242 | res = nfc_initiator_deselect_target(device); | |
243 | cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
244 | 244 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
245 | 245 | |
246 | 246 | return (void *) thread_res; |
65 | 65 | |
66 | 66 | // 1) nfc_target_init should take target in idle mode |
67 | 67 | int res = nfc_target_init(device, &nt, abtRx, sizeof(abtRx), 500); |
68 | cut_assert_operator_int(res, >= , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
68 | cut_assert_operator_int(res, >=, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
69 | 69 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
70 | 70 | |
71 | 71 | // 2) act as target |
91 | 91 | }; |
92 | 92 | sleep(6); |
93 | 93 | res = nfc_target_init(device, &nt1, abtRx, sizeof(abtRx), 0); |
94 | cut_assert_operator_int(res, > , 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
94 | cut_assert_operator_int(res, >, 0, cut_message("Can't initialize NFC device as target: %s", nfc_strerror(device))); | |
95 | 95 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
96 | 96 | |
97 | 97 | res = nfc_target_receive_bytes(device, abtRx, sizeof(abtRx), 500); |
98 | cut_assert_operator_int(res, > , 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
98 | cut_assert_operator_int(res, >, 0, cut_message("Can't receive bytes from initiator: %s", nfc_strerror(device))); | |
99 | 99 | |
100 | 100 | const uint8_t abtAttRx[] = "Hello DEP target!"; |
101 | 101 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); |
103 | 103 | |
104 | 104 | const uint8_t abtTx[] = "Hello DEP initiator!"; |
105 | 105 | res = nfc_target_send_bytes(device, abtTx, sizeof(abtTx), 500); |
106 | cut_assert_operator_int(res, > , 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
106 | cut_assert_operator_int(res, >, 0, cut_message("Can't send bytes to initiator: %s", nfc_strerror(device))); | |
107 | 107 | if (res <= 0) { thread_res = -1; return (void *) thread_res; } |
108 | 108 | |
109 | 109 | // 3) idle mode |
143 | 143 | // Passive mode / 106Kbps |
144 | 144 | printf("=========== INITIATOR %s (Passive mode / 106Kbps) =========\n", nfc_device_get_name(device)); |
145 | 145 | res = nfc_initiator_poll_dep_target(device, NDM_PASSIVE, NBR_106, NULL, &nt1, 5000); |
146 | cut_assert_operator_int(res, > , 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
146 | cut_assert_operator_int(res, >, 0, cut_message("Can't select any DEP target: %s", nfc_strerror(device))); | |
147 | 147 | cut_assert_equal_int(NMT_DEP, nt1.nm.nmt, cut_message("Invalid target modulation")); |
148 | 148 | cut_assert_equal_int(NBR_106, nt1.nm.nbr, cut_message("Invalid target baud rate")); |
149 | 149 | 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")); |
154 | 154 | const uint8_t abtTx[] = "Hello DEP target!"; |
155 | 155 | uint8_t abtRx[1024]; |
156 | 156 | res = nfc_initiator_transceive_bytes(device, abtTx, sizeof(abtTx), abtRx, sizeof(abtRx), 500); |
157 | cut_assert_operator_int(res, >= , 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
157 | cut_assert_operator_int(res, >=, 0, cut_message("Can't transceive bytes to target: %s", nfc_strerror(device))); | |
158 | 158 | |
159 | 159 | const uint8_t abtAttRx[] = "Hello DEP initiator!"; |
160 | 160 | cut_assert_equal_memory(abtAttRx, sizeof(abtAttRx), abtRx, res, cut_message("Invalid received data")); |
161 | 161 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
162 | 162 | |
163 | 163 | res = nfc_initiator_deselect_target(device); |
164 | cut_assert_operator_int(res, >= , 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
164 | cut_assert_operator_int(res, >=, 0, cut_message("Can't deselect target: %s", nfc_strerror(device))); | |
165 | 165 | if (res < 0) { thread_res = -1; return (void *) thread_res; } |
166 | 166 | |
167 | 167 | // 3) As other device should be in idle mode, nfc_initiator_poll_dep_target should return 0 |
0 | 0 | bin_PROGRAMS = \ |
1 | nfc-barcode \ | |
1 | 2 | nfc-emulate-forum-tag4 \ |
2 | 3 | nfc-jewel \ |
3 | 4 | nfc-list \ |
13 | 14 | noinst_LTLIBRARIES = libnfcutils.la |
14 | 15 | |
15 | 16 | libnfcutils_la_SOURCES = nfc-utils.c |
17 | libnfcutils_la_LIBADD = -lnfc | |
18 | ||
19 | nfc_barcode_SOURCES = nfc-barcode.c | |
20 | nfc_barcode_LDADD = $(top_builddir)/libnfc/libnfc.la \ | |
21 | libnfcutils.la | |
16 | 22 | |
17 | 23 | nfc_emulate_forum_tag4_SOURCES = nfc-emulate-forum-tag4.c nfc-utils.h |
18 | 24 | nfc_emulate_forum_tag4_LDADD = $(top_builddir)/libnfc/libnfc.la \ |
45 | 51 | libnfcutils.la |
46 | 52 | |
47 | 53 | dist_man_MANS = \ |
54 | nfc-barcode.1 \ | |
48 | 55 | nfc-emulate-forum-tag4.1 \ |
49 | 56 | nfc-jewel.1 \ |
50 | 57 | nfc-list.1 \ |
96 | 96 | break; |
97 | 97 | default: |
98 | 98 | return false; |
99 | break; | |
100 | 99 | } |
101 | 100 | |
102 | 101 | if (nfc_initiator_transceive_bytes(pnd, (uint8_t *)&req, nLenReq, (uint8_t *)pres, nLenRes, -1) < 0) { |
67 | 67 | abtCmd[1] = ui8Block; // The block address (1K=0x00..0x39, 4K=0x00..0xff) |
68 | 68 | |
69 | 69 | switch (mc) { |
70 | // Read and store command have no parameter | |
70 | // Read and store command have no parameter | |
71 | 71 | case MC_READ: |
72 | 72 | case MC_STORE: |
73 | 73 | szParamLen = 0; |
74 | 74 | break; |
75 | 75 | |
76 | // Authenticate command | |
76 | // Authenticate command | |
77 | 77 | case MC_AUTH_A: |
78 | 78 | case MC_AUTH_B: |
79 | 79 | szParamLen = sizeof(struct mifare_param_auth); |
80 | 80 | break; |
81 | 81 | |
82 | // Data command | |
82 | // Data command | |
83 | 83 | case MC_WRITE: |
84 | 84 | szParamLen = sizeof(struct mifare_param_data); |
85 | 85 | break; |
86 | 86 | |
87 | // Value command | |
87 | // Value command | |
88 | 88 | case MC_DECREMENT: |
89 | 89 | case MC_INCREMENT: |
90 | 90 | case MC_TRANSFER: |
91 | 91 | szParamLen = sizeof(struct mifare_param_value); |
92 | 92 | break; |
93 | 93 | |
94 | // Please fix your code, you never should reach this statement | |
94 | // Please fix your code, you never should reach this statement | |
95 | 95 | default: |
96 | 96 | return false; |
97 | break; | |
98 | 97 | } |
99 | 98 | |
100 | 99 | // When available, copy the parameter bytes |
130 | 129 | |
131 | 130 | // When we have executed a read command, copy the received bytes into the param |
132 | 131 | if (mc == MC_READ) { |
133 | if (res == 16) { | |
132 | ||
133 | //Check the length of response data, with PCSC reader, there have 2 bytes for SW value | |
134 | if (res == 16 || res == (16 + 2)) { | |
134 | 135 | memcpy(pmp->mpd.abtData, abtRx, 16); |
135 | 136 | } else { |
136 | 137 | return false; |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2017-2018 Adam Laurie | |
11 | 12 | * |
12 | 13 | * Redistribution and use in source and binary forms, with or without |
13 | 14 | * modification, are permitted provided that the following conditions are met: |
71 | 72 | uint8_t abtValue[4]; |
72 | 73 | }; |
73 | 74 | |
75 | struct mifare_param_trailer { | |
76 | uint8_t abtKeyA[6]; | |
77 | uint8_t abtAccessBits[4]; | |
78 | uint8_t abtKeyB[6]; | |
79 | }; | |
80 | ||
74 | 81 | typedef union { |
75 | 82 | struct mifare_param_auth mpa; |
76 | 83 | struct mifare_param_data mpd; |
77 | 84 | struct mifare_param_value mpv; |
85 | struct mifare_param_trailer mpt; | |
78 | 86 | } mifare_param; |
79 | 87 | |
80 | 88 | // Reset struct alignment to default |
125 | 133 | uint8_t otp[4]; |
126 | 134 | } mifareul_block_manufacturer; |
127 | 135 | |
136 | // MIFARE Ultralight EV1 MF0UL11 Config Pages | |
137 | typedef struct { | |
138 | uint8_t mod; | |
139 | uint8_t rfui1[2]; | |
140 | uint8_t auth0; | |
141 | uint8_t access; | |
142 | uint8_t vctid; | |
143 | uint8_t rfui2[2]; | |
144 | uint8_t pwd[4]; | |
145 | uint8_t pack[2]; | |
146 | uint8_t rfui3[2]; | |
147 | } mifareul_block_config11; | |
148 | ||
149 | // MIFARE Ultralight EV1 MF0UL21 ConfigA Pages | |
150 | typedef struct { | |
151 | uint8_t lock[3]; | |
152 | uint8_t rfui0; | |
153 | uint8_t mod; | |
154 | uint8_t rfui1[2]; | |
155 | uint8_t auth0; | |
156 | uint8_t access; | |
157 | uint8_t vctid; | |
158 | uint8_t rfui2[2]; | |
159 | uint8_t pwd[4]; | |
160 | } mifareul_block_config21A; | |
161 | ||
162 | // MIFARE Ultralight EV1 MF0UL21 ConfigB Pages | |
163 | typedef struct { | |
164 | uint8_t pack[2]; | |
165 | uint8_t rfui3[2]; | |
166 | uint8_t dummy[12]; | |
167 | } mifareul_block_config21B; | |
168 | ||
169 | // MIFARE NTAG21[3/5/6] Manufacturer Pages | |
170 | typedef struct { | |
171 | uint8_t sn0[4]; | |
172 | } mifarentag_block_manuf21356A; | |
173 | typedef struct { | |
174 | uint8_t sn1[4]; | |
175 | } mifarentag_block_manuf21356B; | |
176 | typedef struct { | |
177 | uint8_t sn2; | |
178 | uint8_t internal; | |
179 | uint8_t lock[2]; | |
180 | } mifarentag_block_manuf21356C; | |
181 | typedef struct { | |
182 | uint8_t cc[4]; | |
183 | } mifarentag_block_manuf21356D; | |
184 | ||
185 | // MIFARE NTAG21[3/5/6] Config Pages | |
186 | typedef struct { | |
187 | uint8_t dynlock[3]; | |
188 | uint8_t rfui0; | |
189 | } mifarentag_block_config21356A; | |
190 | typedef struct { | |
191 | uint8_t cfg0[4]; | |
192 | } mifarentag_block_config21356B; | |
193 | typedef struct { | |
194 | uint8_t cfg1[4]; | |
195 | } mifarentag_block_config21356C; | |
196 | typedef struct { | |
197 | uint8_t pwd[4]; | |
198 | } mifarentag_block_config21356D; | |
199 | typedef struct { | |
200 | uint8_t pack[2]; | |
201 | uint8_t rfui1[2]; | |
202 | } mifarentag_block_config21356E; | |
203 | ||
128 | 204 | typedef struct { |
129 | 205 | uint8_t abtData[16]; |
130 | 206 | } mifareul_block_data; |
131 | 207 | |
208 | typedef struct { | |
209 | uint8_t abtData[4]; | |
210 | } mifarentag_block_data; | |
211 | ||
212 | typedef union { | |
213 | mifarentag_block_manuf21356A mbm21356a; | |
214 | mifarentag_block_manuf21356B mbm21356b; | |
215 | mifarentag_block_manuf21356C mbm21356c; | |
216 | mifarentag_block_manuf21356D mbm21356d; | |
217 | mifarentag_block_data mbd; | |
218 | mifarentag_block_config21356A mbc21356a; | |
219 | mifarentag_block_config21356B mbc21356b; | |
220 | mifarentag_block_config21356C mbc21356c; | |
221 | mifarentag_block_config21356D mbc21356d; | |
222 | mifarentag_block_config21356E mbc21356e; | |
223 | } mifarentag_block; | |
224 | ||
132 | 225 | typedef union { |
133 | 226 | mifareul_block_manufacturer mbm; |
134 | 227 | mifareul_block_data mbd; |
228 | mifareul_block_config11 mbc11; | |
229 | mifareul_block_config21A mbc21a; | |
230 | mifareul_block_config21B mbc21b; | |
135 | 231 | } mifareul_block; |
136 | 232 | |
233 | // standard UL tag - 1 manuf block + 3 user blocks | |
137 | 234 | typedef struct { |
138 | 235 | mifareul_block amb[4]; |
139 | 236 | } mifareul_tag; |
140 | 237 | |
238 | // UL EV1 MF0UL11 tag - 1 manuf block + 3 user blocks + 1 config block | |
239 | typedef struct { | |
240 | mifareul_block amb[5]; | |
241 | } mifareul_ev1_mf0ul11_tag; | |
242 | ||
243 | // UL EV1 MF0UL21 tag - 1 manuf block + 8 user blocks + 1/4 lock block + 1 config block | |
244 | // (note that tag is actually 3 bytes smaller due to 1/4 block, so don't rely on this for sizing!) | |
245 | typedef struct { | |
246 | mifareul_block amb[11]; | |
247 | } mifareul_ev1_mf0ul21_tag; | |
248 | ||
249 | // NTAG is a range of NXP tags some of which are essentially Ultralights so we can support them here | |
250 | // if Edwin van Andel doesn't distract us... | |
251 | // https://www.nxp.com/docs/en/data-sheet/NTAG213_215_216.pdf | |
252 | ||
253 | // NTAG213 EEPROM: 180 bytes, organized in 45 pages of 4 byte per page. | |
254 | // 26 bytes reserved for manufacturer and configuration data | |
255 | // 34 bits used for the read-only locking mechanism | |
256 | // 4 bytes available as capability container | |
257 | // 144 bytes user programmable read/write memory | |
258 | typedef struct { | |
259 | mifarentag_block amb[45]; | |
260 | } mifarentag_213_tag; | |
261 | ||
262 | // NTAG215 EEPROM: 540 bytes, organized in 135 pages of 4 byte per page. | |
263 | // 26 bytes reserved for manufacturer and configuration data | |
264 | // 28 bits used for the read-only locking mechanism | |
265 | // 4 bytes available as capability container | |
266 | // 504 bytes user programmable read/write memory | |
267 | typedef struct { | |
268 | mifarentag_block amb[135]; | |
269 | } mifarentag_215_tag; | |
270 | ||
271 | // NTAG216 EEPROM: 924 bytes, organized in 231 pages of 4 byte per page. | |
272 | // 26 bytes reserved for manufacturer and configuration data | |
273 | // 37 bits used for the read-only locking mechanism | |
274 | // 4 bytes available as capability container | |
275 | // 888 bytes user programmable read/write memory | |
276 | typedef struct { | |
277 | mifarentag_block amb[231]; | |
278 | } mifarentag_216_tag; | |
279 | ||
280 | // dummy max size with all structures in it for reading, rounded up to a multiple of 16 bytes | |
281 | typedef union { | |
282 | mifareul_block ul[58]; | |
283 | mifarentag_block nt[232]; | |
284 | } maxtag; | |
285 | ||
141 | 286 | // Reset struct alignment to default |
142 | 287 | # pragma pack() |
143 | 288 |
0 | .TH nfc-barcode 1 "May, 2017" "libnfc" "libnfc's examples" | |
1 | .SH NAME | |
2 | nfc-barcode \- NFC Barcode (Tag-Talks-First) reader | |
3 | .SH SYNOPSIS | |
4 | .B nfc-barcode | |
5 | .SH DESCRIPTION | |
6 | .B nfc-barcode | |
7 | is a utility to read and decode NFC Barcodes | |
8 | ||
9 | .SH OPTIONS | |
10 | .B -d | |
11 | Decode content, if possible. | |
12 | ||
13 | .B -v | |
14 | Verbose. | |
15 | ||
16 | .SH BUGS | |
17 | Please report any bugs on the | |
18 | .B libnfc | |
19 | issue tracker at: | |
20 | .br | |
21 | .BR https://github.com/nfc-tools/libnfc/issues | |
22 | .SH LICENCE | |
23 | .B libnfc | |
24 | is licensed under the GNU Lesser General Public License (LGPL), version 3. | |
25 | .br | |
26 | .B libnfc-utils | |
27 | and | |
28 | .B libnfc-examples | |
29 | are covered by the the BSD 2-Clause license. | |
30 | .SH AUTHORS | |
31 | Philippe Teuwen <yobibe@gmail.com> | |
32 | .PP | |
33 | This manual page was written by Philippe Teuwen <yobibe@gmail.com>. | |
34 | It is licensed under the terms of the GNU GPL (version 2 or later). |
0 | /*- | |
1 | * Free/Libre Near Field Communication (NFC) library | |
2 | * | |
3 | * Libnfc historical contributors: | |
4 | * Copyright (C) 2017 Philippe Teuwen | |
5 | * See AUTHORS file for a more comprehensive list of contributors. | |
6 | * Additional contributors of this file: | |
7 | * | |
8 | * Redistribution and use in source and binary forms, with or without | |
9 | * modification, are permitted provided that the following conditions are met: | |
10 | * 1) Redistributions of source code must retain the above copyright notice, | |
11 | * this list of conditions and the following disclaimer. | |
12 | * 2 )Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | * | |
28 | * Note that this license only applies on the examples, NFC library itself is under LGPL | |
29 | * | |
30 | */ | |
31 | ||
32 | /** | |
33 | * @file nfc-barcode.c | |
34 | * @brief Reads a NFC Barcode tag | |
35 | */ | |
36 | ||
37 | #ifdef HAVE_CONFIG_H | |
38 | # include "config.h" | |
39 | #endif // HAVE_CONFIG_H | |
40 | ||
41 | #include <stdio.h> | |
42 | #include <stdlib.h> | |
43 | #include <stddef.h> | |
44 | #include <stdint.h> | |
45 | #include <stdbool.h> | |
46 | #include <string.h> | |
47 | ||
48 | #include <nfc/nfc.h> | |
49 | ||
50 | #include "nfc-utils.h" | |
51 | ||
52 | #define MAX_FRAME_LEN 264 | |
53 | ||
54 | static nfc_device *pnd; | |
55 | ||
56 | bool verbose = false; | |
57 | ||
58 | static void | |
59 | print_usage(char *argv[]) | |
60 | { | |
61 | printf("Usage: %s [OPTIONS]\n", argv[0]); | |
62 | printf("Options:\n"); | |
63 | printf("\t-h\tHelp. Print this message.\n"); | |
64 | printf("\t-q\tVerbose mode.\n"); | |
65 | } | |
66 | ||
67 | ||
68 | static bool | |
69 | decode_barcode(uint8_t *pbtBarcode, const size_t szBarcode) | |
70 | { | |
71 | if (verbose) { | |
72 | printf("Manufacturer ID field: %02X\n", pbtBarcode[0]); | |
73 | switch (pbtBarcode[0]) { | |
74 | case 0xb7: | |
75 | printf("Manufacturer: Thinfilm\n"); | |
76 | break; | |
77 | default: | |
78 | printf("Manufacturer: unknown\n"); | |
79 | break; | |
80 | } | |
81 | } | |
82 | if (verbose) { | |
83 | printf("Data Format Field: %02X\n", pbtBarcode[1]); | |
84 | } | |
85 | switch (pbtBarcode[1]) { | |
86 | case 0: | |
87 | printf("Data Format Field: Reserved for allocation by tag manufacturer\n"); | |
88 | return false; | |
89 | break; | |
90 | case 1: | |
91 | case 2: | |
92 | case 3: | |
93 | case 4: | |
94 | switch (pbtBarcode[1]) { | |
95 | case 1: | |
96 | printf("http://www."); | |
97 | break; | |
98 | case 2: | |
99 | printf("https://www."); | |
100 | break; | |
101 | case 3: | |
102 | printf("http://"); | |
103 | break; | |
104 | case 4: | |
105 | printf("https://"); | |
106 | break; | |
107 | } | |
108 | for (uint8_t i = 2; i < 15; i++) { | |
109 | if ((pbtBarcode[i] == 0xfe) || (i == 14)) { | |
110 | pbtBarcode[i] = '\n'; | |
111 | pbtBarcode[i + 1] = 0; | |
112 | break; | |
113 | } | |
114 | } | |
115 | printf("%s", (char *)pbtBarcode + 2); | |
116 | break; | |
117 | case 5: | |
118 | printf("EPC: "); | |
119 | for (uint8_t i = 0; i < 12; i++) { | |
120 | printf("%02x", pbtBarcode[i + 2]); | |
121 | } | |
122 | printf("\n"); | |
123 | break; | |
124 | default: | |
125 | printf("Data Format Field: unknown (%02X)\n", pbtBarcode[1]); | |
126 | printf("Data:"); | |
127 | for (uint8_t i = 2; i < szBarcode - 2; i++) { | |
128 | printf("%02x", pbtBarcode[i]); | |
129 | } | |
130 | printf("\n"); | |
131 | break; | |
132 | } | |
133 | return true; | |
134 | } | |
135 | ||
136 | int | |
137 | main(int argc, char *argv[]) | |
138 | { | |
139 | int arg; | |
140 | ||
141 | // Get commandline options | |
142 | for (arg = 1; arg < argc; arg++) { | |
143 | if (0 == strcmp(argv[arg], "-h")) { | |
144 | print_usage(argv); | |
145 | exit(EXIT_SUCCESS); | |
146 | } else if (0 == strcmp(argv[arg], "-v")) { | |
147 | verbose = true; | |
148 | } else { | |
149 | ERR("%s is not supported option.", argv[arg]); | |
150 | print_usage(argv); | |
151 | exit(EXIT_FAILURE); | |
152 | } | |
153 | } | |
154 | ||
155 | nfc_context *context; | |
156 | nfc_init(&context); | |
157 | if (context == NULL) { | |
158 | ERR("Unable to init libnfc (malloc)"); | |
159 | exit(EXIT_FAILURE); | |
160 | } | |
161 | ||
162 | // Try to open the NFC reader | |
163 | pnd = nfc_open(context, NULL); | |
164 | ||
165 | if (pnd == NULL) { | |
166 | ERR("Error opening NFC reader"); | |
167 | nfc_exit(context); | |
168 | exit(EXIT_FAILURE); | |
169 | } | |
170 | ||
171 | // Initialise NFC device as "initiator" | |
172 | if (nfc_initiator_init(pnd) < 0) { | |
173 | nfc_perror(pnd, "nfc_initiator_init"); | |
174 | nfc_close(pnd); | |
175 | nfc_exit(context); | |
176 | exit(EXIT_FAILURE); | |
177 | } | |
178 | ||
179 | printf("NFC reader: %s opened\n\n", nfc_device_get_name(pnd)); | |
180 | ||
181 | nfc_modulation nm; | |
182 | nm.nmt = NMT_BARCODE; | |
183 | nm.nbr = NBR_106; | |
184 | nfc_target ant[1]; | |
185 | // List NFC Barcode targets | |
186 | if ((nfc_initiator_list_passive_targets(pnd, nm, ant, 1)) == 1) { | |
187 | if (verbose) { | |
188 | for (uint8_t i = 0; i < (&ant[0])->nti.nti.szDataLen; i++) { | |
189 | printf("%02x", (&ant[0])->nti.nti.abtData[i]); | |
190 | } | |
191 | printf("\n"); | |
192 | } | |
193 | decode_barcode((&ant[0])->nti.nti.abtData, (&ant[0])->nti.nti.szDataLen); | |
194 | } | |
195 | nfc_close(pnd); | |
196 | nfc_exit(context); | |
197 | exit(EXIT_SUCCESS); | |
198 | } |
45 | 45 | Please report any bugs on the |
46 | 46 | .Em libnfc |
47 | 47 | issue tracker at: |
48 | .Em http://code.google.com/p/libnfc/issues | |
48 | .Em https://github.com/nfc-tools/libnfc/issues | |
49 | 49 | .Sh LICENCE |
50 | 50 | .Em libnfc |
51 | 51 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
34 | 34 | .B libnfc |
35 | 35 | issue tracker at: |
36 | 36 | .br |
37 | .BR http://code.google.com/p/libnfc/issues | |
37 | .BR https://github.com/nfc-tools/libnfc/issues | |
38 | 38 | .SH LICENCE |
39 | 39 | .B libnfc |
40 | 40 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
26 | 26 | .TP |
27 | 27 | \fB-t\fP \fIX\fP |
28 | 28 | Polls only for types according to bitfield value of \fIX\fP: |
29 | ||
29 | 30 | 1: ISO14443A |
30 | 31 | 2: Felica (212 kbps) |
31 | 32 | 4: Felica (424 kbps) |
33 | 34 | 16: ISO14443B' |
34 | 35 | 32: ISO14443B-2 ST SRx |
35 | 36 | 64: ISO14443B-2 ASK CTx |
36 | 128: Jewel | |
37 | 128: ISO14443B iClass | |
38 | 256: ISO14443A-3 Jewel | |
39 | 512: ISO14443A-2 NFC Barcode | |
37 | 40 | |
38 | So 255 (default) polls for all types. | |
39 | ||
40 | Note that if 16, 32 or 64 then 8 is selected too. | |
41 | So 1023 (default) polls for all types. | |
42 | Note that if 16, 32, 64 or 128 then 8 is selected too. | |
41 | 43 | |
42 | 44 | .SH EXAMPLE |
43 | 45 | For an ISO/IEC 14443-A tag (i.e.Mifare DESFire): |
52 | 54 | .B libnfc |
53 | 55 | issue tracker at: |
54 | 56 | .br |
55 | .BR http://code.google.com/p/libnfc/issues | |
57 | .BR https://github.com/nfc-tools/libnfc/issues | |
56 | 58 | .SH LICENCE |
57 | 59 | .B libnfc |
58 | 60 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2020 Adam Laurie | |
11 | 12 | * |
12 | 13 | * Redistribution and use in source and binary forms, with or without |
13 | 14 | * modification, are permitted provided that the following conditions are met: |
70 | 71 | printf("\t 16: ISO14443B'\n"); |
71 | 72 | printf("\t 32: ISO14443B-2 ST SRx\n"); |
72 | 73 | printf("\t 64: ISO14443B-2 ASK CTx\n"); |
73 | printf("\t 128: Jewel\n"); | |
74 | printf("\tSo 255 (default) polls for all types.\n"); | |
75 | printf("\tNote that if 16, 32 or 64 then 8 is selected too.\n"); | |
74 | printf("\t 128: ISO14443B iClass\n"); | |
75 | printf("\t 256: ISO14443A-3 Jewel\n"); | |
76 | printf("\t 512: ISO14443A-2 NFC Barcode\n"); | |
77 | printf("\tSo 1023 (default) polls for all types.\n"); | |
78 | printf("\tNote that if 16, 32, 64 or 128 then 8 is selected too.\n"); | |
76 | 79 | } |
77 | 80 | |
78 | 81 | int |
83 | 86 | size_t i; |
84 | 87 | bool verbose = false; |
85 | 88 | int res = 0; |
86 | int mask = 0xff; | |
89 | int mask = 0x3ff; | |
87 | 90 | int arg; |
88 | 91 | |
89 | 92 | nfc_context *context; |
107 | 110 | } else if ((0 == strcmp(argv[arg], "-t")) && (arg + 1 < argc)) { |
108 | 111 | arg++; |
109 | 112 | mask = atoi(argv[arg]); |
110 | if ((mask < 1) || (mask > 255)) { | |
113 | if ((mask < 1) || (mask > 0x3ff)) { | |
111 | 114 | ERR("%i is invalid value for type bitfield.", mask); |
112 | 115 | print_usage(argv[0]); |
113 | 116 | exit(EXIT_FAILURE); |
114 | 117 | } |
115 | 118 | // Force TypeB for all derivatives of B |
116 | if (mask & 0x70) | |
119 | if (mask & 0xf0) | |
117 | 120 | mask |= 0x08; |
118 | 121 | } else { |
119 | 122 | ERR("%s is not supported option.", argv[arg]); |
270 | 273 | } |
271 | 274 | |
272 | 275 | if (mask & 0x80) { |
276 | nm.nmt = NMT_ISO14443BICLASS; | |
277 | nm.nbr = NBR_106; | |
278 | // List ISO14443B iClass targets | |
279 | if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { | |
280 | int n; | |
281 | if (verbose || (res > 0)) { | |
282 | printf("%d ISO14443B iClass passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":"); | |
283 | } | |
284 | for (n = 0; n < res; n++) { | |
285 | print_nfc_target(&ant[n], verbose); | |
286 | printf("\n"); | |
287 | } | |
288 | } | |
289 | } | |
290 | ||
291 | if (mask & 0x100) { | |
273 | 292 | nm.nmt = NMT_JEWEL; |
274 | 293 | nm.nbr = NBR_106; |
275 | 294 | // List Jewel targets |
276 | 295 | if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { |
277 | 296 | int n; |
278 | 297 | if (verbose || (res > 0)) { |
279 | printf("%d Jewel passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":"); | |
280 | } | |
281 | for (n = 0; n < res; n++) { | |
282 | print_nfc_target(&ant[n], verbose); | |
283 | printf("\n"); | |
284 | } | |
285 | } | |
286 | } | |
298 | printf("%d ISO14443A-3 Jewel passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":"); | |
299 | } | |
300 | for (n = 0; n < res; n++) { | |
301 | print_nfc_target(&ant[n], verbose); | |
302 | printf("\n"); | |
303 | } | |
304 | } | |
305 | } | |
306 | ||
307 | if (mask & 0x200) { | |
308 | nm.nmt = NMT_BARCODE; | |
309 | nm.nbr = NBR_106; | |
310 | // List NFC Barcode targets | |
311 | if ((res = nfc_initiator_list_passive_targets(pnd, nm, ant, MAX_TARGET_COUNT)) >= 0) { | |
312 | int n; | |
313 | if (verbose || (res > 0)) { | |
314 | printf("%d ISO14443A-2 NFC Barcode passive target(s) found%s\n", res, (res == 0) ? ".\n" : ":"); | |
315 | } | |
316 | for (n = 0; n < res; n++) { | |
317 | print_nfc_target(&ant[n], verbose); | |
318 | printf("\n"); | |
319 | } | |
320 | } | |
321 | } | |
322 | ||
287 | 323 | nfc_close(pnd); |
288 | 324 | } |
289 | 325 |
4 | 4 | .B nfc-mfclassic |
5 | 5 | .RI \fR\fBf\fR|\fR\fBr\fR|\fR\fBR\fR|\fBw\fR\fR|\fBW\fR |
6 | 6 | .RI \fR\fBa\fR|\fR\fBA\fR|\fBb\fR\fR|\fBB\fR |
7 | .RI \fR\fBu\fR\fR|\fBU\fR<\fBuid\fR>\fR | |
7 | 8 | .IR DUMP |
8 | 9 | .RI [ |
9 | 10 | .IR KEYS |
55 | 56 | .B B |
56 | 57 | ). |
57 | 58 | |
59 | When using multiple tags infront of a reader, the | |
60 | .B U | |
61 | option can be used to supply the UID of tag to be read or written. Append the | |
62 | hexadecimal UID to the U option. For example U01ab23cd for the 4 byte UID | |
63 | 0x01 0xab 0x23 0xcd. Using the | |
64 | .B u | |
65 | parameter instead will use whatever libnfc decides which generally is the lowest | |
66 | UID. | |
67 | ||
58 | 68 | *** Note that |
59 | 69 | .B W |
60 | 70 | and |
89 | 99 | B |
90 | 100 | ). |
91 | 101 | .TP |
102 | .BR u " | " U | |
103 | Use the default UID ( | |
104 | .B u | |
105 | ) or supply a valid 4 byte UID ( | |
106 | .B U<uid> | |
107 | ). | |
108 | .TP | |
92 | 109 | .IR DUMP |
93 | 110 | MiFare Dump (MFD) used to write (card to MFD) or (MFD to card) |
94 | 111 | .TP |
105 | 122 | .B libnfc |
106 | 123 | issue tracker at: |
107 | 124 | .br |
108 | .BR http://code.google.com/p/libnfc/issues | |
125 | .BR https://github.com/nfc-tools/libnfc/issues | |
109 | 126 | .SH LICENCE |
110 | 127 | .B libnfc |
111 | 128 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | 11 | * Copyright (C) 2011-2013 Adam Laurie |
12 | * Copyright (C) 2018-2019 Danielle Bruneo | |
12 | 13 | * |
13 | 14 | * Redistribution and use in source and binary forms, with or without |
14 | 15 | * modification, are permitted provided that the following conditions are met: |
69 | 70 | static bool bTolerateFailures; |
70 | 71 | static bool bFormatCard; |
71 | 72 | static bool magic2 = false; |
73 | static bool magic3 = false; | |
74 | static bool unlocked = false; | |
72 | 75 | static uint8_t uiBlocks; |
73 | 76 | static uint8_t keys[] = { |
74 | 77 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
96 | 99 | static uint8_t abtRx[MAX_FRAME_LEN]; |
97 | 100 | static int szRxBits; |
98 | 101 | |
99 | uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 }; | |
102 | uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 }; | |
100 | 103 | |
101 | 104 | // special unlock command |
102 | uint8_t abtUnlock1[1] = { 0x40 }; | |
103 | uint8_t abtUnlock2[1] = { 0x43 }; | |
104 | ||
105 | static bool | |
105 | uint8_t abtUnlock1[1] = { 0x40 }; | |
106 | uint8_t abtUnlock2[1] = { 0x43 }; | |
107 | ||
108 | static bool | |
106 | 109 | transmit_bits(const uint8_t *pbtTx, const size_t szTxBits) |
107 | 110 | { |
108 | 111 | // Show transmitted command |
120 | 123 | } |
121 | 124 | |
122 | 125 | |
123 | static bool | |
126 | static bool | |
124 | 127 | transmit_bytes(const uint8_t *pbtTx, const size_t szTx) |
125 | 128 | { |
126 | 129 | // Show transmitted command |
146 | 149 | *uiBlockCounter += 1; |
147 | 150 | } |
148 | 151 | |
149 | static bool | |
152 | static bool | |
150 | 153 | is_first_block(uint32_t uiBlock) |
151 | 154 | { |
152 | 155 | // Test if we are in the small or big sectors |
156 | 159 | return ((uiBlock) % 16 == 0); |
157 | 160 | } |
158 | 161 | |
159 | static bool | |
162 | static bool | |
160 | 163 | is_trailer_block(uint32_t uiBlock) |
161 | 164 | { |
162 | 165 | // Test if we are in the small or big sectors |
166 | 169 | return ((uiBlock + 1) % 16 == 0); |
167 | 170 | } |
168 | 171 | |
169 | static uint32_t | |
172 | static uint32_t | |
170 | 173 | get_trailer_block(uint32_t uiFirstBlock) |
171 | 174 | { |
172 | 175 | // Test if we are in the small or big sectors |
179 | 182 | return trailer_block; |
180 | 183 | } |
181 | 184 | |
182 | static bool | |
185 | static bool | |
183 | 186 | authenticate(uint32_t uiBlock) |
184 | 187 | { |
185 | 188 | mifare_cmd mc; |
186 | uint32_t uiTrailerBlock; | |
187 | 189 | |
188 | 190 | // Set the authentication information (uid) |
189 | 191 | memcpy(mp.mpa.abtAuthUid, nt.nti.nai.abtUid + nt.nti.nai.szUidLen - 4, 4); |
195 | 197 | if (bUseKeyFile) { |
196 | 198 | |
197 | 199 | // Locate the trailer (with the keys) used for this sector |
200 | uint32_t uiTrailerBlock; | |
198 | 201 | uiTrailerBlock = get_trailer_block(uiBlock); |
199 | 202 | |
200 | 203 | // Extract the right key from dump file |
201 | 204 | if (bUseKeyA) |
202 | memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, 6); | |
205 | memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyA, sizeof(mp.mpa.abtKey)); | |
203 | 206 | else |
204 | memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, 6); | |
207 | memcpy(mp.mpa.abtKey, mtKeys.amb[uiTrailerBlock].mbt.abtKeyB, sizeof(mp.mpa.abtKey)); | |
205 | 208 | |
206 | 209 | // Try to authenticate for the current sector |
207 | 210 | if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) |
208 | 211 | return true; |
209 | } | |
210 | ||
211 | // If formatting or not using key file, try to guess the right key | |
212 | if (bFormatCard || !bUseKeyFile) { | |
212 | ||
213 | } else if (magic3) { | |
214 | //If it's a One Time Write card, we're gonna authenticate with the default keys | |
215 | memcpy(mp.mpa.abtKey, default_key, sizeof(default_key)); | |
216 | ||
217 | ||
218 | // Try to authenticate for the current sector | |
219 | if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) { | |
220 | return true; | |
221 | } | |
222 | // If formatting or not using key file, try to guess the right key | |
223 | } else if (bFormatCard || !bUseKeyFile) { | |
213 | 224 | for (size_t key_index = 0; key_index < num_keys; key_index++) { |
214 | 225 | memcpy(mp.mpa.abtKey, keys + (key_index * 6), 6); |
215 | 226 | if (nfc_initiator_mifare_cmd(pnd, mc, uiBlock, &mp)) { |
216 | 227 | if (bUseKeyA) |
217 | memcpy(mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, 6); | |
228 | memcpy(mtKeys.amb[uiBlock].mbt.abtKeyA, &mp.mpa.abtKey, sizeof(mtKeys.amb[uiBlock].mbt.abtKeyA)); | |
218 | 229 | else |
219 | memcpy(mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, 6); | |
230 | memcpy(mtKeys.amb[uiBlock].mbt.abtKeyB, &mp.mpa.abtKey, sizeof(mtKeys.amb[uiBlock].mbt.abtKeyB)); | |
220 | 231 | return true; |
221 | 232 | } |
222 | 233 | if (nfc_initiator_select_passive_target(pnd, nmMifare, nt.nti.nai.abtUid, nt.nti.nai.szUidLen, NULL) <= 0) { |
232 | 243 | static bool |
233 | 244 | unlock_card(void) |
234 | 245 | { |
235 | if (magic2) { | |
236 | printf("Don't use R/W with this card, this is not required!\n"); | |
237 | return false; | |
238 | } | |
239 | ||
240 | 246 | // Configure the CRC |
241 | 247 | if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { |
242 | 248 | nfc_perror(pnd, "nfc_configure"); |
252 | 258 | transmit_bytes(abtHalt, 4); |
253 | 259 | // now send unlock |
254 | 260 | if (!transmit_bits(abtUnlock1, 7)) { |
255 | printf("unlock failure!\n"); | |
256 | return false; | |
257 | } | |
258 | if (!transmit_bytes(abtUnlock2, 1)) { | |
259 | printf("unlock failure!\n"); | |
260 | return false; | |
261 | printf("Warning: Unlock command [1/2]: failed / not acknowledged.\n"); | |
262 | } else { | |
263 | if (transmit_bytes(abtUnlock2, 1)) { | |
264 | printf("Card unlocked\n"); | |
265 | unlocked = true; | |
266 | } else { | |
267 | printf("Warning: Unlock command [2/2]: failed / not acknowledged.\n"); | |
268 | } | |
261 | 269 | } |
262 | 270 | |
263 | 271 | // reset reader |
278 | 286 | get_rats(void) |
279 | 287 | { |
280 | 288 | int res; |
281 | uint8_t abtRats[2] = { 0xe0, 0x50}; | |
289 | uint8_t abtRats[2] = { 0xe0, 0x50}; | |
282 | 290 | // Use raw send/receive methods |
283 | 291 | if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { |
284 | 292 | nfc_perror(pnd, "nfc_configure"); |
306 | 314 | return res; |
307 | 315 | } |
308 | 316 | |
309 | static bool | |
317 | static bool | |
310 | 318 | read_card(int read_unlocked) |
311 | 319 | { |
312 | 320 | int32_t iBlock; |
313 | bool bFailure = false; | |
321 | bool bFailure = false; | |
314 | 322 | uint32_t uiReadBlocks = 0; |
315 | 323 | |
316 | if (read_unlocked) | |
317 | if (!unlock_card()) | |
318 | return false; | |
324 | if (read_unlocked) { | |
325 | //If the user is attempting an unlocked read, but has a direct-write type magic card, they don't | |
326 | //need to use the R mode. We'll trigger a warning and let them proceed. | |
327 | if (magic2) { | |
328 | printf("Note: This card does not require an unlocked read (R) \n"); | |
329 | read_unlocked = 0; | |
330 | } else { | |
331 | //If User has requested an unlocked read, but we're unable to unlock the card, we'll error out. | |
332 | if (!unlock_card()) { | |
333 | return false; | |
334 | } | |
335 | } | |
336 | } | |
319 | 337 | |
320 | 338 | printf("Reading out %d blocks |", uiBlocks + 1); |
321 | 339 | // Read the card from end to begin |
341 | 359 | // Try to read out the trailer |
342 | 360 | if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) { |
343 | 361 | if (read_unlocked) { |
344 | memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16); | |
362 | memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData)); | |
345 | 363 | } else { |
346 | // Copy the keys over from our key dump and store the retrieved access bits | |
347 | memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, 6); | |
348 | memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpd.abtData + 6, 4); | |
349 | memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, 6); | |
364 | //If we're using a One Time Write ('Magic 3') Badge - we'll use default keys + ACL | |
365 | if (magic3) { | |
366 | memcpy(mtDump.amb[iBlock].mbt.abtKeyA, default_key, sizeof(default_key)); | |
367 | memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); | |
368 | memcpy(mtDump.amb[iBlock].mbt.abtKeyB, default_key, sizeof(default_key)); | |
369 | } else { | |
370 | // Copy the keys over from our key dump and store the retrieved access bits | |
371 | memcpy(mtDump.amb[iBlock].mbt.abtKeyA, mtKeys.amb[iBlock].mbt.abtKeyA, sizeof(mtDump.amb[iBlock].mbt.abtKeyA)); | |
372 | memcpy(mtDump.amb[iBlock].mbt.abtAccessBits, mp.mpt.abtAccessBits, sizeof(mtDump.amb[iBlock].mbt.abtAccessBits)); | |
373 | memcpy(mtDump.amb[iBlock].mbt.abtKeyB, mtKeys.amb[iBlock].mbt.abtKeyB, sizeof(mtDump.amb[iBlock].mbt.abtKeyB)); | |
374 | } | |
350 | 375 | } |
351 | 376 | } else { |
352 | 377 | printf("!\nfailed to read trailer block 0x%02x\n", iBlock); |
357 | 382 | if (!bFailure) { |
358 | 383 | // Try to read out the data block |
359 | 384 | if (nfc_initiator_mifare_cmd(pnd, MC_READ, iBlock, &mp)) { |
360 | memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, 16); | |
385 | memcpy(mtDump.amb[iBlock].mbd.abtData, mp.mpd.abtData, sizeof(mtDump.amb[iBlock].mbd.abtData)); | |
361 | 386 | } else { |
362 | 387 | printf("!\nError: unable to read block 0x%02x\n", iBlock); |
363 | 388 | bFailure = true; |
366 | 391 | } |
367 | 392 | // Show if the readout went well for each block |
368 | 393 | print_success_or_failure(bFailure, &uiReadBlocks); |
369 | if ((! bTolerateFailures) && bFailure) | |
394 | if ((!bTolerateFailures) && bFailure) | |
370 | 395 | return false; |
371 | 396 | } |
372 | 397 | printf("|\n"); |
376 | 401 | return true; |
377 | 402 | } |
378 | 403 | |
379 | static bool | |
404 | static bool | |
380 | 405 | write_card(int write_block_zero) |
381 | 406 | { |
382 | 407 | uint32_t uiBlock; |
383 | bool bFailure = false; | |
408 | bool bFailure = false; | |
384 | 409 | uint32_t uiWriteBlocks = 0; |
385 | 410 | |
386 | if (write_block_zero) | |
387 | if (!unlock_card()) | |
388 | return false; | |
411 | //Determine if we have to unlock the card | |
412 | if (write_block_zero) { | |
413 | //If the user is attempting an unlocked write, but has a direct-write type magic card, they don't | |
414 | //need to use the W mode. We'll trigger a warning and let them proceed. | |
415 | if (magic2) { | |
416 | printf("Note: This card does not require an unlocked write (W) \n"); | |
417 | write_block_zero = 0; | |
418 | } else { | |
419 | //If User has requested an unlocked write, but we're unable to unlock the card, we'll error out. | |
420 | if (!unlock_card()) { | |
421 | return false; | |
422 | } | |
423 | } | |
424 | } | |
389 | 425 | |
390 | 426 | printf("Writing %d blocks |", uiBlocks + 1); |
391 | // Write the card from begin to end; | |
392 | for (uiBlock = 0; uiBlock <= uiBlocks; uiBlock++) { | |
427 | // Completely write the card, end to start, but skipping block 0 | |
428 | for (uiBlock = 4; uiBlock <= uiBlocks; uiBlock++) { | |
393 | 429 | // Authenticate everytime we reach the first sector of a new block |
394 | 430 | if (is_first_block(uiBlock)) { |
395 | 431 | if (bFailure) { |
404 | 440 | fflush(stdout); |
405 | 441 | |
406 | 442 | // Try to authenticate for the current sector |
407 | if (!write_block_zero && !authenticate(uiBlock)) { | |
408 | printf("!\nError: authentication failed for block %02x\n", uiBlock); | |
409 | return false; | |
410 | } | |
411 | } | |
412 | ||
413 | if (is_trailer_block(uiBlock)) { | |
414 | if (bFormatCard) { | |
415 | // Copy the default key and reset the access bits | |
416 | memcpy(mp.mpd.abtData, default_key, 6); | |
417 | memcpy(mp.mpd.abtData + 6, default_acl, 4); | |
418 | memcpy(mp.mpd.abtData + 10, default_key, 6); | |
443 | // If we are are writing to a chinese magic card, we've already unlocked | |
444 | // If we're writing to a One Time Write card, we need to authenticate | |
445 | // If we're writing something else, we'll need to authenticate | |
446 | if ((write_block_zero && magic3) || !write_block_zero) { | |
447 | if (!authenticate(uiBlock) && !bTolerateFailures) { | |
448 | printf("!\nError: authentication failed for block %02x\n", uiBlock); | |
449 | return false; | |
450 | } | |
451 | } | |
452 | ||
453 | if (is_trailer_block(uiBlock)) { | |
454 | if (bFormatCard) { | |
455 | // Copy the default key and reset the access bits | |
456 | memcpy(mp.mpt.abtKeyA, default_key, sizeof(mp.mpt.abtKeyA)); | |
457 | memcpy(mp.mpt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits)); | |
458 | memcpy(mp.mpt.abtKeyB, default_key, sizeof(mp.mpt.abtKeyB)); | |
459 | } else { | |
460 | // Copy the keys over from our key dump and store the retrieved access bits | |
461 | memcpy(mp.mpt.abtKeyA, mtDump.amb[uiBlock].mbt.abtKeyA, sizeof(mp.mpt.abtKeyA)); | |
462 | memcpy(mp.mpt.abtAccessBits, mtDump.amb[uiBlock].mbt.abtAccessBits, sizeof(mp.mpt.abtAccessBits)); | |
463 | memcpy(mp.mpt.abtKeyB, mtDump.amb[uiBlock].mbt.abtKeyB, sizeof(mp.mpt.abtKeyB)); | |
464 | } | |
465 | ||
466 | // Try to write the trailer | |
467 | if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) { | |
468 | printf("failed to write trailer block %d \n", uiBlock); | |
469 | bFailure = true; | |
470 | } | |
419 | 471 | } else { |
420 | // Copy the keys over from our key dump and store the retrieved access bits | |
421 | memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbt.abtKeyA, 6); | |
422 | memcpy(mp.mpd.abtData + 6, mtDump.amb[uiBlock].mbt.abtAccessBits, 4); | |
423 | memcpy(mp.mpd.abtData + 10, mtDump.amb[uiBlock].mbt.abtKeyB, 6); | |
424 | } | |
425 | ||
426 | // Try to write the trailer | |
427 | if (nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp) == false) { | |
428 | printf("failed to write trailer block %d \n", uiBlock); | |
429 | bFailure = true; | |
430 | } | |
431 | } else { | |
472 | // The first block 0x00 is read only, skip this | |
473 | if (uiBlock == 0 && !write_block_zero && !magic2) | |
474 | continue; | |
475 | ||
476 | // Make sure a earlier write did not fail | |
477 | if (!bFailure) { | |
478 | // Try to write the data block | |
479 | if (bFormatCard && uiBlock) | |
480 | ||
481 | memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData)); | |
482 | else | |
483 | memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData)); | |
484 | // do not write a block 0 with incorrect BCC - card will be made invalid! | |
485 | if (uiBlock == 0) { | |
486 | if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { | |
487 | printf("!\nError: incorrect BCC in MFD file!\n"); | |
488 | printf("Expecting BCC=%02X\n", mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3]); | |
489 | return false; | |
490 | } | |
491 | } | |
492 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) { | |
493 | bFailure = true; | |
494 | printf("Failure to write to data block %i\n", uiBlock); | |
495 | } | |
496 | ||
497 | } else { | |
498 | printf("Failure during write process.\n"); | |
499 | } | |
500 | } | |
501 | } | |
502 | // Show if the write went well for each block | |
503 | print_success_or_failure(bFailure, &uiWriteBlocks); | |
504 | if ((! bTolerateFailures) && bFailure) | |
505 | return false; | |
506 | } | |
507 | ||
508 | //Write Block 0 if necessary | |
509 | if (write_block_zero || magic2 || magic3) { | |
510 | for (uiBlock = 0; uiBlock < 4; uiBlock++) { | |
511 | ||
432 | 512 | // The first block 0x00 is read only, skip this |
433 | if (uiBlock == 0 && ! write_block_zero && ! magic2) | |
434 | continue; | |
435 | ||
513 | if (uiBlock == 0) { | |
514 | //If the card is not magic, we're gonna skip over | |
515 | if (write_block_zero || magic2 || magic3) { | |
516 | //NOP | |
517 | } else { | |
518 | continue; | |
519 | } | |
520 | } | |
521 | ||
522 | if (is_first_block(uiBlock)) { | |
523 | if (bFailure) { | |
524 | // When a failure occured we need to redo the anti-collision | |
525 | if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { | |
526 | printf("!\nError: tag was removed\n"); | |
527 | return false; | |
528 | } | |
529 | bFailure = false; | |
530 | } | |
531 | ||
532 | fflush(stdout); | |
533 | // Try to authenticate for the current sector | |
534 | // If we are are writing to a chinese magic card, we've already unlocked | |
535 | // If we're writing to a One Time Write, we need to authenticate | |
536 | // If we're writing something else, we'll need to authenticate | |
537 | if ((write_block_zero && magic3) || !write_block_zero) { | |
538 | if (!authenticate(uiBlock) && !bTolerateFailures) { | |
539 | printf("!\nError: authentication failed for block %02x\n", uiBlock); | |
540 | return false; | |
541 | } | |
542 | } | |
543 | } | |
436 | 544 | |
437 | 545 | // Make sure a earlier write did not fail |
438 | 546 | if (!bFailure) { |
439 | 547 | // Try to write the data block |
440 | 548 | if (bFormatCard && uiBlock) |
441 | memset(mp.mpd.abtData, 0x00, 16); | |
549 | memset(mp.mpd.abtData, 0x00, sizeof(mp.mpd.abtData)); | |
442 | 550 | else |
443 | memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, 16); | |
551 | memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData, sizeof(mp.mpd.abtData)); | |
444 | 552 | // do not write a block 0 with incorrect BCC - card will be made invalid! |
445 | 553 | if (uiBlock == 0) { |
446 | 554 | if ((mp.mpd.abtData[0] ^ mp.mpd.abtData[1] ^ mp.mpd.abtData[2] ^ mp.mpd.abtData[3] ^ mp.mpd.abtData[4]) != 0x00 && !magic2) { |
449 | 557 | return false; |
450 | 558 | } |
451 | 559 | } |
452 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) | |
560 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, uiBlock, &mp)) { | |
453 | 561 | bFailure = true; |
454 | } | |
455 | } | |
456 | // Show if the write went well for each block | |
457 | print_success_or_failure(bFailure, &uiWriteBlocks); | |
458 | if ((! bTolerateFailures) && bFailure) | |
459 | return false; | |
460 | } | |
562 | printf("Failure to write to data block %i\n", uiBlock); | |
563 | } | |
564 | ||
565 | } else { | |
566 | printf("Failure during write process.\n"); | |
567 | } | |
568 | ||
569 | // Show if the write went well for each block | |
570 | print_success_or_failure(bFailure, &uiWriteBlocks); | |
571 | if ((! bTolerateFailures) && bFailure) | |
572 | return false; | |
573 | ||
574 | } | |
575 | ||
576 | } | |
577 | ||
461 | 578 | printf("|\n"); |
462 | 579 | printf("Done, %d of %d blocks written.\n", uiWriteBlocks, uiBlocks + 1); |
463 | 580 | fflush(stdout); |
475 | 592 | print_usage(const char *pcProgramName) |
476 | 593 | { |
477 | 594 | printf("Usage: "); |
478 | printf("%s f|r|R|w|W a|b <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName); | |
595 | printf("%s f|r|R|w|W a|b u|U<01ab23cd> <dump.mfd> [<keys.mfd> [f]]\n", pcProgramName); | |
479 | 596 | printf(" f|r|R|w|W - Perform format (f) or read from (r) or unlocked read from (R) or write to (w) or unlocked write to (W) card\n"); |
480 | 597 | printf(" *** format will reset all keys to FFFFFFFFFFFF and all data to 00 and all ACLs to default\n"); |
481 | 598 | printf(" *** unlocked read does not require authentication and will reveal A and B keys\n"); |
482 | 599 | printf(" *** note that unlocked write will attempt to overwrite block 0 including UID\n"); |
483 | 600 | printf(" *** unlocking only works with special Mifare 1K cards (Chinese clones)\n"); |
484 | 601 | printf(" a|A|b|B - Use A or B keys for action; Halt on errors (a|b) or tolerate errors (A|B)\n"); |
602 | printf(" u|U - Use any (u) uid or supply a uid specifically as U01ab23cd.\n"); | |
485 | 603 | printf(" <dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); |
486 | 604 | printf(" <keys.mfd> - MiFare Dump (MFD) that contain the keys (optional)\n"); |
487 | 605 | printf(" f - Force using the keyfile even if UID does not match (optional)\n"); |
606 | ||
488 | 607 | printf("Examples: \n\n"); |
489 | 608 | printf(" Read card to file, using key A:\n\n"); |
490 | printf(" %s r a mycard.mfd\n\n", pcProgramName); | |
609 | printf(" %s r a u mycard.mfd\n\n", pcProgramName); | |
491 | 610 | printf(" Write file to blank card, using key A:\n\n"); |
492 | printf(" %s w a mycard.mfd\n\n", pcProgramName); | |
611 | printf(" %s w a u mycard.mfd\n\n", pcProgramName); | |
493 | 612 | printf(" Write new data and/or keys to previously written card, using key A:\n\n"); |
494 | printf(" %s w a newdata.mfd mycard.mfd\n\n", pcProgramName); | |
613 | printf(" %s w a u newdata.mfd mycard.mfd\n\n", pcProgramName); | |
495 | 614 | printf(" Format/wipe card (note two passes required to ensure writes for all ACL cases):\n\n"); |
496 | printf(" %s f A dummy.mfd keyfile.mfd f\n", pcProgramName); | |
497 | printf(" %s f B dummy.mfd keyfile.mfd f\n\n", pcProgramName); | |
615 | printf(" %s f A u dummy.mfd keyfile.mfd f\n", pcProgramName); | |
616 | printf(" %s f B u dummy.mfd keyfile.mfd f\n\n", pcProgramName); | |
617 | printf(" Read card to file, using key A and uid 0x01 0xab 0x23 0xcd:\n\n"); | |
618 | printf(" %s r a U01ab23cd mycard.mfd\n\n", pcProgramName); | |
619 | } | |
620 | ||
621 | ||
622 | static bool is_directwrite(void) | |
623 | { | |
624 | printf("Checking if Badge is DirectWrite...\n"); | |
625 | ||
626 | // Set default keys | |
627 | memcpy(mtDump.amb[0].mbt.abtKeyA, default_key, sizeof(default_key)); | |
628 | memcpy(mtDump.amb[0].mbt.abtAccessBits, default_acl, sizeof(mp.mpt.abtAccessBits)); | |
629 | memcpy(mtDump.amb[0].mbt.abtKeyB, default_key, sizeof(default_key)); | |
630 | ||
631 | // Temporarly override bUseKeyFile | |
632 | bool orig_bUseKeyFile = bUseKeyFile; | |
633 | bUseKeyFile = false; | |
634 | // Try to authenticate for the current sector | |
635 | if (!authenticate(0)) { | |
636 | printf("!\nError: authentication failed for block 0x%02x\n", 0); | |
637 | bUseKeyFile = orig_bUseKeyFile; | |
638 | return false; | |
639 | } | |
640 | // restore bUseKeyFile | |
641 | bUseKeyFile = orig_bUseKeyFile; | |
642 | ||
643 | // Try to read block 0 | |
644 | uint8_t original_b0[16]; | |
645 | if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) { | |
646 | memcpy(original_b0, mp.mpd.abtData, sizeof(mp.mpd.abtData)); | |
647 | printf(" Original Block 0: "); | |
648 | for (int i = 0; i < 16; i++) { | |
649 | printf("%02x", original_b0[i]); | |
650 | } | |
651 | printf("\n"); | |
652 | printf(" Original UID: %02x%02x%02x%02x\n", | |
653 | original_b0[0], original_b0[1], original_b0[2], original_b0[3]); | |
654 | } else { | |
655 | printf("!\nError: unable to read block 0x%02x\n", 0); | |
656 | return false; | |
657 | } | |
658 | ||
659 | printf(" Attempt to write Block 0 ...\n"); | |
660 | memcpy(mp.mpd.abtData, original_b0, sizeof(original_b0)); | |
661 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, 0, &mp)) { | |
662 | printf("Failure to write to data block %i\n", 0); | |
663 | return false; | |
664 | } | |
665 | printf(" Block 0 written successfully\n"); | |
666 | ||
667 | return true; | |
498 | 668 | } |
499 | 669 | |
500 | 670 | int |
502 | 672 | { |
503 | 673 | action_t atAction = ACTION_USAGE; |
504 | 674 | uint8_t *pbtUID; |
675 | uint8_t _tag_uid[4]; | |
676 | uint8_t *tag_uid = _tag_uid; | |
677 | ||
505 | 678 | int unlock = 0; |
506 | 679 | |
507 | 680 | if (argc < 2) { |
510 | 683 | } |
511 | 684 | const char *command = argv[1]; |
512 | 685 | |
686 | if (argc < 5) { | |
687 | print_usage(argv[0]); | |
688 | exit(EXIT_FAILURE); | |
689 | } | |
513 | 690 | if (strcmp(command, "r") == 0 || strcmp(command, "R") == 0) { |
514 | if (argc < 4) { | |
515 | print_usage(argv[0]); | |
516 | exit(EXIT_FAILURE); | |
517 | } | |
518 | 691 | atAction = ACTION_READ; |
519 | 692 | if (strcmp(command, "R") == 0) |
520 | 693 | unlock = 1; |
521 | 694 | bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; |
522 | 695 | bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); |
523 | bUseKeyFile = (argc > 4); | |
524 | bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); | |
696 | bUseKeyFile = (argc > 5); | |
697 | bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0)); | |
525 | 698 | } else if (strcmp(command, "w") == 0 || strcmp(command, "W") == 0 || strcmp(command, "f") == 0) { |
526 | if (argc < 4) { | |
527 | print_usage(argv[0]); | |
528 | exit(EXIT_FAILURE); | |
529 | } | |
530 | 699 | atAction = ACTION_WRITE; |
531 | 700 | if (strcmp(command, "W") == 0) |
532 | 701 | unlock = 1; |
533 | 702 | bFormatCard = (strcmp(command, "f") == 0); |
534 | 703 | bUseKeyA = tolower((int)((unsigned char) * (argv[2]))) == 'a'; |
535 | 704 | bTolerateFailures = tolower((int)((unsigned char) * (argv[2]))) != (int)((unsigned char) * (argv[2])); |
536 | bUseKeyFile = (argc > 4); | |
537 | bForceKeyFile = ((argc > 5) && (strcmp((char *)argv[5], "f") == 0)); | |
705 | bUseKeyFile = (argc > 5); | |
706 | bForceKeyFile = ((argc > 6) && (strcmp((char *)argv[6], "f") == 0)); | |
707 | } | |
708 | if (argv[3][0] == 'U') { | |
709 | unsigned long int _uid; | |
710 | ||
711 | if (strlen(argv[3]) != 9) { | |
712 | printf("Error, illegal tag specification, use U01ab23cd for example.\n"); | |
713 | print_usage(argv[0]); | |
714 | exit(EXIT_FAILURE); | |
715 | } | |
716 | _uid = strtoul(argv[3] + 1, NULL, 16); | |
717 | tag_uid[0] = (_uid & 0xff000000UL) >> 24; | |
718 | tag_uid[1] = (_uid & 0x00ff0000UL) >> 16; | |
719 | tag_uid[2] = (_uid & 0x0000ff00UL) >> 8; | |
720 | tag_uid[3] = (_uid & 0x000000ffUL); | |
721 | printf("Attempting to use specific UID: 0x%2x 0x%2x 0x%2x 0x%2x\n", | |
722 | tag_uid[0], tag_uid[1], tag_uid[2], tag_uid[3]); | |
723 | } else { | |
724 | tag_uid = NULL; | |
538 | 725 | } |
539 | 726 | |
540 | 727 | if (atAction == ACTION_USAGE) { |
543 | 730 | } |
544 | 731 | // We don't know yet the card size so let's read only the UID from the keyfile for the moment |
545 | 732 | if (bUseKeyFile) { |
546 | FILE *pfKeys = fopen(argv[4], "rb"); | |
733 | FILE *pfKeys = fopen(argv[5], "rb"); | |
547 | 734 | if (pfKeys == NULL) { |
548 | printf("Could not open keys file: %s\n", argv[4]); | |
735 | printf("Could not open keys file: %s\n", argv[5]); | |
549 | 736 | exit(EXIT_FAILURE); |
550 | 737 | } |
551 | 738 | if (fread(&mtKeys, 1, 4, pfKeys) != 4) { |
552 | printf("Could not read UID from key file: %s\n", argv[4]); | |
739 | printf("Could not read UID from key file: %s\n", argv[5]); | |
553 | 740 | fclose(pfKeys); |
554 | 741 | exit(EXIT_FAILURE); |
555 | 742 | } |
594 | 781 | printf("NFC reader: %s opened\n", nfc_device_get_name(pnd)); |
595 | 782 | |
596 | 783 | // Try to find a MIFARE Classic tag |
597 | if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { | |
784 | int tags; | |
785 | ||
786 | tags = nfc_initiator_select_passive_target(pnd, nmMifare, tag_uid, tag_uid == NULL ? 0 : 4, &nt); | |
787 | if (tags <= 0) { | |
598 | 788 | printf("Error: no tag was found\n"); |
599 | 789 | nfc_close(pnd); |
600 | 790 | nfc_exit(context); |
617 | 807 | fileUid[0], fileUid[1], fileUid[2], fileUid[3]); |
618 | 808 | printf("Got card with UID starting as: %02x%02x%02x%02x\n", |
619 | 809 | pbtUID[0], pbtUID[1], pbtUID[2], pbtUID[3]); |
620 | if (! bForceKeyFile) { | |
810 | if (!bForceKeyFile) { | |
621 | 811 | printf("Aborting!\n"); |
622 | 812 | nfc_close(pnd); |
623 | 813 | nfc_exit(context); |
629 | 819 | print_nfc_target(&nt, false); |
630 | 820 | |
631 | 821 | // Guessing size |
632 | if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02) | |
822 | if ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x02 || nt.nti.nai.btSak == 0x18) | |
633 | 823 | // 4K |
634 | 824 | uiBlocks = 0xff; |
635 | else if ((nt.nti.nai.btSak & 0x01) == 0x01) | |
825 | else if (nt.nti.nai.btSak == 0x09) | |
636 | 826 | // 320b |
637 | 827 | uiBlocks = 0x13; |
638 | 828 | else |
641 | 831 | // Testing RATS |
642 | 832 | int res; |
643 | 833 | if ((res = get_rats()) > 0) { |
834 | printf("RATS support: yes\n"); | |
644 | 835 | if ((res >= 10) && (abtRx[5] == 0xc1) && (abtRx[6] == 0x05) |
645 | 836 | && (abtRx[7] == 0x2f) && (abtRx[8] == 0x2f) |
646 | 837 | && ((nt.nti.nai.abtAtqa[1] & 0x02) == 0x00)) { |
652 | 843 | && (abtRx[7] == 0x19) && (abtRx[8] == 0x10)) { |
653 | 844 | magic2 = true; |
654 | 845 | } |
655 | } | |
656 | printf("Guessing size: seems to be a %i-byte card\n", (uiBlocks + 1) * 16); | |
846 | } else | |
847 | printf("RATS support: no\n"); | |
848 | printf("Guessing size: seems to be a %lu-byte card\n", (unsigned long)((uiBlocks + 1) * sizeof(mifare_classic_block))); | |
849 | ||
850 | //If size is 4k check for direct-write card | |
851 | if (uiBlocks == 0xff) { | |
852 | if (is_directwrite()) { | |
853 | printf("Card is DirectWrite\n"); | |
854 | magic3 = true; | |
855 | unlock = 0; | |
856 | } else { | |
857 | printf("Card is not DirectWrite\n"); | |
858 | } | |
859 | } | |
860 | ||
861 | //Check to see if we have a One Time Write badge (magic3) | |
862 | if (pbtUID[0] == 0xaa && pbtUID[1] == 0x55 && | |
863 | pbtUID[2] == 0xc3 && pbtUID[3] == 0x96) { | |
864 | printf("Card appears to be a One Time Write Card..\n"); | |
865 | magic3 = true; | |
866 | unlock = 0; | |
867 | } | |
868 | ||
657 | 869 | |
658 | 870 | if (bUseKeyFile) { |
659 | FILE *pfKeys = fopen(argv[4], "rb"); | |
871 | FILE *pfKeys = fopen(argv[5], "rb"); | |
660 | 872 | if (pfKeys == NULL) { |
661 | printf("Could not open keys file: %s\n", argv[4]); | |
873 | printf("Could not open keys file: %s\n", argv[5]); | |
662 | 874 | exit(EXIT_FAILURE); |
663 | 875 | } |
664 | 876 | if (fread(&mtKeys, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfKeys) != (uiBlocks + 1) * sizeof(mifare_classic_block)) { |
665 | printf("Could not read keys file: %s\n", argv[4]); | |
877 | printf("Could not read keys file: %s\n", argv[5]); | |
666 | 878 | fclose(pfKeys); |
667 | 879 | exit(EXIT_FAILURE); |
668 | 880 | } |
672 | 884 | if (atAction == ACTION_READ) { |
673 | 885 | memset(&mtDump, 0x00, sizeof(mtDump)); |
674 | 886 | } else { |
675 | FILE *pfDump = fopen(argv[3], "rb"); | |
887 | FILE *pfDump = fopen(argv[4], "rb"); | |
676 | 888 | |
677 | 889 | if (pfDump == NULL) { |
678 | printf("Could not open dump file: %s\n", argv[3]); | |
890 | printf("Could not open dump file: %s\n", argv[4]); | |
679 | 891 | exit(EXIT_FAILURE); |
680 | 892 | |
681 | 893 | } |
682 | 894 | |
683 | 895 | if (fread(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != (uiBlocks + 1) * sizeof(mifare_classic_block)) { |
684 | printf("Could not read dump file: %s\n", argv[3]); | |
896 | printf("Could not read dump file: %s\n", argv[4]); | |
685 | 897 | fclose(pfDump); |
686 | 898 | exit(EXIT_FAILURE); |
687 | 899 | } |
691 | 903 | |
692 | 904 | if (atAction == ACTION_READ) { |
693 | 905 | if (read_card(unlock)) { |
694 | printf("Writing data to file: %s ...", argv[3]); | |
906 | printf("Writing data to file: %s ...", argv[4]); | |
695 | 907 | fflush(stdout); |
696 | FILE *pfDump = fopen(argv[3], "wb"); | |
908 | FILE *pfDump = fopen(argv[4], "wb"); | |
697 | 909 | if (pfDump == NULL) { |
698 | printf("Could not open dump file: %s\n", argv[3]); | |
910 | printf("Could not open dump file: %s\n", argv[4]); | |
699 | 911 | nfc_close(pnd); |
700 | 912 | nfc_exit(context); |
701 | 913 | exit(EXIT_FAILURE); |
702 | 914 | } |
703 | 915 | if (fwrite(&mtDump, 1, (uiBlocks + 1) * sizeof(mifare_classic_block), pfDump) != ((uiBlocks + 1) * sizeof(mifare_classic_block))) { |
704 | printf("\nCould not write to file: %s\n", argv[3]); | |
916 | printf("\nCould not write to file: %s\n", argv[4]); | |
705 | 917 | fclose(pfDump); |
706 | 918 | nfc_close(pnd); |
707 | 919 | nfc_exit(context); |
38 | 38 | .B libnfc |
39 | 39 | issue tracker at: |
40 | 40 | .br |
41 | .BR http://code.google.com/p/libnfc/issues | |
41 | .BR https://github.com/nfc-tools/libnfc/issues | |
42 | 42 | .SH LICENCE |
43 | 43 | .B libnfc |
44 | 44 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
4 | 4 | * Copyright (C) 2009 Roel Verdult |
5 | 5 | * Copyright (C) 2009-2013 Romuald Conty |
6 | 6 | * Copyright (C) 2010-2012 Romain Tartière |
7 | * Copyright (C) 2010-2013 Philippe Teuwen | |
7 | * Copyright (C) 2010-2017 Philippe Teuwen | |
8 | 8 | * Copyright (C) 2012-2013 Ludovic Rousseau |
9 | 9 | * See AUTHORS file for a more comprehensive list of contributors. |
10 | 10 | * Additional contributors of this file: |
11 | * Copyright (C) 2013 Adam Laurie | |
11 | * Copyright (C) 2013-2018 Adam Laurie | |
12 | * Copyright (C) 2018-2019 Daniele Bruneo | |
12 | 13 | * |
13 | 14 | * Redistribution and use in source and binary forms, with or without |
14 | 15 | * modification, are permitted provided that the following conditions are met: |
57 | 58 | #include "nfc-utils.h" |
58 | 59 | #include "mifare.h" |
59 | 60 | |
61 | #define MAX_TARGET_COUNT 16 | |
62 | #define MAX_UID_LEN 10 | |
63 | ||
64 | #define EV1_NONE 0 | |
65 | #define EV1_UL11 1 | |
66 | #define EV1_UL21 2 | |
67 | ||
68 | #define NTAG_NONE 0 | |
69 | #define NTAG_213 1 | |
70 | #define NTAG_215 2 | |
71 | #define NTAG_216 3 | |
72 | ||
60 | 73 | static nfc_device *pnd; |
61 | 74 | static nfc_target nt; |
62 | 75 | static mifare_param mp; |
63 | static mifareul_tag mtDump; | |
64 | static uint32_t uiBlocks = 0xF; | |
76 | static maxtag mtDump; // use the largest tag type for internal storage | |
77 | static uint32_t uiBlocks = 0x10; | |
78 | static uint32_t uiReadPages = 0; | |
79 | static uint8_t iPWD[4] = { 0x0 }; | |
80 | static uint8_t iPACK[2] = { 0x0 }; | |
81 | static uint8_t iEV1Type = EV1_NONE; | |
82 | static uint8_t iNTAGType = NTAG_NONE; | |
83 | ||
84 | // special unlock command | |
85 | uint8_t abtUnlock1[1] = { 0x40 }; | |
86 | uint8_t abtUnlock2[1] = { 0x43 }; | |
87 | ||
88 | // EV1 commands | |
89 | uint8_t abtEV1[3] = { 0x60, 0x00, 0x00 }; | |
90 | uint8_t abtPWAuth[7] = { 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | |
91 | ||
92 | //Halt command | |
93 | uint8_t abtHalt[4] = { 0x50, 0x00, 0x00, 0x00 }; | |
94 | ||
95 | #define MAX_FRAME_LEN 264 | |
96 | ||
97 | static uint8_t abtRx[MAX_FRAME_LEN]; | |
98 | static int szRxBits; | |
99 | static int szRx; | |
65 | 100 | |
66 | 101 | static const nfc_modulation nmMifare = { |
67 | 102 | .nmt = NMT_ISO14443A, |
69 | 104 | }; |
70 | 105 | |
71 | 106 | static void |
72 | print_success_or_failure(bool bFailure, uint32_t *uiCounter) | |
73 | { | |
74 | printf("%c", (bFailure) ? 'x' : '.'); | |
75 | if (uiCounter) | |
76 | *uiCounter += (bFailure) ? 0 : 1; | |
107 | print_success_or_failure(bool bFailure, uint32_t *uiOkCounter, uint32_t *uiFailedCounter) | |
108 | { | |
109 | printf("%c", (bFailure) ? 'f' : '.'); | |
110 | if (uiOkCounter) | |
111 | *uiOkCounter += (bFailure) ? 0 : 1; | |
112 | if (uiFailedCounter) | |
113 | *uiFailedCounter += (bFailure) ? 1 : 0; | |
77 | 114 | } |
78 | 115 | |
79 | 116 | static bool |
81 | 118 | { |
82 | 119 | uint32_t page; |
83 | 120 | bool bFailure = false; |
84 | uint32_t uiReadedPages = 0; | |
85 | ||
86 | printf("Reading %d pages |", uiBlocks + 1); | |
87 | ||
88 | for (page = 0; page <= uiBlocks; page += 4) { | |
121 | uint32_t uiFailedPages = 0; | |
122 | ||
123 | printf("Reading %d pages |", uiBlocks); | |
124 | ||
125 | for (page = 0; page < uiBlocks; page += 4) { | |
89 | 126 | // Try to read out the data block |
90 | 127 | if (nfc_initiator_mifare_cmd(pnd, MC_READ, page, &mp)) { |
91 | memcpy(mtDump.amb[page / 4].mbd.abtData, mp.mpd.abtData, 16); | |
128 | memcpy(mtDump.ul[page / 4].mbd.abtData, mp.mpd.abtData, uiBlocks - page < 4 ? (uiBlocks - page) * 4 : 16); | |
92 | 129 | } else { |
93 | 130 | bFailure = true; |
131 | } | |
132 | for (uint8_t i = 0; i < (uiBlocks - page < 4 ? uiBlocks - page : 4); i++) { | |
133 | print_success_or_failure(bFailure, &uiReadPages, &uiFailedPages); | |
134 | } | |
135 | } | |
136 | printf("|\n"); | |
137 | printf("Done, %d of %d pages read (%d pages failed).\n", uiReadPages, uiBlocks, uiFailedPages); | |
138 | fflush(stdout); | |
139 | ||
140 | // copy EV1 secrets to dump data | |
141 | switch (iEV1Type) { | |
142 | case EV1_UL11: | |
143 | memcpy(mtDump.ul[4].mbc11.pwd, iPWD, 4); | |
144 | memcpy(mtDump.ul[4].mbc11.pack, iPACK, 2); | |
94 | 145 | break; |
95 | } | |
96 | ||
97 | print_success_or_failure(bFailure, &uiReadedPages); | |
98 | print_success_or_failure(bFailure, &uiReadedPages); | |
99 | print_success_or_failure(bFailure, &uiReadedPages); | |
100 | print_success_or_failure(bFailure, &uiReadedPages); | |
101 | } | |
102 | printf("|\n"); | |
103 | printf("Done, %d of %d pages readed.\n", uiReadedPages, uiBlocks + 1); | |
104 | fflush(stdout); | |
146 | case EV1_UL21: | |
147 | memcpy(mtDump.ul[9].mbc21a.pwd, iPWD, 4); | |
148 | memcpy(mtDump.ul[9].mbc21b.pack, iPACK, 2); | |
149 | break; | |
150 | case EV1_NONE: | |
151 | default: | |
152 | break; | |
153 | } | |
154 | // copy NTAG secrets to dump data | |
155 | switch (iNTAGType) { | |
156 | case NTAG_213: | |
157 | memcpy(mtDump.nt[43].mbc21356d.pwd, iPWD, 4); | |
158 | memcpy(mtDump.nt[44].mbc21356e.pack, iPACK, 2); | |
159 | break; | |
160 | case NTAG_215: | |
161 | memcpy(mtDump.nt[133].mbc21356d.pwd, iPWD, 4); | |
162 | memcpy(mtDump.nt[134].mbc21356e.pack, iPACK, 2); | |
163 | break; | |
164 | case NTAG_216: | |
165 | memcpy(mtDump.nt[229].mbc21356d.pwd, iPWD, 4); | |
166 | memcpy(mtDump.nt[230].mbc21356e.pack, iPACK, 2); | |
167 | break; | |
168 | case NTAG_NONE: | |
169 | default: | |
170 | break; | |
171 | } | |
105 | 172 | |
106 | 173 | return (!bFailure); |
107 | 174 | } |
108 | 175 | |
109 | 176 | static bool |
110 | write_card(void) | |
177 | transmit_bits(const uint8_t *pbtTx, const size_t szTxBits) | |
178 | { | |
179 | // Transmit the bit frame command, we don't use the arbitrary parity feature | |
180 | if ((szRxBits = nfc_initiator_transceive_bits(pnd, pbtTx, szTxBits, NULL, abtRx, sizeof(abtRx), NULL)) < 0) | |
181 | return false; | |
182 | ||
183 | return true; | |
184 | } | |
185 | ||
186 | ||
187 | static bool | |
188 | transmit_bytes(const uint8_t *pbtTx, const size_t szTx) | |
189 | { | |
190 | if ((szRx = nfc_initiator_transceive_bytes(pnd, pbtTx, szTx, abtRx, sizeof(abtRx), 0)) < 0) | |
191 | return false; | |
192 | ||
193 | return true; | |
194 | } | |
195 | ||
196 | static bool | |
197 | raw_mode_start(void) | |
198 | { | |
199 | // Configure the CRC | |
200 | if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, false) < 0) { | |
201 | nfc_perror(pnd, "nfc_configure"); | |
202 | return false; | |
203 | } | |
204 | // Use raw send/receive methods | |
205 | if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, false) < 0) { | |
206 | nfc_perror(pnd, "nfc_configure"); | |
207 | return false; | |
208 | } | |
209 | return true; | |
210 | } | |
211 | ||
212 | static bool | |
213 | raw_mode_end(void) | |
214 | { | |
215 | // reset reader | |
216 | // Configure the CRC | |
217 | if (nfc_device_set_property_bool(pnd, NP_HANDLE_CRC, true) < 0) { | |
218 | nfc_perror(pnd, "nfc_device_set_property_bool"); | |
219 | return false; | |
220 | } | |
221 | // Switch off raw send/receive methods | |
222 | if (nfc_device_set_property_bool(pnd, NP_EASY_FRAMING, true) < 0) { | |
223 | nfc_perror(pnd, "nfc_device_set_property_bool"); | |
224 | return false; | |
225 | } | |
226 | return true; | |
227 | } | |
228 | ||
229 | static bool | |
230 | get_ev1_version(void) | |
231 | { | |
232 | if (!raw_mode_start()) | |
233 | return false; | |
234 | iso14443a_crc_append(abtEV1, 1); | |
235 | if (!transmit_bytes(abtEV1, 3)) { | |
236 | raw_mode_end(); | |
237 | return false; | |
238 | } | |
239 | if (!raw_mode_end()) | |
240 | return false; | |
241 | if (!szRx) | |
242 | return false; | |
243 | return true; | |
244 | } | |
245 | ||
246 | static bool | |
247 | ev1_load_pwd(uint8_t target[4], const char *pwd) | |
248 | { | |
249 | unsigned int tmp[4]; | |
250 | if (sscanf(pwd, "%2x%2x%2x%2x", &tmp[0], &tmp[1], &tmp[2], &tmp[3]) != 4) | |
251 | return false; | |
252 | target[0] = tmp[0]; | |
253 | target[1] = tmp[1]; | |
254 | target[2] = tmp[2]; | |
255 | target[3] = tmp[3]; | |
256 | return true; | |
257 | } | |
258 | ||
259 | static bool | |
260 | ev1_pwd_auth(uint8_t *pwd) | |
261 | { | |
262 | if (!raw_mode_start()) | |
263 | return false; | |
264 | memcpy(&abtPWAuth[1], pwd, 4); | |
265 | iso14443a_crc_append(abtPWAuth, 5); | |
266 | if (!transmit_bytes(abtPWAuth, 7)) | |
267 | return false; | |
268 | if (!raw_mode_end()) | |
269 | return false; | |
270 | return true; | |
271 | } | |
272 | ||
273 | static bool | |
274 | unlock_card(void) | |
275 | { | |
276 | if (!raw_mode_start()) | |
277 | return false; | |
278 | iso14443a_crc_append(abtHalt, 2); | |
279 | transmit_bytes(abtHalt, 4); | |
280 | // now send unlock | |
281 | if (!transmit_bits(abtUnlock1, 7)) { | |
282 | return false; | |
283 | } | |
284 | if (!transmit_bytes(abtUnlock2, 1)) { | |
285 | return false; | |
286 | } | |
287 | ||
288 | if (!raw_mode_end()) | |
289 | return false; | |
290 | return true; | |
291 | } | |
292 | ||
293 | static bool check_magic(void) | |
294 | { | |
295 | bool directWrite = true; | |
296 | // Try to read pages 0, 1, 2 | |
297 | uint8_t original_b0[12]; | |
298 | printf("Checking if UL badge is DirectWrite...\n"); | |
299 | if (nfc_initiator_mifare_cmd(pnd, MC_READ, 0, &mp)) { | |
300 | memcpy(original_b0, mp.mpd.abtData, 12); | |
301 | printf(" Original Block 0 (Pages 0-2): "); | |
302 | for (int i = 0; i < 12; i++) { | |
303 | printf("%02x", original_b0[i]); | |
304 | } | |
305 | printf("\n"); | |
306 | printf(" Original UID: %02x%02x%02x%02x%02x%02x%02x\n", | |
307 | original_b0[0], original_b0[1], original_b0[2], original_b0[4], original_b0[5], original_b0[6], original_b0[7]); | |
308 | } else { | |
309 | printf("!\nError: unable to read block 0x%02x\n", 0); | |
310 | directWrite = false; | |
311 | } | |
312 | printf(" Attempt to write Block 0 (pages 0-2) ...\n"); | |
313 | for (uint32_t page = 0; page <= 2; page++) { | |
314 | printf(" Writing Page %i:", page); | |
315 | memcpy(mp.mpd.abtData, original_b0 + page * 4, 4); | |
316 | for (int i = 0; i < 4; i++) { | |
317 | printf(" %02x", mp.mpd.abtData[i]); | |
318 | } | |
319 | printf("\n"); | |
320 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp)) { | |
321 | printf(" Failure writing Page %i\n", page); | |
322 | directWrite = false; | |
323 | break; | |
324 | } | |
325 | } | |
326 | if (directWrite) { | |
327 | printf(" Block 0 written successfully\n"); | |
328 | printf("Card is DirectWrite\n"); | |
329 | return true; | |
330 | } else { | |
331 | printf("Card is not DirectWrite\n"); | |
332 | return unlock_card(); | |
333 | } | |
334 | ||
335 | } | |
336 | ||
337 | static bool | |
338 | write_card(bool write_otp, bool write_lock, bool write_dyn_lock, bool write_uid) | |
111 | 339 | { |
112 | 340 | uint32_t uiBlock = 0; |
113 | 341 | bool bFailure = false; |
114 | uint32_t uiWritenPages = 0; | |
342 | uint32_t uiWrittenPages = 0; | |
115 | 343 | uint32_t uiSkippedPages = 0; |
344 | uint32_t uiFailedPages = 0; | |
116 | 345 | |
117 | 346 | char buffer[BUFSIZ]; |
118 | bool write_otp; | |
119 | bool write_lock; | |
120 | bool write_uid; | |
121 | ||
122 | printf("Write OTP bytes ? [yN] "); | |
123 | if (!fgets(buffer, BUFSIZ, stdin)) { | |
124 | ERR("Unable to read standard input."); | |
125 | } | |
126 | write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y')); | |
127 | printf("Write Lock bytes ? [yN] "); | |
128 | if (!fgets(buffer, BUFSIZ, stdin)) { | |
129 | ERR("Unable to read standard input."); | |
130 | } | |
131 | write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y')); | |
132 | printf("Write UID bytes (only for special writeable UID cards) ? [yN] "); | |
133 | if (!fgets(buffer, BUFSIZ, stdin)) { | |
134 | ERR("Unable to read standard input."); | |
135 | } | |
136 | write_uid = ((buffer[0] == 'y') || (buffer[0] == 'Y')); | |
137 | ||
138 | printf("Writing %d pages |", uiBlocks + 1); | |
347 | ||
348 | if (!write_otp) { | |
349 | printf("Write OTP/Capability Bytes ? [yN] "); | |
350 | if (!fgets(buffer, BUFSIZ, stdin)) { | |
351 | ERR("Unable to read standard input."); | |
352 | } | |
353 | write_otp = ((buffer[0] == 'y') || (buffer[0] == 'Y')); | |
354 | } | |
355 | ||
356 | // Lock Bytes are OTP if set, so warn | |
357 | if (!write_lock) { | |
358 | printf("Write Lock Bytes (Warning: OTP if set) ? [yN] "); | |
359 | if (!fgets(buffer, BUFSIZ, stdin)) { | |
360 | ERR("Unable to read standard input."); | |
361 | } | |
362 | write_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y')); | |
363 | } | |
364 | ||
365 | // NTAG and MF0UL21 have additional lock bytes | |
366 | if (!write_dyn_lock && (iNTAGType != NTAG_NONE || iEV1Type == EV1_UL21)) { | |
367 | printf("Write Dynamic Lock Bytes ? [yN] "); | |
368 | if (!fgets(buffer, BUFSIZ, stdin)) { | |
369 | ERR("Unable to read standard input."); | |
370 | } | |
371 | write_dyn_lock = ((buffer[0] == 'y') || (buffer[0] == 'Y')); | |
372 | } | |
373 | ||
374 | if (!write_uid) { | |
375 | printf("Write UID bytes (only for special writeable UID cards) ? [yN] "); | |
376 | if (!fgets(buffer, BUFSIZ, stdin)) { | |
377 | ERR("Unable to read standard input."); | |
378 | } | |
379 | write_uid = ((buffer[0] == 'y') || (buffer[0] == 'Y')); | |
380 | } | |
381 | ||
139 | 382 | /* We may need to skip 2 first pages. */ |
140 | 383 | if (!write_uid) { |
384 | printf("Writing %d pages |", uiBlocks); | |
141 | 385 | printf("ss"); |
142 | 386 | uiSkippedPages = 2; |
143 | } | |
144 | ||
145 | for (int page = uiSkippedPages; page <= 0xF; page++) { | |
146 | if ((page == 0x2) && (!write_lock)) { | |
387 | } else { | |
388 | if (!check_magic()) { | |
389 | printf("\nUnable to unlock card - are you sure the card is magic?\n"); | |
390 | return false; | |
391 | } | |
392 | printf("Writing %d pages |", uiBlocks); | |
393 | } | |
394 | ||
395 | for (uint32_t page = uiSkippedPages; page < uiBlocks; page++) { | |
396 | if ((!write_lock) && page == 0x2) { | |
147 | 397 | printf("s"); |
148 | 398 | uiSkippedPages++; |
149 | 399 | continue; |
150 | 400 | } |
401 | // OTP/Capability blocks | |
151 | 402 | if ((page == 0x3) && (!write_otp)) { |
152 | 403 | printf("s"); |
153 | 404 | uiSkippedPages++; |
154 | 405 | continue; |
155 | 406 | } |
156 | // Show if the readout went well | |
407 | // NTAG and MF0UL21 have Dynamic Lock Bytes | |
408 | if (((iEV1Type == EV1_UL21 && page == 0x24) || \ | |
409 | (iNTAGType == NTAG_213 && page == 0x28) || \ | |
410 | (iNTAGType == NTAG_215 && page == 0x82) || \ | |
411 | (iNTAGType == NTAG_216 && page == 0xe2)) && (!write_dyn_lock)) { | |
412 | printf("s"); | |
413 | uiSkippedPages++; | |
414 | continue; | |
415 | } | |
416 | // Check if the previous readout went well | |
157 | 417 | if (bFailure) { |
158 | 418 | // When a failure occured we need to redo the anti-collision |
159 | 419 | if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { |
167 | 427 | // page (4 bytes). The Ultralight-specific Write command only |
168 | 428 | // writes one page at a time. |
169 | 429 | uiBlock = page / 4; |
170 | memcpy(mp.mpd.abtData, mtDump.amb[uiBlock].mbd.abtData + ((page % 4) * 4), 16); | |
430 | memcpy(mp.mpd.abtData, mtDump.ul[uiBlock].mbd.abtData + ((page % 4) * 4), 4); | |
431 | memset(mp.mpd.abtData + 4, 0, 12); | |
171 | 432 | if (!nfc_initiator_mifare_cmd(pnd, MC_WRITE, page, &mp)) |
172 | 433 | bFailure = true; |
173 | ||
174 | print_success_or_failure(bFailure, &uiWritenPages); | |
434 | print_success_or_failure(bFailure, &uiWrittenPages, &uiFailedPages); | |
175 | 435 | } |
176 | 436 | printf("|\n"); |
177 | printf("Done, %d of %d pages written (%d pages skipped).\n", uiWritenPages, uiBlocks + 1, uiSkippedPages); | |
178 | ||
179 | return true; | |
437 | printf("Done, %d of %d pages written (%d pages skipped, %d pages failed).\n", uiWrittenPages, uiBlocks, uiSkippedPages, uiFailedPages); | |
438 | ||
439 | return true; | |
440 | } | |
441 | ||
442 | static int list_passive_targets(nfc_device *_pnd) | |
443 | { | |
444 | int res = 0; | |
445 | ||
446 | nfc_target ant[MAX_TARGET_COUNT]; | |
447 | ||
448 | if (nfc_initiator_init(_pnd) < 0) { | |
449 | return -EXIT_FAILURE; | |
450 | } | |
451 | ||
452 | if ((res = nfc_initiator_list_passive_targets(_pnd, nmMifare, ant, MAX_TARGET_COUNT)) >= 0) { | |
453 | int i; | |
454 | ||
455 | if (res > 0) | |
456 | printf("%d ISO14443A passive target(s) found:\n", res); | |
457 | ||
458 | for (i = 0; i < res; i++) { | |
459 | size_t szPos; | |
460 | ||
461 | printf("\t"); | |
462 | for (szPos = 0; szPos < ant[i].nti.nai.szUidLen; szPos++) { | |
463 | printf("%02x", ant[i].nti.nai.abtUid[szPos]); | |
464 | } | |
465 | printf("\n"); | |
466 | } | |
467 | ||
468 | } | |
469 | ||
470 | return 0; | |
471 | } | |
472 | ||
473 | static size_t str_to_uid(const char *str, uint8_t *uid) | |
474 | { | |
475 | uint8_t i; | |
476 | ||
477 | memset(uid, 0x0, MAX_UID_LEN); | |
478 | i = 0; | |
479 | while ((*str != '\0') && ((i >> 1) < MAX_UID_LEN)) { | |
480 | char nibble[2] = { 0x00, '\n' }; /* for strtol */ | |
481 | ||
482 | nibble[0] = *str++; | |
483 | if (isxdigit(nibble[0])) { | |
484 | if (isupper(nibble[0])) | |
485 | nibble[0] = tolower(nibble[0]); | |
486 | uid[i >> 1] |= strtol(nibble, NULL, 16) << ((i % 2) ? 0 : 4) & ((i % 2) ? 0x0f : 0xf0); | |
487 | i++; | |
488 | } | |
489 | } | |
490 | return i >> 1; | |
491 | } | |
492 | ||
493 | static void | |
494 | print_usage(const char *argv[]) | |
495 | { | |
496 | printf("Usage: %s r|w <dump.mfd> [OPTIONS]\n", argv[0]); | |
497 | printf("Arguments:\n"); | |
498 | printf("\tr|w - Perform read or write\n"); | |
499 | printf("\t<dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); | |
500 | printf("Options:\n"); | |
501 | printf("\t--otp - Don't prompt for OTP Bytes writing (Assume yes)\n"); | |
502 | printf("\t--lock - Don't prompt for Lock Bytes (OTP) writing (Assume yes)\n"); | |
503 | printf("\t--dynlock - Don't prompt for Dynamic Lock Bytes writing (Assume yes)\n"); | |
504 | printf("\t--uid - Don't prompt for UID writing (Assume yes)\n"); | |
505 | printf("\t--full - Assume full card write (UID + OTP + Lockbytes + Dynamic Lockbytes)\n"); | |
506 | printf("\t--with-uid <UID> - Specify UID to read/write from\n"); | |
507 | printf("\t--pw <PWD> - Specify 8 HEX digit PASSWORD for EV1\n"); | |
508 | printf("\t--partial - Allow source data size to be other than tag capacity\n"); | |
180 | 509 | } |
181 | 510 | |
182 | 511 | int |
183 | 512 | main(int argc, const char *argv[]) |
184 | 513 | { |
185 | bool bReadAction; | |
514 | int iAction = 0; | |
515 | size_t iDumpSize = sizeof(mifareul_tag); | |
516 | uint8_t iUID[MAX_UID_LEN] = { 0x0 }; | |
517 | size_t szUID = 0; | |
518 | bool bOTP = false; | |
519 | bool bLock = false; | |
520 | bool bDynLock = false; | |
521 | bool bUID = false; | |
522 | bool bPWD = false; | |
523 | bool bPart = false; | |
524 | bool bFilename = false; | |
186 | 525 | FILE *pfDump; |
187 | 526 | |
188 | if (argc < 3) { | |
189 | printf("\n"); | |
190 | printf("%s r|w <dump.mfd>\n", argv[0]); | |
191 | printf("\n"); | |
192 | printf("r|w - Perform read from or write to card\n"); | |
193 | printf("<dump.mfd> - MiFare Dump (MFD) used to write (card to MFD) or (MFD to card)\n"); | |
194 | printf("\n"); | |
527 | if (argc == 0) { | |
528 | print_usage(argv); | |
195 | 529 | exit(EXIT_FAILURE); |
196 | 530 | } |
197 | 531 | |
198 | 532 | DBG("\nChecking arguments and settings\n"); |
199 | 533 | |
200 | bReadAction = tolower((int)((unsigned char) * (argv[1])) == 'r'); | |
201 | ||
202 | if (bReadAction) { | |
203 | memset(&mtDump, 0x00, sizeof(mtDump)); | |
204 | } else { | |
205 | pfDump = fopen(argv[2], "rb"); | |
206 | ||
207 | if (pfDump == NULL) { | |
208 | ERR("Could not open dump file: %s\n", argv[2]); | |
209 | exit(EXIT_FAILURE); | |
210 | } | |
211 | ||
212 | if (fread(&mtDump, 1, sizeof(mtDump), pfDump) != sizeof(mtDump)) { | |
213 | ERR("Could not read from dump file: %s\n", argv[2]); | |
214 | fclose(pfDump); | |
215 | exit(EXIT_FAILURE); | |
216 | } | |
217 | fclose(pfDump); | |
218 | } | |
219 | DBG("Successfully opened the dump file\n"); | |
534 | // Get commandline options | |
535 | for (int arg = 1; arg < argc; arg++) { | |
536 | if (0 == strcmp(argv[arg], "r")) { | |
537 | iAction = 1; | |
538 | } else if (0 == strcmp(argv[arg], "w")) { | |
539 | iAction = 2; | |
540 | } else if (0 == strcmp(argv[arg], "--with-uid")) { | |
541 | if (arg + 1 == argc) { | |
542 | ERR("Please supply a UID of 4, 7 or 10 bytes long. Ex: a1:b2:c3:d4"); | |
543 | exit(EXIT_FAILURE); | |
544 | } | |
545 | szUID = str_to_uid(argv[++arg], iUID); | |
546 | } else if (0 == strcmp(argv[arg], "--full")) { | |
547 | bOTP = true; | |
548 | bLock = true; | |
549 | bDynLock = true; | |
550 | bUID = true; | |
551 | } else if (0 == strcmp(argv[arg], "--otp")) { | |
552 | bOTP = true; | |
553 | } else if (0 == strcmp(argv[arg], "--lock")) { | |
554 | bLock = true; | |
555 | } else if (0 == strcmp(argv[arg], "--dynlock")) { | |
556 | bDynLock = true; | |
557 | } else if (0 == strcmp(argv[arg], "--uid")) { | |
558 | bUID = true; | |
559 | } else if (0 == strcmp(argv[arg], "--check-magic")) { | |
560 | iAction = 3; | |
561 | } else if (0 == strcmp(argv[arg], "--partial")) { | |
562 | bPart = true; | |
563 | } else if (0 == strcmp(argv[arg], "--pw")) { | |
564 | bPWD = true; | |
565 | if (arg + 1 == argc || strlen(argv[++arg]) != 8 || ! ev1_load_pwd(iPWD, argv[arg])) { | |
566 | ERR("Please supply a PASSWORD of 8 HEX digits"); | |
567 | exit(EXIT_FAILURE); | |
568 | } | |
569 | } else { | |
570 | //Skip validation of the filename | |
571 | if (arg != 2) { | |
572 | ERR("%s is not a supported option.", argv[arg]); | |
573 | print_usage(argv); | |
574 | exit(EXIT_FAILURE); | |
575 | } else { | |
576 | bFilename = true; | |
577 | } | |
578 | } | |
579 | } | |
580 | if (iAction != 3 && !bFilename) { | |
581 | ERR("Please supply a Mifare Dump filename"); | |
582 | exit(EXIT_FAILURE); | |
583 | } | |
220 | 584 | |
221 | 585 | nfc_context *context; |
222 | 586 | nfc_init(&context); |
232 | 596 | nfc_exit(context); |
233 | 597 | exit(EXIT_FAILURE); |
234 | 598 | } |
599 | printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); | |
600 | ||
601 | if (list_passive_targets(pnd)) { | |
602 | nfc_perror(pnd, "nfc_device_set_property_bool"); | |
603 | nfc_close(pnd); | |
604 | nfc_exit(context); | |
605 | exit(EXIT_FAILURE); | |
606 | } | |
235 | 607 | |
236 | 608 | if (nfc_initiator_init(pnd) < 0) { |
237 | 609 | nfc_perror(pnd, "nfc_initiator_init"); |
248 | 620 | exit(EXIT_FAILURE); |
249 | 621 | } |
250 | 622 | |
251 | printf("NFC device: %s opened\n", nfc_device_get_name(pnd)); | |
252 | ||
253 | 623 | // Try to find a MIFARE Ultralight tag |
254 | if (nfc_initiator_select_passive_target(pnd, nmMifare, NULL, 0, &nt) <= 0) { | |
624 | if (nfc_initiator_select_passive_target(pnd, nmMifare, (szUID) ? iUID : NULL, szUID, &nt) <= 0) { | |
255 | 625 | ERR("no tag was found\n"); |
256 | 626 | nfc_close(pnd); |
257 | 627 | nfc_exit(context); |
258 | 628 | exit(EXIT_FAILURE); |
259 | 629 | } |
630 | ||
260 | 631 | // Test if we are dealing with a MIFARE compatible tag |
261 | ||
262 | 632 | if (nt.nti.nai.abtAtqa[1] != 0x44) { |
263 | 633 | ERR("tag is not a MIFARE Ultralight card\n"); |
264 | 634 | nfc_close(pnd); |
266 | 636 | exit(EXIT_FAILURE); |
267 | 637 | } |
268 | 638 | // Get the info from the current tag |
269 | printf("Found MIFARE Ultralight card with UID: "); | |
639 | printf("Using MIFARE Ultralight card with UID: "); | |
270 | 640 | size_t szPos; |
271 | 641 | for (szPos = 0; szPos < nt.nti.nai.szUidLen; szPos++) { |
272 | 642 | printf("%02x", nt.nti.nai.abtUid[szPos]); |
273 | 643 | } |
274 | 644 | printf("\n"); |
275 | 645 | |
276 | if (bReadAction) { | |
277 | if (read_card()) { | |
278 | printf("Writing data to file: %s ... ", argv[2]); | |
279 | fflush(stdout); | |
280 | pfDump = fopen(argv[2], "wb"); | |
281 | if (pfDump == NULL) { | |
282 | printf("Could not open file: %s\n", argv[2]); | |
283 | nfc_close(pnd); | |
284 | nfc_exit(context); | |
285 | exit(EXIT_FAILURE); | |
286 | } | |
287 | if (fwrite(&mtDump, 1, sizeof(mtDump), pfDump) != sizeof(mtDump)) { | |
288 | printf("Could not write to file: %s\n", argv[2]); | |
289 | fclose(pfDump); | |
290 | nfc_close(pnd); | |
291 | nfc_exit(context); | |
292 | exit(EXIT_FAILURE); | |
293 | } | |
646 | // test if tag is EV1 or NTAG | |
647 | if (get_ev1_version()) { | |
648 | if (!bPWD) | |
649 | printf("WARNING: Tag is EV1 or NTAG - PASSWORD may be required\n"); | |
650 | if (abtRx[6] == 0x0b || abtRx[6] == 0x00) { | |
651 | printf("EV1 type: MF0UL11 (48 bytes)\n"); | |
652 | uiBlocks = 20; // total number of 4 byte 'pages' | |
653 | iDumpSize = uiBlocks * 4; | |
654 | iEV1Type = EV1_UL11; | |
655 | } else if (abtRx[6] == 0x0e) { | |
656 | printf("EV1 type: MF0UL21 (128 user bytes)\n"); | |
657 | uiBlocks = 41; | |
658 | iDumpSize = uiBlocks * 4; | |
659 | iEV1Type = EV1_UL21; | |
660 | } else if (abtRx[6] == 0x0f) { | |
661 | printf("NTAG Type: NTAG213 (144 user bytes)\n"); | |
662 | uiBlocks = 45; | |
663 | iDumpSize = uiBlocks * 4; | |
664 | iNTAGType = NTAG_213; | |
665 | } else if (abtRx[6] == 0x11) { | |
666 | printf("NTAG Type: NTAG215 (504 user bytes)\n"); | |
667 | uiBlocks = 135; | |
668 | iDumpSize = uiBlocks * 4; | |
669 | iNTAGType = NTAG_215; | |
670 | } else if (abtRx[6] == 0x13) { | |
671 | printf("NTAG Type: NTAG216 (888 user bytes)\n"); | |
672 | uiBlocks = 231; | |
673 | iDumpSize = uiBlocks * 4; | |
674 | iNTAGType = NTAG_216; | |
675 | } else { | |
676 | printf("unknown! (0x%02x)\n", abtRx[6]); | |
677 | exit(EXIT_FAILURE); | |
678 | } | |
679 | } else { | |
680 | // re-init non EV1 tag | |
681 | if (nfc_initiator_select_passive_target(pnd, nmMifare, (szUID) ? iUID : NULL, szUID, &nt) <= 0) { | |
682 | ERR("no tag was found\n"); | |
683 | nfc_close(pnd); | |
684 | nfc_exit(context); | |
685 | exit(EXIT_FAILURE); | |
686 | } | |
687 | } | |
688 | ||
689 | // EV1 login required | |
690 | if (bPWD) { | |
691 | printf("Authing with PWD: %02x%02x%02x%02x ", iPWD[0], iPWD[1], iPWD[2], iPWD[3]); | |
692 | if (!ev1_pwd_auth(iPWD)) { | |
693 | printf("\n"); | |
694 | ERR("AUTH failed!\n"); | |
695 | exit(EXIT_FAILURE); | |
696 | } else { | |
697 | printf("Success - PACK: %02x%02x\n", abtRx[0], abtRx[1]); | |
698 | memcpy(iPACK, abtRx, 2); | |
699 | } | |
700 | } | |
701 | ||
702 | if (iAction == 1) { | |
703 | memset(&mtDump, 0x00, sizeof(mtDump)); | |
704 | } else if (iAction == 2) { | |
705 | pfDump = fopen(argv[2], "rb"); | |
706 | ||
707 | if (pfDump == NULL) { | |
708 | ERR("Could not open dump file: %s\n", argv[2]); | |
709 | exit(EXIT_FAILURE); | |
710 | } | |
711 | ||
712 | size_t szDump; | |
713 | if (((szDump = fread(&mtDump, 1, sizeof(mtDump), pfDump)) != iDumpSize && !bPart) || szDump <= 0) { | |
714 | ERR("Could not read from dump file or size mismatch: %s (read %lu, expected %lu)\n", argv[2], (unsigned long)szDump, (unsigned long)iDumpSize); | |
294 | 715 | fclose(pfDump); |
295 | printf("Done.\n"); | |
296 | } | |
716 | exit(EXIT_FAILURE); | |
717 | } | |
718 | if (szDump != iDumpSize) | |
719 | printf("Performing partial write\n"); | |
720 | fclose(pfDump); | |
721 | DBG("Successfully opened the dump file\n"); | |
722 | } else if (iAction == 3) { | |
723 | DBG("Switching to Check Magic Mode\n"); | |
297 | 724 | } else { |
298 | write_card(); | |
725 | ERR("Unable to determine operating mode"); | |
726 | exit(EXIT_FAILURE); | |
727 | } | |
728 | ||
729 | if (iAction == 1) { | |
730 | bool bRF = read_card(); | |
731 | printf("Writing data to file: %s ... ", argv[2]); | |
732 | fflush(stdout); | |
733 | pfDump = fopen(argv[2], "wb"); | |
734 | if (pfDump == NULL) { | |
735 | printf("Could not open file: %s\n", argv[2]); | |
736 | nfc_close(pnd); | |
737 | nfc_exit(context); | |
738 | exit(EXIT_FAILURE); | |
739 | } | |
740 | if (fwrite(&mtDump, 1, uiReadPages * 4, pfDump) != uiReadPages * 4) { | |
741 | printf("Could not write to file: %s\n", argv[2]); | |
742 | fclose(pfDump); | |
743 | nfc_close(pnd); | |
744 | nfc_exit(context); | |
745 | exit(EXIT_FAILURE); | |
746 | } | |
747 | fclose(pfDump); | |
748 | printf("Done.\n"); | |
749 | if (!bRF) | |
750 | printf("Warning! Read failed - partial data written to file!\n"); | |
751 | } else if (iAction == 2) { | |
752 | write_card(bOTP, bLock, bDynLock, bUID); | |
753 | } else if (iAction == 3) { | |
754 | if (!check_magic()) { | |
755 | printf("Card is not magic\n"); | |
756 | nfc_close(pnd); | |
757 | nfc_exit(context); | |
758 | exit(EXIT_FAILURE); | |
759 | } else { | |
760 | printf("Card is magic\n"); | |
761 | } | |
299 | 762 | } |
300 | 763 | |
301 | 764 | nfc_close(pnd); |
29 | 29 | .B libnfc |
30 | 30 | issue tracker at: |
31 | 31 | .br |
32 | .BR http://code.google.com/p/libnfc/issues | |
32 | .BR https://github.com/nfc-tools/libnfc/issues | |
33 | 33 | .SH LICENCE |
34 | 34 | .B libnfc |
35 | 35 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
177 | 177 | case 'h': |
178 | 178 | print_usage(argv[0]); |
179 | 179 | exit(EXIT_SUCCESS); |
180 | break; | |
181 | 180 | case 'q': |
182 | 181 | quiet = true; |
183 | 182 | break; |
33 | 33 | Commands are read from file descriptor 3 |
34 | 34 | Responses are sent to file descriptor 4 |
35 | 35 | |
36 | \fB-s\fP | |
37 | Swap roles of found devices | |
38 | Usually the first found device is used as target (emulator) and the second | |
39 | as initiator (reader). Using this option these roles are inversed. | |
40 | ||
36 | 41 | \fB-n\fP \fIN\fP |
37 | 42 | Adds a waiting time of \fIN\fP seconds (integer) in the loop |
38 | 43 | |
64 | 69 | .B libnfc |
65 | 70 | issue tracker at: |
66 | 71 | .br |
67 | .BR http://code.google.com/p/libnfc/issues | |
72 | .BR https://github.com/nfc-tools/libnfc/issues | |
68 | 73 | .SH LICENCE |
69 | 74 | .B libnfc |
70 | 75 | is licensed under the GNU Lesser General Public License (LGPL), version 3. |
98 | 98 | printf("\t-q\tQuiet mode. Suppress printing of relayed data (improves timing).\n"); |
99 | 99 | printf("\t-t\tTarget mode only (the one on reader side). Data expected from FD3 to FD4.\n"); |
100 | 100 | printf("\t-i\tInitiator mode only (the one on tag side). Data expected from FD3 to FD4.\n"); |
101 | printf("\t-s\tSwap roles of found devices.\n"); | |
101 | 102 | printf("\t-n N\tAdds a waiting time of N seconds (integer) in the relay to mimic long distance.\n"); |
102 | 103 | } |
103 | 104 | |
225 | 226 | nfc_exit(context); |
226 | 227 | exit(EXIT_FAILURE); |
227 | 228 | } |
228 | if ((fd4 = fdopen(4, "r")) == NULL) { | |
229 | if ((fd4 = fdopen(4, "w")) == NULL) { | |
229 | 230 | ERR("Could not open file descriptor 4"); |
230 | 231 | nfc_exit(context); |
231 | 232 | exit(EXIT_FAILURE); |