Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

SerialCommPort.cc

Go to the documentation of this file.
00001 #include "SerialCommPort.h"
00002 #include <termios.h>
00003 #include <sys/ioctl.h>
00004 #include <errno.h>
00005 #ifdef __APPLE__
00006 #  include <IOKit/serial/ioss.h>
00007 #endif
00008 
00009 #ifdef __CYGWIN__
00010 // Cygwin doesn't provide cfmakeraw...
00011 // this definition found in port of unix 'script' utility
00012 // by Alan Evans (Alan_Evans AT iwv com), 2002-09-27
00013 // http://marc.info/?l=cygwin&m=103314951904556&w=2
00014 void cfmakeraw(struct termios *termios_p) {
00015   termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
00016         |INLCR|IGNCR|ICRNL|IXON);
00017   termios_p->c_oflag &= ~OPOST;
00018   termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
00019   termios_p->c_cflag &= ~(CSIZE|PARENB);
00020   termios_p->c_cflag |= CS8;
00021 }
00022 #endif
00023 
00024 using namespace std;
00025 
00026 const char * const SerialCommPort::parityNames[] = { "EVEN", "ODD", "NONE", "" };
00027 INSTANTIATE_NAMEDENUMERATION_STATICS(SerialCommPort::parity_t);
00028 
00029 const std::string SerialCommPort::autoRegisterSerialCommPort = CommPort::getRegistry().registerType<SerialCommPort>("SerialCommPort");
00030 
00031 void SerialCommPort::setupSerial() {
00032   if(fd<0)
00033     return;
00034   
00035   // ** first do a basic setup to initialize our access to the serial port **
00036   
00037   // get current termios structure (sys/termios.h)
00038   struct termios  theTermios;
00039   int ret = tcgetattr(fd, &theTermios);
00040   cfmakeraw(&theTermios);
00041   
00042 #ifndef __APPLE__
00043   // linux can handle non-standard baud rates directly
00044   // we'll handle Darwin below, uses an ioctl call instead
00045   cfsetispeed(&theTermios, baudRate);
00046   cfsetospeed(&theTermios, baudRate);
00047 #endif
00048   
00049   // turn on READ and ignore modem control lines
00050   theTermios.c_cflag |= CREAD | CLOCAL;
00051   //theTermios.c_cflag = CIGNORE;
00052   
00053   switch (dataBits) {
00054     case 5:   theTermios.c_cflag |= CS5;    break;
00055     case 6:   theTermios.c_cflag |= CS6;    break;
00056     case 7:   theTermios.c_cflag |= CS7;    break;
00057     case 8:   theTermios.c_cflag |= CS8;    break;
00058     default: std::cerr << "SerialCommPort: bad DataBits value " << dataBits << std::endl; 
00059   }
00060   
00061   // stop bit(s)?
00062   if(stopBits==1)
00063     theTermios.c_cflag &= ~CSTOPB;
00064   else if(stopBits==2)
00065     theTermios.c_cflag |= CSTOPB;
00066   else
00067     std::cerr << "SerialCommPort: bad StopBits value " << stopBits << std::endl; 
00068   
00069   // parity?
00070   switch(parity) {
00071     case EVEN:
00072       theTermios.c_cflag |= PARENB; theTermios.c_cflag &= ~PARODD; break;
00073     case ODD:
00074       theTermios.c_cflag |= PARENB; theTermios.c_cflag |= PARODD; break;
00075     case NONE:
00076       theTermios.c_cflag &= ~PARENB; break;
00077   }
00078   // default no flow control:
00079   theTermios.c_iflag &= ~(IXON | IXOFF);
00080   theTermios.c_cflag &= ~CRTSCTS;
00081   
00082   // apply our settings
00083   ret = tcsetattr(fd, TCSAFLUSH, &theTermios);
00084   //ret = ioctl(fd, TIOCSETA, &theTermios); // alternative ?
00085   if (ret)
00086     dispError("tcsetattr(TCSAFLUSH)",ret,errno);
00087   
00088 #ifdef __APPLE__
00089   // this allows higher (non-standard) baud rates, apparently not supported (on darwin) via termios
00090   const int TGTBAUD = baudRate;
00091   ret = ioctl(fd, IOSSIOSPEED, &TGTBAUD); // as opposed to setting it in theTermios ?
00092   if (ret)
00093     dispError("ioctl(IOSSIOSPEED)",ret,errno);
00094 #endif
00095   
00096   // this part doesn't seem to be necessary, but better safe than sorry...
00097   int modem;
00098   ret = ioctl(fd, TIOCMGET, &modem);
00099   if (ret)
00100     dispError("ioctl(TIOCMGET)",ret,errno);
00101   modem |= TIOCM_DTR;
00102   ret = ioctl(fd, TIOCMSET, &modem);
00103   if (ret)
00104     dispError("ioctl(TIOCMSET)",ret,errno);
00105   
00106   if(sttyConfig.size()>0) {
00107     // ** do additional setup by calling out to stty **
00108   #ifdef __linux__
00109     std::string cmd="stty -F "+path+" "+sttyConfig;
00110   #else /* assume BSD style... use a -f instead of -F (...sigh...) */
00111     std::string cmd="stty -f "+path+" "+sttyConfig;
00112   #endif
00113     switch(::system(cmd.c_str())) {
00114       case 0:
00115         break; // good!
00116       case -1:
00117         perror("Warning: SerialCommPort could not make system call to stty"); break;
00118       case 127:
00119         std::cerr << "Warning: SerialCommPort could not make system call to stty: no shell found" << std::endl; break;
00120       default:
00121         std::cerr << "Warning: SerialCommPort stty reported error on configuration string: " << sttyConfig << std::endl; break;
00122     }
00123   }
00124 }
00125 
00126 void SerialCommPort::dispError(const char* where, int ret, int err) {
00127   std::cerr << where << " returned " << ret << " (errno " << err << ": " << strerror(err) << ")" << std::endl;
00128 }
00129 
00130 
00131 /*! @file
00132  * @brief 
00133  * @author Ethan Tira-Thompson (ejt) (Creator)
00134  *
00135  * $Author: ejt $
00136  * $Name: tekkotsu-4_0 $
00137  * $Revision: 1.9 $
00138  * $State: Exp $
00139  * $Date: 2007/11/08 16:30:46 $
00140  */

Tekkotsu Hardware Abstraction Layer 4.0
Generated Thu Nov 22 01:00:53 2007 by Doxygen 1.5.4