Main Page   Namespace List   Compound List   File List   Namespace Members   Compound Members   Related Pages  

serialPAL.hpp

Go to the documentation of this file.
00001 
00002 #ifndef __SERIAL_POSIX_PAL_HPP__
00003 #define __SERIAL_POSIX_PAL_HPP__
00004 
00005 #include <assert.h>
00006 #include <ctype.h>
00007 #include <string.h>
00008 #include <stdio.h>
00009 #include <fcntl.h>
00010 #include <errno.h>
00011 #include <sys/ioctl.h>
00012 #include <termios.h>
00013 #include <unistd.h>
00014 
00015 namespace lfc
00016 {
00017 namespace posixPAL
00018 {
00019 
00021 
00025 namespace serial
00026 {
00027 
00028 const int MAX_ERROR_CODE = 2;
00029 
00030 enum ErrorCodes
00031 {
00032     errOk,
00033     errGeneric,
00034     errNotSupported,
00035 };
00036 
00037 extern const char *messagesTable[MAX_ERROR_CODE + 1];
00038 
00039 
00041 typedef int Handle;
00042 
00044 const Handle NULL_HANDLE = -1;
00045 
00046 
00048 struct PortSettings
00049 {
00050     termios dcb;
00051 };
00052 
00053 
00055 const int
00056     purgeInput      = 0x0001,
00057     purgeOutput     = 0x0002;
00058 
00060 const int
00061     mstatusDSR      = 0x0001,
00062     mstatusDTR      = 0x0002,//$ not supported!
00063     mstatusRTS      = 0x0004,//$ not supported!
00064     mstatusCTS      = 0x0008,
00065     mstatusDCD      = 0x0010,
00066     mstatusRNG      = 0x0020;
00067 
00068 
00070 
00073 inline int init()
00074 {
00075     return errOk;
00076 }
00077 
00078 
00080 
00083 inline int cleanup()
00084 {
00085     return errOk;
00086 }
00087 
00088 
00090 
00095 inline int open(Handle &handle, const char *name)
00096 {
00097     assert(handle == NULL_HANDLE);
00098 
00099     Handle h = ::open(name, O_RDWR | O_NOCTTY | O_NDELAY);
00100     if(h != NULL_HANDLE)
00101     {
00102         handle = h;
00103         return errOk;
00104     }
00105     else
00106         return errGeneric;
00107 }
00108 
00109 
00111 
00115 inline int close(Handle handle)
00116 {
00117     assert(handle != NULL_HANDLE);
00118     return ::close(handle) == 0 ? errOk : errGeneric;
00119 }
00120 
00121 
00123 
00130 inline int write(Handle handle, const void *buff, long count, long &writtenCount)
00131 {
00132     assert(handle != NULL_HANDLE);
00133     
00134     long wc = ::write(handle, buff, count);
00135 
00136     if(wc != -1)
00137     {
00138         writtenCount = wc;
00139         return errOk;
00140     }
00141     else if(errno == EAGAIN)
00142     {
00143         writtenCount = 0;
00144         return errOk;
00145     }
00146     else
00147         return errGeneric;
00148 }
00149 
00151 
00158 inline int read(Handle handle, void *buff, long count, long &readCount)
00159 {
00160     assert(handle != NULL_HANDLE);
00161     
00162     long rc = ::read(handle, buff, count);
00163 
00164     if(rc != -1)
00165     {
00166         readCount = rc;
00167         return errOk;
00168     }
00169     else if(errno == EAGAIN)
00170     {
00171         readCount = 0;
00172         return errOk;
00173     }
00174     else
00175         return errGeneric;
00176 }
00177 
00178 
00180 
00184 inline int flush(Handle handle)
00185 {
00186     assert(handle != NULL_HANDLE);
00187     return ::tcdrain(handle) == 0 ? errOk : errGeneric;
00188 }
00189 
00190 
00192 
00204 inline int setup(Handle handle, const char *portSettings)
00205 {
00206     assert(handle != NULL_HANDLE);
00207     assert(portSettings != NULL);
00208 
00209     const char *p = portSettings;
00210     long baud = 0;
00211     long byteSize = 0;
00212     long stopBits = 0;
00213     char parity = '#';
00214     
00215     // parse settings
00216     while(isdigit(*p))
00217         baud = baud * 10 + *p++ - '0';
00218     if(*p++ != ',')
00219         return errGeneric;
00220     byteSize = *p++ - '0';
00221     if(byteSize < 4 || byteSize > 8)
00222         return errGeneric;
00223     parity = toupper(*p++);
00224     if(::strchr("NOES", parity) == NULL)
00225         return errGeneric;
00226     stopBits = *p++ - '0';
00227     if(stopBits != 1 && stopBits != 2)
00228         return errGeneric;
00229     if(*p != 0)
00230         return errGeneric;
00231         
00232     // setup port settings: baud, byteSize, parity, stopBits
00233     termios dcb = {0};
00234     
00235     // get current settings
00236     if(::tcgetattr(handle, &dcb))
00237         return errGeneric;
00238         
00239     // other flags ($ CLOCAL might not be always wantted...)
00240     ::cfmakeraw(&dcb);
00241     dcb.c_cflag |= (CLOCAL | CREAD);
00242     dcb.c_iflag |= (INPCK | ISTRIP);
00243     
00244     // set speed
00245     speed_t speed = 0;
00246     switch(baud)
00247     {
00248     case 50:        speed = B50; break;
00249     case 75:        speed = B75; break;
00250     case 110:       speed = B110; break;
00251     case 134:       speed = B134; break;
00252     case 150:       speed = B150; break;
00253     case 200:       speed = B200; break;
00254     case 300:       speed = B300; break;
00255     case 600:       speed = B600; break;
00256     case 1200:      speed = B1200; break;
00257     case 1800:      speed = B1800; break;
00258     case 2400:      speed = B2400; break;
00259     case 4800:      speed = B4800; break;
00260     case 9600:      speed = B9600; break;
00261     case 19200:     speed = B19200; break;
00262     case 38400:     speed = B38400; break;
00263     case 57600:     speed = B57600; break;
00264     case 115200:    speed = B115200; break;
00265     case 230400:    speed = B230400; break;
00266 
00267     default: return errGeneric;
00268     }
00269     
00270     if(::cfsetospeed(&dcb, speed))
00271         return errGeneric;
00272     if(::cfsetispeed(&dcb, speed))
00273         return errGeneric;
00274         
00275     // set byte size
00276     int posixByteSize = -1;
00277     
00278     switch(byteSize)
00279     {
00280     case 5: posixByteSize = CS5; break;
00281     case 6: posixByteSize = CS6; break;
00282     case 7: posixByteSize = CS7; break;
00283     case 8: posixByteSize = CS8; break;
00284 
00285     default: return errGeneric;
00286     }
00287     
00288     dcb.c_cflag &= ~CSIZE;
00289     dcb.c_cflag |= posixByteSize;
00290     
00291     // set parity
00292     switch(parity)
00293     {
00294     case 'N': dcb.c_cflag &= ~PARENB; break;
00295     case 'O': dcb.c_cflag |= (PARENB | PARODD); break;
00296     case 'E': dcb.c_cflag |= PARENB; dcb.c_cflag &= ~PARODD; break;
00297     case 'S': dcb.c_cflag &= ~PARENB; break;
00298 
00299     default: return errGeneric;
00300     }
00301     
00302     // set stop bits
00303     if(stopBits == 1)
00304         dcb.c_cflag &= ~CSTOPB;
00305     else
00306         dcb.c_cflag |= CSTOPB;
00307         
00308     // finally setup serial port
00309     return ::tcsetattr(handle, TCSANOW, &dcb) == 0 ? errOk : errGeneric;
00310 }
00311 
00312 
00314 
00319 inline int availableCount(Handle handle, long &count)
00320 {
00321     assert(handle != NULL_HANDLE);
00322     
00323     int tmp = -1;
00324     if(::ioctl(handle, FIONREAD, &tmp))
00325         return errGeneric;
00326     count = tmp;
00327     return errOk;
00328 }
00329 
00330 
00332 
00337 inline int setHardwareFlowControl(Handle handle, bool bEnable)
00338 {
00339     assert(handle != NULL_HANDLE);
00340 
00341     termios dcb = {0};
00342     
00343     // get current settings
00344     if(::tcgetattr(handle, &dcb))
00345         return errGeneric;
00346         
00347     if(bEnable)
00348         dcb.c_cflag |= CRTSCTS;
00349     else
00350         dcb.c_cflag &= ~CRTSCTS;
00351 
00352     return ::tcsetattr(handle, TCSANOW, &dcb) == 0 ? errOk : errGeneric;
00353 }
00354 
00355 
00357 
00364 inline int setSoftwareFlowControl(Handle handle, bool bEnable, char Xon, char Xoff)
00365 {
00366     assert(handle != NULL_HANDLE);
00367 
00368     termios dcb = {0};
00369     
00370     // get current settings
00371     if(::tcgetattr(handle, &dcb))
00372         return errGeneric;
00373         
00374     if(bEnable)
00375     {
00376         dcb.c_iflag |= (IXON | IXOFF);
00377         dcb.c_cc[VSTART] = Xon;
00378         dcb.c_cc[VSTOP] = Xoff;
00379     }
00380     else
00381         dcb.c_iflag &= ~(IXON | IXOFF | IXANY);
00382 
00383     return ::tcsetattr(handle, TCSANOW, &dcb) == 0 ? errOk : errGeneric;
00384 }
00385 
00386 
00388 
00393 inline int setReadTimeouts(Handle handle, long timeout)
00394 {
00395     assert(handle != NULL_HANDLE);
00396 
00397     termios dcb = {0};
00398     
00399     // get current settings
00400     if(::tcgetattr(handle, &dcb))
00401         return errGeneric;
00402         
00403     dcb.c_cc[VMIN] = 0;
00404     dcb.c_cc[VTIME] = timeout / 100;
00405 
00406     return ::tcsetattr(handle, TCSANOW, &dcb) == 0 ? errOk : errGeneric;
00407 }
00408 
00409 
00411 
00418 inline int setBlockingRead(Handle handle, bool bBlocking)
00419 {
00420     assert(handle != NULL_HANDLE);
00421     return ::fcntl(handle, F_SETFL, bBlocking ? 0 : FNDELAY) != -1 ? errOk : errGeneric;
00422 }
00423 
00424 
00426 
00433 inline int purgeBuffer(Handle handle, int flags)
00434 {
00435     assert(handle != NULL_HANDLE);
00436     
00437     int posixPurgeFlags = -1;
00438     
00439     if(flags == purgeInput)
00440         posixPurgeFlags = TCIFLUSH;
00441     else if(flags == purgeOutput)
00442         posixPurgeFlags = TCOFLUSH;
00443     else if(flags == (purgeInput | purgeOutput))
00444         posixPurgeFlags = TCIOFLUSH;
00445     else
00446         return errGeneric;
00447 
00448     return ::tcflush(handle, posixPurgeFlags) == 0 ? errOk : errGeneric;
00449 }
00450 
00451 
00453 
00457 inline int sendBreak(Handle handle)
00458 {
00459     assert(handle != NULL_HANDLE);
00460     return ::tcsendbreak(handle, 0) == 0 ? errOk : errGeneric;
00461 }
00462 
00463 
00465 
00475 inline int getModemStatus(Handle handle, int &status)
00476 {
00477     assert(handle != NULL_HANDLE);
00478     
00479     int posixFlags = 0;
00480     
00481     if(::ioctl(handle, TIOCMGET, &posixFlags))
00482         return errGeneric;
00483         
00484     status = 0;
00485     status |= posixFlags & TIOCM_CTS ? mstatusCTS : 0;
00486     status |= posixFlags & TIOCM_DSR ? mstatusDSR : 0;
00487     status |= posixFlags & TIOCM_RNG ? mstatusRNG : 0;
00488     status |= posixFlags & TIOCM_CAR ? mstatusDCD : 0;
00489     
00490     return errOk;
00491 }
00492 
00493 
00495 
00501 inline int setDTR(Handle handle, bool bEnable)
00502 {
00503     assert(handle != NULL_HANDLE);
00504     
00505     int posixFlags = 0;
00506     
00507     if(::ioctl(handle, TIOCMGET, &posixFlags))
00508         return errGeneric;
00509 
00510     if(bEnable)
00511         posixFlags |= TIOCM_DTR;
00512     else
00513         posixFlags &= ~TIOCM_DTR;
00514 
00515     if(::ioctl(handle, TIOCMSET, &posixFlags))
00516         return errGeneric;
00517 
00518     return errOk;
00519 }
00520 
00521 
00523 
00529 inline int setRTS(Handle handle, bool bEnable)
00530 {
00531     assert(handle != NULL_HANDLE);
00532     
00533     int posixFlags = 0;
00534     
00535     if(::ioctl(handle, TIOCMGET, &posixFlags))
00536         return errGeneric;
00537 
00538     if(bEnable)
00539         posixFlags |= TIOCM_RTS;
00540     else
00541         posixFlags &= ~TIOCM_RTS;
00542 
00543     if(::ioctl(handle, TIOCMSET, &posixFlags))
00544         return errGeneric;
00545 
00546     return errOk;
00547 }
00548 
00549 
00551 
00556 inline int saveSettings(Handle handle, PortSettings &settings)
00557 {
00558     assert(handle != NULL_HANDLE);
00559     return ::tcgetattr(handle, &settings.dcb) == 0 ? errOk : errGeneric;
00560 }
00561 
00562 
00564 
00569 inline int restoreSettings(Handle handle, const PortSettings &settings)
00570 {
00571     assert(handle != NULL_HANDLE);
00572     return ::tcsetattr(handle, TCSANOW, &settings.dcb) == 0 ? errOk : errGeneric;
00573 }
00574 
00575 
00577 
00580 inline const char *message(int index)
00581 {
00582     assert(index >= 0 && index <= MAX_ERROR_CODE);
00583     return messagesTable[index];
00584 }
00585 
00586 
00587 } // namespace posixPAL::serial
00588 } // namespace posixPAL
00589 
00590 namespace pal = posixPAL;
00591 
00592 } // namespace lfc
00593 
00594 
00595 #endif  // __SERIAL_POSIX_PAL_HPP__

Generated on Sat Jan 26 00:34:58 2002 for LFC2 PAL by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001