serial_port.cpp

Go to the documentation of this file.
00001 /*
00002 This program is distributed under the terms of the 'MIT license'. The text
00003 of this licence follows...
00004 
00005 Copyright (c) 2006,2009 J.D.Medhurst (a.k.a. Tixy)
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00022 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00023 THE SOFTWARE.
00024 */
00025 
00032 #include "../../common/common.h"
00033 #include "../ymodem_tx.h"
00034 
00035 
00036 #include <sys/types.h>
00037 #include <sys/stat.h>
00038 #include <fcntl.h>
00039 #include <termios.h>
00040 #include <stdio.h>
00041 #include <errno.h>
00042 #include <string.h>
00043 #include <unistd.h>
00044 
00048 #define DEVICE_NAME_ROOT "/dev/ttyS"
00049 
00050 // comment in next line to get a log of all port trafic...
00051 // #define DEBUG_LOG
00052 
00061 class LinuxSerialPort : public SerialPort
00062     {
00063 public:
00064     LinuxSerialPort();
00065     int Open(unsigned port);
00066     int Initialise(unsigned baud);
00067     int Out(const uint8_t* data, size_t size, unsigned timeout);
00068     int In(uint8_t* data, size_t maxSize, unsigned timeout);
00069     void Close();
00070 private:
00071     ~LinuxSerialPort();
00072     int Error(int defaultError=ErrorUnspecified);
00073 private:
00074     int SerialHandle; 
00075 #ifdef DEBUG_LOG
00076     void DebugDump(const char* prefix, const uint8_t* data, size_t size);
00077     FILE* DebugLog;
00078 #endif
00079     };
00080 
00081 
00089 int LinuxSerialPort::Error(int defaultError)
00090     {
00091 #ifdef DEBUG_LOG
00092     if(DebugLog)
00093         fprintf(DebugLog,"ERROR: %d (errno=%d '%s')",defaultError,errno,strerror(errno));
00094 #endif
00095     return defaultError;
00096     }
00097 
00098 
00099 int LinuxSerialPort::Open(unsigned port)
00100     {
00101     // make name for port...
00102     char name[] = DEVICE_NAME_ROOT "???.???";
00103     char* nameNumber = name+sizeof(name)-8;
00104     char* nameEnd = nameNumber;
00105     if(port>999)
00106         return ErrorInvalidPort;
00107     if(port>99)
00108         {
00109         *nameEnd++ = '0'+port/100;
00110         port %= 100;
00111         }
00112     if(port>9)
00113         {
00114         *nameEnd++ = '0'+port/10;
00115         port %= 10;
00116         }
00117     *nameEnd++ = '0'+port;
00118     *nameEnd = 0;
00119 
00120     // open port...
00121     SerialHandle = open(name, O_RDWR | O_NOCTTY);
00122     if(SerialHandle<0)
00123         {
00124         switch(errno)
00125             {
00126 // Linux seems to allow more than one program to access port at the same time
00127 // so there's no way to detect an 'already in use' error...
00128 //          case ?:
00129 //              return Error(ErrorPortInUse);
00130             default:
00131                 return Error(ErrorInvalidPort);
00132             }
00133         }
00134 
00135 #ifdef DEBUG_LOG
00136     strcpy(nameEnd,".log");
00137     DebugLog = fopen(nameNumber,"w+b");
00138 #endif
00139 
00140     return 0;
00141     }
00142 
00143 
00144 int LinuxSerialPort::Initialise(unsigned baud)
00145     {
00146     switch(baud)
00147         {
00148         case 1200: baud = B1200; break;
00149         case 2400: baud = B2400; break;
00150         case 4800: baud = B4800; break;
00151         case 9600: baud = B9600; break;
00152         case 19200: baud = B19200; break;
00153         case 38400: baud = B38400; break;
00154         case 57600: baud = B57600; break;
00155         case 115200: baud = B115200; break;
00156         case 230400: baud = B230400; break;
00157         default: return ErrorInvalidSettings;
00158         }
00159 
00160     struct termios tio;
00161     memset(&tio, 0, sizeof(tio));
00162     tio.c_cflag     = baud | CRTSCTS | CS8 | CLOCAL | CREAD;
00163     tio.c_iflag     = IGNPAR;
00164     tio.c_oflag     = 0;
00165     tio.c_lflag     = 0;    // set input mode (non-canonical, no echo,...)
00166     tio.c_cc[VTIME] = 0;    // inter-character timer unused
00167     tio.c_cc[VMIN]  = 0;    // don't block if no chars available
00168 
00169     tcflush(SerialHandle, TCIFLUSH);
00170     if(tcsetattr(SerialHandle,TCSANOW,&tio)<0)
00171         return ErrorInvalidSettings;
00172 
00173     return 0;
00174     }
00175 
00176 
00177 int LinuxSerialPort::Out(const uint8_t* data, size_t size, unsigned timeout)
00178     {
00179 retry:
00180     // wait for serial port to be ready to write...
00181     fd_set writefds;
00182     FD_ZERO(&writefds);
00183     FD_SET(SerialHandle,&writefds);
00184     timeval wait;
00185     wait.tv_sec = timeout/1000;
00186     wait.tv_usec = timeout%1000*1000;
00187     int selectResult = select(SerialHandle+1, 0, &writefds, 0, &wait);
00188 
00189     int bytes;
00190     if(selectResult==0)
00191         {
00192         // timeout...
00193         bytes = 0;
00194         }
00195     else if(selectResult<0)
00196         {
00197         // a select error...
00198         if(errno==EINTR)
00199             goto retry; // interupted by a signal so just retry
00200         bytes = -1; // flag error
00201         }
00202     else
00203         {
00204         // ready for write...
00205         bytes = write(SerialHandle,data,size);
00206         }
00207 
00208     if(bytes<0)
00209         return Error(ErrorTransmitError);
00210 
00211 #ifdef DEBUG_LOG
00212     DebugDump(">",data,bytes);
00213 #endif
00214 
00215     return bytes;
00216     }
00217 
00218 
00219 int LinuxSerialPort::In(uint8_t* data, size_t maxSize, unsigned timeout)
00220     {
00221 retry:
00222     // wait for serial port to be ready to read...
00223     fd_set readfds;
00224     FD_ZERO(&readfds);
00225     FD_SET(SerialHandle,&readfds);
00226     timeval wait;
00227     wait.tv_sec = timeout/1000;
00228     wait.tv_usec = timeout%1000*1000;
00229     int selectResult = select(SerialHandle+1, &readfds, 0, 0, &wait);
00230 
00231     int bytes;
00232     if(selectResult==0)
00233         {
00234         // timeout...
00235         bytes = 0;
00236         }
00237     else if(selectResult<0)
00238         {
00239         // a select error...
00240         if(errno==EINTR)
00241             goto retry; // interupted by a signal so just retry
00242         bytes = -1; // flag error
00243         }
00244     else
00245         {
00246         // ready for read...
00247         bytes = read(SerialHandle,data,maxSize);
00248         }
00249 
00250     if(bytes<0)
00251         return Error(ErrorReceiveError);
00252 
00253 #ifdef DEBUG_LOG
00254     DebugDump("<",data,bytes);
00255 #endif
00256 
00257     return bytes;
00258     }
00259 
00260 
00261 void LinuxSerialPort::Close()
00262     {
00263     if(SerialHandle)
00264         {
00265         close(SerialHandle);
00266         SerialHandle = 0;
00267         }
00268 #ifdef DEBUG_LOG
00269     if(DebugLog)
00270         {
00271         fclose(DebugLog);
00272         DebugLog = 0;
00273         }
00274 #endif
00275     }
00276 
00277 
00278 #ifdef DEBUG_LOG
00279 
00280 void LinuxSerialPort::DebugDump(const char* prefix, const uint8_t* data, size_t size)
00281     {
00282     if(!DebugLog)
00283         return;
00284 
00285     size_t i=0;
00286     while(i<size)
00287         {
00288         fprintf(DebugLog,prefix);
00289         unsigned j;
00290         for(j=0; j<16 && i+j<size; j++)
00291             {
00292             fprintf(DebugLog," %02x",data[i+j]);
00293             }
00294         fprintf(DebugLog," ");
00295         for(unsigned k=0; k<j; k++)
00296             {
00297             uint8_t c = data[i+k];
00298             if(c<' '|| c>=0x7f)
00299                 c = '.';
00300             fprintf(DebugLog,"%c",c);
00301             }
00302         fprintf(DebugLog,"\n");
00303         i += j;
00304         }
00305     }
00306 
00307 #endif
00308 
00309 
00310 inline LinuxSerialPort::LinuxSerialPort()
00311     : SerialHandle(0)
00312 #ifdef DEBUG_LOG
00313     ,DebugLog(0)
00314 #endif
00315     {
00316     }
00317 
00318 
00319 LinuxSerialPort::~LinuxSerialPort()
00320     {
00321     Close();
00322     }
00323 
00324 
00325 SerialPort* SerialPort::New()
00326     {
00327     return new LinuxSerialPort;
00328     }
00329 
00330 
00331 SerialPort::~SerialPort()
00332     {
00333     }
00334 
00335 

Generated by  doxygen 1.6.1