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,
00063 mstatusRTS = 0x0004,
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
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
00233 termios dcb = {0};
00234
00235
00236 if(::tcgetattr(handle, &dcb))
00237 return errGeneric;
00238
00239
00240 ::cfmakeraw(&dcb);
00241 dcb.c_cflag |= (CLOCAL | CREAD);
00242 dcb.c_iflag |= (INPCK | ISTRIP);
00243
00244
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
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
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
00303 if(stopBits == 1)
00304 dcb.c_cflag &= ~CSTOPB;
00305 else
00306 dcb.c_cflag |= CSTOPB;
00307
00308
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
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
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
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 }
00588 }
00589
00590 namespace pal = posixPAL;
00591
00592 }
00593
00594
00595 #endif // __SERIAL_POSIX_PAL_HPP__