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

Generated on 8 May 2010 for libnfc by  doxygen 1.6.1