libnfc 1.4.2

uart_posix.c

Go to the documentation of this file.
00001 /*-
00002  * Public platform independent Near Field Communication (NFC) library
00003  * 
00004  * Copyright (C) 2009, 2010, Roel Verdult, Romuald Conty
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  */
00020 
00026 #  include <sys/select.h>
00027 #  include <sys/param.h>
00028 #  include <termios.h>
00029 typedef struct termios term_info;
00030 typedef struct {
00031   int     fd;                   // Serial port file descriptor
00032   term_info tiOld;              // Terminal info before using the port
00033   term_info tiNew;              // Terminal info during the transaction
00034 } serial_port_unix;
00035 
00036 // timeval struct that define timeout delay for serial port:
00037 //  first is constant and currently related to PN53x response delay
00038 static const unsigned long int uiTimeoutStatic = 15000; // 15 ms to allow device to respond
00039 //  second is a per-byte timeout (sets when setting baudrate)
00040 static unsigned long int uiTimeoutPerByte = 0;
00041 
00042 // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct
00043 #  define CCLAIMED 0x80000000
00044 
00045 serial_port
00046 uart_open (const char *pcPortName)
00047 {
00048   serial_port_unix *sp = malloc (sizeof (serial_port_unix));
00049 
00050   if (sp == 0)
00051     return INVALID_SERIAL_PORT;
00052 
00053   sp->fd = open (pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK);
00054   if (sp->fd == -1) {
00055     uart_close (sp);
00056     return INVALID_SERIAL_PORT;
00057   }
00058 
00059   if (tcgetattr (sp->fd, &sp->tiOld) == -1) {
00060     uart_close (sp);
00061     return INVALID_SERIAL_PORT;
00062   }
00063   // Make sure the port is not claimed already
00064   if (sp->tiOld.c_iflag & CCLAIMED) {
00065     uart_close (sp);
00066     return CLAIMED_SERIAL_PORT;
00067   }
00068   // Copy the old terminal info struct
00069   sp->tiNew = sp->tiOld;
00070 
00071   sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD;
00072   sp->tiNew.c_iflag = CCLAIMED | IGNPAR;
00073   sp->tiNew.c_oflag = 0;
00074   sp->tiNew.c_lflag = 0;
00075 
00076   sp->tiNew.c_cc[VMIN] = 0;     // block until n bytes are received
00077   sp->tiNew.c_cc[VTIME] = 0;    // block until a timer expires (n * 100 mSec.)
00078 
00079   if (tcsetattr (sp->fd, TCSANOW, &sp->tiNew) == -1) {
00080     uart_close (sp);
00081     return INVALID_SERIAL_PORT;
00082   }
00083 
00084   tcflush (sp->fd, TCIFLUSH);
00085   return sp;
00086 }
00087 
00099 #define UART_BAUDRATE_T0_BYTE_DURATION(X) ((1000000 * 10)/ X)
00100 
00101 void
00102 uart_set_speed (serial_port sp, const uint32_t uiPortSpeed)
00103 {
00104   // Set per-byte timeout
00105   uiTimeoutPerByte = UART_BAUDRATE_T0_BYTE_DURATION(uiPortSpeed);
00106   DBG ("Serial port speed requested to be set to %d bauds (%lu µs).", uiPortSpeed, uiTimeoutPerByte);
00107   const serial_port_unix *spu = (serial_port_unix *) sp;
00108 
00109   // Portability note: on some systems, B9600 != 9600 so we have to do
00110   // uint32_t <=> speed_t associations by hand.
00111   speed_t stPortSpeed = B9600;
00112   switch (uiPortSpeed) {
00113   case 9600:
00114     stPortSpeed = B9600;
00115     break;
00116   case 19200:
00117     stPortSpeed = B19200;
00118     break;
00119   case 38400:
00120     stPortSpeed = B38400;
00121     break;
00122 #  ifdef B57600
00123   case 57600:
00124     stPortSpeed = B57600;
00125     break;
00126 #  endif
00127 #  ifdef B115200
00128   case 115200:
00129     stPortSpeed = B115200;
00130     break;
00131 #  endif
00132 #  ifdef B230400
00133   case 230400:
00134     stPortSpeed = B230400;
00135     break;
00136 #  endif
00137 #  ifdef B460800
00138   case 460800:
00139     stPortSpeed = B460800;
00140     break;
00141 #  endif
00142   default:
00143     ERR ("Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).",
00144          uiPortSpeed);
00145     return;
00146   };
00147 
00148   // Set port speed (Input and Output)
00149   cfsetispeed ((struct termios *) &(spu->tiNew), stPortSpeed);
00150   cfsetospeed ((struct termios *) &(spu->tiNew), stPortSpeed);
00151   if (tcsetattr (spu->fd, TCSADRAIN, &(spu->tiNew)) == -1) {
00152     ERR ("%s", "Unable to apply new speed settings.");
00153   }
00154 }
00155 
00156 uint32_t
00157 uart_get_speed (serial_port sp)
00158 {
00159   uint32_t uiPortSpeed = 0;
00160   const serial_port_unix *spu = (serial_port_unix *) sp;
00161   switch (cfgetispeed (&spu->tiNew)) {
00162   case B9600:
00163     uiPortSpeed = 9600;
00164     break;
00165   case B19200:
00166     uiPortSpeed = 19200;
00167     break;
00168   case B38400:
00169     uiPortSpeed = 38400;
00170     break;
00171 #  ifdef B57600
00172   case B57600:
00173     uiPortSpeed = 57600;
00174     break;
00175 #  endif
00176 #  ifdef B115200
00177   case B115200:
00178     uiPortSpeed = 115200;
00179     break;
00180 #  endif
00181 #  ifdef B230400
00182   case B230400:
00183     uiPortSpeed = 230400;
00184     break;
00185 #  endif
00186 #  ifdef B460800
00187   case B460800:
00188     uiPortSpeed = 460800;
00189     break;
00190 #  endif
00191   }
00192 
00193   return uiPortSpeed;
00194 }
00195 
00196 void
00197 uart_close (const serial_port sp)
00198 {
00199   if (((serial_port_unix *) sp)->fd >= 0) {
00200     tcsetattr (((serial_port_unix *) sp)->fd, TCSANOW, &((serial_port_unix *) sp)->tiOld);
00201     close (((serial_port_unix *) sp)->fd);
00202   }
00203   free (sp);
00204 }
00205 
00211 int
00212 uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRx)
00213 {
00214   int     res;
00215   int     byteCount;
00216   fd_set  rfds;
00217 
00218   int     iExpectedByteCount = (int)*pszRx;
00219   DBG ("iExpectedByteCount == %d", iExpectedByteCount);
00220   struct timeval tvTimeout = {
00221     .tv_sec = 0,
00222     .tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * iExpectedByteCount),
00223   };
00224   struct timeval tv = tvTimeout;
00225 
00226   // Reset the output count  
00227   *pszRx = 0;
00228   do {
00229     // Reset file descriptor
00230     FD_ZERO (&rfds);
00231     FD_SET (((serial_port_unix *) sp)->fd, &rfds);
00232     res = select (((serial_port_unix *) sp)->fd + 1, &rfds, NULL, NULL, &tv);
00233 
00234     // Read error
00235     if (res < 0) {
00236       DBG ("%s", "RX error.");
00237       return DEIO;
00238     }
00239     // Read time-out
00240     if (res == 0) {
00241       if (*pszRx == 0) {
00242         // Error, we received no data
00243         // DBG ("RX time-out (%lu µs), buffer empty.", tvTimeout.tv_usec);
00244         return DETIMEOUT;
00245       } else {
00246         // We received some data, but nothing more is available
00247         return 0;
00248       }
00249     }
00250     // Retrieve the count of the incoming bytes
00251     res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &byteCount);
00252     if (res < 0) {
00253       return DEIO;
00254     }
00255     // There is something available, read the data
00256     res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRx), MIN(byteCount, iExpectedByteCount));
00257     iExpectedByteCount -= MIN (byteCount, iExpectedByteCount);
00258 
00259     // Stop if the OS has some troubles reading the data
00260     if (res <= 0) {
00261       return DEIO;
00262     }
00263 
00264     *pszRx += res;
00265     // Reload timeout with a low value to prevent from waiting too long on slow devices (16x is enought to took at least 1 byte)
00266     tv.tv_usec = uiTimeoutPerByte * MIN( iExpectedByteCount, 16 ); 
00267     // DBG("Timeout reloaded at: %d µs", tv.tv_usec);
00268   } while (byteCount && (iExpectedByteCount > 0));
00269   DBG ("byteCount == %d, iExpectedByteCount == %d", byteCount, iExpectedByteCount);
00270   return 0;
00271 }
00272 
00278 int
00279 uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTx)
00280 {
00281   int32_t res;
00282   size_t  szPos = 0;
00283   fd_set  rfds;
00284   struct timeval tvTimeout = {
00285     .tv_sec = 0,
00286     .tv_usec = uiTimeoutStatic + (uiTimeoutPerByte * szTx),
00287   };
00288   struct timeval tv = tvTimeout;
00289 
00290   while (szPos < szTx) {
00291     // Reset file descriptor
00292     FD_ZERO (&rfds);
00293     FD_SET (((serial_port_unix *) sp)->fd, &rfds);
00294     res = select (((serial_port_unix *) sp)->fd + 1, NULL, &rfds, NULL, &tv);
00295 
00296     // Write error
00297     if (res < 0) {
00298       DBG ("%s", "TX error.");
00299       return DEIO;
00300     }
00301     // Write time-out
00302     if (res == 0) {
00303       DBG ("%s", "TX time-out.");
00304       return DETIMEOUT;
00305     }
00306     // Send away the bytes
00307     res = write (((serial_port_unix *) sp)->fd, pbtTx + szPos, szTx - szPos);
00308 
00309     // Stop if the OS has some troubles sending the data
00310     if (res <= 0) {
00311       return DEIO;
00312     }
00313 
00314     szPos += res;
00315 
00316     // Reload timeout with a low value to prevent from waiting too long on slow devices (16x is enought to took at least 1 byte)
00317     tv.tv_usec = uiTimeoutStatic + uiTimeoutPerByte * MIN( szTx - szPos, 16 ); 
00318   }
00319   return 0;
00320 }
00321