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