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 
00031 #include <stdio.h>
00032 #include <string.h>
00033 
00034 #include "pn532_uart.h"
00035 
00036 #include <nfc/nfc.h>
00037 #include <nfc/nfc-messages.h>
00038 
00039 // Bus
00040 #include "uart.h"
00041 
00042 #define BUFFER_LENGTH 256
00043 
00044 #define SERIAL_DEFAULT_PORT_SPEED 115200
00045 
00046 void    pn532_uart_wakeup (const nfc_device_spec_t nds);
00047 bool    pn532_uart_check_communication (const nfc_device_spec_t nds, bool * success);
00048 
00049 nfc_device_desc_t *
00050 pn532_uart_pick_device (void)
00051 {
00052   nfc_device_desc_t *pndd;
00053 
00054   if ((pndd = malloc (sizeof (*pndd)))) {
00055     size_t  szN;
00056 
00057     if (!pn532_uart_list_devices (pndd, 1, &szN)) {
00058       DBG ("%s", "pn532_uart_list_devices failed");
00059       return NULL;
00060     }
00061 
00062     if (szN == 0) {
00063       DBG ("%s", "No device found");
00064       return NULL;
00065     }
00066   }
00067 
00068   return pndd;
00069 }
00070 
00071 bool
00072 pn532_uart_list_devices (nfc_device_desc_t pnddDevices[], size_t szDevices, size_t * pszDeviceFound)
00073 {
00077 #ifndef SERIAL_AUTOPROBE_ENABLED
00078   (void) pnddDevices;
00079   (void) szDevices;
00080   *pszDeviceFound = 0;
00081   DBG ("%s", "Serial auto-probing have been disabled at compile time. Skipping autoprobe.");
00082   return false;
00083 #else /* SERIAL_AUTOPROBE_ENABLED */
00084   *pszDeviceFound = 0;
00085 
00086   serial_port sp;
00087   const char *pcPorts[] = DEFAULT_SERIAL_PORTS;
00088   const char *pcPort;
00089   int     iDevice = 0;
00090 
00091   while ((pcPort = pcPorts[iDevice++])) {
00092     sp = uart_open (pcPort);
00093     DBG ("Trying to find PN532 device on serial port: %s at %d bauds.", pcPort, SERIAL_DEFAULT_PORT_SPEED);
00094 
00095     if ((sp != INVALID_SERIAL_PORT) && (sp != CLAIMED_SERIAL_PORT)) {
00096       bool    bComOk;
00097       // Serial port claimed but we need to check if a PN532_UART is connected.
00098       uart_set_speed (sp, SERIAL_DEFAULT_PORT_SPEED);
00099       // PN532 could be powered down, we need to wake it up before line testing.
00100       pn532_uart_wakeup ((nfc_device_spec_t) sp);
00101       // Check communication using "Diagnose" command, with "Comunication test" (0x00)
00102       if (!pn532_uart_check_communication ((nfc_device_spec_t) sp, &bComOk))
00103         return false;
00104       if (!bComOk)
00105         continue;
00106       uart_close (sp);
00107 
00108       snprintf (pnddDevices[*pszDeviceFound].acDevice, DEVICE_NAME_LENGTH - 1, "%s (%s)", "PN532", pcPort);
00109       pnddDevices[*pszDeviceFound].acDevice[DEVICE_NAME_LENGTH - 1] = '\0';
00110       pnddDevices[*pszDeviceFound].pcDriver = PN532_UART_DRIVER_NAME;
00111       pnddDevices[*pszDeviceFound].pcPort = strdup (pcPort);
00112       pnddDevices[*pszDeviceFound].uiSpeed = SERIAL_DEFAULT_PORT_SPEED;
00113       DBG ("Device found: %s.", pnddDevices[*pszDeviceFound].acDevice);
00114       (*pszDeviceFound)++;
00115 
00116       // Test if we reach the maximum "wanted" devices
00117       if ((*pszDeviceFound) >= szDevices)
00118         break;
00119     }
00120 #  ifdef DEBUG
00121     if (sp == INVALID_SERIAL_PORT)
00122       DBG ("Invalid serial port: %s", pcPort);
00123     if (sp == CLAIMED_SERIAL_PORT)
00124       DBG ("Serial port already claimed: %s", pcPort);
00125 #  endif
00126        /* DEBUG */
00127   }
00128 #endif /* SERIAL_AUTOPROBE_ENABLED */
00129   return true;
00130 }
00131 
00132 nfc_device_t *
00133 pn532_uart_connect (const nfc_device_desc_t * pndd)
00134 {
00135   serial_port sp;
00136   nfc_device_t *pnd = NULL;
00137   bool    bComOk;
00138 
00139   DBG ("Attempt to connect to: %s at %d bauds.", pndd->pcPort, pndd->uiSpeed);
00140   sp = uart_open (pndd->pcPort);
00141 
00142   if (sp == INVALID_SERIAL_PORT)
00143     ERR ("Invalid serial port: %s", pndd->pcPort);
00144   if (sp == CLAIMED_SERIAL_PORT)
00145     ERR ("Serial port already claimed: %s", pndd->pcPort);
00146   if ((sp == CLAIMED_SERIAL_PORT) || (sp == INVALID_SERIAL_PORT))
00147     return NULL;
00148 
00149   uart_set_speed (sp, pndd->uiSpeed);
00150 
00151   // PN532 could be powered down, we need to wake it up before line testing.
00152   pn532_uart_wakeup ((nfc_device_spec_t) sp);
00153   // Check communication using "Diagnose" command, with "Comunication test" (0x00)
00154   if (!pn532_uart_check_communication ((nfc_device_spec_t) sp, &bComOk))
00155     return NULL;
00156   if (!bComOk)
00157     return NULL;
00158 
00159   DBG ("Successfully connected to: %s", pndd->pcPort);
00160 
00161   // We have a connection
00162   pnd = malloc (sizeof (nfc_device_t));
00163   strncpy (pnd->acName, pndd->acDevice, DEVICE_NAME_LENGTH - 1);
00164   pnd->acName[DEVICE_NAME_LENGTH - 1] = '\0';
00165 
00166   pnd->nc = NC_PN532;
00167   pnd->nds = (nfc_device_spec_t) sp;
00168   pnd->bActive = true;
00169   pnd->bCrc = true;
00170   pnd->bPar = true;
00171   pnd->ui8TxBits = 0;
00172   return pnd;
00173 }
00174 
00175 void
00176 pn532_uart_disconnect (nfc_device_t * pnd)
00177 {
00178   uart_close ((serial_port) pnd->nds);
00179   free (pnd);
00180 }
00181 
00182 bool
00183 pn532_uart_transceive (nfc_device_t * pnd, const byte_t * pbtTx, const size_t szTxLen, byte_t * pbtRx,
00184                        size_t * pszRxLen)
00185 {
00186   byte_t  abtTxBuf[BUFFER_LENGTH] = { 0x00, 0x00, 0xff };       // Every packet must start with "00 00 ff"
00187   byte_t  abtRxBuf[BUFFER_LENGTH];
00188   size_t  szRxBufLen = BUFFER_LENGTH;
00189   size_t  szPos;
00190   int     res;
00191   // TODO: Move this one level up for libnfc-1.6
00192   uint8_t ack_frame[] = { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00 };
00193 
00194   // Packet length = data length (len) + checksum (1) + end of stream marker (1)
00195   abtTxBuf[3] = szTxLen;
00196   // Packet length checksum
00197   abtTxBuf[4] = BUFFER_LENGTH - abtTxBuf[3];
00198   // Copy the PN53X command into the packet buffer
00199   memmove (abtTxBuf + 5, pbtTx, szTxLen);
00200 
00201   // Calculate data payload checksum
00202   abtTxBuf[szTxLen + 5] = 0;
00203   for (szPos = 0; szPos < szTxLen; szPos++) {
00204     abtTxBuf[szTxLen + 5] -= abtTxBuf[szPos + 5];
00205   }
00206 
00207   // End of stream marker
00208   abtTxBuf[szTxLen + 6] = 0;
00209 
00210 #ifdef DEBUG
00211   PRINT_HEX ("TX", abtTxBuf, szTxLen + 7);
00212 #endif
00213   res = uart_send ((serial_port) pnd->nds, abtTxBuf, szTxLen + 7);
00214   if (res != 0) {
00215     ERR ("%s", "Unable to transmit data. (TX)");
00216     pnd->iLastError = res;
00217     return false;
00218   }
00219 
00220   res = uart_receive ((serial_port) pnd->nds, abtRxBuf, &szRxBufLen);
00221   if (res != 0) {
00222     ERR ("%s", "Unable to receive data. (RX)");
00223     pnd->iLastError = res;
00224     return false;
00225   }
00226 #ifdef DEBUG
00227   PRINT_HEX ("RX", abtRxBuf, szRxBufLen);
00228 #endif
00229 
00230   // WARN: UART is a per byte reception, so you usually receive ACK and next frame the same time
00231   if (!pn53x_transceive_check_ack_frame_callback (pnd, abtRxBuf, szRxBufLen))
00232     return false;
00233   szRxBufLen -= sizeof (ack_frame);
00234   memmove (abtRxBuf, abtRxBuf + sizeof (ack_frame), szRxBufLen);
00235 
00236   if (szRxBufLen == 0) {
00237     szRxBufLen = BUFFER_LENGTH;
00238     do {
00239       delay_ms (10);
00240       res = uart_receive ((serial_port) pnd->nds, abtRxBuf, &szRxBufLen);
00241     } while (res != 0);
00242 #ifdef DEBUG
00243     PRINT_HEX ("RX", abtRxBuf, szRxBufLen);
00244 #endif
00245   }
00246 
00247 #ifdef DEBUG
00248   PRINT_HEX ("TX", ack_frame, 6);
00249 #endif
00250   res = uart_send ((serial_port) pnd->nds, ack_frame, 6);
00251   if (res != 0) {
00252     ERR ("%s", "Unable to transmit data. (TX)");
00253     pnd->iLastError = res;
00254     return false;
00255   }
00256 
00257   if (!pn53x_transceive_check_error_frame_callback (pnd, abtRxBuf, szRxBufLen))
00258     return false;
00259 
00260   // When the answer should be ignored, just return a successful result
00261   if (pbtRx == NULL || pszRxLen == NULL)
00262     return true;
00263 
00264   // Only succeed when the result is at least 00 00 FF xx Fx Dx xx .. .. .. xx 00 (x = variable)
00265   if (szRxBufLen < 9) {
00266     pnd->iLastError = DEINVAL;
00267     return false;
00268   }
00269   // Remove the preceding and appending bytes 00 00 ff 00 ff 00 00 00 FF xx Fx .. .. .. xx 00 (x = variable)
00270   *pszRxLen = szRxBufLen - 9;
00271   memcpy (pbtRx, abtRxBuf + 7, *pszRxLen);
00272 
00273   return true;
00274 }
00275 
00276 void
00277 pn532_uart_wakeup (const nfc_device_spec_t nds)
00278 {
00279   byte_t  abtRx[BUFFER_LENGTH];
00280   size_t  szRxLen;
00284   const byte_t pncmd_pn532c106_wakeup_preamble[] =
00285     { 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03, 0xfd, 0xd4, 0x14, 0x01, 0x17, 0x00, 0x00, 0xff, 0x03, 0xfd,
00286 0xd4, 0x14, 0x01, 0x17, 0x00 };
00287 #ifdef DEBUG
00288   PRINT_HEX ("TX", pncmd_pn532c106_wakeup_preamble, sizeof (pncmd_pn532c106_wakeup_preamble));
00289 #endif
00290   uart_send ((serial_port) nds, pncmd_pn532c106_wakeup_preamble, sizeof (pncmd_pn532c106_wakeup_preamble));
00291   if (0 == uart_receive ((serial_port) nds, abtRx, &szRxLen)) {
00292 #ifdef DEBUG
00293     PRINT_HEX ("RX", abtRx, szRxLen);
00294 #endif
00295   }
00296 }
00297 
00298 bool
00299 pn532_uart_check_communication (const nfc_device_spec_t nds, bool * success)
00300 {
00301   byte_t  abtRx[BUFFER_LENGTH];
00302   size_t  szRxLen;
00303   const byte_t attempted_result[] =
00304     { 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x09, 0xf7, 0xD5, 0x01, 0x00, 'l', 'i', 'b', 'n', 'f', 'c',
00305 0xbc, 0x00 };
00306   int     res;
00307 
00309   const byte_t pncmd_communication_test[] =
00310     { 0x00, 0x00, 0xff, 0x09, 0xf7, 0xd4, 0x00, 0x00, 'l', 'i', 'b', 'n', 'f', 'c', 0xbe, 0x00 };
00311 
00312   *success = false;
00313 
00314 #ifdef DEBUG
00315   PRINT_HEX ("TX", pncmd_communication_test, sizeof (pncmd_communication_test));
00316 #endif
00317   res = uart_send ((serial_port) nds, pncmd_communication_test, sizeof (pncmd_communication_test));
00318   if (res != 0) {
00319     ERR ("%s", "Unable to transmit data. (TX)");
00320     return false;
00321   }
00322 
00323   res = uart_receive ((serial_port) nds, abtRx, &szRxLen);
00324   if (res != 0) {
00325     ERR ("%s", "Unable to receive data. (RX)");
00326     return false;
00327   }
00328 #ifdef DEBUG
00329   PRINT_HEX ("RX", abtRx, szRxLen);
00330 #endif
00331 
00332   if (0 == memcmp (abtRx, attempted_result, sizeof (attempted_result)))
00333     *success = true;
00334 
00335   return true;
00336 }