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
00085
00086
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
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
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
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
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
00171
00172
00173
00174 m_slavefd = open(slave_name, O_RDWR | O_NOCTTY);
00175
00176
00177
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
00212 _respawn_pty();
00213 return 0;
00214 }
00215 if( retval <= 0 ) {
00216
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
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
00250 const int devname_ofst = 7;
00251 char portname[128];
00252
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
00263 int baudrate = 115200;
00264
00265 if( (conn_str[i] != '\0') || (conn_str[i+1]=='\0') ) {
00266 i++;
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