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 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 "windows.h"
00037 
00038 
00039 // comment in next line to get a log of all port trafic...
00040 // #define DEBUG_LOG
00041 
00042 #ifdef DEBUG_LOG
00043 #include "stdio.h"
00044 #endif
00045 
00046 
00051 class WindowsSerialPort : public SerialPort
00052     {
00053 public:
00054     WindowsSerialPort();
00055     int Open(unsigned port);
00056     int Initialise(unsigned baud);
00057     int Out(const uint8_t* data, size_t size, unsigned timeout);
00058     int In(uint8_t* data, size_t maxSize, unsigned timeout);
00059     void Close();
00060 private:
00061     ~WindowsSerialPort();
00062     int Error(int defaultError=ErrorUnspecified);
00063 private:
00064     HANDLE hSerial; 
00065 #ifdef DEBUG_LOG
00066     void DebugDump(const char* prefix, const uint8_t* data, size_t size);
00067     FILE* DebugLog;
00068 #endif
00069     };
00070 
00071 
00079 int WindowsSerialPort::Error(int defaultError)
00080     {
00081 #ifdef DEBUG_LOG
00082     char errorMessage[1024];
00083     DWORD error = GetLastError();
00084     FormatMessage
00085         (
00086         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
00087         NULL,
00088         error,
00089         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
00090         errorMessage,
00091         sizeof(errorMessage),
00092         NULL
00093         );
00094     OutputDebugString(errorMessage);
00095     if(DebugLog)
00096         fprintf(DebugLog,"ERROR: Windows error %d : %s",error,errorMessage);
00097     BREAKPOINT;
00098 //  MessageBox( NULL, errorMessage, "Error", MB_OK | MB_ICONINFORMATION );
00099 #endif
00100     // if we wanted to we could convert a Windows error from GetLastError()
00101     // into one of our error values, but just return defaultError...
00102     return defaultError;
00103     }
00104 
00105 
00106 int WindowsSerialPort::Open(unsigned port)
00107     {
00108     // make name for port...
00109     char name[] = "\\\\.\\com???.???";
00110     char* nameNumber = name+sizeof(name)-8;
00111     char* nameEnd = nameNumber;
00112     if(port>999)
00113         return ErrorInvalidPort;
00114     if(port>99)
00115         {
00116         *nameEnd++ = '0'+port/100;
00117         port %= 100;
00118         }
00119     if(port>9)
00120         {
00121         *nameEnd++ = '0'+port/10;
00122         port %= 10;
00123         }
00124     *nameEnd++ = '0'+port;
00125     *nameEnd = 0;
00126 
00127     // open port...
00128     hSerial = CreateFile(name, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
00129     if(hSerial==INVALID_HANDLE_VALUE)
00130         {
00131         switch(GetLastError())
00132             {
00133             case ERROR_FILE_NOT_FOUND:
00134                 return ErrorInvalidPort;
00135             case ERROR_ACCESS_DENIED:
00136                 return ErrorPortInUse;
00137             default:
00138                 return Error();
00139             }
00140         }
00141 
00142 #ifdef DEBUG_LOG
00143     strcpy(nameEnd,".log");
00144     DebugLog = fopen(nameNumber,"w+b");
00145 #endif
00146 
00147     return 0;
00148     }
00149 
00150 
00151 int WindowsSerialPort::Initialise(unsigned baud)
00152     {
00153     // flush port...
00154     if(!FlushFileBuffers(hSerial))
00155         return Error();
00156     if(!PurgeComm(hSerial, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR))
00157         return Error();
00158 
00159     // configure port...
00160     DCB dcb = {0};
00161     if(!GetCommState(hSerial, &dcb))
00162         return Error();
00163     dcb.BaudRate    = baud;
00164     dcb.ByteSize    = 8;
00165     dcb.StopBits    = ONESTOPBIT;
00166     dcb.Parity      = NOPARITY;
00167     if(!SetCommState(hSerial, &dcb))
00168         {
00169         if(GetLastError()==ERROR_INVALID_PARAMETER)
00170             return ErrorInvalidSettings;
00171         return Error();
00172         }
00173 
00174     // set timeouts to zero so read/writes return immediately...
00175     COMMTIMEOUTS timeouts = {0};
00176     timeouts.ReadIntervalTimeout        = MAXDWORD;
00177     timeouts.ReadTotalTimeoutConstant   = 0;
00178     timeouts.ReadTotalTimeoutMultiplier = 0;
00179     timeouts.WriteTotalTimeoutConstant  = 0;
00180     timeouts.WriteTotalTimeoutMultiplier= 0;
00181     if(!SetCommTimeouts(hSerial, &timeouts))
00182         return Error();
00183 
00184     // flush port again...
00185     if(!PurgeComm(hSerial, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR))
00186         return Error();
00187 
00188     return 0;
00189     }
00190 
00191 
00192 int WindowsSerialPort::Out(const uint8_t* data, size_t size, unsigned timeout)
00193     {
00194     DWORD bytes = 0;
00195     for(;;)
00196         {
00197         // read...
00198         if(!WriteFile(hSerial,data,size,&bytes,NULL))
00199             return Error(ErrorTransmitError);
00200         if(bytes)
00201             break; // end if any data was received
00202         if(timeout==0)
00203             break; // end if we have timed out
00204 
00205         // wait for 10 milliseconds...
00206         unsigned sleep = 10;
00207         if(sleep>timeout)
00208             sleep = timeout;
00209         timeout -= sleep;
00210         Sleep(sleep);
00211         }
00212 
00213 #ifdef DEBUG_LOG
00214     DebugDump(">",data,bytes);
00215 #endif
00216 
00217     return bytes;
00218     }
00219 
00220 
00221 int WindowsSerialPort::In(uint8_t* data, size_t maxSize, unsigned timeout)
00222     {
00223     DWORD bytes = 0;
00224     for(;;)
00225         {
00226         // read...
00227         if(!ReadFile(hSerial,data,maxSize,&bytes,NULL))
00228             return Error(ErrorReceiveError);
00229         if(bytes)
00230             break; // end if any data was received
00231         if(timeout==0)
00232             break; // end if we have timed out
00233 
00234         // wait for 10 milliseconds...
00235         unsigned sleep = 10;
00236         if(sleep>timeout)
00237             sleep = timeout;
00238         timeout -= sleep;
00239         Sleep(sleep);
00240         }
00241 
00242 #ifdef DEBUG_LOG
00243     DebugDump("<",data,bytes);
00244 #endif
00245 
00246     return bytes;
00247     }
00248 
00249 
00250 #ifdef DEBUG_LOG
00251 
00252 void WindowsSerialPort::DebugDump(const char* prefix, const uint8_t* data, size_t size)
00253     {
00254     if(!DebugLog)
00255         return;
00256 
00257     size_t i=0;
00258     while(i<size)
00259         {
00260         fprintf(DebugLog,prefix);
00261         unsigned j;
00262         for(j=0; j<16 && i+j<size; j++)
00263             {
00264             fprintf(DebugLog," %02x",data[i+j]);
00265             }
00266         fprintf(DebugLog," ");
00267         for(unsigned k=0; k<j; k++)
00268             {
00269             uint8_t c = data[i+k];
00270             if(c<' '|| c>=0x7f)
00271                 c = '.';
00272             fprintf(DebugLog,"%c",c);
00273             }
00274         fprintf(DebugLog,"\n");
00275         i += j;
00276         }
00277     }
00278 
00279 #endif
00280 
00281 
00282 void WindowsSerialPort::Close()
00283     {
00284     if(hSerial!=INVALID_HANDLE_VALUE)
00285         {
00286         CloseHandle(hSerial);
00287         hSerial = INVALID_HANDLE_VALUE;
00288         }
00289 #ifdef DEBUG_LOG
00290     if(DebugLog)
00291         {
00292         fclose(DebugLog);
00293         DebugLog = 0;
00294         }
00295 #endif
00296     }
00297 
00298 
00299 inline WindowsSerialPort::WindowsSerialPort()
00300     : hSerial(0)
00301 #ifdef DEBUG_LOG
00302     ,DebugLog(0)
00303 #endif
00304     {
00305     }
00306 
00307 
00308 WindowsSerialPort::~WindowsSerialPort()
00309     {
00310     Close();
00311     }
00312 
00313 
00314 SerialPort* SerialPort::New()
00315     {
00316     return new WindowsSerialPort;
00317     }
00318 
00319 
00320 SerialPort::~SerialPort()
00321     {
00322     }
00323 
00324 

Generated by  doxygen 1.6.1