Rearrange source code.

This commit is contained in:
Romain Tartiere 2010-04-07 14:37:19 +00:00
parent be1639b452
commit c7d77d7664
59 changed files with 43 additions and 107 deletions

49
libnfc/CMakeLists.txt Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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__

View 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
View 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
View 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
View 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
View 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__

View 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);
}

View 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
View 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;
}

View 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__

View 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);
}

View 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
View 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;
}

View 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

File diff suppressed because it is too large Load diff