Rearrange source code.
This commit is contained in:
parent
be1639b452
commit
c7d77d7664
59 changed files with 43 additions and 107 deletions
49
libnfc/CMakeLists.txt
Normal file
49
libnfc/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Library's chips
|
||||
SET(CHIPS_SOURCES chips/pn53x)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/chips)
|
||||
|
||||
# Library's buses
|
||||
SET(BUSES_SOURCES buses/uart)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/buses)
|
||||
|
||||
# Library's drivers
|
||||
SET(DRIVERS_SOURCES drivers/arygon drivers/pn532_uart)
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/drivers)
|
||||
|
||||
## find PCSC library and headers
|
||||
IF(LIBNFC_PCSC)
|
||||
FIND_PACKAGE(PCSC REQUIRED)
|
||||
ADD_DEFINITIONS("-DHAVE_PCSC_LITE=1")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PCSC_CFLAGS_OTHER}")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/acr122")
|
||||
ENDIF(LIBNFC_PCSC)
|
||||
|
||||
## find libusb library and headers
|
||||
IF(LIBNFC_USB)
|
||||
FIND_PACKAGE(LIBUSB REQUIRED)
|
||||
ADD_DEFINITIONS("-DHAVE_LIBUSB=1")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBUSB_CFLAGS_OTHER}")
|
||||
SET(DRIVERS_SOURCES ${DRIVERS_SOURCES} "drivers/pn531_usb" "drivers/pn533_usb" "drivers/pn53x_usb.c")
|
||||
ENDIF(LIBNFC_USB)
|
||||
|
||||
INCLUDE_DIRECTORIES(${LIBUSB_INCLUDE_DIRS} ${PCSC_INCLUDE_DIRS})
|
||||
LINK_DIRECTORIES(${LIBUSB_LIBRARY_DIRS} ${PCSC_LIBRARY_DIRS})
|
||||
|
||||
# Library
|
||||
SET(LIBRARY_SOURCES nfc bitutils ${DRIVERS_SOURCES} ${BUSES_SOURCES} ${CHIPS_SOURCES})
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
ADD_LIBRARY(nfc SHARED ${LIBRARY_SOURCES})
|
||||
TARGET_LINK_LIBRARIES(nfc ${LIBUSB_LIBRARIES} ${PCSC_LIBRARIES})
|
||||
SET_TARGET_PROPERTIES(nfc PROPERTIES SOVERSION 0)
|
||||
|
||||
IF(MSVC)
|
||||
# On Windows the shared (runtime) library should be either in the same
|
||||
# directory as the excutables or in the path, we add it to same directory
|
||||
INSTALL(TARGETS nfc RUNTIME DESTINATION bin COMPONENT libraries)
|
||||
|
||||
# At compile time we need the .LIB file, we place it in the lib directory
|
||||
INSTALL(TARGETS nfc ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT headers)
|
||||
ELSE(MSVC)
|
||||
INSTALL(TARGETS nfc LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries)
|
||||
ENDIF(MSVC)
|
||||
|
||||
25
libnfc/Makefile.am
Normal file
25
libnfc/Makefile.am
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
SUBDIRS = chips buses drivers .
|
||||
|
||||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = libnfc.la
|
||||
libnfc_la_SOURCES = nfc.c bitutils.c
|
||||
libnfc_la_LDFLAGS = -no-undefined -version-info=0:0:0
|
||||
libnfc_la_CFLAGS =
|
||||
libnfc_la_LIBADD = \
|
||||
$(top_builddir)/libnfc/chips/libnfcchips.la \
|
||||
$(top_builddir)/libnfc/buses/libnfcbuses.la \
|
||||
$(top_builddir)/libnfc/drivers/libnfcdrivers.la
|
||||
|
||||
if PCSC_LITE_ENABLED
|
||||
libnfc_la_CFLAGS += @LIBPCSCLITE_CFLAGS@ -DHAVE_PCSC_LITE
|
||||
libnfc_la_LIBADD += @LIBPCSCLITE_LIBS@
|
||||
endif
|
||||
|
||||
if LIBUSB_ENABLED
|
||||
libnfc_la_CFLAGS += @LIBUSB_CFLAGS@ -DHAVE_LIBUSB
|
||||
libnfc_la_LIBADD += @LIBUSB_LIBS@
|
||||
endif
|
||||
|
||||
EXTRA_DIST = CMakeLists.txt chips.h buses.h drivers.h bitutils.h
|
||||
214
libnfc/bitutils.c
Normal file
214
libnfc/bitutils.c
Normal file
|
|
@ -0,0 +1,214 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file bitutils.c
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bitutils.h"
|
||||
|
||||
const static byte_t OddParity[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||
};
|
||||
|
||||
const static byte_t ByteMirror[256] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30,
|
||||
0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98,
|
||||
0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64,
|
||||
0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc,
|
||||
0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02,
|
||||
0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2,
|
||||
0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a,
|
||||
0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e,
|
||||
0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81,
|
||||
0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71,
|
||||
0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
|
||||
0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15,
|
||||
0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad,
|
||||
0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43,
|
||||
0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b,
|
||||
0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97,
|
||||
0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f,
|
||||
0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
|
||||
};
|
||||
|
||||
byte_t oddparity(const byte_t bt)
|
||||
{
|
||||
return OddParity[bt];
|
||||
}
|
||||
|
||||
void oddparity_bytes(const byte_t* pbtData, const size_t szLen, byte_t* pbtPar)
|
||||
{
|
||||
size_t szByteNr;
|
||||
|
||||
// Calculate the parity bits for the command
|
||||
for (szByteNr=0; szByteNr<szLen; szByteNr++)
|
||||
{
|
||||
pbtPar[szByteNr] = OddParity[pbtData[szByteNr]];
|
||||
}
|
||||
}
|
||||
|
||||
byte_t mirror(byte_t bt)
|
||||
{
|
||||
return ByteMirror[bt];
|
||||
}
|
||||
|
||||
void mirror_bytes(byte_t *pbts, size_t szLen)
|
||||
{
|
||||
size_t szByteNr;
|
||||
|
||||
for (szByteNr=0; szByteNr<szLen; szByteNr++)
|
||||
{
|
||||
*pbts = ByteMirror[*pbts];
|
||||
pbts++;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t mirror32(uint32_t ui32Bits)
|
||||
{
|
||||
mirror_bytes((byte_t*)&ui32Bits,4);
|
||||
return ui32Bits;
|
||||
}
|
||||
|
||||
uint64_t mirror64(uint64_t ui64Bits)
|
||||
{
|
||||
mirror_bytes((byte_t*)&ui64Bits,8);
|
||||
return ui64Bits;
|
||||
}
|
||||
|
||||
uint32_t swap_endian32(const void* pui32)
|
||||
{
|
||||
uint32_t ui32N = *((uint32_t*)pui32);
|
||||
return (((ui32N&0xFF)<<24)+((ui32N&0xFF00)<<8)+((ui32N&0xFF0000)>>8)+((ui32N&0xFF000000)>>24));
|
||||
}
|
||||
|
||||
uint64_t swap_endian64(const void* pui64)
|
||||
{
|
||||
uint64_t ui64N = *((uint64_t *)pui64);
|
||||
return (((ui64N&0xFF)<<56)+((ui64N&0xFF00)<<40)+((ui64N&0xFF0000)<<24)+((ui64N&0xFF000000)<<8)+((ui64N&0xFF00000000ull)>>8)+((ui64N&0xFF0000000000ull)>>24)+((ui64N&0xFF000000000000ull)>>40)+((ui64N&0xFF00000000000000ull)>>56));
|
||||
}
|
||||
|
||||
void iso14443a_crc(byte_t* pbtData, size_t szLen, byte_t* pbtCrc)
|
||||
{
|
||||
byte_t bt;
|
||||
uint32_t wCrc = 0x6363;
|
||||
|
||||
do {
|
||||
bt = *pbtData++;
|
||||
bt = (bt^(byte_t)(wCrc & 0x00FF));
|
||||
bt = (bt^(bt<<4));
|
||||
wCrc = (wCrc >> 8)^((uint32_t)bt << 8)^((uint32_t)bt<<3)^((uint32_t)bt>>4);
|
||||
} while (--szLen);
|
||||
|
||||
*pbtCrc++ = (byte_t) (wCrc & 0xFF);
|
||||
*pbtCrc = (byte_t) ((wCrc >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
void append_iso14443a_crc(byte_t* pbtData, size_t szLen)
|
||||
{
|
||||
iso14443a_crc(pbtData, szLen, pbtData + szLen);
|
||||
}
|
||||
|
||||
void print_hex(const byte_t* pbtData, const size_t szBytes)
|
||||
{
|
||||
size_t szPos;
|
||||
|
||||
for (szPos=0; szPos < szBytes; szPos++)
|
||||
{
|
||||
printf("%02x ",pbtData[szPos]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_hex_bits(const byte_t* pbtData, const size_t szBits)
|
||||
{
|
||||
uint8_t uRemainder;
|
||||
size_t szPos;
|
||||
size_t szBytes = szBits/8;
|
||||
|
||||
for (szPos=0; szPos < szBytes; szPos++)
|
||||
{
|
||||
printf("%02x ",pbtData[szPos]);
|
||||
}
|
||||
|
||||
uRemainder = szBits % 8;
|
||||
// Print the rest bits
|
||||
if (uRemainder != 0)
|
||||
{
|
||||
if (uRemainder < 5)
|
||||
printf("%01x (%d bits)",pbtData[szBytes], uRemainder);
|
||||
else
|
||||
printf("%02x (%d bits)",pbtData[szBytes], uRemainder);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbtDataPar)
|
||||
{
|
||||
uint8_t uRemainder;
|
||||
size_t szPos;
|
||||
size_t szBytes = szBits/8;
|
||||
|
||||
for (szPos=0; szPos < szBytes; szPos++)
|
||||
{
|
||||
printf("%02x",pbtData[szPos]);
|
||||
if (OddParity[pbtData[szPos]] != pbtDataPar[szPos])
|
||||
{
|
||||
printf("! ");
|
||||
} else {
|
||||
printf(" ");
|
||||
}
|
||||
}
|
||||
|
||||
uRemainder = szBits % 8;
|
||||
// Print the rest bits, these cannot have parity bit
|
||||
if (uRemainder != 0)
|
||||
{
|
||||
if (uRemainder < 5)
|
||||
printf("%01x (%d bits)",pbtData[szBytes], uRemainder);
|
||||
else
|
||||
printf("%02x (%d bits)",pbtData[szBytes], uRemainder);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
62
libnfc/bitutils.h
Normal file
62
libnfc/bitutils.h
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file bitutils.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef _LIBNFC_BITUTILS_H_
|
||||
#define _LIBNFC_BITUTILS_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
/*
|
||||
* FIXME: There is no place for this here
|
||||
*/
|
||||
#if defined (_WIN32)
|
||||
#if defined(nfc_EXPORTS)
|
||||
#define NFC_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define NFC_EXPORT __declspec(dllimport)
|
||||
#endif /* nfc_EXPORTS */
|
||||
#else /* defined (_WIN32) */
|
||||
#define NFC_EXPORT
|
||||
#endif
|
||||
|
||||
byte_t oddparity(const byte_t bt);
|
||||
void oddparity_byte_ts(const byte_t* pbtData, const size_t szLen, byte_t* pbtPar);
|
||||
|
||||
NFC_EXPORT byte_t mirror(byte_t bt);
|
||||
NFC_EXPORT uint32_t mirror32(uint32_t ui32Bits);
|
||||
NFC_EXPORT uint64_t mirror64(uint64_t ui64Bits);
|
||||
NFC_EXPORT void mirror_byte_ts(byte_t *pbts, size_t szLen);
|
||||
|
||||
NFC_EXPORT uint32_t swap_endian32(const void* pui32);
|
||||
NFC_EXPORT uint64_t swap_endian64(const void* pui64);
|
||||
|
||||
NFC_EXPORT void append_iso14443a_crc(byte_t* pbtData, size_t szLen);
|
||||
|
||||
NFC_EXPORT void print_hex(const byte_t* pbtData, const size_t szLen);
|
||||
NFC_EXPORT void print_hex_bits(const byte_t* pbtData, const size_t szBits);
|
||||
NFC_EXPORT void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbtDataPar);
|
||||
|
||||
#endif // _LIBNFC_BITUTILS_H_
|
||||
|
||||
25
libnfc/buses.h
Normal file
25
libnfc/buses.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file buses.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
9
libnfc/buses/Makefile.am
Normal file
9
libnfc/buses/Makefile.am
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
||||
|
||||
noinst_HEADERS = uart.h
|
||||
noinst_LTLIBRARIES = libnfcbuses.la
|
||||
libnfcbuses_la_SOURCES = uart.c
|
||||
libnfcbuses_la_CFLAGS = -I$(top_srcdir)/libnfc
|
||||
|
||||
415
libnfc/buses/uart.c
Normal file
415
libnfc/buses/uart.c
Normal file
|
|
@ -0,0 +1,415 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file uart.c
|
||||
* @brief UART driver
|
||||
*
|
||||
* This file contains 2 implementations of UART driver: first for POSIX systems, second for Windows system.
|
||||
*/
|
||||
|
||||
/*
|
||||
Based on RS232 code written by Teunis van Beelen available:
|
||||
http://www.teuniz.net/RS-232/index.html
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include "uart.h"
|
||||
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
// Test if we are dealing with unix operating systems
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <sys/select.h>
|
||||
#include <termios.h>
|
||||
typedef struct termios term_info;
|
||||
typedef struct {
|
||||
int fd; // Serial port file descriptor
|
||||
term_info tiOld; // Terminal info before using the port
|
||||
term_info tiNew; // Terminal info during the transaction
|
||||
} serial_port_unix;
|
||||
|
||||
// Set time-out on 30 miliseconds
|
||||
const struct timeval timeout = {
|
||||
.tv_sec = 0, // 0 second
|
||||
.tv_usec = 30000 // 30000 micro seconds
|
||||
};
|
||||
|
||||
// Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
|
||||
#define CCLAIMED 0x80000000
|
||||
|
||||
serial_port uart_open(const char* pcPortName)
|
||||
{
|
||||
serial_port_unix* sp = malloc(sizeof(serial_port_unix));
|
||||
|
||||
if (sp == 0) return INVALID_SERIAL_PORT;
|
||||
|
||||
sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if(sp->fd == -1)
|
||||
{
|
||||
uart_close(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
if(tcgetattr(sp->fd,&sp->tiOld) == -1)
|
||||
{
|
||||
uart_close(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
// Make sure the port is not claimed already
|
||||
if (sp->tiOld.c_iflag & CCLAIMED)
|
||||
{
|
||||
uart_close(sp);
|
||||
return CLAIMED_SERIAL_PORT;
|
||||
}
|
||||
|
||||
// Copy the old terminal info struct
|
||||
sp->tiNew = sp->tiOld;
|
||||
|
||||
sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
|
||||
sp->tiNew.c_iflag = CCLAIMED | IGNPAR;
|
||||
sp->tiNew.c_oflag = 0;
|
||||
sp->tiNew.c_lflag = 0;
|
||||
|
||||
sp->tiNew.c_cc[VMIN] = 0; // block until n bytes are received
|
||||
sp->tiNew.c_cc[VTIME] = 0; // block until a timer expires (n * 100 mSec.)
|
||||
|
||||
if(tcsetattr(sp->fd,TCSANOW,&sp->tiNew) == -1)
|
||||
{
|
||||
uart_close(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
tcflush(sp->fd, TCIFLUSH);
|
||||
return sp;
|
||||
}
|
||||
|
||||
void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
|
||||
{
|
||||
DBG("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
|
||||
// Set port speed (Input and Output)
|
||||
|
||||
// Portability note: on some systems, B9600 != 9600 so we have to do
|
||||
// uint32_t <=> speed_t associations by hand.
|
||||
speed_t stPortSpeed = B9600;
|
||||
switch(uiPortSpeed) {
|
||||
case 9600: stPortSpeed = B9600;
|
||||
break;
|
||||
case 19200: stPortSpeed = B19200;
|
||||
break;
|
||||
case 38400: stPortSpeed = B38400;
|
||||
break;
|
||||
#ifdef B57600
|
||||
case 57600: stPortSpeed = B57600;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B115200
|
||||
case 115200: stPortSpeed = B115200;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B230400
|
||||
case 230400: stPortSpeed = B230400;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B460800
|
||||
case 460800: stPortSpeed = B460800;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
ERR("Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).", uiPortSpeed);
|
||||
};
|
||||
const serial_port_unix* spu = (serial_port_unix*)sp;
|
||||
cfsetispeed((struct termios*)&spu->tiNew, stPortSpeed);
|
||||
cfsetospeed((struct termios*)&spu->tiNew, stPortSpeed);
|
||||
if( tcsetattr(spu->fd, TCSADRAIN, &spu->tiNew) == -1)
|
||||
{
|
||||
ERR("%s", "Unable to apply new speed settings.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t uart_get_speed(const serial_port sp)
|
||||
{
|
||||
uint32_t uiPortSpeed = 0;
|
||||
const serial_port_unix* spu = (serial_port_unix*)sp;
|
||||
switch (cfgetispeed(&spu->tiNew))
|
||||
{
|
||||
case B9600: uiPortSpeed = 9600;
|
||||
break;
|
||||
case B19200: uiPortSpeed = 19200;
|
||||
break;
|
||||
case B38400: uiPortSpeed = 38400;
|
||||
break;
|
||||
#ifdef B57600
|
||||
case B57600: uiPortSpeed = 57600;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B115200
|
||||
case B115200: uiPortSpeed = 115200;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B230400
|
||||
case B230400: uiPortSpeed = 230400;
|
||||
break;
|
||||
#endif
|
||||
#ifdef B460800
|
||||
case B460800: uiPortSpeed = 460800;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
return uiPortSpeed;
|
||||
}
|
||||
|
||||
void uart_close(const serial_port sp)
|
||||
{
|
||||
if (((serial_port_unix*)sp)->fd >= 0) {
|
||||
tcsetattr(((serial_port_unix*)sp)->fd,TCSANOW,&((serial_port_unix*)sp)->tiOld);
|
||||
close(((serial_port_unix*)sp)->fd);
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
|
||||
bool uart_cts(const serial_port sp)
|
||||
{
|
||||
char status;
|
||||
if (ioctl(((serial_port_unix*)sp)->fd,TIOCMGET,&status) < 0) return false;
|
||||
return (status & TIOCM_CTS);
|
||||
}
|
||||
|
||||
bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen)
|
||||
{
|
||||
int res;
|
||||
int byteCount;
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
|
||||
// Reset the output count
|
||||
*pszRxLen = 0;
|
||||
|
||||
do {
|
||||
// Reset file descriptor
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(((serial_port_unix*)sp)->fd,&rfds);
|
||||
tv = timeout;
|
||||
res = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv);
|
||||
|
||||
// Read error
|
||||
if (res < 0) {
|
||||
DBG("%s", "RX error.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read time-out
|
||||
if (res == 0) {
|
||||
if (*pszRxLen == 0) {
|
||||
// Error, we received no data
|
||||
DBG("%s", "RX time-out, buffer empty.");
|
||||
return false;
|
||||
} else {
|
||||
// We received some data, but nothing more is available
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the count of the incoming bytes
|
||||
res = ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
|
||||
if (res < 0) return false;
|
||||
|
||||
// There is something available, read the data
|
||||
res = read(((serial_port_unix*)sp)->fd,pbtRx+(*pszRxLen),byteCount);
|
||||
|
||||
// Stop if the OS has some troubles reading the data
|
||||
if (res <= 0) return false;
|
||||
|
||||
*pszRxLen += res;
|
||||
|
||||
} while (byteCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen)
|
||||
{
|
||||
int32_t res;
|
||||
size_t szPos = 0;
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
|
||||
while (szPos < szTxLen)
|
||||
{
|
||||
// Reset file descriptor
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(((serial_port_unix*)sp)->fd,&rfds);
|
||||
tv = timeout;
|
||||
res = select(((serial_port_unix*)sp)->fd+1, NULL, &rfds, NULL, &tv);
|
||||
|
||||
// Write error
|
||||
if (res < 0) {
|
||||
DBG("%s", "TX error.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write time-out
|
||||
if (res == 0) {
|
||||
DBG("%s", "TX time-out.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Send away the bytes
|
||||
res = write(((serial_port_unix*)sp)->fd,pbtTx+szPos,szTxLen-szPos);
|
||||
|
||||
// Stop if the OS has some troubles sending the data
|
||||
if (res <= 0) return false;
|
||||
|
||||
szPos += res;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#else
|
||||
// The windows serial port implementation
|
||||
|
||||
typedef struct {
|
||||
HANDLE hPort; // Serial port handle
|
||||
DCB dcb; // Device control settings
|
||||
COMMTIMEOUTS ct; // Serial port time-out configuration
|
||||
} serial_port_windows;
|
||||
|
||||
serial_port uart_open(const char* pcPortName)
|
||||
{
|
||||
char acPortName[255];
|
||||
serial_port_windows* sp = malloc(sizeof(serial_port_windows));
|
||||
|
||||
// Copy the input "com?" to "\\.\COM?" format
|
||||
sprintf(acPortName,"\\\\.\\%s",pcPortName);
|
||||
_strupr(acPortName);
|
||||
|
||||
// Try to open the serial port
|
||||
sp->hPort = CreateFileA(acPortName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
|
||||
if (sp->hPort == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
uart_close(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
// Prepare the device control
|
||||
memset(&sp->dcb, 0, sizeof(DCB));
|
||||
sp->dcb.DCBlength = sizeof(DCB);
|
||||
if(!BuildCommDCBA("baud=9600 data=8 parity=N stop=1",&sp->dcb))
|
||||
{
|
||||
uart_close(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
// Update the active serial port
|
||||
if(!SetCommState(sp->hPort,&sp->dcb))
|
||||
{
|
||||
uart_close(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
sp->ct.ReadIntervalTimeout = 0;
|
||||
sp->ct.ReadTotalTimeoutMultiplier = 0;
|
||||
sp->ct.ReadTotalTimeoutConstant = 30;
|
||||
sp->ct.WriteTotalTimeoutMultiplier = 0;
|
||||
sp->ct.WriteTotalTimeoutConstant = 30;
|
||||
|
||||
if(!SetCommTimeouts(sp->hPort,&sp->ct))
|
||||
{
|
||||
uart_close(sp);
|
||||
return INVALID_SERIAL_PORT;
|
||||
}
|
||||
|
||||
PurgeComm(sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
|
||||
|
||||
return sp;
|
||||
}
|
||||
|
||||
void uart_close(const serial_port sp)
|
||||
{
|
||||
if (((serial_port_windows*)sp)->hPort != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(((serial_port_windows*)sp)->hPort);
|
||||
}
|
||||
free(sp);
|
||||
}
|
||||
|
||||
void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed)
|
||||
{
|
||||
serial_port_windows* spw;
|
||||
|
||||
DBG("Serial port speed requested to be set to %d bauds.", uiPortSpeed);
|
||||
// Set port speed (Input and Output)
|
||||
switch(uiPortSpeed) {
|
||||
case 9600:
|
||||
case 19200:
|
||||
case 38400:
|
||||
case 57600:
|
||||
case 115200:
|
||||
case 230400:
|
||||
case 460800:
|
||||
break;
|
||||
default:
|
||||
ERR("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);
|
||||
};
|
||||
|
||||
spw = (serial_port_windows*)sp;
|
||||
spw->dcb.BaudRate = uiPortSpeed;
|
||||
if (!SetCommState(spw->hPort, &spw->dcb))
|
||||
{
|
||||
ERR("Unable to apply new speed settings.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t uart_get_speed(const serial_port sp)
|
||||
{
|
||||
const serial_port_windows* spw = (serial_port_windows*)sp;
|
||||
if (!GetCommState(spw->hPort, (serial_port)&spw->dcb))
|
||||
return spw->dcb.BaudRate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool uart_cts(const serial_port sp)
|
||||
{
|
||||
DWORD ModemStat;
|
||||
const serial_port_windows* spw = (serial_port_windows*)sp;
|
||||
if (!GetCommModemStatus(spw->hPort,&ModemStat)) return false;
|
||||
return (ModemStat & MS_CTS_ON);
|
||||
}
|
||||
|
||||
bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen)
|
||||
{
|
||||
ReadFile(((serial_port_windows*)sp)->hPort,pbtRx,*pszRxLen,(LPDWORD)pszRxLen,NULL);
|
||||
return (*pszRxLen != 0);
|
||||
}
|
||||
|
||||
bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen)
|
||||
{
|
||||
DWORD dwTxLen = 0;
|
||||
return WriteFile(((serial_port_windows*)sp)->hPort,pbtTx,szTxLen,&dwTxLen,NULL);
|
||||
return (dwTxLen != 0);
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
66
libnfc/buses/uart.h
Normal file
66
libnfc/buses/uart.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file uart.h
|
||||
* @brief UART driver header
|
||||
*/
|
||||
|
||||
#ifndef __NFC_BUS_UART_H__
|
||||
#define __NFC_BUS_UART_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
// Handle platform specific includes
|
||||
#ifndef _WIN32
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <limits.h>
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// Define shortcut to types to make code more readable
|
||||
typedef void* serial_port;
|
||||
#define INVALID_SERIAL_PORT (void*)(~1)
|
||||
#define CLAIMED_SERIAL_PORT (void*)(~2)
|
||||
|
||||
serial_port uart_open(const char* pcPortName);
|
||||
void uart_close(const serial_port sp);
|
||||
|
||||
void uart_set_speed(serial_port sp, const uint32_t uiPortSpeed);
|
||||
uint32_t uart_get_speed(const serial_port sp);
|
||||
|
||||
bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen);
|
||||
bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen);
|
||||
|
||||
#endif // __NFC_BUS_UART_H__
|
||||
|
||||
|
||||
32
libnfc/chips.h
Normal file
32
libnfc/chips.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file chips.h
|
||||
* @brief NFC chips header
|
||||
*/
|
||||
|
||||
#ifndef __NFC_CHIPS_H__
|
||||
#define __NFC_CHIPS_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
#include "chips/pn53x.h"
|
||||
|
||||
#endif // __NFC_CHIPS_H__
|
||||
|
||||
9
libnfc/chips/Makefile.am
Normal file
9
libnfc/chips/Makefile.am
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
||||
|
||||
noinst_HEADERS = pn53x.h
|
||||
noinst_LTLIBRARIES = libnfcchips.la
|
||||
libnfcchips_la_SOURCES = pn53x.c
|
||||
libnfcchips_la_CFLAGS = -I$(top_srcdir)/libnfc
|
||||
|
||||
239
libnfc/chips/pn53x.c
Normal file
239
libnfc/chips/pn53x.c
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pn53x.h
|
||||
* @brief PN531, PN532 and PN533 common functions
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pn53x.h"
|
||||
|
||||
#include "../bitutils.h"
|
||||
|
||||
// PN53X configuration
|
||||
const byte_t pncmd_get_firmware_version [ 2] = { 0xD4,0x02 };
|
||||
const byte_t pncmd_get_general_status [ 2] = { 0xD4,0x04 };
|
||||
const byte_t pncmd_get_register [ 4] = { 0xD4,0x06 };
|
||||
const byte_t pncmd_set_register [ 5] = { 0xD4,0x08 };
|
||||
const byte_t pncmd_set_parameters [ 3] = { 0xD4,0x12 };
|
||||
const byte_t pncmd_rf_configure [ 14] = { 0xD4,0x32 };
|
||||
|
||||
// Reader
|
||||
const byte_t pncmd_initiator_list_passive [264] = { 0xD4,0x4A };
|
||||
const byte_t pncmd_initiator_jump_for_dep [ 68] = { 0xD4,0x56 };
|
||||
const byte_t pncmd_initiator_select [ 3] = { 0xD4,0x54 };
|
||||
const byte_t pncmd_initiator_deselect [ 3] = { 0xD4,0x44,0x00 };
|
||||
const byte_t pncmd_initiator_release [ 3] = { 0xD4,0x52,0x00 };
|
||||
const byte_t pncmd_initiator_set_baud_rate [ 5] = { 0xD4,0x4E };
|
||||
const byte_t pncmd_initiator_exchange_data [265] = { 0xD4,0x40 };
|
||||
const byte_t pncmd_initiator_exchange_raw_data [266] = { 0xD4,0x42 };
|
||||
const byte_t pncmd_initiator_auto_poll [ 5] = { 0xD4,0x60 };
|
||||
|
||||
// Target
|
||||
const byte_t pncmd_target_get_data [ 2] = { 0xD4,0x86 };
|
||||
const byte_t pncmd_target_set_data [264] = { 0xD4,0x8E };
|
||||
const byte_t pncmd_target_init [ 39] = { 0xD4,0x8C };
|
||||
const byte_t pncmd_target_virtual_card [ 4] = { 0xD4,0x14 };
|
||||
const byte_t pncmd_target_receive [ 2] = { 0xD4,0x88 };
|
||||
const byte_t pncmd_target_send [264] = { 0xD4,0x90 };
|
||||
const byte_t pncmd_target_get_status [ 2] = { 0xD4,0x8A };
|
||||
|
||||
|
||||
bool pn53x_transceive(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
|
||||
{
|
||||
byte_t abtRx[MAX_FRAME_LEN];
|
||||
size_t szRxLen;
|
||||
|
||||
// Check if receiving buffers are available, if not, replace them
|
||||
if (!pszRxLen || !pbtRx)
|
||||
{
|
||||
pbtRx = abtRx;
|
||||
pszRxLen = &szRxLen;
|
||||
}
|
||||
|
||||
*pszRxLen = MAX_FRAME_LEN;
|
||||
// Call the tranceive callback function of the current device
|
||||
if (!pnd->pdc->transceive(pnd->nds,pbtTx,szTxLen,pbtRx,pszRxLen)) return false;
|
||||
|
||||
// Make sure there was no failure reported by the PN53X chip (0x00 == OK)
|
||||
if (pbtRx[0] != 0) return false;
|
||||
|
||||
// Succesful transmission
|
||||
return true;
|
||||
}
|
||||
|
||||
byte_t pn53x_get_reg(const nfc_device_t* pnd, uint16_t ui16Reg)
|
||||
{
|
||||
uint8_t ui8Value;
|
||||
size_t szValueLen = 1;
|
||||
byte_t abtCmd[sizeof(pncmd_get_register)];
|
||||
memcpy(abtCmd,pncmd_get_register,sizeof(pncmd_get_register));
|
||||
|
||||
abtCmd[2] = ui16Reg >> 8;
|
||||
abtCmd[3] = ui16Reg & 0xff;
|
||||
// We can not use pn53x_transceive() because abtRx[0] gives no status info
|
||||
pnd->pdc->transceive(pnd->nds,abtCmd,4,&ui8Value,&szValueLen);
|
||||
return ui8Value;
|
||||
}
|
||||
|
||||
bool pn53x_set_reg(const nfc_device_t* pnd, uint16_t ui16Reg, uint8_t ui8SybmolMask, uint8_t ui8Value)
|
||||
{
|
||||
byte_t abtCmd[sizeof(pncmd_set_register)];
|
||||
memcpy(abtCmd,pncmd_set_register,sizeof(pncmd_set_register));
|
||||
|
||||
abtCmd[2] = ui16Reg >> 8;
|
||||
abtCmd[3] = ui16Reg & 0xff;
|
||||
abtCmd[4] = ui8Value | (pn53x_get_reg(pnd,ui16Reg) & (~ui8SybmolMask));
|
||||
// We can not use pn53x_transceive() because abtRx[0] gives no status info
|
||||
return pnd->pdc->transceive(pnd->nds,abtCmd,5,NULL,NULL);
|
||||
}
|
||||
|
||||
bool pn53x_set_parameters(const nfc_device_t* pnd, uint8_t ui8Value)
|
||||
{
|
||||
byte_t abtCmd[sizeof(pncmd_set_parameters)];
|
||||
memcpy(abtCmd,pncmd_set_parameters,sizeof(pncmd_set_parameters));
|
||||
|
||||
abtCmd[2] = ui8Value;
|
||||
// We can not use pn53x_transceive() because abtRx[0] gives no status info
|
||||
return pnd->pdc->transceive(pnd->nds,abtCmd,3,NULL,NULL);
|
||||
}
|
||||
|
||||
bool pn53x_set_tx_bits(const nfc_device_t* pnd, uint8_t ui8Bits)
|
||||
{
|
||||
// Test if we need to update the transmission bits register setting
|
||||
if (pnd->ui8TxBits != ui8Bits)
|
||||
{
|
||||
// Set the amount of transmission bits in the PN53X chip register
|
||||
if (!pn53x_set_reg(pnd,REG_CIU_BIT_FRAMING,SYMBOL_TX_LAST_BITS,ui8Bits)) return false;
|
||||
|
||||
// Store the new setting
|
||||
((nfc_device_t*)pnd)->ui8TxBits = ui8Bits;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pn53x_wrap_frame(const byte_t* pbtTx, const size_t szTxBits, const byte_t* pbtTxPar, byte_t* pbtFrame, size_t* pszFrameBits)
|
||||
{
|
||||
byte_t btFrame;
|
||||
byte_t btData;
|
||||
uint32_t uiBitPos;
|
||||
uint32_t uiDataPos = 0;
|
||||
size_t szBitsLeft = szTxBits;
|
||||
|
||||
// Make sure we should frame at least something
|
||||
if (szBitsLeft == 0) return false;
|
||||
|
||||
// Handle a short response (1byte) as a special case
|
||||
if (szBitsLeft < 9)
|
||||
{
|
||||
*pbtFrame = *pbtTx;
|
||||
*pszFrameBits = szTxBits;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We start by calculating the frame length in bits
|
||||
*pszFrameBits = szTxBits + (szTxBits/8);
|
||||
|
||||
// Parse the data bytes and add the parity bits
|
||||
// This is really a sensitive process, mirror the frame bytes and append parity bits
|
||||
// buffer = mirror(frame-byte) + parity + mirror(frame-byte) + parity + ...
|
||||
// split "buffer" up in segments of 8 bits again and mirror them
|
||||
// air-bytes = mirror(buffer-byte) + mirror(buffer-byte) + mirror(buffer-byte) + ..
|
||||
while(true)
|
||||
{
|
||||
// Reset the temporary frame byte;
|
||||
btFrame = 0;
|
||||
|
||||
for (uiBitPos=0; uiBitPos<8; uiBitPos++)
|
||||
{
|
||||
// Copy as much data that fits in the frame byte
|
||||
btData = mirror(pbtTx[uiDataPos]);
|
||||
btFrame |= (btData >> uiBitPos);
|
||||
// Save this frame byte
|
||||
*pbtFrame = mirror(btFrame);
|
||||
// Set the remaining bits of the date in the new frame byte and append the parity bit
|
||||
btFrame = (btData << (8-uiBitPos));
|
||||
btFrame |= ((pbtTxPar[uiDataPos] & 0x01) << (7-uiBitPos));
|
||||
// Backup the frame bits we have so far
|
||||
pbtFrame++;
|
||||
*pbtFrame = mirror(btFrame);
|
||||
// Increase the data (without parity bit) position
|
||||
uiDataPos++;
|
||||
// Test if we are done
|
||||
if (szBitsLeft < 9) return true;
|
||||
szBitsLeft -= 8;
|
||||
}
|
||||
// Every 8 data bytes we lose one frame byte to the parities
|
||||
pbtFrame++;
|
||||
}
|
||||
}
|
||||
|
||||
bool pn53x_unwrap_frame(const byte_t* pbtFrame, const size_t szFrameBits, byte_t* pbtRx, size_t* pszRxBits, byte_t* pbtRxPar)
|
||||
{
|
||||
byte_t btFrame;
|
||||
byte_t btData;
|
||||
uint8_t uiBitPos;
|
||||
uint32_t uiDataPos = 0;
|
||||
byte_t* pbtFramePos = (byte_t*) pbtFrame;
|
||||
size_t szBitsLeft = szFrameBits;
|
||||
|
||||
// Make sure we should frame at least something
|
||||
if (szBitsLeft == 0) return false;
|
||||
|
||||
// Handle a short response (1byte) as a special case
|
||||
if (szBitsLeft < 9)
|
||||
{
|
||||
*pbtRx = *pbtFrame;
|
||||
*pszRxBits = szFrameBits;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Calculate the data length in bits
|
||||
*pszRxBits = szFrameBits - (szFrameBits/9);
|
||||
|
||||
// Parse the frame bytes, remove the parity bits and store them in the parity array
|
||||
// This process is the reverse of WrapFrame(), look there for more info
|
||||
while(true)
|
||||
{
|
||||
for (uiBitPos=0; uiBitPos<8; uiBitPos++)
|
||||
{
|
||||
btFrame = mirror(pbtFramePos[uiDataPos]);
|
||||
btData = (btFrame << uiBitPos);
|
||||
btFrame = mirror(pbtFramePos[uiDataPos+1]);
|
||||
btData |= (btFrame >> (8-uiBitPos));
|
||||
pbtRx[uiDataPos] = mirror(btData);
|
||||
if(pbtRxPar != NULL) pbtRxPar[uiDataPos] = ((btFrame >> (7-uiBitPos)) & 0x01);
|
||||
// Increase the data (without parity bit) position
|
||||
uiDataPos++;
|
||||
// Test if we are done
|
||||
if (szBitsLeft < 9) return true;
|
||||
szBitsLeft -= 9;
|
||||
}
|
||||
// Every 8 data bytes we lose one frame byte to the parities
|
||||
pbtFramePos++;
|
||||
}
|
||||
}
|
||||
|
||||
80
libnfc/chips/pn53x.h
Normal file
80
libnfc/chips/pn53x.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file pn53x.h
|
||||
* @brief PN531, PN532 and PN533 common functions
|
||||
*/
|
||||
|
||||
#ifndef __NFC_CHIPS_PN53X_H__
|
||||
#define __NFC_CHIPS_PN53X_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
// Registers and symbols masks used to covers parts within a register
|
||||
#define REG_CIU_TX_MODE 0x6302
|
||||
#define SYMBOL_TX_CRC_ENABLE 0x80
|
||||
#define REG_CIU_RX_MODE 0x6303
|
||||
#define SYMBOL_RX_CRC_ENABLE 0x80
|
||||
#define SYMBOL_RX_NO_ERROR 0x08
|
||||
#define SYMBOL_RX_MULTIPLE 0x04
|
||||
#define REG_CIU_TX_AUTO 0x6305
|
||||
#define SYMBOL_FORCE_100_ASK 0x40
|
||||
#define SYMBOL_AUTO_WAKE_UP 0x20
|
||||
#define SYMBOL_INITIAL_RF_ON 0x04
|
||||
#define REG_CIU_MANUAL_RCV 0x630D
|
||||
#define SYMBOL_PARITY_DISABLE 0x10
|
||||
#define REG_CIU_STATUS2 0x6338
|
||||
#define SYMBOL_MF_CRYPTO1_ON 0x08
|
||||
#define REG_CIU_CONTROL 0x633C
|
||||
#define SYMBOL_INITIATOR 0x10
|
||||
#define SYMBOL_RX_LAST_BITS 0x07
|
||||
#define REG_CIU_BIT_FRAMING 0x633D
|
||||
#define SYMBOL_TX_LAST_BITS 0x07
|
||||
|
||||
// Internal parameters flags
|
||||
#define PARAM_NONE 0x00
|
||||
#define PARAM_NAD_USED 0x01
|
||||
#define PARAM_DID_USED 0x02
|
||||
#define PARAM_AUTO_ATR_RES 0x04
|
||||
#define PARAM_AUTO_RATS 0x10
|
||||
#define PARAM_14443_4_PICC 0x20
|
||||
#define PARAM_NO_AMBLE 0x40
|
||||
|
||||
// Radio Field Configure Items // Configuration Data length
|
||||
#define RFCI_FIELD 0x01 // 1
|
||||
#define RFCI_TIMING 0x02 // 3
|
||||
#define RFCI_RETRY_DATA 0x04 // 1
|
||||
#define RFCI_RETRY_SELECT 0x05 // 3
|
||||
#define RFCI_ANALOG_TYPE_A_106 0x0A // 11
|
||||
#define RFCI_ANALOG_TYPE_A_212_424 0x0B // 8
|
||||
#define RFCI_ANALOG_TYPE_B 0x0C // 3
|
||||
#define RFCI_ANALOG_TYPE_14443_4 0x0D // 9
|
||||
|
||||
bool pn53x_transceive(const nfc_device_t* pnd, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
|
||||
byte_t pn53x_get_reg(const nfc_device_t* pnd, uint16_t ui16Reg);
|
||||
bool pn53x_set_reg(const nfc_device_t* pnd, uint16_t ui16Reg, uint8_t ui8SybmolMask, uint8_t ui8Value);
|
||||
bool pn53x_set_parameters(const nfc_device_t* pnd, uint8_t ui8Value);
|
||||
bool pn53x_set_tx_bits(const nfc_device_t* pnd, uint8_t ui8Bits);
|
||||
bool pn53x_wrap_frame(const byte_t* pbtTx, const size_t szTxBits, const byte_t* pbtTxPar, byte_t* pbtFrame, size_t* pszFrameBits);
|
||||
bool pn53x_unwrap_frame(const byte_t* pbtFrame, const size_t szFrameBits, byte_t* pbtRx, size_t* pszRxBits, byte_t* pbtRxPar);
|
||||
|
||||
#endif // __NFC_CHIPS_PN53X_H__
|
||||
|
||||
60
libnfc/drivers.h
Normal file
60
libnfc/drivers.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file drivers.h
|
||||
* @brief Supported drivers header
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVERS_H__
|
||||
#define __NFC_DRIVERS_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
#ifdef HAVE_PCSC_LITE
|
||||
#include "drivers/acr122.h"
|
||||
#endif /* HAVE_PCSC_LITE */
|
||||
|
||||
#ifdef HAVE_LIBUSB
|
||||
#include "drivers/pn53x_usb.h"
|
||||
#include "drivers/pn531_usb.h"
|
||||
#include "drivers/pn533_usb.h"
|
||||
#endif /* HAVE_LIBUSB */
|
||||
|
||||
#include "drivers/arygon.h"
|
||||
#include "drivers/pn532_uart.h"
|
||||
|
||||
#define DRIVERS_MAX_DEVICES 16
|
||||
#define MAX_FRAME_LEN 264
|
||||
|
||||
const static struct driver_callbacks drivers_callbacks_list[] = {
|
||||
// Driver Name Pick Device List Devices Connect Transceive Disconnect
|
||||
#ifdef HAVE_PCSC_LITE
|
||||
{ ACR122_DRIVER_NAME, acr122_pick_device, acr122_list_devices, acr122_connect, acr122_transceive, acr122_disconnect },
|
||||
#endif /* HAVE_PCSC_LITE */
|
||||
#ifdef HAVE_LIBUSB
|
||||
{ PN531_USB_DRIVER_NAME, pn531_usb_pick_device, pn531_usb_list_devices, pn531_usb_connect, pn53x_usb_transceive, pn53x_usb_disconnect },
|
||||
{ PN533_USB_DRIVER_NAME, pn533_usb_pick_device, pn533_usb_list_devices, pn533_usb_connect, pn53x_usb_transceive, pn53x_usb_disconnect },
|
||||
#endif /* HAVE_LIBUSB */
|
||||
{ PN532_UART_DRIVER_NAME, pn532_uart_pick_device, pn532_uart_list_devices, pn532_uart_connect, pn532_uart_transceive, pn532_uart_disconnect },
|
||||
{ ARYGON_DRIVER_NAME, NULL, NULL, arygon_connect, arygon_transceive, arygon_disconnect }
|
||||
};
|
||||
|
||||
#endif // __NFC_DRIVERS_H__
|
||||
|
||||
23
libnfc/drivers/Makefile.am
Normal file
23
libnfc/drivers/Makefile.am
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# set the include path found by configure
|
||||
INCLUDES= $(all_includes) $(LIBNFC_CFLAGS)
|
||||
|
||||
noinst_HEADERS = arygon.h pn532_uart.h
|
||||
noinst_LTLIBRARIES = libnfcdrivers.la
|
||||
libnfcdrivers_la_SOURCES = arygon.c pn532_uart.c
|
||||
libnfcdrivers_la_CFLAGS = -I$(top_srcdir)/libnfc -I$(top_srcdir)/libnfc/buses
|
||||
libnfcdrivers_la_LIBADD =
|
||||
|
||||
if PCSC_LITE_ENABLED
|
||||
noinst_HEADERS += acr122.h
|
||||
libnfcdrivers_la_CFLAGS += @LIBPCSCLITE_CFLAGS@ -DHAVE_PCSC_LITE
|
||||
libnfcdrivers_la_SOURCES += acr122.c
|
||||
libnfcdrivers_la_LIBADD += @LIBPCSCLITE_LIBS@
|
||||
endif
|
||||
|
||||
if LIBUSB_ENABLED
|
||||
noinst_HEADERS += pn531_usb.h pn533_usb.h pn53x_usb.h
|
||||
libnfcdrivers_la_CFLAGS += @LIBUSB_CFLAGS@ -DHAVE_LIBUSB
|
||||
libnfcdrivers_la_SOURCES += pn531_usb.c pn533_usb.c pn53x_usb.c
|
||||
libnfcdrivers_la_LIBADD += @LIBUSB_LIBS@
|
||||
endif
|
||||
|
||||
362
libnfc/drivers/acr122.c
Normal file
362
libnfc/drivers/acr122.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file acr122.c
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "acr122.h"
|
||||
#include "../drivers.h"
|
||||
#include "../bitutils.h"
|
||||
|
||||
// Bus
|
||||
#include <winscard.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <wintypes.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
// WINDOWS: #define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE SCARD_CTL_CODE(3500)
|
||||
#define IOCTL_CCID_ESCAPE_SCARD_CTL_CODE (((0x31) << 16) | ((3500) << 2))
|
||||
#define SCARD_OPERATION_SUCCESS 0x61
|
||||
#define SCARD_OPERATION_ERROR 0x63
|
||||
|
||||
#ifndef SCARD_PROTOCOL_UNDEFINED
|
||||
#define SCARD_PROTOCOL_UNDEFINED SCARD_PROTOCOL_UNSET
|
||||
#endif
|
||||
|
||||
#define FIRMWARE_TEXT "ACR122U" // Tested on: ACR122U101(ACS), ACR122U102(Tikitag), ACR122U203(ACS)
|
||||
|
||||
#define ACR122_WRAP_LEN 5
|
||||
#define ACR122_COMMAND_LEN 266
|
||||
#define ACR122_RESPONSE_LEN 268
|
||||
|
||||
const char *supported_devices[] = {
|
||||
"ACS ACR122",
|
||||
"ACS ACR 38U-CCID",
|
||||
" CCID USB",
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
SCARDHANDLE hCard;
|
||||
SCARD_IO_REQUEST ioCard;
|
||||
} acr122_spec_t;
|
||||
|
||||
static SCARDCONTEXT _SCardContext;
|
||||
static int _iSCardContextRefCount = 0;
|
||||
|
||||
SCARDCONTEXT*
|
||||
acr122_get_scardcontext(void)
|
||||
{
|
||||
if ( _iSCardContextRefCount == 0 )
|
||||
{
|
||||
if (SCardEstablishContext(SCARD_SCOPE_USER,NULL,NULL,&_SCardContext) != SCARD_S_SUCCESS) return NULL;
|
||||
}
|
||||
_iSCardContextRefCount++;
|
||||
|
||||
return &_SCardContext;
|
||||
}
|
||||
|
||||
void
|
||||
acr122_free_scardcontext(void)
|
||||
{
|
||||
if (_iSCardContextRefCount)
|
||||
{
|
||||
_iSCardContextRefCount--;
|
||||
if (!_iSCardContextRefCount)
|
||||
{
|
||||
SCardReleaseContext(_SCardContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nfc_device_desc_t *
|
||||
acr122_pick_device (void)
|
||||
{
|
||||
nfc_device_desc_t *pndd;
|
||||
|
||||
if ((pndd = malloc (sizeof (*pndd)))) {
|
||||
size_t szN;
|
||||
|
||||
if (!acr122_list_devices (pndd, 1, &szN)) {
|
||||
DBG("%s", "acr122_list_devices failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (szN == 0) {
|
||||
DBG("%s", "No device found");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pndd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief List connected devices
|
||||
*
|
||||
* Probe PCSC to find NFC capable hardware.
|
||||
*
|
||||
* @param pnddDevices Array of nfc_device_desc_t previously allocated by the caller.
|
||||
* @param szDevices size of the pnddDevices array.
|
||||
* @param pszDeviceFound number of devices found.
|
||||
* @return true if succeeded, false otherwise.
|
||||
*/
|
||||
bool
|
||||
acr122_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound)
|
||||
{
|
||||
size_t szPos = 0;
|
||||
char acDeviceNames[256+64*DRIVERS_MAX_DEVICES];
|
||||
size_t szDeviceNamesLen = sizeof(acDeviceNames);
|
||||
uint32_t uiBusIndex = 0;
|
||||
SCARDCONTEXT *pscc;
|
||||
bool bSupported;
|
||||
int i;
|
||||
|
||||
// Clear the reader list
|
||||
memset(acDeviceNames, '\0', szDeviceNamesLen);
|
||||
|
||||
*pszDeviceFound = 0;
|
||||
|
||||
// Test if context succeeded
|
||||
if (!(pscc = acr122_get_scardcontext ()))
|
||||
{
|
||||
DBG("%s","PCSC context not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Retrieve the string array of all available pcsc readers
|
||||
if (SCardListReaders(*pscc,NULL,acDeviceNames,(void*)&szDeviceNamesLen) != SCARD_S_SUCCESS) return false;
|
||||
|
||||
DBG("%s", "PCSC reports following device(s):");
|
||||
|
||||
while ((acDeviceNames[szPos] != '\0') && ((*pszDeviceFound) < szDevices)) {
|
||||
uiBusIndex++;
|
||||
|
||||
DBG("- %s (pos=%d)", acDeviceNames + szPos, szPos);
|
||||
|
||||
bSupported = false;
|
||||
for (i = 0; supported_devices[i] && !bSupported; i++) {
|
||||
int l = strlen(supported_devices[i]);
|
||||
bSupported = 0 == strncmp(supported_devices[i], acDeviceNames + szPos, l);
|
||||
}
|
||||
|
||||
if (bSupported)
|
||||
{
|
||||
// Supported ACR122 device found
|
||||
strncpy(pnddDevices[*pszDeviceFound].acDevice, acDeviceNames + szPos, DEVICE_NAME_LENGTH - 1);
|
||||
pnddDevices[*pszDeviceFound].acDevice[DEVICE_NAME_LENGTH - 1] = '\0';
|
||||
pnddDevices[*pszDeviceFound].pcDriver = ACR122_DRIVER_NAME;
|
||||
pnddDevices[*pszDeviceFound].uiBusIndex = uiBusIndex;
|
||||
(*pszDeviceFound)++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("PCSC device [%s] is not NFC capable or not supported by libnfc.", acDeviceNames + szPos);
|
||||
}
|
||||
|
||||
// Find next device name position
|
||||
while (acDeviceNames[szPos++] != '\0');
|
||||
}
|
||||
acr122_free_scardcontext ();
|
||||
|
||||
if(*pszDeviceFound)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
nfc_device_t* acr122_connect(const nfc_device_desc_t* pndd)
|
||||
{
|
||||
nfc_device_t* pnd = NULL;
|
||||
acr122_spec_t as;
|
||||
acr122_spec_t* pas;
|
||||
char* pcFirmware;
|
||||
|
||||
SCARDCONTEXT *pscc;
|
||||
|
||||
DBG("Connecting to %s",pndd->acDevice);
|
||||
// We no longer support connecting with a NULL
|
||||
if(pndd == NULL) return NULL;
|
||||
// Test if context succeeded
|
||||
if (!(pscc = acr122_get_scardcontext ())) return NULL;
|
||||
// Test if we were able to connect to the "emulator" card
|
||||
if (SCardConnect(*pscc,pndd->acDevice,SCARD_SHARE_EXCLUSIVE,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&(as.hCard),(void*)&(as.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
|
||||
{
|
||||
// Connect to ACR122 firmware version >2.0
|
||||
if (SCardConnect(*pscc,pndd->acDevice,SCARD_SHARE_DIRECT,0,&(as.hCard),(void*)&(as.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
|
||||
{
|
||||
// We can not connect to this device.
|
||||
DBG("%s","PCSC connect failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// Configure I/O settings for card communication
|
||||
as.ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST);
|
||||
|
||||
// Retrieve the current firmware version
|
||||
pcFirmware = acr122_firmware((nfc_device_t*)&as);
|
||||
if (strstr(pcFirmware,FIRMWARE_TEXT) != NULL)
|
||||
{
|
||||
// Allocate memory and store the device specification
|
||||
pas = malloc(sizeof(acr122_spec_t));
|
||||
*pas = as;
|
||||
|
||||
// Done, we found the reader we are looking for
|
||||
pnd = malloc(sizeof(nfc_device_t));
|
||||
strcpy(pnd->acName,pndd->acDevice);
|
||||
strcpy(pnd->acName + strlen(pnd->acName)," / ");
|
||||
strcpy(pnd->acName + strlen(pnd->acName),pcFirmware);
|
||||
pnd->nc = NC_PN532;
|
||||
pnd->nds = (nfc_device_spec_t)pas;
|
||||
pnd->bActive = true;
|
||||
pnd->bCrc = true;
|
||||
pnd->bPar = true;
|
||||
pnd->ui8TxBits = 0;
|
||||
return pnd;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void acr122_disconnect(nfc_device_t* pnd)
|
||||
{
|
||||
acr122_spec_t* pas = (acr122_spec_t*)pnd->nds;
|
||||
SCardDisconnect(pas->hCard,SCARD_LEAVE_CARD);
|
||||
acr122_free_scardcontext ();
|
||||
free(pas);
|
||||
free(pnd);
|
||||
}
|
||||
|
||||
bool acr122_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
|
||||
{
|
||||
byte_t abtRxCmd[5] = { 0xFF,0xC0,0x00,0x00 };
|
||||
size_t szRxCmdLen = sizeof(abtRxCmd);
|
||||
byte_t abtRxBuf[ACR122_RESPONSE_LEN];
|
||||
size_t szRxBufLen;
|
||||
byte_t abtTxBuf[ACR122_WRAP_LEN+ACR122_COMMAND_LEN] = { 0xFF, 0x00, 0x00, 0x00 };
|
||||
acr122_spec_t* pas = (acr122_spec_t*)nds;
|
||||
|
||||
// Make sure the command does not overflow the send buffer
|
||||
if (szTxLen > ACR122_COMMAND_LEN) return false;
|
||||
|
||||
// Store the length of the command we are going to send
|
||||
abtTxBuf[4] = szTxLen;
|
||||
|
||||
// Prepare and transmit the send buffer
|
||||
memcpy(abtTxBuf+5,pbtTx,szTxLen);
|
||||
szRxBufLen = sizeof(abtRxBuf);
|
||||
#ifdef DEBUG
|
||||
printf(" TX: ");
|
||||
print_hex(abtTxBuf,szTxLen+5);
|
||||
#endif
|
||||
|
||||
if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
|
||||
{
|
||||
if (SCardControl(pas->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtTxBuf,szTxLen+5,abtRxBuf,szRxBufLen,(void*)&szRxBufLen) != SCARD_S_SUCCESS) return false;
|
||||
} else {
|
||||
if (SCardTransmit(pas->hCard,&(pas->ioCard),abtTxBuf,szTxLen+5,NULL,abtRxBuf,(void*)&szRxBufLen) != SCARD_S_SUCCESS) return false;
|
||||
}
|
||||
|
||||
if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_T0)
|
||||
{
|
||||
// Make sure we received the byte-count we expected
|
||||
if (szRxBufLen != 2) return false;
|
||||
|
||||
// Check if the operation was successful, so an answer is available
|
||||
if (*abtRxBuf == SCARD_OPERATION_ERROR) return false;
|
||||
|
||||
// Retrieve the response bytes
|
||||
abtRxCmd[4] = abtRxBuf[1];
|
||||
szRxBufLen = sizeof(abtRxBuf);
|
||||
if (SCardTransmit(pas->hCard,&(pas->ioCard),abtRxCmd,szRxCmdLen,NULL,abtRxBuf,(void*)&szRxBufLen) != SCARD_S_SUCCESS) return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" RX: ");
|
||||
print_hex(abtRxBuf,szRxBufLen);
|
||||
#endif
|
||||
|
||||
// When the answer should be ignored, just return a succesful result
|
||||
if (pbtRx == NULL || pszRxLen == NULL) return true;
|
||||
|
||||
// Make sure we have an emulated answer that fits the return buffer
|
||||
if (szRxBufLen < 4 || (szRxBufLen-4) > *pszRxLen) return false;
|
||||
// Wipe out the 4 APDU emulation bytes: D5 4B .. .. .. 90 00
|
||||
*pszRxLen = ((size_t)szRxBufLen)-4;
|
||||
memcpy(pbtRx,abtRxBuf+2,*pszRxLen);
|
||||
|
||||
// Transmission went successful
|
||||
return true;
|
||||
}
|
||||
|
||||
char* acr122_firmware(const nfc_device_spec_t nds)
|
||||
{
|
||||
byte_t abtGetFw[5] = { 0xFF,0x00,0x48,0x00,0x00 };
|
||||
uint32_t uiResult;
|
||||
|
||||
acr122_spec_t* pas = (acr122_spec_t*)nds;
|
||||
static char abtFw[11];
|
||||
size_t szFwLen = sizeof(abtFw);
|
||||
memset(abtFw,0x00,szFwLen);
|
||||
if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
|
||||
{
|
||||
uiResult = SCardControl(pas->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtGetFw,sizeof(abtGetFw),abtFw,szFwLen,(void*)&szFwLen);
|
||||
} else {
|
||||
uiResult = SCardTransmit(pas->hCard,&(pas->ioCard),abtGetFw,sizeof(abtGetFw),NULL,(byte_t*)abtFw,(void*)&szFwLen);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (uiResult != SCARD_S_SUCCESS)
|
||||
{
|
||||
printf("No ACR122 firmware received, Error: %08x\n",uiResult);
|
||||
}
|
||||
#endif
|
||||
|
||||
return abtFw;
|
||||
}
|
||||
|
||||
bool acr122_led_red(const nfc_device_spec_t nds, bool bOn)
|
||||
{
|
||||
byte_t abtLed[9] = { 0xFF,0x00,0x40,0x05,0x04,0x00,0x00,0x00,0x00 };
|
||||
acr122_spec_t* pas = (acr122_spec_t*)nds;
|
||||
byte_t abtBuf[2];
|
||||
size_t szBufLen = sizeof(abtBuf);
|
||||
if (pas->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
|
||||
{
|
||||
return (SCardControl(pas->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtLed,sizeof(abtLed),abtBuf,szBufLen,(void*)&szBufLen) == SCARD_S_SUCCESS);
|
||||
} else {
|
||||
return (SCardTransmit(pas->hCard,&(pas->ioCard),abtLed,sizeof(abtLed),NULL,(byte_t*)abtBuf,(void*)&szBufLen) == SCARD_S_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
50
libnfc/drivers/acr122.h
Normal file
50
libnfc/drivers/acr122.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file acr122.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_ACR122_H__
|
||||
#define __NFC_DRIVER_ACR122_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
#define ACR122_DRIVER_NAME "ACR122"
|
||||
|
||||
nfc_device_desc_t* acr122_pick_device(void);
|
||||
bool acr122_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound);
|
||||
|
||||
// Functions used by developer to handle connection to this device
|
||||
nfc_device_t* acr122_connect(const nfc_device_desc_t* pndd);
|
||||
void acr122_disconnect(nfc_device_t* pnd);
|
||||
|
||||
// Callback function used by libnfc to transmit commands to the PN53X chip
|
||||
bool acr122_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
|
||||
|
||||
// Various additional features this device supports
|
||||
char* acr122_firmware(const nfc_device_spec_t nds);
|
||||
bool acr122_led_red(const nfc_device_spec_t nds, bool bOn);
|
||||
|
||||
#endif // ! __NFC_DRIVER_ACR122_H__
|
||||
|
||||
227
libnfc/drivers/arygon.c
Normal file
227
libnfc/drivers/arygon.c
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file arygon.c
|
||||
* @brief ARYGON readers driver
|
||||
*
|
||||
* This driver can handle ARYGON readers that use UART as bus.
|
||||
* UART connection can be direct (host<->arygon_uc) or could be provided by internal USB to serial interface (e.g. host<->ftdi_chip<->arygon_uc)
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include "../drivers.h"
|
||||
#include "../bitutils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "arygon.h"
|
||||
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
// Bus
|
||||
#include "../buses/uart.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SERIAL_STRING "COM"
|
||||
#define delay_ms( X ) Sleep( X )
|
||||
#else
|
||||
// unistd.h is needed for usleep() fct.
|
||||
#include <unistd.h>
|
||||
#define delay_ms( X ) usleep( X * 1000 )
|
||||
|
||||
#ifdef __APPLE__
|
||||
// MacOS
|
||||
#define SERIAL_STRING "/dev/tty.SLAB_USBtoUART"
|
||||
#else
|
||||
// *BSD, Linux, other POSIX systems
|
||||
#define SERIAL_STRING "/dev/ttyUSB"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BUFFER_LENGTH 256
|
||||
|
||||
/** @def DEV_ARYGON_PROTOCOL_ARYGON_ASCII
|
||||
* @brief High level language in ASCII format. (Common µC commands and Mifare® commands)
|
||||
*/
|
||||
#define DEV_ARYGON_PROTOCOL_ARYGON_ASCII '0'
|
||||
/** @def DEV_ARYGON_MODE_HL_ASCII
|
||||
* @brief High level language in Binary format With AddressingByte for party line. (Common µC commands and Mifare® commands)
|
||||
*/
|
||||
#define DEV_ARYGON_PROTOCOL_ARYGON_BINARY_WAB '1'
|
||||
/** @def DEV_ARYGON_PROTOCOL_TAMA
|
||||
* @brief Philips protocol (TAMA language) in binary format.
|
||||
*/
|
||||
#define DEV_ARYGON_PROTOCOL_TAMA '2'
|
||||
/** @def DEV_ARYGON_PROTOCOL_TAMA_WAB
|
||||
* @brief Philips protocol (TAMA language) in binary With AddressingByte for party line.
|
||||
*/
|
||||
#define DEV_ARYGON_PROTOCOL_TAMA_WAB '3'
|
||||
|
||||
#define SERIAL_DEFAULT_PORT_SPEED 9600
|
||||
|
||||
/**
|
||||
* @note ARYGON-ADRA (PN531): ???,n,8,1
|
||||
* @note ARYGON-ADRB (PN532): 9600,n,8,1
|
||||
* @note ARYGON-APDA (PN531): 9600,n,8,1
|
||||
* @note ARYGON-APDB1UA33N (PN532): 115200,n,8,1
|
||||
* @note ARYGON-APDB2UA33 (PN532 + ARYGON µC): 9600,n,8,1
|
||||
*/
|
||||
|
||||
nfc_device_t* arygon_connect(const nfc_device_desc_t* pndd)
|
||||
{
|
||||
uint32_t uiDevNr;
|
||||
serial_port sp;
|
||||
char acConnect[BUFFER_LENGTH];
|
||||
nfc_device_t* pnd = NULL;
|
||||
|
||||
if( pndd == NULL ) {
|
||||
#ifndef SERIAL_AUTOPROBE_ENABLED
|
||||
INFO("%s", "Sorry, serial auto-probing have been disabled at compile time.");
|
||||
return NULL;
|
||||
#else /* SERIAL_AUTOPROBE_ENABLED */
|
||||
DBG("Trying to find ARYGON device on serial port: %s# at %d bauds.",SERIAL_STRING, SERIAL_DEFAULT_PORT_SPEED);
|
||||
// I have no idea how MAC OS X deals with multiple devices, so a quick workaround
|
||||
for (uiDevNr=0; uiDevNr<DRIVERS_MAX_DEVICES; uiDevNr++)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
strcpy(acConnect,SERIAL_STRING);
|
||||
#else
|
||||
sprintf(acConnect,"%s%d",SERIAL_STRING,uiDevNr);
|
||||
#endif /* __APPLE__ */
|
||||
|
||||
sp = uart_open(acConnect);
|
||||
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT))
|
||||
{
|
||||
uart_set_speed(sp, SERIAL_DEFAULT_PORT_SPEED);
|
||||
break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (sp == INVALID_SERIAL_PORT) DBG("Invalid serial port: %s",acConnect);
|
||||
if (sp == CLAIMED_SERIAL_PORT) DBG("Serial port already claimed: %s",acConnect);
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
||||
|
||||
// Test if we have found a device
|
||||
if (uiDevNr == DRIVERS_MAX_DEVICES) return NULL;
|
||||
} else {
|
||||
DBG("Connecting to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed);
|
||||
strcpy(acConnect,pndd->pcPort);
|
||||
sp = uart_open(acConnect);
|
||||
if (sp == INVALID_SERIAL_PORT) ERR("Invalid serial port: %s",acConnect);
|
||||
if (sp == CLAIMED_SERIAL_PORT) ERR("Serial port already claimed: %s",acConnect);
|
||||
if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL;
|
||||
|
||||
uart_set_speed(sp, pndd->uiSpeed);
|
||||
}
|
||||
|
||||
DBG("Successfully connected to: %s",acConnect);
|
||||
|
||||
// We have a connection
|
||||
pnd = malloc(sizeof(nfc_device_t));
|
||||
strcpy(pnd->acName,"ARYGON");
|
||||
pnd->nc = NC_PN532;
|
||||
pnd->nds = (nfc_device_spec_t)sp;
|
||||
pnd->bActive = true;
|
||||
pnd->bCrc = true;
|
||||
pnd->bPar = true;
|
||||
pnd->ui8TxBits = 0;
|
||||
return pnd;
|
||||
}
|
||||
|
||||
void arygon_disconnect(nfc_device_t* pnd)
|
||||
{
|
||||
uart_close((serial_port)pnd->nds);
|
||||
free(pnd);
|
||||
}
|
||||
|
||||
bool arygon_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
|
||||
{
|
||||
byte_t abtTxBuf[BUFFER_LENGTH] = { DEV_ARYGON_PROTOCOL_TAMA, 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||
byte_t abtRxBuf[BUFFER_LENGTH];
|
||||
size_t szRxBufLen = BUFFER_LENGTH;
|
||||
size_t szPos;
|
||||
|
||||
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
|
||||
abtTxBuf[4] = szTxLen;
|
||||
// Packet length checksum
|
||||
abtTxBuf[5] = BUFFER_LENGTH - abtTxBuf[4];
|
||||
// Copy the PN53X command into the packet buffer
|
||||
memmove(abtTxBuf+6,pbtTx,szTxLen);
|
||||
|
||||
// Calculate data payload checksum
|
||||
abtTxBuf[szTxLen+6] = 0;
|
||||
for(szPos=0; szPos < szTxLen; szPos++)
|
||||
{
|
||||
abtTxBuf[szTxLen+6] -= abtTxBuf[szPos+6];
|
||||
}
|
||||
|
||||
// End of stream marker
|
||||
abtTxBuf[szTxLen+7] = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" TX: ");
|
||||
print_hex(abtTxBuf,szTxLen+8);
|
||||
#endif
|
||||
if (!uart_send((serial_port)nds,abtTxBuf,szTxLen+8)) {
|
||||
ERR("%s", "Unable to transmit data. (TX)");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @note PN532 (at 115200 bauds) need 20ms between sending and receiving frame. No information regarding this in ARYGON datasheet...
|
||||
* It seems to be a required delay to able to send from host to device, plus the device computation then device respond transmission
|
||||
*/
|
||||
delay_ms(20);
|
||||
|
||||
/** @note PN532 (at 115200 bauds) need 30ms more to be stable (report correctly present tag, at each try: 20ms seems to be enought for one shot...)
|
||||
* PN532 seems to work correctly with 50ms at 115200 bauds.
|
||||
*/
|
||||
delay_ms(30);
|
||||
|
||||
/** @note Unfortunately, adding delay is not enought for ARYGON readers which are equipped with an ARYGON µC + PN532 running at 9600 bauds.
|
||||
* There are too many timing problem to solve them by adding more and more delay.
|
||||
* For more information, see Issue 23 on development site : http://code.google.com/p/libnfc/issues/detail?id=23
|
||||
*/
|
||||
|
||||
if (!uart_receive((serial_port)nds,abtRxBuf,&szRxBufLen)) {
|
||||
ERR("%s", "Unable to receive data. (RX)");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" RX: ");
|
||||
print_hex(abtRxBuf,szRxBufLen);
|
||||
#endif
|
||||
|
||||
// When the answer should be ignored, just return a successful result
|
||||
if(pbtRx == NULL || pszRxLen == NULL) return true;
|
||||
|
||||
// Only succeed when the result is at least 00 00 ff 00 ff 00 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
|
||||
if(szRxBufLen < 15) return false;
|
||||
|
||||
// Remove the preceding and appending bytes 00 00 ff 00 ff 00 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
|
||||
*pszRxLen = szRxBufLen - 15;
|
||||
memcpy(pbtRx, abtRxBuf+13, *pszRxLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
39
libnfc/drivers/arygon.h
Normal file
39
libnfc/drivers/arygon.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file arygon.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_ARYGON_H__
|
||||
#define __NFC_DRIVER_ARYGON_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
#define ARYGON_DRIVER_NAME "ARYGON"
|
||||
|
||||
// Functions used by developer to handle connection to this device
|
||||
nfc_device_t* arygon_connect(const nfc_device_desc_t* pndd);
|
||||
void arygon_disconnect(nfc_device_t* pnd);
|
||||
|
||||
// Callback function used by libnfc to transmit commands to the PN53X chip
|
||||
bool arygon_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
|
||||
|
||||
#endif // ! __NFC_DRIVER_ARYGON_H__
|
||||
|
||||
72
libnfc/drivers/pn531_usb.c
Normal file
72
libnfc/drivers/pn531_usb.c
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pn531_usb.c
|
||||
* @brief Driver for PN531 chip using USB
|
||||
*/
|
||||
|
||||
/*
|
||||
Thanks to d18c7db and Okko for example code
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../drivers.h"
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
nfc_device_desc_t * pn531_usb_pick_device (void)
|
||||
{
|
||||
nfc_device_desc_t *pndd;
|
||||
|
||||
if ((pndd = malloc (sizeof (*pndd))))
|
||||
{
|
||||
size_t szN;
|
||||
|
||||
if (!pn531_usb_list_devices (pndd, 1, &szN))
|
||||
{
|
||||
DBG("%s", "pn531_usb_list_devices failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (szN == 0)
|
||||
{
|
||||
DBG("%s", "No device found");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return pndd;
|
||||
}
|
||||
|
||||
bool pn531_usb_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound)
|
||||
{
|
||||
// array of {vendor,product} pairs for USB devices
|
||||
usb_candidate_t candidates[]= {{0x04CC,0x0531},{0x054c,0x0193}};
|
||||
|
||||
return pn53x_usb_list_devices(&pnddDevices[0], szDevices, pszDeviceFound, &candidates[0], sizeof(candidates) / sizeof(usb_candidate_t),PN531_USB_DRIVER_NAME);
|
||||
}
|
||||
|
||||
nfc_device_t* pn531_usb_connect(const nfc_device_desc_t* pndd)
|
||||
{
|
||||
return pn53x_usb_connect(pndd, pndd->acDevice, NC_PN531);
|
||||
}
|
||||
35
libnfc/drivers/pn531_usb.h
Normal file
35
libnfc/drivers/pn531_usb.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file pn531_usb.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_PN531_USB_H__
|
||||
#define __NFC_DRIVER_PN531_USB_H__
|
||||
|
||||
#define PN531_USB_DRIVER_NAME "PN531_USB"
|
||||
|
||||
// Functions used by developer to handle connection to this device
|
||||
nfc_device_t* pn531_usb_connect(const nfc_device_desc_t* pndd);
|
||||
bool pn531_usb_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound);
|
||||
nfc_device_desc_t * pn531_usb_pick_device (void);
|
||||
|
||||
#endif // ! __NFC_DRIVER_PN531_USB_H__
|
||||
|
||||
253
libnfc/drivers/pn532_uart.c
Normal file
253
libnfc/drivers/pn532_uart.c
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pn532_uart.c
|
||||
* @brief PN532 driver using UART bus (UART, RS232, etc.)
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include "../drivers.h"
|
||||
#include "../bitutils.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pn532_uart.h"
|
||||
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
|
||||
// Bus
|
||||
#include "uart.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SERIAL_STRING "COM"
|
||||
#define snprintf _snprintf
|
||||
#define strdup _strdup
|
||||
#else
|
||||
// unistd.h is needed for usleep() fct.
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
// MacOS
|
||||
// TODO: find UART connection string for PN53X device on Mac OS X
|
||||
#define SERIAL_STRING ""
|
||||
#else
|
||||
// *BSD, Linux and others POSIX systems
|
||||
#define SERIAL_STRING "/dev/ttyUSB"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BUFFER_LENGTH 256
|
||||
|
||||
#define SERIAL_DEFAULT_PORT_SPEED 115200
|
||||
|
||||
nfc_device_desc_t *
|
||||
pn532_uart_pick_device (void)
|
||||
{
|
||||
nfc_device_desc_t *pndd;
|
||||
|
||||
if ((pndd = malloc (sizeof (*pndd)))) {
|
||||
size_t szN;
|
||||
|
||||
if (!pn532_uart_list_devices (pndd, 1, &szN)) {
|
||||
DBG("%s", "pn532_uart_list_devices failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (szN == 0) {
|
||||
DBG("%s", "No device found");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pndd;
|
||||
}
|
||||
|
||||
bool
|
||||
pn532_uart_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound)
|
||||
{
|
||||
/* @note: Due to UART bus we can't know if its really a pn532 without
|
||||
* sending some PN53x commands. But using this way to probe devices, we can
|
||||
* have serious problem with other device on this bus */
|
||||
#ifndef SERIAL_AUTOPROBE_ENABLED
|
||||
*pszDeviceFound = 0;
|
||||
DBG("%s", "Serial auto-probing have been disabled at compile time. Skipping autoprobe.");
|
||||
return false;
|
||||
#else /* SERIAL_AUTOPROBE_ENABLED */
|
||||
*pszDeviceFound = 0;
|
||||
|
||||
serial_port sp;
|
||||
char acConnect[BUFFER_LENGTH];
|
||||
int iDevice;
|
||||
|
||||
// I have no idea how MAC OS X deals with multiple devices, so a quick workaround
|
||||
for (iDevice=0; iDevice<DRIVERS_MAX_DEVICES; iDevice++)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
strcpy(acConnect,SERIAL_STRING);
|
||||
#else /* __APPLE__ */
|
||||
sprintf(acConnect,"%s%d",SERIAL_STRING,iDevice);
|
||||
#endif /* __APPLE__ */
|
||||
sp = uart_open(acConnect);
|
||||
DBG("Trying to find PN532 device on serial port: %s at %d bauds.",acConnect, SERIAL_DEFAULT_PORT_SPEED);
|
||||
|
||||
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT))
|
||||
{
|
||||
// PN532_UART device found
|
||||
uart_close(sp);
|
||||
snprintf(pnddDevices[*pszDeviceFound].acDevice, DEVICE_NAME_LENGTH - 1, "%s (%s)", "PN532", acConnect);
|
||||
pnddDevices[*pszDeviceFound].acDevice[DEVICE_NAME_LENGTH - 1] = '\0';
|
||||
pnddDevices[*pszDeviceFound].pcDriver = PN532_UART_DRIVER_NAME;
|
||||
//pnddDevices[*pszDeviceFound].pcPort = strndup(acConnect, BUFFER_LENGTH - 1);
|
||||
pnddDevices[*pszDeviceFound].pcPort = strdup(acConnect);
|
||||
pnddDevices[*pszDeviceFound].pcPort[BUFFER_LENGTH] = '\0';
|
||||
pnddDevices[*pszDeviceFound].uiSpeed = SERIAL_DEFAULT_PORT_SPEED;
|
||||
DBG("Device found: %s.", pnddDevices[*pszDeviceFound].acDevice);
|
||||
(*pszDeviceFound)++;
|
||||
|
||||
// Test if we reach the maximum "wanted" devices
|
||||
if((*pszDeviceFound) >= szDevices) break;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (sp == INVALID_SERIAL_PORT) DBG("Invalid serial port: %s",acConnect);
|
||||
if (sp == CLAIMED_SERIAL_PORT) DBG("Serial port already claimed: %s",acConnect);
|
||||
#endif /* DEBUG */
|
||||
}
|
||||
#endif /* SERIAL_AUTOPROBE_ENABLED */
|
||||
return true;
|
||||
}
|
||||
|
||||
nfc_device_t* pn532_uart_connect(const nfc_device_desc_t* pndd)
|
||||
{
|
||||
/** @info PN532C106 wakeup. */
|
||||
/** @todo Put this command in pn53x init process */
|
||||
byte_t abtRxBuf[BUFFER_LENGTH];
|
||||
size_t szRxBufLen;
|
||||
const byte_t pncmd_pn532c106_wakeup[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xFF,0x03,0xFD,0xD4,0x14,0x01,0x17,0x00 };
|
||||
|
||||
serial_port sp;
|
||||
nfc_device_t* pnd = NULL;
|
||||
|
||||
if( pndd == NULL ) {
|
||||
DBG("%s", "pn532_uart_connect() need an nfc_device_desc_t struct.");
|
||||
return NULL;
|
||||
} else {
|
||||
DBG("Connecting to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed);
|
||||
sp = uart_open(pndd->pcPort);
|
||||
|
||||
if (sp == INVALID_SERIAL_PORT) ERR("Invalid serial port: %s",pndd->pcPort);
|
||||
if (sp == CLAIMED_SERIAL_PORT) ERR("Serial port already claimed: %s",pndd->pcPort);
|
||||
if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL;
|
||||
|
||||
uart_set_speed(sp, pndd->uiSpeed);
|
||||
}
|
||||
|
||||
uart_send(sp, pncmd_pn532c106_wakeup, sizeof(pncmd_pn532c106_wakeup));
|
||||
|
||||
if (!uart_receive(sp,abtRxBuf,&szRxBufLen)) {
|
||||
ERR("%s", "Unable to receive data. (RX)");
|
||||
return NULL;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
printf(" RX: ");
|
||||
print_hex(abtRxBuf,szRxBufLen);
|
||||
#endif
|
||||
|
||||
DBG("Successfully connected to: %s",pndd->pcPort);
|
||||
|
||||
// We have a connection
|
||||
pnd = malloc(sizeof(nfc_device_t));
|
||||
strncpy(pnd->acName, pndd->acDevice, DEVICE_NAME_LENGTH - 1);
|
||||
pnd->acName[DEVICE_NAME_LENGTH - 1] = '\0';
|
||||
|
||||
pnd->nc = NC_PN532;
|
||||
pnd->nds = (nfc_device_spec_t)sp;
|
||||
pnd->bActive = true;
|
||||
pnd->bCrc = true;
|
||||
pnd->bPar = true;
|
||||
pnd->ui8TxBits = 0;
|
||||
return pnd;
|
||||
}
|
||||
|
||||
void pn532_uart_disconnect(nfc_device_t* pnd)
|
||||
{
|
||||
uart_close((serial_port)pnd->nds);
|
||||
free(pnd);
|
||||
}
|
||||
|
||||
bool pn532_uart_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
|
||||
{
|
||||
byte_t abtTxBuf[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||
byte_t abtRxBuf[BUFFER_LENGTH];
|
||||
size_t szRxBufLen = BUFFER_LENGTH;
|
||||
size_t szPos;
|
||||
|
||||
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
|
||||
abtTxBuf[3] = szTxLen;
|
||||
// Packet length checksum
|
||||
abtTxBuf[4] = BUFFER_LENGTH - abtTxBuf[3];
|
||||
// Copy the PN53X command into the packet buffer
|
||||
memmove(abtTxBuf+5,pbtTx,szTxLen);
|
||||
|
||||
// Calculate data payload checksum
|
||||
abtTxBuf[szTxLen+5] = 0;
|
||||
for(szPos=0; szPos < szTxLen; szPos++)
|
||||
{
|
||||
abtTxBuf[szTxLen+5] -= abtTxBuf[szPos+5];
|
||||
}
|
||||
|
||||
// End of stream marker
|
||||
abtTxBuf[szTxLen+6] = 0;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" TX: ");
|
||||
print_hex(abtTxBuf,szTxLen+7);
|
||||
#endif
|
||||
if (!uart_send((serial_port)nds,abtTxBuf,szTxLen+7)) {
|
||||
ERR("%s", "Unable to transmit data. (TX)");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!uart_receive((serial_port)nds,abtRxBuf,&szRxBufLen)) {
|
||||
ERR("%s", "Unable to receive data. (RX)");
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" RX: ");
|
||||
print_hex(abtRxBuf,szRxBufLen);
|
||||
#endif
|
||||
|
||||
// When the answer should be ignored, just return a successful result
|
||||
if(pbtRx == NULL || pszRxLen == NULL) return true;
|
||||
|
||||
// Only succeed when the result is at least 00 00 ff 00 ff 00 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
|
||||
if(szRxBufLen < 15) return false;
|
||||
|
||||
// Remove the preceding and appending bytes 00 00 ff 00 ff 00 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
|
||||
*pszRxLen = szRxBufLen - 15;
|
||||
memcpy(pbtRx, abtRxBuf+13, *pszRxLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
42
libnfc/drivers/pn532_uart.h
Normal file
42
libnfc/drivers/pn532_uart.h
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file pn532_uart.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_PN532_UART_H__
|
||||
#define __NFC_DRIVER_PN532_UART_H__
|
||||
|
||||
#include <nfc/nfc-types.h>
|
||||
|
||||
#define PN532_UART_DRIVER_NAME "PN532_UART"
|
||||
|
||||
// Functions used by developer to handle connection to this device
|
||||
nfc_device_desc_t * pn532_uart_pick_device (void);
|
||||
bool pn532_uart_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound);
|
||||
|
||||
nfc_device_t* pn532_uart_connect(const nfc_device_desc_t* pndd);
|
||||
void pn532_uart_disconnect(nfc_device_t* pnd);
|
||||
|
||||
// Callback function used by libnfc to transmit commands to the PN53X chip
|
||||
bool pn532_uart_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
|
||||
|
||||
#endif // ! __NFC_DRIVER_PN532_UART_H__
|
||||
|
||||
70
libnfc/drivers/pn533_usb.c
Normal file
70
libnfc/drivers/pn533_usb.c
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pn533_usb.c
|
||||
* @brief Driver for PN533 chip using USB
|
||||
*/
|
||||
|
||||
/*
|
||||
Thanks to d18c7db and Okko for example code
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "../drivers.h"
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
nfc_device_desc_t * pn533_usb_pick_device (void)
|
||||
{
|
||||
nfc_device_desc_t *pndd;
|
||||
|
||||
if ((pndd = malloc (sizeof (*pndd)))) {
|
||||
size_t szN;
|
||||
|
||||
if (!pn533_usb_list_devices (pndd, 1, &szN)) {
|
||||
DBG("%s", "pn533_usb_list_devices failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (szN == 0) {
|
||||
DBG("%s", "No device found");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return pndd;
|
||||
}
|
||||
|
||||
bool pn533_usb_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound)
|
||||
{
|
||||
// array of {vendor,product} pairs for USB devices
|
||||
usb_candidate_t candidates[]= {{0x04CC,0x2533},{0x04E6,0x5591}};
|
||||
|
||||
return pn53x_usb_list_devices(&pnddDevices[0], szDevices, pszDeviceFound, &candidates[0], sizeof(candidates) / sizeof(usb_candidate_t),PN533_USB_DRIVER_NAME);
|
||||
}
|
||||
|
||||
nfc_device_t* pn533_usb_connect(const nfc_device_desc_t* pndd)
|
||||
{
|
||||
return pn53x_usb_connect(pndd, pndd->acDevice, NC_PN533);
|
||||
}
|
||||
35
libnfc/drivers/pn533_usb.h
Normal file
35
libnfc/drivers/pn533_usb.h
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file pn533_usb.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DRIVER_PN533_USB_H__
|
||||
#define __NFC_DRIVER_PN533_USB_H__
|
||||
|
||||
#define PN533_USB_DRIVER_NAME "PN533_USB"
|
||||
|
||||
// Functions used by developer to handle connection to this device
|
||||
nfc_device_t* pn533_usb_connect(const nfc_device_desc_t* pndd);
|
||||
bool pn533_usb_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound);
|
||||
nfc_device_desc_t * pn533_usb_pick_device (void);
|
||||
|
||||
#endif // ! __NFC_DRIVER_PN533_USB_H__
|
||||
|
||||
331
libnfc/drivers/pn53x_usb.c
Normal file
331
libnfc/drivers/pn53x_usb.c
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*-
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file pn53x_usb.c
|
||||
* @brief Driver common routines for PN53x chips using USB
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
/*
|
||||
Thanks to d18c7db and Okko for example code
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <usb.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../drivers.h"
|
||||
#include "../bitutils.h"
|
||||
|
||||
#include <nfc/nfc-messages.h>
|
||||
|
||||
#define BUFFER_LENGTH 256
|
||||
#define USB_TIMEOUT 30000
|
||||
|
||||
// Find transfer endpoints for bulk transfers
|
||||
void get_end_points(struct usb_device *dev, usb_spec_t* pus)
|
||||
{
|
||||
uint32_t uiIndex;
|
||||
uint32_t uiEndPoint;
|
||||
struct usb_interface_descriptor* puid = dev->config->interface->altsetting;
|
||||
|
||||
// 3 Endpoints maximum: Interrupt In, Bulk In, Bulk Out
|
||||
for(uiIndex = 0; uiIndex < puid->bNumEndpoints; uiIndex++)
|
||||
{
|
||||
// Only accept bulk transfer endpoints (ignore interrupt endpoints)
|
||||
if(puid->endpoint[uiIndex].bmAttributes != USB_ENDPOINT_TYPE_BULK) continue;
|
||||
|
||||
// Copy the endpoint to a local var, makes it more readable code
|
||||
uiEndPoint = puid->endpoint[uiIndex].bEndpointAddress;
|
||||
|
||||
// Test if we dealing with a bulk IN endpoint
|
||||
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_IN)
|
||||
{
|
||||
DBG("Bulk endpoint in : 0x%02X", uiEndPoint);
|
||||
pus->uiEndPointIn = uiEndPoint;
|
||||
}
|
||||
|
||||
// Test if we dealing with a bulk OUT endpoint
|
||||
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
|
||||
{
|
||||
DBG("Bulk endpoint in : 0x%02X", uiEndPoint);
|
||||
pus->uiEndPointOut = uiEndPoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pn53x_usb_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound,usb_candidate_t candidates[], int num_candidates, char * target_name)
|
||||
{
|
||||
int ret, i;
|
||||
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev;
|
||||
usb_dev_handle *udev;
|
||||
uint32_t uiBusIndex = 0;
|
||||
char string[256];
|
||||
|
||||
string[0]= '\0';
|
||||
usb_init();
|
||||
|
||||
if ((ret= usb_find_busses() < 0)) return NULL;
|
||||
DBG("%d busses",ret);
|
||||
if ((ret= usb_find_devices() < 0)) return NULL;
|
||||
DBG("%d devices",ret);
|
||||
|
||||
*pszDeviceFound= 0;
|
||||
|
||||
for (bus = usb_get_busses(); bus; bus = bus->next)
|
||||
{
|
||||
for (dev = bus->devices; dev; dev = dev->next, uiBusIndex++)
|
||||
{
|
||||
for(i = 0; i < num_candidates; ++i)
|
||||
{
|
||||
DBG("Checking device %04x:%04x (%04x:%04x)",dev->descriptor.idVendor,dev->descriptor.idProduct,candidates[i].idVendor,candidates[i].idProduct);
|
||||
if (candidates[i].idVendor==dev->descriptor.idVendor && candidates[i].idProduct==dev->descriptor.idProduct)
|
||||
{
|
||||
// Make sure there are 2 endpoints available
|
||||
// with libusb-win32 we got some null pointers so be robust before looking at endpoints:
|
||||
if (dev->config == NULL || dev->config->interface == NULL || dev->config->interface->altsetting == NULL)
|
||||
{
|
||||
// Nope, we maybe want the next one, let's try to find another
|
||||
continue;
|
||||
}
|
||||
if (dev->config->interface->altsetting->bNumEndpoints < 2)
|
||||
{
|
||||
// Nope, we maybe want the next one, let's try to find another
|
||||
continue;
|
||||
}
|
||||
if (dev->descriptor.iManufacturer || dev->descriptor.iProduct)
|
||||
{
|
||||
udev = usb_open(dev);
|
||||
if(udev)
|
||||
{
|
||||
usb_get_string_simple(udev, dev->descriptor.iManufacturer, string, sizeof(string));
|
||||
if(strlen(string) > 0)
|
||||
strcpy(string + strlen(string)," / ");
|
||||
usb_get_string_simple(udev, dev->descriptor.iProduct, string + strlen(string), sizeof(string) - strlen(string));
|
||||
}
|
||||
usb_close(udev);
|
||||
}
|
||||
if(strlen(string) == 0)
|
||||
strcpy(pnddDevices[*pszDeviceFound].acDevice, target_name);
|
||||
else
|
||||
strcpy(pnddDevices[*pszDeviceFound].acDevice, string);
|
||||
pnddDevices[*pszDeviceFound].pcDriver = target_name;
|
||||
pnddDevices[*pszDeviceFound].uiBusIndex = uiBusIndex;
|
||||
(*pszDeviceFound)++;
|
||||
DBG("%s","Match!");
|
||||
// Test if we reach the maximum "wanted" devices
|
||||
if((*pszDeviceFound) == szDevices)
|
||||
{
|
||||
DBG("Found %d devices",*pszDeviceFound);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
DBG("Found %d devices",*pszDeviceFound);
|
||||
if(*pszDeviceFound)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
nfc_device_t* pn53x_usb_connect(const nfc_device_desc_t* pndd,const char * target_name, int target_chip)
|
||||
{
|
||||
nfc_device_t* pnd = NULL;
|
||||
usb_spec_t* pus;
|
||||
usb_spec_t us;
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev;
|
||||
uint32_t uiBusIndex;
|
||||
|
||||
us.uiEndPointIn = 0;
|
||||
us.uiEndPointOut = 0;
|
||||
us.pudh = NULL;
|
||||
|
||||
|
||||
// must specify device to connect to
|
||||
if(pndd == NULL) return NULL;
|
||||
|
||||
DBG("Connecting %s device",target_name);
|
||||
usb_init();
|
||||
|
||||
uiBusIndex= pndd->uiBusIndex;
|
||||
|
||||
DBG("Skipping to device no. %d",uiBusIndex);
|
||||
for (bus = usb_get_busses(); bus; bus = bus->next)
|
||||
{
|
||||
for (dev = bus->devices; dev; dev = dev->next, uiBusIndex--)
|
||||
{
|
||||
DBG("Checking device %04x:%04x",dev->descriptor.idVendor,dev->descriptor.idProduct);
|
||||
if(uiBusIndex == 0)
|
||||
{
|
||||
DBG("Found device index %d", pndd->uiBusIndex);
|
||||
|
||||
// Open the USB device
|
||||
us.pudh = usb_open(dev);
|
||||
|
||||
get_end_points(dev,&us);
|
||||
if(usb_set_configuration(us.pudh,1) < 0)
|
||||
{
|
||||
DBG("%s", "Setting config failed");
|
||||
usb_close(us.pudh);
|
||||
// we failed to use the specified device
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(usb_claim_interface(us.pudh,0) < 0)
|
||||
{
|
||||
DBG("%s", "Can't claim interface");
|
||||
usb_close(us.pudh);
|
||||
// we failed to use the specified device
|
||||
return NULL;
|
||||
}
|
||||
// Allocate memory for the device info and specification, fill it and return the info
|
||||
pus = malloc(sizeof(usb_spec_t));
|
||||
*pus = us;
|
||||
pnd = malloc(sizeof(nfc_device_t));
|
||||
strcpy(pnd->acName,target_name);
|
||||
pnd->nc = target_chip;
|
||||
pnd->nds = (nfc_device_spec_t)pus;
|
||||
pnd->bActive = true;
|
||||
pnd->bCrc = true;
|
||||
pnd->bPar = true;
|
||||
pnd->ui8TxBits = 0;
|
||||
return pnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
// We ran out of devices before the index required
|
||||
DBG("%s","Device index not found!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void pn53x_usb_disconnect(nfc_device_t* pnd)
|
||||
{
|
||||
usb_spec_t* pus = (usb_spec_t*)pnd->nds;
|
||||
int ret;
|
||||
|
||||
DBG("%s","resetting USB");
|
||||
usb_reset(pus->pudh);
|
||||
if((ret= usb_release_interface(pus->pudh,0)) < 0)
|
||||
DBG("usb_release failed %i",ret);
|
||||
if((ret= usb_close(pus->pudh)) < 0)
|
||||
DBG("usb_close failed %i",ret);
|
||||
free(pnd->nds);
|
||||
free(pnd);
|
||||
DBG("%s","done!");
|
||||
}
|
||||
|
||||
bool pn53x_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
|
||||
{
|
||||
size_t uiPos = 0;
|
||||
int ret = 0;
|
||||
byte_t abtTx[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
|
||||
byte_t abtRx[BUFFER_LENGTH];
|
||||
usb_spec_t* pus = (usb_spec_t*)nds;
|
||||
|
||||
// Packet length = data length (len) + checksum (1) + end of stream marker (1)
|
||||
abtTx[3] = szTxLen;
|
||||
// Packet length checksum
|
||||
abtTx[4] = BUFFER_LENGTH - abtTx[3];
|
||||
// Copy the PN53X command into the packet abtTx
|
||||
memmove(abtTx+5,pbtTx,szTxLen);
|
||||
|
||||
// Calculate data payload checksum
|
||||
abtTx[szTxLen+5] = 0;
|
||||
for(uiPos=0; uiPos < szTxLen; uiPos++)
|
||||
{
|
||||
abtTx[szTxLen+5] -= abtTx[uiPos+5];
|
||||
}
|
||||
|
||||
// End of stream marker
|
||||
abtTx[szTxLen+6] = 0;
|
||||
|
||||
DBG("%s","pn53x_usb_transceive");
|
||||
#ifdef DEBUG
|
||||
printf(" TX: ");
|
||||
print_hex(abtTx,szTxLen+7);
|
||||
#endif
|
||||
|
||||
ret = usb_bulk_write(pus->pudh, pus->uiEndPointOut, (char*)abtTx, szTxLen+7, USB_TIMEOUT);
|
||||
if( ret < 0 )
|
||||
{
|
||||
DBG("usb_bulk_write failed with error %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT);
|
||||
if( ret < 0 )
|
||||
{
|
||||
DBG( "usb_bulk_read failed with error %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" RX: ");
|
||||
print_hex(abtRx,ret);
|
||||
#endif
|
||||
|
||||
if( ret == 6 )
|
||||
{
|
||||
ret = usb_bulk_read(pus->pudh, pus->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT);
|
||||
if( ret < 0 )
|
||||
{
|
||||
DBG("usb_bulk_read failed with error %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf(" RX: ");
|
||||
print_hex(abtRx,ret);
|
||||
#endif
|
||||
}
|
||||
|
||||
// When the answer should be ignored, just return a succesful result
|
||||
if(pbtRx == NULL || pszRxLen == NULL) return true;
|
||||
|
||||
// Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
|
||||
if(ret < 9)
|
||||
{
|
||||
DBG("%s","No data");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
|
||||
*pszRxLen = ret - 7 - 2;
|
||||
|
||||
// Get register: nuke extra byte (awful hack)
|
||||
if ((abtRx[5]==0xd5) && (abtRx[6]==0x07) && (*pszRxLen==2)) {
|
||||
// printf("Got %02x %02x, keep %02x\n", abtRx[7], abtRx[8], abtRx[8]);
|
||||
*pszRxLen = (*pszRxLen) - 1;
|
||||
memcpy( pbtRx, abtRx + 8, *pszRxLen);
|
||||
return true;
|
||||
}
|
||||
|
||||
memcpy( pbtRx, abtRx + 7, *pszRxLen);
|
||||
|
||||
return true;
|
||||
}
|
||||
41
libnfc/drivers/pn53x_usb.h
Normal file
41
libnfc/drivers/pn53x_usb.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file pn53x_usb.h
|
||||
* @brief
|
||||
*/
|
||||
|
||||
#include <usb.h>
|
||||
|
||||
typedef struct {
|
||||
usb_dev_handle* pudh;
|
||||
uint32_t uiEndPointIn;
|
||||
uint32_t uiEndPointOut;
|
||||
} usb_spec_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t idVendor;
|
||||
uint16_t idProduct;
|
||||
} usb_candidate_t;
|
||||
|
||||
nfc_device_t* pn53x_usb_connect(const nfc_device_desc_t* pndd,const char * target_name, int target_chip);
|
||||
void get_end_points(struct usb_device *dev, usb_spec_t* pus);
|
||||
void pn53x_usb_disconnect(nfc_device_t* pnd);
|
||||
bool pn53x_usb_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
|
||||
bool pn53x_usb_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound,usb_candidate_t candidates[], int num_candidates, char * target_name);
|
||||
1044
libnfc/nfc.c
Normal file
1044
libnfc/nfc.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue