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), is_run(false), file_descriptor(INVALID_HANDLE_VALUE)
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 (strstr(port_name.c_str(), "\\\\.\\"))
00060 port = port_name;
00061 else
00062 port = std::string("\\\\.\\") + port_name;
00063
00064
00065
00066
00067 m_osRead.Offset = 0;
00068 m_osRead.OffsetHigh = 0;
00069 if (! (m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
00070 throw StandardException(LOC, OpenError, "Serial port failed to open - could not configure offsets.");
00071 }
00072 m_osWrite.Offset = 0;
00073 m_osWrite.OffsetHigh = 0;
00074 if (! (m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
00075 throw StandardException(LOC, OpenError, "Serial port failed to open - could not configure offsets.");
00076 }
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 file_descriptor = CreateFileA( port.c_str(),
00089 GENERIC_READ | GENERIC_WRITE,
00090 0,
00091 NULL,
00092 OPEN_EXISTING,
00093 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
00094 NULL);
00095
00096
00097
00098
00099 if (file_descriptor == INVALID_HANDLE_VALUE ) {
00100 int error = GetLastError();
00101 switch (error) {
00102 case (ERROR_PATH_NOT_FOUND) : {
00103 throw StandardException(LOC,NotFoundError);
00104 break;
00105 }
00106 case (ERROR_FILE_NOT_FOUND) : {
00107 throw StandardException(LOC,NotFoundError);
00108 break;
00109 }
00110 default : {
00111 throw StandardException(LOC,OpenError);
00112 }
00113 }
00114 }
00115
00116
00117
00118
00119 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 };
00120 static const int stop_bits_flags[] = { ONESTOPBIT, TWOSTOPBITS };
00121 static const int parity_types_flags[] = { NOPARITY, ODDPARITY, EVENPARITY };
00122 static const int data_bits_flags[] = { 5, 6, 7, 8 };
00123
00124
00125
00126
00127
00128 SetCommMask( file_descriptor, EV_RXCHAR );
00129
00130
00131
00132
00133 SetupComm( file_descriptor, 2048, 2048 );
00134
00135
00136
00137
00138 PurgeComm( file_descriptor, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR );
00139
00140
00141
00142
00143 COMMTIMEOUTS timeouts;
00144 GetCommTimeouts( file_descriptor, &timeouts );
00145 timeouts.WriteTotalTimeoutMultiplier = 0;
00146 timeouts.WriteTotalTimeoutConstant = 0;
00147 SetCommTimeouts( file_descriptor, &timeouts );
00148
00149
00150
00151
00152 DCB dcb;
00153
00154 FillMemory(&dcb, sizeof(dcb), 0);
00155
00156
00157
00158 if ( !GetCommState( file_descriptor, &dcb) ) {
00159 throw StandardException(LOC,ConfigurationError,"There was an error retrieving the state of the port.");
00160 };
00161
00162
00163
00164
00165 dcb.DCBlength = sizeof(dcb);
00166 dcb.BaudRate = baud_rate_flags[baud_rate];
00167 dcb.ByteSize = data_bits_flags[data_bits];
00168 dcb.Parity = parity_types_flags[parity];
00169 dcb.StopBits = stop_bits_flags[stop_bits];
00170 dcb.fNull= FALSE;
00171
00172
00173
00174
00175
00176
00177 dcb.fInX = FALSE;
00178 dcb.fOutX = FALSE;
00179 dcb.fDtrControl = DTR_CONTROL_DISABLE;
00180 dcb.fRtsControl = RTS_CONTROL_DISABLE;
00181
00182 dcb.fOutxCtsFlow = FALSE;
00183 dcb.fOutxDsrFlow = FALSE;
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193 if (!SetCommState( file_descriptor, &dcb)) {
00194 int error = GetLastError();
00195 switch ( error ) {
00196 case ( ERROR_INVALID_PARAMETER ) : {
00197 throw StandardException(LOC,ConfigurationError,"A parameter was configured incorrectly (ERROR_INVALID_PARAMETER).");
00198 break;
00199 }
00200 default: {
00201 throw StandardException(LOC,ConfigurationError);
00202 break;
00203 }
00204 }
00205 }
00206
00207
00208
00209
00210 is_run = true;
00211 event_receiver.cancel();
00212 event_receiver.start(generateFunctionObject(event_proc, this));
00213
00214 block(5000);
00215 is_open = true;
00216 }
00217
00218 void Serial::close() {
00219 if ( open() ) {
00220
00221
00222 is_run = false;
00223 event_receiver.join();
00224 event_receiver.cancel();
00225
00226 if (file_descriptor != INVALID_HANDLE_VALUE) {
00227
00228 SetCommMask(file_descriptor, 0);
00229 PurgeComm(file_descriptor, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR );
00230 CloseHandle(file_descriptor);
00231 file_descriptor = INVALID_HANDLE_VALUE;
00232 }
00233
00234 is_open = false;
00235 }
00236 }
00237
00238
00239
00240
00241 void event_proc(void* arg) {
00242 Serial* owner = (Serial*)arg;
00243 if (!owner)
00244 return;
00245 while (owner->is_run) {
00246 DWORD mask;
00247 if (!WaitCommEvent(owner->file_descriptor, &mask, NULL)) {
00248 if (0x000003e3 == GetLastError()) {
00249 break;
00250 }
00251 }
00252 }
00253 owner->file_descriptor = INVALID_HANDLE_VALUE;
00254 owner->is_open = false;
00255 }
00256
00257
00258
00259
00260
00261 long Serial::write(const char &c) ecl_assert_throw_decl(StandardException) {
00262 return write(&c, 1);
00263 }
00264
00265 long Serial::write(const char *s, unsigned long n) ecl_assert_throw_decl(StandardException) {
00266 DWORD written, error, error_flags;
00267 COMSTAT comstat;
00268 int result;
00269
00270 result = WriteFile( file_descriptor, s, n, &written, &m_osWrite);
00271
00272 if (!result) {
00273 if (GetLastError() == ERROR_IO_PENDING) {
00274 while (!GetOverlappedResult(file_descriptor, &m_osWrite, &written, TRUE)) {
00275 error = GetLastError();
00276 if (error != ERROR_IO_INCOMPLETE) {
00277 ClearCommError( file_descriptor, &error_flags, &comstat);
00278 break;
00279 }
00280 }
00281 } else {
00282 written = 0;
00283 ClearCommError(file_descriptor, &error_flags, &comstat);
00284 }
00285 }
00286 ecl_assert_throw( written != 0, StandardException(LOC,WriteError) );
00287 return written;
00288 }
00289
00290
00291
00292
00293
00294 void Serial::block(const long &timeout) ecl_assert_throw_decl(StandardException) {
00295
00296 ecl_assert_throw( timeout >= 0, StandardException(LOC, InvalidInputError, "Serial port timeouts must be greater than 0ms.") );
00297 COMMTIMEOUTS timeouts;
00298 GetCommTimeouts( file_descriptor, &timeouts );
00299
00300
00301
00302 timeouts.ReadIntervalTimeout = MAXDWORD;
00303 timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
00304 timeouts.ReadTotalTimeoutConstant = static_cast<DWORD>(timeout);
00305 SetCommTimeouts( file_descriptor, &timeouts );
00306 }
00307
00308 void Serial::unblock() {
00309 COMMTIMEOUTS timeouts;
00310 GetCommTimeouts( file_descriptor, &timeouts );
00311
00312
00313
00314 timeouts.ReadIntervalTimeout = MAXDWORD;
00315 timeouts.ReadTotalTimeoutMultiplier = 0;
00316 timeouts.ReadTotalTimeoutConstant = 0;
00317 SetCommTimeouts( file_descriptor, &timeouts );
00318 }
00319
00320
00321
00322
00323 long Serial::remaining() {
00324 unsigned long error;
00325 _COMSTAT status;
00326 if ( ClearCommError(file_descriptor,&error,&status) ) {
00327 return status.cbInQue;
00328 } else {
00329 return -1;
00330 }
00331 }
00332
00333 long Serial::read(char &c) ecl_assert_throw_decl(StandardException) {
00334 return read(&c,1);
00335 }
00336
00337 long Serial::read(char *s, const unsigned long &n) ecl_assert_throw_decl(StandardException)
00338 {
00339 COMSTAT comstat;
00340 DWORD read=0, error, error_flags;
00341 DWORD dwRes;
00342
00343
00344
00345
00346
00347
00348
00349
00350 if (file_descriptor == INVALID_HANDLE_VALUE) {
00351 return 0;
00352 }
00353
00354 if (!ReadFile( file_descriptor, s, n, &read, &m_osRead) ) {
00355 error = GetLastError();
00356
00357 if( error != ERROR_IO_PENDING ) {
00358 if (error != ERROR_ACCESS_DENIED)
00359 ClearCommError(file_descriptor, &error_flags, &comstat);
00360
00361 return 0;
00362 } else {
00363 dwRes = WaitForSingleObject( m_osRead.hEvent, INFINITE );
00364
00365 switch( dwRes ) {
00366 case WAIT_OBJECT_0:
00367 if( !GetOverlappedResult( file_descriptor, &m_osRead, &read, FALSE) ) {
00368 ClearCommError(file_descriptor, &error_flags, &comstat);
00369 return 0;
00370 } else {
00371 ClearCommError(file_descriptor, &error_flags, &comstat);
00372 return read;
00373 }
00374 break;
00375 default:
00376 {
00377 ClearCommError(file_descriptor, &error_flags, &comstat);
00378 return 0;
00379 }
00380 break;
00381 }
00382 }
00383 }
00384 return read;
00385 }
00386 }
00387
00388 #endif