diff --git a/src/Makefile.am b/src/Makefile.am index 985ef96..2c50dce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,13 +3,13 @@ SUBDIRS = . examples # set the include path found by configure INCLUDES= $(all_includes) -nfc_devices_headers = dev_arygon.h +nfc_devices_headers = dev_arygon.h dev_pn532_uart.h nfcinclude_HEADERS = libnfc.h bitutils.h defines.h types.h rs232.h devices.h messages.h nfcinclude_HEADERS += $(nfc_devices_headers) nfcincludedir = $(includedir)/libnfc lib_LTLIBRARIES = libnfc.la -libnfc_la_SOURCES = bitutils.c libnfc.c rs232.c dev_arygon.c +libnfc_la_SOURCES = bitutils.c libnfc.c rs232.c dev_arygon.c dev_pn532_uart.c libnfc_la_CFLAGS = libnfc_la_LIBADD = diff --git a/src/dev_pn532_uart.c b/src/dev_pn532_uart.c new file mode 100644 index 0000000..20bd1ed --- /dev/null +++ b/src/dev_pn532_uart.c @@ -0,0 +1,176 @@ +/* + +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 + +*/ + +#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 + #ifdef __APPLE__ + #define SERIAL_STRING "/dev/tty.SLAB_USBtoUART" + #else + // unistd.h is needed for usleep() fct. + #include + #define delay_ms( X ) usleep( X * 1000 ) + #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; uiDevNrpcPort, 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,"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; +} diff --git a/src/dev_pn532_uart.h b/src/dev_pn532_uart.h new file mode 100644 index 0000000..1149d22 --- /dev/null +++ b/src/dev_pn532_uart.h @@ -0,0 +1,35 @@ +/* + +Public platform independent Near Field Communication (NFC) library +Copyright (C) 2009, Roel Verdult + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with this program. If not, see + +*/ + +#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_ + diff --git a/src/devices.h b/src/devices.h index 0d1e155..ba0b4a8 100644 --- a/src/devices.h +++ b/src/devices.h @@ -31,6 +31,7 @@ along with this program. If not, see #include "dev_pn533.h" #endif /* HAVE_LIBUSB */ #include "dev_arygon.h" +#include "dev_pn532_uart.h" const static struct dev_callbacks dev_callbacks_list[] = { // Driver Name Connect Transceive Disconnect @@ -41,6 +42,7 @@ const static struct dev_callbacks dev_callbacks_list[] = { { "PN531USB", dev_pn531_connect, dev_pn531_transceive, dev_pn531_disconnect }, { "PN533USB", dev_pn533_connect, dev_pn533_transceive, dev_pn533_disconnect }, #endif /* HAVE_LIBUSB */ + { "PN532_UART", dev_pn532_uart_connect, dev_pn532_uart_transceive, dev_pn532_uart_disconnect }, { "ARYGON", dev_arygon_connect, dev_arygon_transceive, dev_arygon_disconnect } };