21 #include "../../include/ecl/devices/serial_w32.hpp"
33 Serial::Serial(
const std::string& port_name,
const BaudRate &baud_rate,
const DataBits &data_bits,
35 port(port_name), is_run(false), file_descriptor(INVALID_HANDLE_VALUE)
38 open(port_name, baud_rate, data_bits, stop_bits, parity);
39 }
catch ( StandardException &e ) {
40 throw StandardException(LOC,e);
52 void Serial::open(
const std::string& port_name,
const BaudRate &baud_rate,
const DataBits &data_bits,
59 if (strstr(port_name.c_str(),
"\\\\.\\"))
62 port = std::string(
"\\\\.\\") + port_name;
68 m_osRead.OffsetHigh = 0;
69 if (! (m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
70 throw StandardException(LOC, OpenError,
"Serial port failed to open - could not configure offsets.");
73 m_osWrite.OffsetHigh = 0;
74 if (! (m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) {
75 throw StandardException(LOC, OpenError,
"Serial port failed to open - could not configure offsets.");
88 file_descriptor = CreateFileA( port.c_str(),
89 GENERIC_READ | GENERIC_WRITE,
93 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
99 if (file_descriptor == INVALID_HANDLE_VALUE ) {
100 int error = GetLastError();
102 case (ERROR_PATH_NOT_FOUND) : {
103 throw StandardException(LOC,NotFoundError);
106 case (ERROR_FILE_NOT_FOUND) : {
107 throw StandardException(LOC,NotFoundError);
111 throw StandardException(LOC,OpenError);
119 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 };
120 static const int stop_bits_flags[] = { ONESTOPBIT, TWOSTOPBITS };
121 static const int parity_types_flags[] = { NOPARITY, ODDPARITY, EVENPARITY };
122 static const int data_bits_flags[] = { 5, 6, 7, 8 };
128 SetCommMask( file_descriptor, EV_RXCHAR );
133 SetupComm( file_descriptor, 2048, 2048 );
138 PurgeComm( file_descriptor, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR );
143 COMMTIMEOUTS timeouts;
144 GetCommTimeouts( file_descriptor, &timeouts );
145 timeouts.WriteTotalTimeoutMultiplier = 0;
146 timeouts.WriteTotalTimeoutConstant = 0;
147 SetCommTimeouts( file_descriptor, &timeouts );
154 FillMemory(&dcb,
sizeof(dcb), 0);
158 if ( !GetCommState( file_descriptor, &dcb) ) {
159 throw StandardException(LOC,ConfigurationError,
"There was an error retrieving the state of the port.");
165 dcb.DCBlength =
sizeof(dcb);
166 dcb.BaudRate = baud_rate_flags[baud_rate];
167 dcb.ByteSize = data_bits_flags[data_bits];
168 dcb.Parity = parity_types_flags[parity];
169 dcb.StopBits = stop_bits_flags[stop_bits];
179 dcb.fDtrControl = DTR_CONTROL_DISABLE;
180 dcb.fRtsControl = RTS_CONTROL_DISABLE;
182 dcb.fOutxCtsFlow = FALSE;
183 dcb.fOutxDsrFlow = FALSE;
193 if (!SetCommState( file_descriptor, &dcb)) {
194 int error = GetLastError();
196 case ( ERROR_INVALID_PARAMETER ) : {
197 throw StandardException(LOC,ConfigurationError,
"A parameter was configured incorrectly (ERROR_INVALID_PARAMETER).");
201 throw StandardException(LOC,ConfigurationError);
211 event_receiver.cancel();
218 void Serial::close() {
223 event_receiver.join();
224 event_receiver.cancel();
226 if (file_descriptor != INVALID_HANDLE_VALUE) {
228 SetCommMask(file_descriptor, 0);
229 PurgeComm(file_descriptor, PURGE_TXABORT | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_RXCLEAR );
230 CloseHandle(file_descriptor);
231 file_descriptor = INVALID_HANDLE_VALUE;
241 void event_proc(
void* arg) {
242 Serial* owner = (Serial*)arg;
245 while (owner->is_run) {
247 if (!WaitCommEvent(owner->file_descriptor, &mask, NULL)) {
248 if (0x000003e3 == GetLastError()) {
253 owner->file_descriptor = INVALID_HANDLE_VALUE;
254 owner->is_open =
false;
261 long Serial::write(
const char &c) {
265 long Serial::write(
const char *s,
unsigned long n) {
266 DWORD written, error, error_flags;
270 result = WriteFile( file_descriptor, s, n, &written, &m_osWrite);
273 if (GetLastError() == ERROR_IO_PENDING) {
274 while (!GetOverlappedResult(file_descriptor, &m_osWrite, &written, TRUE)) {
275 error = GetLastError();
276 if (error != ERROR_IO_INCOMPLETE) {
277 ClearCommError( file_descriptor, &error_flags, &comstat);
283 ClearCommError(file_descriptor, &error_flags, &comstat);
294 void Serial::block(
const long &timeout) {
296 ecl_assert_throw( timeout >= 0, StandardException(LOC, InvalidInputError,
"Serial port timeouts must be greater than 0ms.") );
297 COMMTIMEOUTS timeouts;
298 GetCommTimeouts( file_descriptor, &timeouts );
302 timeouts.ReadIntervalTimeout = MAXDWORD;
303 timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
304 timeouts.ReadTotalTimeoutConstant =
static_cast<DWORD
>(timeout);
305 SetCommTimeouts( file_descriptor, &timeouts );
308 void Serial::unblock() {
309 COMMTIMEOUTS timeouts;
310 GetCommTimeouts( file_descriptor, &timeouts );
314 timeouts.ReadIntervalTimeout = MAXDWORD;
315 timeouts.ReadTotalTimeoutMultiplier = 0;
316 timeouts.ReadTotalTimeoutConstant = 0;
317 SetCommTimeouts( file_descriptor, &timeouts );
323 long Serial::remaining() {
326 if ( ClearCommError(file_descriptor,&error,&status) ) {
327 return status.cbInQue;
333 long Serial::read(
char &c) {
337 long Serial::read(
char *s,
const unsigned long &n)
340 DWORD read=0, error, error_flags;
350 if (file_descriptor == INVALID_HANDLE_VALUE) {
354 if (!ReadFile( file_descriptor, s, n, &read, &m_osRead) ) {
355 error = GetLastError();
357 if( error != ERROR_IO_PENDING ) {
358 if (error != ERROR_ACCESS_DENIED)
359 ClearCommError(file_descriptor, &error_flags, &comstat);
363 dwRes = WaitForSingleObject( m_osRead.hEvent, INFINITE );
367 if( !GetOverlappedResult( file_descriptor, &m_osRead, &read, FALSE) ) {
368 ClearCommError(file_descriptor, &error_flags, &comstat);
371 ClearCommError(file_descriptor, &error_flags, &comstat);
377 ClearCommError(file_descriptor, &error_flags, &comstat);