libnfc 1.4.2
|
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