pn532_uart.c

Go to the documentation of this file.
00001 /*-
00002  * Public platform independent Near Field Communication (NFC) library
00003  * 
00004  * Copyright (C) 2009, Roel Verdult
00005  * 
00006  * This program is free software: you can redistribute it and/or modify it
00007  * under the terms of the GNU Lesser General Public License as published by the
00008  * Free Software Foundation, either version 3 of the License, or (at your
00009  * option) any later version.
00010  * 
00011  * This program is distributed in the hope that it will be useful, but WITHOUT
00012  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00013  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00014  * more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 
00025 #ifdef HAVE_CONFIG_H
00026   #include "config.h"
00027 #endif // HAVE_CONFIG_H
00028 
00029 #include "../drivers.h"
00030 #include "../bitutils.h"
00031 
00032 #include <stdio.h>
00033 #include <string.h>
00034 
00035 #include "pn532_uart.h"
00036 
00037 #include <nfc/nfc-messages.h>
00038 
00039 
00040 // Bus
00041 #include "uart.h"
00042 
00043 #ifdef _WIN32
00044   #define SERIAL_STRING "COM"
00045   #define snprintf _snprintf
00046   #define strdup _strdup
00047 #else
00048   // unistd.h is needed for usleep() fct.
00049   #include <unistd.h>
00050 
00051   #ifdef __APPLE__
00052     // MacOS
00053     // TODO: find UART connection string for PN53X device on Mac OS X
00054     #define SERIAL_STRING ""
00055   #else
00056     // *BSD, Linux and others POSIX systems
00057     #define SERIAL_STRING "/dev/ttyUSB"
00058   #endif
00059 #endif
00060 
00061 #define BUFFER_LENGTH 256
00062 
00063 #define SERIAL_DEFAULT_PORT_SPEED 115200
00064 
00065 nfc_device_desc_t *
00066 pn532_uart_pick_device (void)
00067 {
00068   nfc_device_desc_t *pndd;
00069 
00070   if ((pndd = malloc (sizeof (*pndd)))) {
00071     size_t szN;
00072 
00073     if (!pn532_uart_list_devices (pndd, 1, &szN)) {
00074       DBG("%s", "pn532_uart_list_devices failed");
00075       return NULL;
00076     }
00077 
00078     if (szN == 0) {
00079       DBG("%s", "No device found");
00080       return NULL;
00081     }
00082   }
00083 
00084   return pndd;
00085 }
00086 
00087 bool
00088 pn532_uart_list_devices(nfc_device_desc_t pnddDevices[], size_t szDevices, size_t *pszDeviceFound)
00089 {
00090 /* @note: Due to UART bus we can't know if its really a pn532 without
00091  * sending some PN53x commands. But using this way to probe devices, we can
00092  * have serious problem with other device on this bus */
00093 #ifndef SERIAL_AUTOPROBE_ENABLED
00094   *pszDeviceFound = 0;
00095   INFO("%s", "Sorry, serial auto-probing have been disabled at compile time.");
00096   return false;
00097 #else /* SERIAL_AUTOPROBE_ENABLED */
00098   *pszDeviceFound = 0;
00099 
00100   serial_port sp;
00101   char acConnect[BUFFER_LENGTH];
00102   int iDevice;
00103 
00104   // I have no idea how MAC OS X deals with multiple devices, so a quick workaround
00105   for (iDevice=0; iDevice<DRIVERS_MAX_DEVICES; iDevice++)
00106   {
00107 #ifdef __APPLE__
00108     strcpy(acConnect,SERIAL_STRING);
00109 #else /* __APPLE__ */
00110     sprintf(acConnect,"%s%d",SERIAL_STRING,iDevice);
00111 #endif /* __APPLE__ */
00112     sp = uart_open(acConnect);
00113     DBG("Trying to find PN532 device on serial port: %s at %d bauds.",acConnect, SERIAL_DEFAULT_PORT_SPEED);
00114 
00115     if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT))
00116     {
00117       // PN532_UART device found
00118       uart_close(sp);
00119       snprintf(pnddDevices[*pszDeviceFound].acDevice, DEVICE_NAME_LENGTH - 1, "%s (%s)", "PN532", acConnect);
00120       pnddDevices[*pszDeviceFound].acDevice[DEVICE_NAME_LENGTH - 1] = '\0';
00121       pnddDevices[*pszDeviceFound].pcDriver = PN532_UART_DRIVER_NAME;
00122       //pnddDevices[*pszDeviceFound].pcPort = strndup(acConnect, BUFFER_LENGTH - 1);
00123       pnddDevices[*pszDeviceFound].pcPort = strdup(acConnect);
00124       pnddDevices[*pszDeviceFound].pcPort[BUFFER_LENGTH] = '\0';
00125       pnddDevices[*pszDeviceFound].uiSpeed = SERIAL_DEFAULT_PORT_SPEED;
00126       DBG("Device found: %s.", pnddDevices[*pszDeviceFound].acDevice);
00127       (*pszDeviceFound)++;
00128 
00129       // Test if we reach the maximum "wanted" devices
00130       if((*pszDeviceFound) >= szDevices) break;
00131     }
00132 #ifdef DEBUG
00133     if (sp == INVALID_SERIAL_PORT) DBG("Invalid serial port: %s",acConnect);
00134     if (sp == CLAIMED_SERIAL_PORT) DBG("Serial port already claimed: %s",acConnect);
00135 #endif /* DEBUG */
00136   }
00137 #endif /* SERIAL_AUTOPROBE_ENABLED */
00138   return true;
00139 }
00140 
00141 nfc_device_t* pn532_uart_connect(const nfc_device_desc_t* pndd)
00142 {
00145   byte_t abtRxBuf[BUFFER_LENGTH];
00146   size_t szRxBufLen;
00147   const byte_t pncmd_pn532c106_wakeup[] = { 0x55,0x55,0x00,0x00,0x00,0x00,0x00,0xFF,0x03,0xFD,0xD4,0x14,0x01,0x17,0x00 };
00148 
00149   serial_port sp;
00150   nfc_device_t* pnd = NULL;
00151 
00152   if( pndd == NULL ) {
00153     DBG("%s", "pn532_uart_connect() need an nfc_device_desc_t struct.");
00154     return NULL;
00155   } else {
00156     DBG("Connecting to: %s at %d bauds.",pndd->pcPort, pndd->uiSpeed);
00157     sp = uart_open(pndd->pcPort);
00158 
00159     if (sp == INVALID_SERIAL_PORT) ERR("Invalid serial port: %s",pndd->pcPort);
00160     if (sp == CLAIMED_SERIAL_PORT) ERR("Serial port already claimed: %s",pndd->pcPort);
00161     if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT)) return NULL;
00162 
00163     uart_set_speed(sp, pndd->uiSpeed);
00164   }
00165 
00166   uart_send(sp, pncmd_pn532c106_wakeup, sizeof(pncmd_pn532c106_wakeup));
00167 
00168   if (!uart_receive(sp,abtRxBuf,&szRxBufLen)) {
00169     ERR("%s", "Unable to receive data. (RX)");
00170     return NULL;
00171   }
00172 #ifdef DEBUG
00173   printf(" RX: ");
00174   print_hex(abtRxBuf,szRxBufLen);
00175 #endif
00176 
00177   DBG("Successfully connected to: %s",pndd->pcPort);
00178 
00179   // We have a connection
00180   pnd = malloc(sizeof(nfc_device_t));
00181   strncpy(pnd->acName, pndd->acDevice, DEVICE_NAME_LENGTH - 1);
00182   pnd->acName[DEVICE_NAME_LENGTH - 1] = '\0';
00183 
00184   pnd->nc = NC_PN532;
00185   pnd->nds = (nfc_device_spec_t)sp;
00186   pnd->bActive = true;
00187   pnd->bCrc = true;
00188   pnd->bPar = true;
00189   pnd->ui8TxBits = 0;
00190   return pnd;
00191 }
00192 
00193 void pn532_uart_disconnect(nfc_device_t* pnd)
00194 {
00195   uart_close((serial_port)pnd->nds);
00196   free(pnd);
00197 }
00198 
00199 bool pn532_uart_transceive(const nfc_device_spec_t nds, const byte_t* pbtTx, const size_t szTxLen, byte_t* pbtRx, size_t* pszRxLen)
00200 {
00201   byte_t abtTxBuf[BUFFER_LENGTH] = { 0x00, 0x00, 0xff }; // Every packet must start with "00 00 ff"
00202   byte_t abtRxBuf[BUFFER_LENGTH];
00203   size_t szRxBufLen = BUFFER_LENGTH;
00204   size_t szPos;
00205 
00206   // Packet length = data length (len) + checksum (1) + end of stream marker (1)
00207   abtTxBuf[3] = szTxLen;
00208   // Packet length checksum
00209   abtTxBuf[4] = BUFFER_LENGTH - abtTxBuf[3];
00210   // Copy the PN53X command into the packet buffer
00211   memmove(abtTxBuf+5,pbtTx,szTxLen);
00212 
00213   // Calculate data payload checksum
00214   abtTxBuf[szTxLen+5] = 0;
00215   for(szPos=0; szPos < szTxLen; szPos++) 
00216   {
00217     abtTxBuf[szTxLen+5] -= abtTxBuf[szPos+5];
00218   }
00219 
00220   // End of stream marker
00221   abtTxBuf[szTxLen+6] = 0;
00222 
00223 #ifdef DEBUG
00224   printf(" TX: ");
00225   print_hex(abtTxBuf,szTxLen+7);
00226 #endif
00227   if (!uart_send((serial_port)nds,abtTxBuf,szTxLen+7)) {
00228     ERR("%s", "Unable to transmit data. (TX)");
00229     return false;
00230   }
00231 
00232   if (!uart_receive((serial_port)nds,abtRxBuf,&szRxBufLen)) {
00233     ERR("%s", "Unable to receive data. (RX)");
00234     return false;
00235   }
00236 
00237 #ifdef DEBUG
00238   printf(" RX: ");
00239   print_hex(abtRxBuf,szRxBufLen);
00240 #endif
00241 
00242   // When the answer should be ignored, just return a successful result
00243   if(pbtRx == NULL || pszRxLen == NULL) return true;
00244 
00245   // 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)
00246   if(szRxBufLen < 15) return false;
00247 
00248   // Remove the preceding and appending bytes 00 00 ff 00 ff 00 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
00249   *pszRxLen = szRxBufLen - 15;
00250   memcpy(pbtRx, abtRxBuf+13, *pszRxLen);
00251 
00252   return true;
00253 }
Generated by  doxygen 1.6.2-20100208