00001 
00009 
00010 
00011 
00012 
00013 #include <ecl/config.hpp>
00014 #ifdef ECL_IS_WIN32
00015 
00016 
00017 
00018 
00019 
00020 #include <ecl/exceptions/standard_exception.hpp>
00021 #include "../../include/ecl/devices/serial_w32.hpp"
00022 
00023 
00024 
00025 
00026 
00027 namespace ecl {
00028 
00029 
00030 
00031 
00032 
00033 Serial::Serial(const std::string& port_name, const BaudRate &baud_rate, const DataBits &data_bits,
00034                 const StopBits &stop_bits, const Parity &parity ) throw(StandardException) :
00035                                 port(port_name)
00036 {
00037         try {
00038                 open(port_name, baud_rate, data_bits, stop_bits, parity);
00039         } catch ( StandardException &e ) {
00040                 throw StandardException(LOC,e);
00041         }
00042 }
00043 
00044 Serial::~Serial() {
00045         close();
00046 }
00047 
00048 
00049 
00050 
00051 
00052 void Serial::open(const std::string& port_name, const BaudRate &baud_rate, const DataBits &data_bits,
00053                 const StopBits &stop_bits, const Parity &parity ) throw(StandardException) {
00054 
00055         if ( open() ) {
00056                 close();
00057         }
00058 
00059     if ( port_name.length() == 5 ) {
00060         
00061 
00062 
00063         
00064         port = std::string("\\\\.\\") + port_name;
00065     }
00066     
00067 
00068 
00069     m_osRead.Offset = 0;
00070     m_osRead.OffsetHigh = 0;
00071     if (! (m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
00072         throw StandardException(LOC, OpenError, "Serial port failed to open - could not configure offsets.");
00073     }
00074     m_osWrite.Offset = 0;
00075     m_osWrite.OffsetHigh = 0;
00076     if (! (m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
00077         throw StandardException(LOC, OpenError, "Serial port failed to open - could not configure offsets.");
00078     }
00079     
00080 
00081 
00082     
00083 
00084 
00085 
00086 
00087 
00088 
00089     file_descriptor = CreateFileA( port.c_str(),
00090                             GENERIC_READ | GENERIC_WRITE,
00091                             0,
00092                             NULL,
00093                             OPEN_EXISTING, 
00094                             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
00095                             NULL);
00096 
00097     
00098 
00099 
00100     if (file_descriptor == INVALID_HANDLE_VALUE ) {
00101         int error = GetLastError();
00102         switch (error) {
00103             case (ERROR_PATH_NOT_FOUND) : {
00104                 throw StandardException(LOC,OpenError);
00105                 break;
00106             }
00107             case (ERROR_FILE_NOT_FOUND) : {
00108                 throw StandardException(LOC,OpenError);
00109                 break;
00110             }
00111             default : {
00112                 throw StandardException(LOC,OpenError);
00113             }
00114         }
00115     }
00116 
00117     
00118 
00119 
00120     static const int baud_rate_flags[] = { CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400, CBR_4800, CBR_9600, CBR_19200, CBR_38400, CBR_57600, CBR_115200 };
00121     static const int stop_bits_flags[] = { ONESTOPBIT, TWOSTOPBITS }; 
00122     static const int parity_types_flags[] = { NOPARITY, ODDPARITY, EVENPARITY }; 
00123     static const int data_bits_flags[] = { 5, 6, 7, 8 };
00124 
00125     
00126 
00127 
00128     
00129     SetCommMask( file_descriptor, EV_RXCHAR );
00130 
00131     
00132 
00133 
00134     SetupComm( file_descriptor, 2048, 2048 ); 
00135 
00136     
00137 
00138 
00139     PurgeComm( file_descriptor, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR );
00140 
00141         
00142 
00143 
00144         COMMTIMEOUTS    timeouts;
00145         GetCommTimeouts( file_descriptor, &timeouts );
00146         timeouts.WriteTotalTimeoutMultiplier = 0;
00147         timeouts.WriteTotalTimeoutConstant = 0;
00148         SetCommTimeouts( file_descriptor, &timeouts );
00149 
00150         
00151 
00152 
00153         DCB dcb;
00154 
00155         FillMemory(&dcb, sizeof(dcb), 0);
00156 
00157         
00158         
00159         if ( !GetCommState( file_descriptor, &dcb) ) {
00160          throw StandardException(LOC,ConfigurationError,"There was an error retrieving the state of the port.");
00161         };
00162 
00163         
00164 
00165 
00166         dcb.DCBlength = sizeof(dcb);
00167         dcb.BaudRate = baud_rate_flags[baud_rate];
00168         dcb.ByteSize = data_bits_flags[data_bits];
00169         dcb.Parity = parity_types_flags[parity];
00170         dcb.StopBits = stop_bits_flags[stop_bits];
00171         dcb.fNull= FALSE; 
00172 
00173         
00174 
00175         
00176 
00177 
00178         dcb.fInX = FALSE; 
00179         dcb.fOutX = FALSE; 
00180         dcb.fDtrControl = DTR_CONTROL_DISABLE; 
00181         dcb.fRtsControl = RTS_CONTROL_DISABLE; 
00182 
00183         dcb.fOutxCtsFlow = FALSE; 
00184         dcb.fOutxDsrFlow = FALSE; 
00185 
00186         
00187         
00188         
00189         
00190 
00191     
00192 
00193 
00194     if (!SetCommState( file_descriptor, &dcb)) {
00195         int error = GetLastError();
00196         switch ( error ) {
00197             case ( ERROR_INVALID_PARAMETER ) : {
00198                 throw StandardException(LOC,ConfigurationError,"A parameter was configured incorrectly (ERROR_INVALID_PARAMETER).");
00199                 break;
00200             }
00201             default: {
00202                 throw StandardException(LOC,ConfigurationError);
00203                 break;
00204             }
00205         }
00206     }
00207 
00208     block(5000);
00209     is_open = true;
00210 }
00211 void Serial::close() {
00212         if ( open() ) {
00213             
00214             SetCommMask(file_descriptor, 0);
00215             PurgeComm(file_descriptor, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR );
00216             CloseHandle(file_descriptor);
00217             is_open = false;
00218         }
00219 }
00220 
00221 
00222 
00223 
00224 long Serial::write(const char &c) ecl_assert_throw_decl(StandardException) {
00225         return write(&c, 1);
00226 }
00227 
00228 long Serial::write(const char *s, unsigned long n) ecl_assert_throw_decl(StandardException) {
00229         DWORD   written, error, error_flags;
00230         COMSTAT comstat;
00231         int    result;
00232 
00233         result = WriteFile( file_descriptor, s, n, &written, &m_osWrite);
00234 
00235         if (!result) {
00236                 if (GetLastError() == ERROR_IO_PENDING) {
00237                         while (!GetOverlappedResult(file_descriptor, &m_osWrite, &written, TRUE)) {
00238                                 error = GetLastError();
00239                                 if (error != ERROR_IO_INCOMPLETE) {
00240                                         ClearCommError( file_descriptor, &error_flags, &comstat);
00241                                         break;
00242                                 }
00243                         }
00244                 } else {
00245                         written = 0;
00246                         ClearCommError(file_descriptor, &error_flags, &comstat);
00247                 }
00248         }
00249         ecl_assert_throw( written != 0, StandardException(LOC,WriteError) );
00250         return written;
00251 }
00252 
00253 
00254 
00255 
00256 
00257 void Serial::block(const long &timeout) ecl_assert_throw_decl(StandardException) {
00258 
00259         ecl_assert_throw( timeout >= 0, StandardException(LOC, InvalidInputError, "Serial port timeouts must be greater than 0ms.") );
00260     COMMTIMEOUTS    timeouts;
00261     GetCommTimeouts( file_descriptor, &timeouts );
00262 
00263     
00264     
00265     timeouts.ReadIntervalTimeout = MAXDWORD;
00266     timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
00267     timeouts.ReadTotalTimeoutConstant = static_cast<DWORD>(timeout);
00268     SetCommTimeouts( file_descriptor, &timeouts );
00269 }
00270 
00271 void Serial::unblock() {
00272     COMMTIMEOUTS    timeouts;
00273     GetCommTimeouts( file_descriptor, &timeouts );
00274 
00275     
00276     
00277     timeouts.ReadIntervalTimeout = MAXDWORD;
00278     timeouts.ReadTotalTimeoutMultiplier = 0;
00279     timeouts.ReadTotalTimeoutConstant = 0;
00280     SetCommTimeouts( file_descriptor, &timeouts );
00281 }
00282 
00283 
00284 
00285 
00286 long Serial::remaining() {
00287     unsigned long error;
00288     _COMSTAT status;
00289     if ( ClearCommError(file_descriptor,&error,&status) ) {
00290         return status.cbInQue;
00291     } else {
00292         return -1;
00293     }
00294 }
00295 
00296 long Serial::read(char &c) ecl_assert_throw_decl(StandardException) {
00297         return read(&c,1);
00298 }
00299 
00300 long Serial::read(char *s, const unsigned long &n) ecl_assert_throw_decl(StandardException)
00301 {
00302     COMSTAT comstat;
00303     DWORD   read=0, error, error_flags;
00304     DWORD dwRes;
00305 
00306     
00307 
00308 
00309     
00310     
00311 
00312 
00313     if (!ReadFile( file_descriptor, s, n, &read, &m_osRead) ) {
00314         error = GetLastError();
00315 
00316         if( error != ERROR_IO_PENDING ) {
00317             ClearCommError(file_descriptor, &error_flags, &comstat);
00318 
00319             return 0;
00320         } else {
00321             dwRes = WaitForSingleObject( m_osRead.hEvent, INFINITE );
00322 
00323             switch( dwRes ) {
00324             case WAIT_OBJECT_0:
00325                 if( !GetOverlappedResult( file_descriptor, &m_osRead, &read, FALSE) ) {
00326                     ClearCommError(file_descriptor, &error_flags, &comstat);
00327                     return 0;
00328                 } else {
00329                     ClearCommError(file_descriptor, &error_flags, &comstat);
00330                     return read;
00331                 }
00332                 break;
00333             default:
00334                 {
00335                     ClearCommError(file_descriptor, &error_flags, &comstat);
00336                     return 0;
00337                 }
00338                 break;
00339             }
00340         }
00341     }
00342     return read;
00343 }
00344 } 
00345 
00346 #endif