First attempt to reorganize tree.

This commit is contained in:
Romuald Conty 2009-11-03 14:51:14 +00:00
parent 36cb0ff5f9
commit ab62855d80
20 changed files with 0 additions and 0 deletions

190
src/lib/bitutils.c Normal file
View file

@ -0,0 +1,190 @@
/**
* 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
*/
#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 append_iso14443a_crc(byte_t* pbtData, size_t szLen)
{
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);
*pbtData++ = (byte_t) (wCrc & 0xFF);
*pbtData = (byte_t) ((wCrc >> 8) & 0xFF);
}
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)
{
size_t szPos;
size_t szBytes = szBits/8;
for (szPos=0; szPos < szBytes; szPos++)
{
printf("%02x ",pbtData[szPos]);
}
// Print the rest bits, these cannot have no parity bit
if (szBits%8 != 0) printf("%02x",pbtData[szBytes]);
printf("\n");
}
void print_hex_par(const byte_t* pbtData, const size_t szBits, const byte_t* pbtDataPar)
{
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(" ");
}
}
// Print the rest bits, these cannot have no parity bit
if (szBits%8 != 0) printf("%02x",pbtData[szBytes]);
printf("\n");
}

348
src/lib/bus/rs232.c Normal file
View file

@ -0,0 +1,348 @@
/**
* 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 rs232.c
* @brief
*/
/*
Based on rs232-code written by Teunis van Beelen available:
http://www.teuniz.net/RS-232/index.html
*/
#include "rs232.h"
#include "messages.h"
// Test if we are dealing with unix operating systems
#ifndef _WIN32
#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
struct timeval tv = {
.tv_sec = 0, // 0 second
.tv_usec = 30000 // 30,000 micro seconds
};
// Work-around to claim rs232 interface using the c_iflag (software input processing) from the termios struct
#define CCLAIMED 0x80000000
serial_port rs232_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_NDELAY | O_NONBLOCK);
if(sp->fd == -1)
{
rs232_close(sp);
return INVALID_SERIAL_PORT;
}
if(tcgetattr(sp->fd,&sp->tiOld) == -1)
{
rs232_close(sp);
return INVALID_SERIAL_PORT;
}
// Make sure the port is not claimed already
if (sp->tiOld.c_iflag & CCLAIMED)
{
rs232_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)
{
rs232_close(sp);
return INVALID_SERIAL_PORT;
}
tcflush(sp->fd, TCIFLUSH);
return sp;
}
void rs232_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)
speed_t stPortSpeed = B9600;
switch(uiPortSpeed) {
case 9600: stPortSpeed = B9600;
break;
case 19200: stPortSpeed = B19200;
break;
case 38400: stPortSpeed = B38400;
break;
case 57600: stPortSpeed = B57600;
break;
case 115200: stPortSpeed = B115200;
break;
case 230400: stPortSpeed = B230400;
break;
#ifdef B460800
case 460800: stPortSpeed = B460800;
break;
#endif
default:
#ifdef B460800
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);
#else
ERR("Unable to set serial port speed to %d bauds. Speed value must be one of these constants: 9600 (default), 19200, 38400, 57600, 115200 or 230400.", uiPortSpeed);
#endif
};
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("Unable to apply new speed settings.");
}
}
uint32_t rs232_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;
case B57600: uiPortSpeed = 57600;
break;
case B115200: uiPortSpeed = 115200;
break;
case B230400: uiPortSpeed = 230400;
break;
#ifdef B460800
case B460800: uiPortSpeed = 460800;
break;
#endif
}
return uiPortSpeed;
}
void rs232_close(const serial_port sp)
{
tcsetattr(((serial_port_unix*)sp)->fd,TCSANOW,&((serial_port_unix*)sp)->tiOld);
close(((serial_port_unix*)sp)->fd);
free(sp);
}
bool rs232_cts(const serial_port sp)
{
char status;
if (ioctl(((serial_port_unix*)sp)->fd,TIOCMGET,&status) < 0) return false;
return (status & TIOCM_CTS);
}
bool rs232_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen)
{
int iResult;
int byteCount;
fd_set rfds;
// Reset file descriptor
FD_ZERO(&rfds);
FD_SET(((serial_port_unix*)sp)->fd,&rfds);
iResult = select(((serial_port_unix*)sp)->fd+1, &rfds, NULL, NULL, &tv);
// Read error
if (iResult < 0) {
DBG("RX error.");
*pszRxLen = 0;
return false;
}
// Read time-out
if (iResult == 0) {
DBG("RX time-out.");
*pszRxLen = 0;
return false;
}
// Number of bytes in the input buffer
ioctl(((serial_port_unix*)sp)->fd, FIONREAD, &byteCount);
// Empty buffer
if (byteCount == 0) {
DBG("RX empty buffer.");
*pszRxLen = 0;
return false;
}
// There is something available, read the data
*pszRxLen = read(((serial_port_unix*)sp)->fd,pbtRx,byteCount);
return (*pszRxLen > 0);
}
bool rs232_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen)
{
int iResult;
iResult = write(((serial_port_unix*)sp)->fd,pbtTx,szTxLen);
return (iResult >= 0);
}
#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 rs232_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)
{
rs232_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))
{
rs232_close(sp);
return INVALID_SERIAL_PORT;
}
// Update the active serial port
if(!SetCommState(sp->hPort,&sp->dcb))
{
rs232_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))
{
rs232_close(sp);
return INVALID_SERIAL_PORT;
}
PurgeComm(sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR);
return sp;
}
void rs232_close(const serial_port sp)
{
CloseHandle(((serial_port_windows*)sp)->hPort);
free(sp);
}
void rs232_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 rs232_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 rs232_cts(const serial_port sp)
{
DWORD dwStatus;
if (!GetCommModemStatus(((serial_port_windows*)sp)->hPort,&dwStatus)) return false;
return (dwStatus & MS_CTS_ON);
}
bool rs232_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 rs232_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

65
src/lib/bus/rs232.h Normal file
View file

@ -0,0 +1,65 @@
/**
* 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 rs232.h
* @brief
*/
#ifndef _LIBNFC_RS232_H_
#define _LIBNFC_RS232_H_
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "defines.h"
#include "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 rs232_open(const char* pcPortName);
void rs232_close(const serial_port sp);
void rs232_set_speed(serial_port sp, const uint32_t uiPortSpeed);
uint32_t rs232_get_speed(const serial_port sp);
bool rs232_cts(const serial_port sp);
bool rs232_receive(const serial_port sp, byte_t* pbtRx, size_t* pszRxLen);
bool rs232_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen);
#endif // _LIBNFC_RS232_H_

276
src/lib/drivers/acr122.c Normal file
View file

@ -0,0 +1,276 @@
/**
* 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 dev_acr122.c
* @brief
*/
#include "dev_acr122.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <winscard.h>
#ifdef __APPLE__
#include <wintypes.h>
#endif
#include "defines.h"
#include "messages.h"
#include "bitutils.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
typedef struct {
SCARDCONTEXT hCtx;
SCARDHANDLE hCard;
SCARD_IO_REQUEST ioCard;
} dev_spec_acr122;
dev_info* dev_acr122_connect(const nfc_device_desc_t* pndd)
{
char* pacReaders[MAX_DEVICES];
char acList[256+64*MAX_DEVICES];
size_t szListLen = sizeof(acList);
size_t szPos;
uint32_t uiReaderCount;
uint32_t uiReader;
uint32_t uiDevIndex;
dev_info* pdi;
dev_spec_acr122* pdsa;
dev_spec_acr122 dsa;
char* pcFirmware;
// Clear the reader list
memset(acList,0x00,szListLen);
// Test if context succeeded
if (SCardEstablishContext(SCARD_SCOPE_USER,NULL,NULL,&(dsa.hCtx)) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
// Retrieve the string array of all available pcsc readers
if (SCardListReaders(dsa.hCtx,NULL,acList,(void*)&szListLen) != SCARD_S_SUCCESS) return INVALID_DEVICE_INFO;
DBG("PCSC reports following device(s):");
DBG("- %s",acList);
pacReaders[0] = acList;
uiReaderCount = 1;
for (szPos=0; szPos<szListLen; szPos++)
{
// Make sure don't break out of our reader array
if (uiReaderCount == MAX_DEVICES) break;
// Test if there is a next reader available
if (acList[szPos] == 0x00)
{
// Test if we are at the end of the list
if (acList[szPos+1] == 0x00)
{
break;
}
// Store the position of the next reader and search for more readers
pacReaders[uiReaderCount] = acList+szPos+1;
uiReaderCount++;
DBG("- %s",acList+szPos+1);
}
}
// Initialize the device index we are seaching for
if( pndd == NULL ) {
uiDevIndex = 0;
} else {
uiDevIndex = pndd->uiIndex;
}
// Iterate through all readers and try to find the ACR122 on requested index
for (uiReader=0; uiReader<uiReaderCount; uiReader++)
{
// Test if we were able to connect to the "emulator" card
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_EXCLUSIVE,SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
{
// Connect to ACR122 firmware version >2.0
if (SCardConnect(dsa.hCtx,pacReaders[uiReader],SCARD_SHARE_DIRECT,0,&(dsa.hCard),(void*)&(dsa.ioCard.dwProtocol)) != SCARD_S_SUCCESS)
{
// We can not connect to this device, we will just ignore it
continue;
}
}
// Configure I/O settings for card communication
dsa.ioCard.cbPciLength = sizeof(SCARD_IO_REQUEST);
// Retrieve the current firmware version
pcFirmware = dev_acr122_firmware((dev_info*)&dsa);
if (strstr(pcFirmware,FIRMWARE_TEXT) != NULL)
{
// We found a occurence, test if it has the right index
if (uiDevIndex != 0)
{
// Let's look for the next reader
uiDevIndex--;
continue;
}
// Allocate memory and store the device specification
pdsa = malloc(sizeof(dev_spec_acr122));
*pdsa = dsa;
// Done, we found the reader we are looking for
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,pcFirmware);
pdi->ct = CT_PN532;
pdi->ds = (dev_spec)pdsa;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
}
// Too bad, the reader could not be located;
return INVALID_DEVICE_INFO;
}
void dev_acr122_disconnect(dev_info* pdi)
{
dev_spec_acr122* pdsa = (dev_spec_acr122*)pdi->ds;
SCardDisconnect(pdsa->hCard,SCARD_LEAVE_CARD);
SCardReleaseContext(pdsa->hCtx);
free(pdsa);
free(pdi);
}
bool dev_acr122_transceive(const dev_spec ds, 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 };
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
// 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 (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
if (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtTxBuf,szTxLen+5,abtRxBuf,szRxBufLen,(void*)&szRxBufLen) != SCARD_S_SUCCESS) return false;
} else {
if (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtTxBuf,szTxLen+5,NULL,abtRxBuf,(void*)&szRxBufLen) != SCARD_S_SUCCESS) return false;
}
if (pdsa->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(pdsa->hCard,&(pdsa->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* dev_acr122_firmware(const dev_spec ds)
{
byte_t abtGetFw[5] = { 0xFF,0x00,0x48,0x00,0x00 };
uint32_t uiResult;
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
static char abtFw[11];
size_t szFwLen = sizeof(abtFw);
memset(abtFw,0x00,szFwLen);
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
uiResult = SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtGetFw,sizeof(abtGetFw),abtFw,szFwLen,(void*)&szFwLen);
} else {
uiResult = SCardTransmit(pdsa->hCard,&(pdsa->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 dev_acr122_led_red(const dev_spec ds, bool bOn)
{
byte_t abtLed[9] = { 0xFF,0x00,0x40,0x05,0x04,0x00,0x00,0x00,0x00 };
dev_spec_acr122* pdsa = (dev_spec_acr122*)ds;
byte_t abtBuf[2];
size_t szBufLen = sizeof(abtBuf);
if (pdsa->ioCard.dwProtocol == SCARD_PROTOCOL_UNDEFINED)
{
return (SCardControl(pdsa->hCard,IOCTL_CCID_ESCAPE_SCARD_CTL_CODE,abtLed,sizeof(abtLed),abtBuf,szBufLen,(void*)&szBufLen) == SCARD_S_SUCCESS);
} else {
return (SCardTransmit(pdsa->hCard,&(pdsa->ioCard),abtLed,sizeof(abtLed),NULL,(byte_t*)abtBuf,(void*)&szBufLen) == SCARD_S_SUCCESS);
}
}

45
src/lib/drivers/acr122.h Normal file
View file

@ -0,0 +1,45 @@
/**
* 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 dev_acr122.h
* @brief
*/
#ifndef _LIBNFC_DEV_ACR122_H_
#define _LIBNFC_DEV_ACR122_H_
#include <stdint.h>
#include <stdbool.h>
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_acr122_connect(const nfc_device_desc_t* pndd);
void dev_acr122_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_acr122_transceive(const dev_spec ds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
// Various additional features this device supports
char* dev_acr122_firmware(const dev_spec ds);
bool dev_acr122_led_red(const dev_spec ds, bool bOn);
#endif // _LIBNFC_DEV_ACR122_H_

212
src/lib/drivers/arygon.c Normal file
View file

@ -0,0 +1,212 @@
/**
* 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 dev_arygon.c
* @brief
*/
#include "dev_arygon.h"
#include "rs232.h"
#include "bitutils.h"
#include "messages.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): ???,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
*/
dev_info* dev_arygon_connect(const nfc_device_desc_t* pndd)
{
uint32_t uiDevNr;
serial_port sp;
char acConnect[BUFFER_LENGTH];
dev_info* pdi = INVALID_DEVICE_INFO;
if( pndd == NULL ) {
#ifdef DISABLE_SERIAL_AUTOPROBE
INFO("Sorry, serial auto-probing have been disabled at compile time.");
return INVALID_DEVICE_INFO;
#else
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<MAX_DEVICES; uiDevNr++)
{
#ifdef __APPLE__
strcpy(acConnect,SERIAL_STRING);
#else
sprintf(acConnect,"%s%d",SERIAL_STRING,uiDevNr);
#endif /* __APPLE__ */
sp = rs232_open(acConnect);
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT))
{
rs232_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
// Test if we have found a device
if (uiDevNr == MAX_DEVICES) return INVALID_DEVICE_INFO;
} else {
DBG("Connecting to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed);
strcpy(acConnect,pndd->pcPort);
sp = rs232_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 INVALID_DEVICE_INFO;
rs232_set_speed(sp, pndd->uiSpeed);
}
DBG("Successfully connected to: %s",acConnect);
// We have a connection
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,"ARYGON");
pdi->ct = CT_PN532;
pdi->ds = (dev_spec)sp;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
void dev_arygon_disconnect(dev_info* pdi)
{
rs232_close((serial_port)pdi->ds);
free(pdi);
}
bool dev_arygon_transceive(const dev_spec ds, 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 (!rs232_send((serial_port)ds,abtTxBuf,szTxLen+8)) {
ERR("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 (!rs232_receive((serial_port)ds,abtRxBuf,&szRxBufLen)) {
ERR("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;
}

38
src/lib/drivers/arygon.h Normal file
View file

@ -0,0 +1,38 @@
/**
* 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 dev_arygon.h
* @brief
*/
#ifndef _LIBNFC_DEV_ARYGON_H_
#define _LIBNFC_DEV_ARYGON_H_
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_arygon_connect(const nfc_device_desc_t* pndd);
void dev_arygon_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_arygon_transceive(const dev_spec ds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
#endif // _LIBNFC_DEV_ARYGON_H_

256
src/lib/drivers/pn531.c Normal file
View file

@ -0,0 +1,256 @@
/**
* 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 dev_pn531.c
* @brief
*/
/*
Thanks to d18c7db and Okko for example code
*/
#include <stdio.h>
#include <stddef.h>
#include <usb.h>
#include <string.h>
#include "defines.h"
#include "dev_pn531.h"
#include "bitutils.h"
#include "messages.h"
#define BUFFER_LENGTH 256
#define USB_TIMEOUT 30000
typedef struct {
usb_dev_handle* pudh;
uint32_t uiEndPointIn;
uint32_t uiEndPointOut;
} dev_spec_pn531;
// Find transfer endpoints for bulk transfers
static void get_end_points(struct usb_device *dev, dev_spec_pn531* pdsp)
{
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)
{
#ifdef DEBUG
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointIn = uiEndPoint;
}
// Test if we dealing with a bulk OUT endpoint
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
{
#ifdef DEBUG
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointOut = uiEndPoint;
}
}
}
dev_info* dev_pn531_connect(const nfc_device_desc_t* pndd)
{
int idvendor = 0x04CC;
int idproduct = 0x0531;
int idvendor_alt = 0x054c;
int idproduct_alt = 0x0193;
struct usb_bus *bus;
struct usb_device *dev;
dev_info* pdi = INVALID_DEVICE_INFO;
dev_spec_pn531* pdsp;
dev_spec_pn531 dsp;
uint32_t uiDevIndex;
dsp.uiEndPointIn = 0;
dsp.uiEndPointOut = 0;
dsp.pudh = NULL;
usb_init();
if (usb_find_busses() < 0) return INVALID_DEVICE_INFO;
if (usb_find_devices() < 0) return INVALID_DEVICE_INFO;
// Initialize the device index we are seaching for
if( pndd == NULL ) {
uiDevIndex = 0;
} else {
uiDevIndex = pndd->uiIndex;
}
for (bus = usb_get_busses(); bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if ((idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct) ||
(idvendor_alt==dev->descriptor.idVendor && idproduct_alt==dev->descriptor.idProduct))
{
// Make sure there are 2 endpoints available
if (dev->config->interface->altsetting->bNumEndpoints < 2) return pdi;
// Test if we are looking for this device according to the current index
if (uiDevIndex != 0)
{
// Nope, we maybe want the next one, let's try to find another
uiDevIndex--;
continue;
}
DBG("Found PN531 device");
// Open the PN531 USB device
dsp.pudh = usb_open(dev);
get_end_points(dev,&dsp);
if(usb_set_configuration(dsp.pudh,1) < 0)
{
DBG("Set config failed");
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
if(usb_claim_interface(dsp.pudh,0) < 0)
{
DBG("Can't claim interface");
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
// Allocate memory for the device info and specification, fill it and return the info
pdsp = malloc(sizeof(dev_spec_pn531));
*pdsp = dsp;
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,"PN531USB");
pdi->ct = CT_PN531;
pdi->ds = (dev_spec)pdsp;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
}
}
return pdi;
}
void dev_pn531_disconnect(dev_info* pdi)
{
dev_spec_pn531* pdsp = (dev_spec_pn531*)pdi->ds;
usb_release_interface(pdsp->pudh,0);
usb_close(pdsp->pudh);
free(pdi->ds);
free(pdi);
}
bool dev_pn531_transceive(const dev_spec ds, 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];
dev_spec_pn531* pdsp = (dev_spec_pn531*)ds;
// 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;
#ifdef DEBUG
printf("Tx: ");
print_hex(abtTx,szTxLen+7);
#endif
ret = usb_bulk_write(pdsp->pudh, pdsp->uiEndPointOut, (char*)abtTx, szTxLen+7, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef DEBUG
printf("usb_bulk_write failed with error %d\n", ret);
#endif
return false;
}
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef DEBUG
printf( "usb_bulk_read failed with error %d\n", ret);
#endif
return false;
}
#ifdef DEBUG
printf("Rx: ");
print_hex(abtRx,ret);
#endif
if( ret == 6 )
{
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef DEBUG
printf("usb_bulk_read failed with error %d\n", ret);
#endif
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) return false;
// Remove the preceding and appending bytes 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
*pszRxLen = ret - 7 - 2;
memcpy( pbtRx, abtRx + 7, *pszRxLen);
return true;
}

41
src/lib/drivers/pn531.h Normal file
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 dev_pn531.h
* @brief
*/
#ifndef _LIBNFC_DEV_PN531_H_
#define _LIBNFC_DEV_PN531_H_
#include <stdint.h>
#include <stdbool.h>
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_pn531_connect(const nfc_device_desc_t* pndd);
void dev_pn531_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_pn531_transceive(const dev_spec ds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
#endif // _LIBNFC_DEV_PN531_H_

View file

@ -0,0 +1,199 @@
/**
* 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 dev_pn532_uart.c
* @brief
*/
#include "dev_pn532_uart.h"
#include "rs232.h"
#include "bitutils.h"
#include "messages.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 and others POSIX systems
#define SERIAL_STRING "/dev/ttyUSB"
#endif
#endif
#define BUFFER_LENGTH 256
#define SERIAL_DEFAULT_PORT_SPEED 115200
dev_info* dev_pn532_uart_connect(const nfc_device_desc_t* pndd)
{
uint32_t uiDevNr;
serial_port sp;
char acConnect[BUFFER_LENGTH];
dev_info* pdi = INVALID_DEVICE_INFO;
if( pndd == NULL ) {
#ifdef DISABLE_SERIAL_AUTOPROBE
INFO("Sorry, serial auto-probing have been disabled at compile time.");
return INVALID_DEVICE_INFO;
#else
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<MAX_DEVICES; uiDevNr++)
{
#ifdef __APPLE__
strcpy(acConnect,SERIAL_STRING);
#else
sprintf(acConnect,"%s%d",SERIAL_STRING,uiDevNr);
#endif /* __APPLE__ */
sp = rs232_open(acConnect);
if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT))
{
rs232_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
// Test if we have found a device
if (uiDevNr == MAX_DEVICES) return INVALID_DEVICE_INFO;
} else {
DBG("Connecting to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed);
strcpy(acConnect,pndd->pcPort);
sp = rs232_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 INVALID_DEVICE_INFO;
rs232_set_speed(sp, pndd->uiSpeed);
}
/** @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 };
rs232_send(sp, pncmd_pn532c106_wakeup, sizeof(pncmd_pn532c106_wakeup));
delay_ms(10);
if (!rs232_receive(sp,abtRxBuf,&szRxBufLen)) {
ERR("Unable to receive data. (RX)");
return NULL;
}
#ifdef DEBUG
printf(" RX: ");
print_hex(abtRxBuf,szRxBufLen);
#endif
DBG("Successfully connected to: %s",acConnect);
// We have a connection
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,"PN532_UART");
pdi->ct = CT_PN532;
pdi->ds = (dev_spec)sp;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
void dev_pn532_uart_disconnect(dev_info* pdi)
{
rs232_close((serial_port)pdi->ds);
free(pdi);
}
bool dev_pn532_uart_transceive(const dev_spec ds, 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 (!rs232_send((serial_port)ds,abtTxBuf,szTxLen+7)) {
ERR("Unable to transmit data. (TX)");
return false;
}
/** @note PN532 (at 115200 bauds) need 20ms between sending and receiving frame.
* 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);
if (!rs232_receive((serial_port)ds,abtRxBuf,&szRxBufLen)) {
ERR("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,38 @@
/**
* 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 dev_pn532_uart.h
* @brief
*/
#ifndef _LIBNFC_DEV_PN532_UART_H_
#define _LIBNFC_DEV_PN532_UART_H_
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_pn532_uart_connect(const nfc_device_desc_t* pndd);
void dev_pn532_uart_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_pn532_uart_transceive(const dev_spec ds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
#endif // _LIBNFC_DEV_PN532_UART_H_

260
src/lib/drivers/pn533.c Normal file
View file

@ -0,0 +1,260 @@
/**
* 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 dev_pn533.c
* @brief
*/
/*
Thanks to d18c7db and Okko for example code
*/
#include "dev_pn533.h"
#include <usb.h>
#include <stdio.h>
#include <string.h>
#include "defines.h"
#include "bitutils.h"
#include "messages.h"
#define BUFFER_LENGTH 256
#define USB_TIMEOUT 30000
typedef struct {
usb_dev_handle* pudh;
uint32_t uiEndPointIn;
uint32_t uiEndPointOut;
} dev_spec_pn533;
// Find transfer endpoints for bulk transfers
static void get_end_points(struct usb_device *dev, dev_spec_pn533* pdsp)
{
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)
{
#ifdef DEBUG
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointIn = uiEndPoint;
}
// Test if we dealing with a bulk OUT endpoint
if((uiEndPoint & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
{
#ifdef DEBUG
printf("Bulk endpoint in : 0x%02X\n", uiEndPoint);
#endif
pdsp->uiEndPointOut = uiEndPoint;
}
}
}
dev_info* dev_pn533_connect(const nfc_device_desc_t* pndd)
{
int idvendor = 0x04e6;
int idproduct = 0x5591;
struct usb_bus *bus;
struct usb_device *dev;
dev_info* pdi = INVALID_DEVICE_INFO;
dev_spec_pn533* pdsp;
dev_spec_pn533 dsp;
uint32_t uiDevIndex;
dsp.uiEndPointIn = 0;
dsp.uiEndPointOut = 0;
dsp.pudh = NULL;
usb_init();
if (usb_find_busses() < 0) return INVALID_DEVICE_INFO;
if (usb_find_devices() < 0) return INVALID_DEVICE_INFO;
// Initialize the device index we are seaching for
if( pndd == NULL ) {
uiDevIndex = 0;
} else {
uiDevIndex = pndd->uiIndex;
}
for (bus = usb_get_busses(); bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
if (idvendor==dev->descriptor.idVendor && idproduct==dev->descriptor.idProduct)
{
// Make sure there are 2 endpoints available
if (dev->config->interface->altsetting->bNumEndpoints < 2) return pdi;
// Test if we are looking for this device according to the current index
if (uiDevIndex != 0)
{
// Nope, we maybe want the next one, let's try to find another
uiDevIndex--;
continue;
}
DBG("Found PN533 device");
// Open the PN533 USB device
dsp.pudh = usb_open(dev);
get_end_points(dev,&dsp);
if(usb_set_configuration(dsp.pudh,1) < 0)
{
DBG("Setting config failed");
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
if(usb_claim_interface(dsp.pudh,0) < 0)
{
DBG("Can't claim interface");
usb_close(dsp.pudh);
return INVALID_DEVICE_INFO;
}
// Allocate memory for the device info and specification, fill it and return the info
pdsp = malloc(sizeof(dev_spec_pn533));
*pdsp = dsp;
pdi = malloc(sizeof(dev_info));
strcpy(pdi->acName,"PN533USB");
pdi->ct = CT_PN533;
pdi->ds = (dev_spec)pdsp;
pdi->bActive = true;
pdi->bCrc = true;
pdi->bPar = true;
pdi->ui8TxBits = 0;
return pdi;
}
}
}
return pdi;
}
void dev_pn533_disconnect(dev_info* pdi)
{
dev_spec_pn533* pdsp = (dev_spec_pn533*)pdi->ds;
usb_release_interface(pdsp->pudh,0);
usb_close(pdsp->pudh);
free(pdi->ds);
free(pdi);
}
bool dev_pn533_transceive(const dev_spec ds, 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];
dev_spec_pn533* pdsp = (dev_spec_pn533*)ds;
// 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;
#ifdef DEBUG
printf(" TX: ");
print_hex(abtTx,szTxLen+7);
#endif
ret = usb_bulk_write(pdsp->pudh, pdsp->uiEndPointOut, (char*)abtTx, szTxLen+7, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef DEBUG
printf("usb_bulk_write failed with error %d\n", ret);
#endif
return false;
}
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef DEBUG
printf( "usb_bulk_read failed with error %d\n", ret);
#endif
return false;
}
#ifdef DEBUG
printf(" RX: ");
print_hex(abtRx,ret);
#endif
if( ret == 6 )
{
ret = usb_bulk_read(pdsp->pudh, pdsp->uiEndPointIn, (char*)abtRx, BUFFER_LENGTH, USB_TIMEOUT);
if( ret < 0 )
{
#ifdef DEBUG
printf("usb_bulk_read failed with error %d\n", ret);
#endif
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) 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;
}

38
src/lib/drivers/pn533.h Normal file
View file

@ -0,0 +1,38 @@
/**
* 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 dev_pn533.h
* @brief
*/
#ifndef _LIBNFC_DEV_PN533_H_
#define _LIBNFC_DEV_PN533_H_
#include "defines.h"
#include "types.h"
// Functions used by developer to handle connection to this device
dev_info* dev_pn533_connect(const nfc_device_desc_t* pndd);
void dev_pn533_disconnect(dev_info* pdi);
// Callback function used by libnfc to transmit commands to the PN53X chip
bool dev_pn533_transceive(const dev_spec ds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen);
#endif // _LIBNFC_DEV_PN533_H_

1006
src/lib/nfc.c Normal file

File diff suppressed because it is too large Load diff