libnfc 1.3.9
|
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 00028 /* 00029 Based on RS232 code written by Teunis van Beelen available: 00030 http://www.teuniz.net/RS-232/index.html 00031 */ 00032 00033 #ifdef HAVE_CONFIG_H 00034 # include "config.h" 00035 #endif // HAVE_CONFIG_H 00036 00037 #include "uart.h" 00038 00039 #include <nfc/nfc.h> 00040 #include <nfc/nfc-messages.h> 00041 00042 // Test if we are dealing with unix operating systems 00043 #ifndef _WIN32 00044 00045 # include <sys/select.h> 00046 # include <termios.h> 00047 typedef struct termios term_info; 00048 typedef struct { 00049 int fd; // Serial port file descriptor 00050 term_info tiOld; // Terminal info before using the port 00051 term_info tiNew; // Terminal info during the transaction 00052 } serial_port_unix; 00053 00054 // timeval struct that define timeout delay for serial port 00055 const struct timeval timeout = { 00056 .tv_sec = 0, // 0 second 00057 .tv_usec = 60000 // 60 ms 00058 }; 00059 00060 // Work-around to claim uart interface using the c_iflag (software input processing) from the termios struct 00061 # define CCLAIMED 0x80000000 00062 00063 serial_port 00064 uart_open (const char *pcPortName) 00065 { 00066 serial_port_unix *sp = malloc (sizeof (serial_port_unix)); 00067 00068 if (sp == 0) 00069 return INVALID_SERIAL_PORT; 00070 00071 sp->fd = open (pcPortName, O_RDWR | O_NOCTTY | O_NONBLOCK); 00072 if (sp->fd == -1) { 00073 uart_close (sp); 00074 return INVALID_SERIAL_PORT; 00075 } 00076 00077 if (tcgetattr (sp->fd, &sp->tiOld) == -1) { 00078 uart_close (sp); 00079 return INVALID_SERIAL_PORT; 00080 } 00081 // Make sure the port is not claimed already 00082 if (sp->tiOld.c_iflag & CCLAIMED) { 00083 uart_close (sp); 00084 return CLAIMED_SERIAL_PORT; 00085 } 00086 // Copy the old terminal info struct 00087 sp->tiNew = sp->tiOld; 00088 00089 sp->tiNew.c_cflag = CS8 | CLOCAL | CREAD; 00090 sp->tiNew.c_iflag = CCLAIMED | IGNPAR; 00091 sp->tiNew.c_oflag = 0; 00092 sp->tiNew.c_lflag = 0; 00093 00094 sp->tiNew.c_cc[VMIN] = 0; // block until n bytes are received 00095 sp->tiNew.c_cc[VTIME] = 0; // block until a timer expires (n * 100 mSec.) 00096 00097 if (tcsetattr (sp->fd, TCSANOW, &sp->tiNew) == -1) { 00098 uart_close (sp); 00099 return INVALID_SERIAL_PORT; 00100 } 00101 00102 tcflush (sp->fd, TCIFLUSH); 00103 return sp; 00104 } 00105 00106 void 00107 uart_set_speed (serial_port sp, const uint32_t uiPortSpeed) 00108 { 00109 DBG ("Serial port speed requested to be set to %d bauds.", uiPortSpeed); 00110 const serial_port_unix *spu = (serial_port_unix *) sp; 00111 00112 // Portability note: on some systems, B9600 != 9600 so we have to do 00113 // uint32_t <=> speed_t associations by hand. 00114 speed_t stPortSpeed = B9600; 00115 switch (uiPortSpeed) { 00116 case 9600: 00117 stPortSpeed = B9600; 00118 break; 00119 case 19200: 00120 stPortSpeed = B19200; 00121 break; 00122 case 38400: 00123 stPortSpeed = B38400; 00124 break; 00125 # ifdef B57600 00126 case 57600: 00127 stPortSpeed = B57600; 00128 break; 00129 # endif 00130 # ifdef B115200 00131 case 115200: 00132 stPortSpeed = B115200; 00133 break; 00134 # endif 00135 # ifdef B230400 00136 case 230400: 00137 stPortSpeed = B230400; 00138 break; 00139 # endif 00140 # ifdef B460800 00141 case 460800: 00142 stPortSpeed = B460800; 00143 break; 00144 # endif 00145 default: 00146 ERR ("Unable to set serial port speed to %d bauds. Speed value must be one of those defined in termios(3).", 00147 uiPortSpeed); 00148 }; 00149 00150 // Set port speed (Input and Output) 00151 cfsetispeed ((struct termios *) &(spu->tiNew), stPortSpeed); 00152 cfsetospeed ((struct termios *) &(spu->tiNew), stPortSpeed); 00153 if (tcsetattr (spu->fd, TCSADRAIN, &(spu->tiNew)) == -1) { 00154 ERR ("%s", "Unable to apply new speed settings."); 00155 } 00156 } 00157 00158 uint32_t 00159 uart_get_speed (serial_port sp) 00160 { 00161 uint32_t uiPortSpeed = 0; 00162 const serial_port_unix *spu = (serial_port_unix *) sp; 00163 switch (cfgetispeed (&spu->tiNew)) { 00164 case B9600: 00165 uiPortSpeed = 9600; 00166 break; 00167 case B19200: 00168 uiPortSpeed = 19200; 00169 break; 00170 case B38400: 00171 uiPortSpeed = 38400; 00172 break; 00173 # ifdef B57600 00174 case B57600: 00175 uiPortSpeed = 57600; 00176 break; 00177 # endif 00178 # ifdef B115200 00179 case B115200: 00180 uiPortSpeed = 115200; 00181 break; 00182 # endif 00183 # ifdef B230400 00184 case B230400: 00185 uiPortSpeed = 230400; 00186 break; 00187 # endif 00188 # ifdef B460800 00189 case B460800: 00190 uiPortSpeed = 460800; 00191 break; 00192 # endif 00193 } 00194 00195 return uiPortSpeed; 00196 } 00197 00198 void 00199 uart_close (const serial_port sp) 00200 { 00201 if (((serial_port_unix *) sp)->fd >= 0) { 00202 tcsetattr (((serial_port_unix *) sp)->fd, TCSANOW, &((serial_port_unix *) sp)->tiOld); 00203 close (((serial_port_unix *) sp)->fd); 00204 } 00205 free (sp); 00206 } 00207 00213 int 00214 uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRxLen) 00215 { 00216 int res; 00217 int byteCount; 00218 fd_set rfds; 00219 struct timeval tv; 00220 00221 // Reset the output count 00222 *pszRxLen = 0; 00223 00224 do { 00225 // Reset file descriptor 00226 FD_ZERO (&rfds); 00227 FD_SET (((serial_port_unix *) sp)->fd, &rfds); 00228 tv = timeout; 00229 res = select (((serial_port_unix *) sp)->fd + 1, &rfds, NULL, NULL, &tv); 00230 00231 // Read error 00232 if (res < 0) { 00233 DBG ("%s", "RX error."); 00234 return DEIO; 00235 } 00236 // Read time-out 00237 if (res == 0) { 00238 if (*pszRxLen == 0) { 00239 // Error, we received no data 00240 DBG ("%s", "RX time-out, buffer empty."); 00241 return DETIMEOUT; 00242 } else { 00243 // We received some data, but nothing more is available 00244 return 0; 00245 } 00246 } 00247 // Retrieve the count of the incoming bytes 00248 res = ioctl (((serial_port_unix *) sp)->fd, FIONREAD, &byteCount); 00249 if (res < 0) { 00250 return DEIO; 00251 } 00252 // There is something available, read the data 00253 res = read (((serial_port_unix *) sp)->fd, pbtRx + (*pszRxLen), byteCount); 00254 00255 // Stop if the OS has some troubles reading the data 00256 if (res <= 0) { 00257 return DEIO; 00258 } 00259 00260 *pszRxLen += res; 00261 00262 } while (byteCount); 00263 00264 return 0; 00265 } 00266 00272 int 00273 uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTxLen) 00274 { 00275 int32_t res; 00276 size_t szPos = 0; 00277 fd_set rfds; 00278 struct timeval tv; 00279 00280 while (szPos < szTxLen) { 00281 // Reset file descriptor 00282 FD_ZERO (&rfds); 00283 FD_SET (((serial_port_unix *) sp)->fd, &rfds); 00284 tv = timeout; 00285 res = select (((serial_port_unix *) sp)->fd + 1, NULL, &rfds, NULL, &tv); 00286 00287 // Write error 00288 if (res < 0) { 00289 DBG ("%s", "TX error."); 00290 return DEIO; 00291 } 00292 // Write time-out 00293 if (res == 0) { 00294 DBG ("%s", "TX time-out."); 00295 return DETIMEOUT; 00296 } 00297 // Send away the bytes 00298 res = write (((serial_port_unix *) sp)->fd, pbtTx + szPos, szTxLen - szPos); 00299 00300 // Stop if the OS has some troubles sending the data 00301 if (res <= 0) { 00302 return DEIO; 00303 } 00304 00305 szPos += res; 00306 } 00307 return 0; 00308 } 00309 00310 #else 00311 // The windows serial port implementation 00312 00313 typedef struct { 00314 HANDLE hPort; // Serial port handle 00315 DCB dcb; // Device control settings 00316 COMMTIMEOUTS ct; // Serial port time-out configuration 00317 } serial_port_windows; 00318 00319 serial_port 00320 uart_open (const char *pcPortName) 00321 { 00322 char acPortName[255]; 00323 serial_port_windows *sp = malloc (sizeof (serial_port_windows)); 00324 00325 // Copy the input "com?" to "\\.\COM?" format 00326 sprintf (acPortName, "\\\\.\\%s", pcPortName); 00327 _strupr (acPortName); 00328 00329 // Try to open the serial port 00330 sp->hPort = CreateFileA (acPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); 00331 if (sp->hPort == INVALID_HANDLE_VALUE) { 00332 uart_close (sp); 00333 return INVALID_SERIAL_PORT; 00334 } 00335 // Prepare the device control 00336 memset (&sp->dcb, 0, sizeof (DCB)); 00337 sp->dcb.DCBlength = sizeof (DCB); 00338 if (!BuildCommDCBA ("baud=9600 data=8 parity=N stop=1", &sp->dcb)) { 00339 uart_close (sp); 00340 return INVALID_SERIAL_PORT; 00341 } 00342 // Update the active serial port 00343 if (!SetCommState (sp->hPort, &sp->dcb)) { 00344 uart_close (sp); 00345 return INVALID_SERIAL_PORT; 00346 } 00347 00348 sp->ct.ReadIntervalTimeout = 0; 00349 sp->ct.ReadTotalTimeoutMultiplier = 0; 00350 sp->ct.ReadTotalTimeoutConstant = 30; 00351 sp->ct.WriteTotalTimeoutMultiplier = 0; 00352 sp->ct.WriteTotalTimeoutConstant = 30; 00353 00354 if (!SetCommTimeouts (sp->hPort, &sp->ct)) { 00355 uart_close (sp); 00356 return INVALID_SERIAL_PORT; 00357 } 00358 00359 PurgeComm (sp->hPort, PURGE_RXABORT | PURGE_RXCLEAR); 00360 00361 return sp; 00362 } 00363 00364 void 00365 uart_close (const serial_port sp) 00366 { 00367 if (((serial_port_windows *) sp)->hPort != INVALID_HANDLE_VALUE) { 00368 CloseHandle (((serial_port_windows *) sp)->hPort); 00369 } 00370 free (sp); 00371 } 00372 00373 void 00374 uart_set_speed (serial_port sp, const uint32_t uiPortSpeed) 00375 { 00376 serial_port_windows *spw; 00377 00378 DBG ("Serial port speed requested to be set to %d bauds.", uiPortSpeed); 00379 // Set port speed (Input and Output) 00380 switch (uiPortSpeed) { 00381 case 9600: 00382 case 19200: 00383 case 38400: 00384 case 57600: 00385 case 115200: 00386 case 230400: 00387 case 460800: 00388 break; 00389 default: 00390 ERR 00391 ("Unable to set serial port speed to %d bauds. Speed value must be one of these constants: 9600 (default), 19200, 38400, 57600, 115200, 230400 or 460800.", 00392 uiPortSpeed); 00393 }; 00394 00395 spw = (serial_port_windows *) sp; 00396 spw->dcb.BaudRate = uiPortSpeed; 00397 if (!SetCommState (spw->hPort, &spw->dcb)) { 00398 ERR ("Unable to apply new speed settings."); 00399 } 00400 } 00401 00402 uint32_t 00403 uart_get_speed (const serial_port sp) 00404 { 00405 const serial_port_windows *spw = (serial_port_windows *) sp; 00406 if (!GetCommState (spw->hPort, (serial_port) & spw->dcb)) 00407 return spw->dcb.BaudRate; 00408 00409 return 0; 00410 } 00411 00412 int 00413 uart_receive (serial_port sp, byte_t * pbtRx, size_t * pszRxLen) 00414 { 00415 if (!ReadFile (((serial_port_windows *) sp)->hPort, pbtRx, *pszRxLen, (LPDWORD) pszRxLen, NULL)) { 00416 return DEIO; 00417 } 00418 if (!*pszRxLen) 00419 return DEIO; 00420 return 0; 00421 } 00422 00423 int 00424 uart_send (serial_port sp, const byte_t * pbtTx, const size_t szTxLen) 00425 { 00426 DWORD dwTxLen = 0; 00427 if (!WriteFile (((serial_port_windows *) sp)->hPort, pbtTx, szTxLen, &dwTxLen, NULL)) { 00428 return DEIO; 00429 } 00430 if (!dwTxLen) 00431 return DEIO; 00432 return 0; 00433 } 00434 00435 #endif /* _WIN32 */