First attempt to reorganize tree.
This commit is contained in:
parent
36cb0ff5f9
commit
ab62855d80
20 changed files with 0 additions and 0 deletions
276
src/lib/drivers/acr122.c
Normal file
276
src/lib/drivers/acr122.c
Normal 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
45
src/lib/drivers/acr122.h
Normal 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
212
src/lib/drivers/arygon.c
Normal 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
38
src/lib/drivers/arygon.h
Normal 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
256
src/lib/drivers/pn531.c
Normal 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
41
src/lib/drivers/pn531.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Public platform independent Near Field Communication (NFC) library
|
||||
*
|
||||
* Copyright (C) 2009, Roel Verdult
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*
|
||||
*
|
||||
* @file 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_
|
||||
|
||||
199
src/lib/drivers/pn532_uart.c
Normal file
199
src/lib/drivers/pn532_uart.c
Normal 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;
|
||||
}
|
||||
38
src/lib/drivers/pn532_uart.h
Normal file
38
src/lib/drivers/pn532_uart.h
Normal 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
260
src/lib/drivers/pn533.c
Normal 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
38
src/lib/drivers/pn533.h
Normal 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_
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue