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