port.cpp
Go to the documentation of this file.
00001 
00048 #include <string.h>
00049 #include <stdio.h>
00050 #include <stdlib.h>
00051 #include <unistd.h>
00052 #include <fcntl.h>
00053 #include <signal.h>
00054 #include <errno.h>
00055 #include <termios.h>
00056 
00057 #include <iostream>
00058 #include <sstream>
00059 using namespace std;
00060 
00061 #include "port.h"
00062 #include "serial.h"
00063 
00064 PortException::PortException(const char* con, const char* msg) :
00065     conn_str(con), message(msg)
00066 {
00067     fprintf(stderr,"PortException: %s: %s\n", conn_str, message);
00068     fflush(stderr);
00069 }
00070 
00071 
00072 Port::Port(const char* conn_string, struct pollfd* pollfd_ptr)
00073     : m_conn_string(conn_string), m_pollfd_ptr(pollfd_ptr)
00074 {
00075     if (m_pollfd_ptr == 0) {
00076         throw new PortException(m_conn_string, "pollfd object not specified.");
00077     } else {
00078         m_pollfd_ptr->fd = -1;
00079         m_pollfd_ptr->events = POLLIN;
00080     }
00081 }
00082 
00083 Port::~Port() {
00084     /* Trivial destructor.  But if you inline this in the class definition,
00085      * you'll find that gcc spits a bunch of undefined vtable references
00086      * in your face. */
00087 }
00088 
00097 Port* Port::create(const char *conn_string, struct pollfd* pollfd_ptr) {
00098     if( ! strncmp(conn_string, "serial:", 7) ) {
00099         return new SerialPort(conn_string, pollfd_ptr);
00100     } else if( !strncmp(conn_string, "pty:", 4) ) {
00101         return new PtyPort(conn_string + 4, pollfd_ptr);
00102     } else {
00103         return new PtyPort(conn_string, pollfd_ptr);
00104     }
00105 }
00106     
00107 short Port::poll_revents() {
00108     return m_pollfd_ptr->revents;
00109 }
00110 
00115 PtyPort::PtyPort(const char* path, struct pollfd* pollfd_ptr) : Port(0, pollfd_ptr), m_path(path), m_slavefd(-1)
00116 {
00117     /* Make sure no file already exists at path */
00118     if( ! access(m_path, F_OK) ) {
00119         throw new PortException(m_path, "File already exists");
00120     }
00121 
00122     _create_pty();
00123 }
00124 
00128 PtyPort::~PtyPort()
00129 {
00130     unlink(m_path);
00131     if(m_pollfd_ptr->fd >= -1) close(m_pollfd_ptr->fd);
00132     if(m_slavefd >= -1) close(m_slavefd);
00133 }
00134 
00139 void PtyPort::_create_pty()
00140 {
00141     /* Create the PTY */
00142     m_pollfd_ptr->fd = posix_openpt( O_RDWR | O_NOCTTY | O_NDELAY);
00143     if( m_pollfd_ptr->fd == -1 ) {
00144         throw new PortException(m_path, strerror(errno));
00145     }
00146 
00147     if( grantpt(m_pollfd_ptr->fd) ) {
00148         throw new PortException(m_path, strerror(errno));
00149         }
00150         if( unlockpt(m_pollfd_ptr->fd) ) {
00151         throw new PortException(m_path, strerror(errno));
00152         }
00153 
00154     /* Disable echoing */
00155     struct termios pty_attr;
00156     if( tcgetattr(m_pollfd_ptr->fd, &pty_attr) ) {
00157         throw new PortException(m_path, strerror(errno));
00158     }
00159     cfmakeraw(&pty_attr);
00160     if( tcsetattr(m_pollfd_ptr->fd, TCSANOW, &pty_attr) ) {
00161         throw new PortException(m_path, strerror(errno));
00162     }
00163 
00164     /* Obtain the name of the slave device file */
00165         const char *slave_name = (const char*)ptsname(m_pollfd_ptr->fd);
00166     if( !slave_name ) {
00167         throw new PortException(m_path, strerror(errno));
00168         }
00169 
00170     /* Open the slave device 
00171      * We never ever actually do anything with this.  This is a hack; it 
00172      * ensures that there is always an open file descriptor to the pty, so
00173      * it doesn't get closed when a client process closes the slave */
00174     m_slavefd = open(slave_name, O_RDWR | O_NOCTTY);
00175 
00176     /* Create a symlink to the slave device file */
00177     // Remove any old symlink
00178     int retval = unlink( m_path );
00179     if( (retval) && (errno!=ENOENT) ) {
00180         throw new PortException(m_path, strerror(errno));
00181     }
00182     retval = symlink(slave_name, m_path);
00183     if(retval) {
00184         throw new PortException(m_path, strerror(errno));
00185     }
00186 
00187     printf("\nCreated pty: %s --> %s\n", m_path, slave_name);
00188 }
00189 
00193 void PtyPort::_respawn_pty()
00194 {
00195     if( m_pollfd_ptr->fd >= 0 ) close(m_pollfd_ptr->fd);
00196     _create_pty();
00197 }
00198 
00205 ssize_t PtyPort::read(void *buf, size_t count)
00206 {
00207     if(m_pollfd_ptr->fd == -1 ) throw new PortException(m_path, "Attempted read from invalid pty");
00208 
00209     int retval = ::read(m_pollfd_ptr->fd, buf, count);
00210     if( (retval < 0) && (errno!=EAGAIN) ) {
00211         /* I/O error, attempt to respawn pty */ 
00212         _respawn_pty();
00213         return 0;
00214     } 
00215     if( retval <= 0 ) {
00216         // No data
00217         return 0;
00218     }
00219     return 1;
00220 }
00221 
00227 ssize_t PtyPort::write(void *buf, size_t count)
00228 {
00229     if(m_pollfd_ptr->fd == -1) throw new PortException(m_path, "Attempted write to invalid pty");
00230 
00231     int retval = ::write(m_pollfd_ptr->fd, buf, count);
00232     if( (retval < 0) && (errno!=EAGAIN) ) {
00233         /* I/O error, attempt to respawn pty */
00234         _respawn_pty();
00235     }
00236 }
00237 
00243 SerialPort::SerialPort(const char* conn_str, struct pollfd* pollfd_ptr)
00244     : Port(conn_str, pollfd_ptr)
00245 {
00246     if( strncmp(conn_str, "serial:", 7) ) 
00247         throw new PortException(conn_str, "Bad serial connection string");
00248 
00249     /* Parse out the device name */
00250     const int devname_ofst = 7;
00251     char portname[128];
00252     // Dev name ends with the comma, or end of string
00253     int i;
00254     for(i=devname_ofst; conn_str[i]!='\0' && conn_str[i]!=','; ++i) {
00255         if( i>= 128 )
00256             throw new PortException(conn_str, "Buffer overrun reading device name");
00257 
00258         portname[i-devname_ofst] = conn_str[i];
00259     }
00260     portname[i-devname_ofst] = '\0';
00261 
00262     /* Parse out the baud rate */
00263     int baudrate = 115200;
00264     // If nothing followed the dev name, we just use default baud
00265     if( (conn_str[i] != '\0') || (conn_str[i+1]=='\0') ) {
00266         i++;  // at beginning of baud rate
00267         baudrate = atoi(conn_str+i);
00268     }
00269 
00270     printf("Opening serial port: %s, b%d\n", portname, baudrate);
00271     if( OpenSerial(&m_pollfd_ptr->fd, portname) < 0) {
00272         perror("OpenSerial");
00273         throw new PortException(conn_str, "Failed to open device.");
00274     }
00275 
00276     if( SetupSerial(m_pollfd_ptr->fd, baudrate) < 0) {
00277         perror("SetupSerial");
00278         throw new PortException(conn_str, "Failed to configure serial port.");
00279     }
00280 }
00281 
00285 SerialPort::~SerialPort()
00286 {
00287     if(m_pollfd_ptr->fd != -1) close(m_pollfd_ptr->fd);
00288 }
00289 
00290 ssize_t SerialPort::read(void *buf, size_t count)
00291 {
00292     return ::read(m_pollfd_ptr->fd, buf, count);
00293 }
00294 
00295 ssize_t SerialPort::write(void *buf, size_t count)
00296 {
00297     int n = 0;
00298     do {
00299         errno = 0;
00300             n = ::write(m_pollfd_ptr->fd, buf, count);
00301     } while( errno == EAGAIN);
00302     return n;
00303 }
00304 


kingfisher_bringup
Author(s): Mike Purvis, Ryan Gariepy
autogenerated on Sat Dec 28 2013 17:08:06