win.cc
Go to the documentation of this file.
1 #if defined(_WIN32)
2 
3 /* Copyright 2012 William Woodall and John Harrison */
4 
5 #include <sstream>
6 
7 #include "serial/impl/win.h"
8 
9 using std::string;
10 using std::wstring;
11 using std::stringstream;
12 using std::invalid_argument;
13 using serial::Serial;
14 using serial::Timeout;
15 using serial::bytesize_t;
16 using serial::parity_t;
17 using serial::stopbits_t;
22 
23 inline wstring
24 _prefix_port_if_needed(const wstring &input)
25 {
26  static wstring windows_com_port_prefix = L"\\\\.\\";
27  if (input.compare(windows_com_port_prefix) != 0)
28  {
29  return windows_com_port_prefix + input;
30  }
31  return input;
32 }
33 
34 Serial::SerialImpl::SerialImpl (const string &port, unsigned long baudrate,
35  bytesize_t bytesize,
36  parity_t parity, stopbits_t stopbits,
37  flowcontrol_t flowcontrol)
38  : port_ (port.begin(), port.end()), fd_ (INVALID_HANDLE_VALUE), is_open_ (false),
39  baudrate_ (baudrate), parity_ (parity),
40  bytesize_ (bytesize), stopbits_ (stopbits), flowcontrol_ (flowcontrol)
41 {
42  if (port_.empty () == false)
43  open ();
44  read_mutex = CreateMutex(NULL, false, NULL);
45  write_mutex = CreateMutex(NULL, false, NULL);
46 }
47 
48 Serial::SerialImpl::~SerialImpl ()
49 {
50  this->close();
51  CloseHandle(read_mutex);
52  CloseHandle(write_mutex);
53 }
54 
55 void
56 Serial::SerialImpl::open ()
57 {
58  if (port_.empty ()) {
59  throw invalid_argument ("Empty port is invalid.");
60  }
61  if (is_open_ == true) {
62  throw SerialException ("Serial port already open.");
63  }
64 
65  // See: https://github.com/wjwwood/serial/issues/84
66  wstring port_with_prefix = _prefix_port_if_needed(port_);
67  LPCWSTR lp_port = port_with_prefix.c_str();
68  fd_ = CreateFileW(lp_port,
69  GENERIC_READ | GENERIC_WRITE,
70  0,
71  0,
72  OPEN_EXISTING,
73  FILE_ATTRIBUTE_NORMAL,
74  0);
75 
76  if (fd_ == INVALID_HANDLE_VALUE) {
77  DWORD create_file_err = GetLastError();
78  stringstream ss;
79  switch (create_file_err) {
80  case ERROR_FILE_NOT_FOUND:
81  // Use this->getPort to convert to a std::string
82  ss << "Specified port, " << this->getPort() << ", does not exist.";
83  THROW (IOException, ss.str().c_str());
84  default:
85  ss << "Unknown error opening the serial port: " << create_file_err;
86  THROW (IOException, ss.str().c_str());
87  }
88  }
89 
90  reconfigurePort();
91  is_open_ = true;
92 }
93 
94 void
95 Serial::SerialImpl::reconfigurePort ()
96 {
97  if (fd_ == INVALID_HANDLE_VALUE) {
98  // Can only operate on a valid file descriptor
99  THROW (IOException, "Invalid file descriptor, is the serial port open?");
100  }
101 
102  DCB dcbSerialParams = {0};
103 
104  dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
105 
106  if (!GetCommState(fd_, &dcbSerialParams)) {
107  //error getting state
108  THROW (IOException, "Error getting the serial port state.");
109  }
110 
111  // setup baud rate
112  switch (baudrate_) {
113 #ifdef CBR_0
114  case 0: dcbSerialParams.BaudRate = CBR_0; break;
115 #endif
116 #ifdef CBR_50
117  case 50: dcbSerialParams.BaudRate = CBR_50; break;
118 #endif
119 #ifdef CBR_75
120  case 75: dcbSerialParams.BaudRate = CBR_75; break;
121 #endif
122 #ifdef CBR_110
123  case 110: dcbSerialParams.BaudRate = CBR_110; break;
124 #endif
125 #ifdef CBR_134
126  case 134: dcbSerialParams.BaudRate = CBR_134; break;
127 #endif
128 #ifdef CBR_150
129  case 150: dcbSerialParams.BaudRate = CBR_150; break;
130 #endif
131 #ifdef CBR_200
132  case 200: dcbSerialParams.BaudRate = CBR_200; break;
133 #endif
134 #ifdef CBR_300
135  case 300: dcbSerialParams.BaudRate = CBR_300; break;
136 #endif
137 #ifdef CBR_600
138  case 600: dcbSerialParams.BaudRate = CBR_600; break;
139 #endif
140 #ifdef CBR_1200
141  case 1200: dcbSerialParams.BaudRate = CBR_1200; break;
142 #endif
143 #ifdef CBR_1800
144  case 1800: dcbSerialParams.BaudRate = CBR_1800; break;
145 #endif
146 #ifdef CBR_2400
147  case 2400: dcbSerialParams.BaudRate = CBR_2400; break;
148 #endif
149 #ifdef CBR_4800
150  case 4800: dcbSerialParams.BaudRate = CBR_4800; break;
151 #endif
152 #ifdef CBR_7200
153  case 7200: dcbSerialParams.BaudRate = CBR_7200; break;
154 #endif
155 #ifdef CBR_9600
156  case 9600: dcbSerialParams.BaudRate = CBR_9600; break;
157 #endif
158 #ifdef CBR_14400
159  case 14400: dcbSerialParams.BaudRate = CBR_14400; break;
160 #endif
161 #ifdef CBR_19200
162  case 19200: dcbSerialParams.BaudRate = CBR_19200; break;
163 #endif
164 #ifdef CBR_28800
165  case 28800: dcbSerialParams.BaudRate = CBR_28800; break;
166 #endif
167 #ifdef CBR_57600
168  case 57600: dcbSerialParams.BaudRate = CBR_57600; break;
169 #endif
170 #ifdef CBR_76800
171  case 76800: dcbSerialParams.BaudRate = CBR_76800; break;
172 #endif
173 #ifdef CBR_38400
174  case 38400: dcbSerialParams.BaudRate = CBR_38400; break;
175 #endif
176 #ifdef CBR_115200
177  case 115200: dcbSerialParams.BaudRate = CBR_115200; break;
178 #endif
179 #ifdef CBR_128000
180  case 128000: dcbSerialParams.BaudRate = CBR_128000; break;
181 #endif
182 #ifdef CBR_153600
183  case 153600: dcbSerialParams.BaudRate = CBR_153600; break;
184 #endif
185 #ifdef CBR_230400
186  case 230400: dcbSerialParams.BaudRate = CBR_230400; break;
187 #endif
188 #ifdef CBR_256000
189  case 256000: dcbSerialParams.BaudRate = CBR_256000; break;
190 #endif
191 #ifdef CBR_460800
192  case 460800: dcbSerialParams.BaudRate = CBR_460800; break;
193 #endif
194 #ifdef CBR_921600
195  case 921600: dcbSerialParams.BaudRate = CBR_921600; break;
196 #endif
197  default:
198  // Try to blindly assign it
199  dcbSerialParams.BaudRate = baudrate_;
200  }
201 
202  // setup char len
203  if (bytesize_ == eightbits)
204  dcbSerialParams.ByteSize = 8;
205  else if (bytesize_ == sevenbits)
206  dcbSerialParams.ByteSize = 7;
207  else if (bytesize_ == sixbits)
208  dcbSerialParams.ByteSize = 6;
209  else if (bytesize_ == fivebits)
210  dcbSerialParams.ByteSize = 5;
211  else
212  throw invalid_argument ("invalid char len");
213 
214  // setup stopbits
215  if (stopbits_ == stopbits_one)
216  dcbSerialParams.StopBits = ONESTOPBIT;
217  else if (stopbits_ == stopbits_one_point_five)
218  dcbSerialParams.StopBits = ONE5STOPBITS;
219  else if (stopbits_ == stopbits_two)
220  dcbSerialParams.StopBits = TWOSTOPBITS;
221  else
222  throw invalid_argument ("invalid stop bit");
223 
224  // setup parity
225  if (parity_ == parity_none) {
226  dcbSerialParams.Parity = NOPARITY;
227  } else if (parity_ == parity_even) {
228  dcbSerialParams.Parity = EVENPARITY;
229  } else if (parity_ == parity_odd) {
230  dcbSerialParams.Parity = ODDPARITY;
231  } else if (parity_ == parity_mark) {
232  dcbSerialParams.Parity = MARKPARITY;
233  } else if (parity_ == parity_space) {
234  dcbSerialParams.Parity = SPACEPARITY;
235  } else {
236  throw invalid_argument ("invalid parity");
237  }
238 
239  // setup flowcontrol
240  if (flowcontrol_ == flowcontrol_none) {
241  dcbSerialParams.fOutxCtsFlow = false;
242  dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
243  dcbSerialParams.fOutX = false;
244  dcbSerialParams.fInX = false;
245  }
246  if (flowcontrol_ == flowcontrol_software) {
247  dcbSerialParams.fOutxCtsFlow = false;
248  dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
249  dcbSerialParams.fOutX = true;
250  dcbSerialParams.fInX = true;
251  }
252  if (flowcontrol_ == flowcontrol_hardware) {
253  dcbSerialParams.fOutxCtsFlow = true;
254  dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;
255  dcbSerialParams.fOutX = false;
256  dcbSerialParams.fInX = false;
257  }
258 
259  // activate settings
260  if (!SetCommState(fd_, &dcbSerialParams)){
261  CloseHandle(fd_);
262  THROW (IOException, "Error setting serial port settings.");
263  }
264 
265  // Setup timeouts
266  COMMTIMEOUTS timeouts = {0};
267  timeouts.ReadIntervalTimeout = timeout_.inter_byte_timeout;
268  timeouts.ReadTotalTimeoutConstant = timeout_.read_timeout_constant;
269  timeouts.ReadTotalTimeoutMultiplier = timeout_.read_timeout_multiplier;
270  timeouts.WriteTotalTimeoutConstant = timeout_.write_timeout_constant;
271  timeouts.WriteTotalTimeoutMultiplier = timeout_.write_timeout_multiplier;
272  if (!SetCommTimeouts(fd_, &timeouts)) {
273  THROW (IOException, "Error setting timeouts.");
274  }
275 }
276 
277 void
278 Serial::SerialImpl::close ()
279 {
280  if (is_open_ == true) {
281  if (fd_ != INVALID_HANDLE_VALUE) {
282  int ret;
283  ret = CloseHandle(fd_);
284  if (ret == 0) {
285  stringstream ss;
286  ss << "Error while closing serial port: " << GetLastError();
287  THROW (IOException, ss.str().c_str());
288  } else {
289  fd_ = INVALID_HANDLE_VALUE;
290  }
291  }
292  is_open_ = false;
293  }
294 }
295 
296 bool
297 Serial::SerialImpl::isOpen () const
298 {
299  return is_open_;
300 }
301 
302 size_t
303 Serial::SerialImpl::available ()
304 {
305  if (!is_open_) {
306  return 0;
307  }
308  COMSTAT cs;
309  if (!ClearCommError(fd_, NULL, &cs)) {
310  stringstream ss;
311  ss << "Error while checking status of the serial port: " << GetLastError();
312  THROW (IOException, ss.str().c_str());
313  }
314  return static_cast<size_t>(cs.cbInQue);
315 }
316 
317 bool
318 Serial::SerialImpl::waitReadable (uint32_t /*timeout*/)
319 {
320  THROW (IOException, "waitReadable is not implemented on Windows.");
321  return false;
322 }
323 
324 void
325 Serial::SerialImpl::waitByteTimes (size_t /*count*/)
326 {
327  THROW (IOException, "waitByteTimes is not implemented on Windows.");
328 }
329 
330 size_t
331 Serial::SerialImpl::read (uint8_t *buf, size_t size)
332 {
333  if (!is_open_) {
334  throw PortNotOpenedException ("Serial::read");
335  }
336  DWORD bytes_read;
337  if (!ReadFile(fd_, buf, static_cast<DWORD>(size), &bytes_read, NULL)) {
338  stringstream ss;
339  ss << "Error while reading from the serial port: " << GetLastError();
340  THROW (IOException, ss.str().c_str());
341  }
342  return (size_t) (bytes_read);
343 }
344 
345 size_t
346 Serial::SerialImpl::write (const uint8_t *data, size_t length)
347 {
348  if (is_open_ == false) {
349  throw PortNotOpenedException ("Serial::write");
350  }
351  DWORD bytes_written;
352  if (!WriteFile(fd_, data, static_cast<DWORD>(length), &bytes_written, NULL)) {
353  stringstream ss;
354  ss << "Error while writing to the serial port: " << GetLastError();
355  THROW (IOException, ss.str().c_str());
356  }
357  return (size_t) (bytes_written);
358 }
359 
360 void
361 Serial::SerialImpl::setPort (const string &port)
362 {
363  port_ = wstring(port.begin(), port.end());
364 }
365 
366 string
367 Serial::SerialImpl::getPort () const
368 {
369  return string(port_.begin(), port_.end());
370 }
371 
372 void
373 Serial::SerialImpl::setTimeout (serial::Timeout &timeout)
374 {
375  timeout_ = timeout;
376  if (is_open_) {
377  reconfigurePort ();
378  }
379 }
380 
382 Serial::SerialImpl::getTimeout () const
383 {
384  return timeout_;
385 }
386 
387 void
388 Serial::SerialImpl::setBaudrate (unsigned long baudrate)
389 {
390  baudrate_ = baudrate;
391  if (is_open_) {
392  reconfigurePort ();
393  }
394 }
395 
396 unsigned long
397 Serial::SerialImpl::getBaudrate () const
398 {
399  return baudrate_;
400 }
401 
402 void
403 Serial::SerialImpl::setBytesize (serial::bytesize_t bytesize)
404 {
405  bytesize_ = bytesize;
406  if (is_open_) {
407  reconfigurePort ();
408  }
409 }
410 
412 Serial::SerialImpl::getBytesize () const
413 {
414  return bytesize_;
415 }
416 
417 void
418 Serial::SerialImpl::setParity (serial::parity_t parity)
419 {
420  parity_ = parity;
421  if (is_open_) {
422  reconfigurePort ();
423  }
424 }
425 
427 Serial::SerialImpl::getParity () const
428 {
429  return parity_;
430 }
431 
432 void
433 Serial::SerialImpl::setStopbits (serial::stopbits_t stopbits)
434 {
435  stopbits_ = stopbits;
436  if (is_open_) {
437  reconfigurePort ();
438  }
439 }
440 
442 Serial::SerialImpl::getStopbits () const
443 {
444  return stopbits_;
445 }
446 
447 void
448 Serial::SerialImpl::setFlowcontrol (serial::flowcontrol_t flowcontrol)
449 {
450  flowcontrol_ = flowcontrol;
451  if (is_open_) {
452  reconfigurePort ();
453  }
454 }
455 
457 Serial::SerialImpl::getFlowcontrol () const
458 {
459  return flowcontrol_;
460 }
461 
462 void
463 Serial::SerialImpl::flush ()
464 {
465  if (is_open_ == false) {
466  throw PortNotOpenedException ("Serial::flush");
467  }
468  FlushFileBuffers (fd_);
469 }
470 
471 void
472 Serial::SerialImpl::flushInput ()
473 {
474  if (is_open_ == false) {
475  throw PortNotOpenedException("Serial::flushInput");
476  }
477  PurgeComm(fd_, PURGE_RXCLEAR);
478 }
479 
480 void
481 Serial::SerialImpl::flushOutput ()
482 {
483  if (is_open_ == false) {
484  throw PortNotOpenedException("Serial::flushOutput");
485  }
486  PurgeComm(fd_, PURGE_TXCLEAR);
487 }
488 
489 void
490 Serial::SerialImpl::sendBreak (int /*duration*/)
491 {
492  THROW (IOException, "sendBreak is not supported on Windows.");
493 }
494 
495 void
496 Serial::SerialImpl::setBreak (bool level)
497 {
498  if (is_open_ == false) {
499  throw PortNotOpenedException ("Serial::setBreak");
500  }
501  if (level) {
502  EscapeCommFunction (fd_, SETBREAK);
503  } else {
504  EscapeCommFunction (fd_, CLRBREAK);
505  }
506 }
507 
508 void
509 Serial::SerialImpl::setRTS (bool level)
510 {
511  if (is_open_ == false) {
512  throw PortNotOpenedException ("Serial::setRTS");
513  }
514  if (level) {
515  EscapeCommFunction (fd_, SETRTS);
516  } else {
517  EscapeCommFunction (fd_, CLRRTS);
518  }
519 }
520 
521 void
522 Serial::SerialImpl::setDTR (bool level)
523 {
524  if (is_open_ == false) {
525  throw PortNotOpenedException ("Serial::setDTR");
526  }
527  if (level) {
528  EscapeCommFunction (fd_, SETDTR);
529  } else {
530  EscapeCommFunction (fd_, CLRDTR);
531  }
532 }
533 
534 bool
535 Serial::SerialImpl::waitForChange ()
536 {
537  if (is_open_ == false) {
538  throw PortNotOpenedException ("Serial::waitForChange");
539  }
540  DWORD dwCommEvent;
541 
542  if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
543  // Error setting communications mask
544  return false;
545  }
546 
547  if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
548  // An error occurred waiting for the event.
549  return false;
550  } else {
551  // Event has occurred.
552  return true;
553  }
554 }
555 
556 bool
557 Serial::SerialImpl::getCTS ()
558 {
559  if (is_open_ == false) {
560  throw PortNotOpenedException ("Serial::getCTS");
561  }
562  DWORD dwModemStatus;
563  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
564  THROW (IOException, "Error getting the status of the CTS line.");
565  }
566 
567  return (MS_CTS_ON & dwModemStatus) != 0;
568 }
569 
570 bool
571 Serial::SerialImpl::getDSR ()
572 {
573  if (is_open_ == false) {
574  throw PortNotOpenedException ("Serial::getDSR");
575  }
576  DWORD dwModemStatus;
577  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
578  THROW (IOException, "Error getting the status of the DSR line.");
579  }
580 
581  return (MS_DSR_ON & dwModemStatus) != 0;
582 }
583 
584 bool
585 Serial::SerialImpl::getRI()
586 {
587  if (is_open_ == false) {
588  throw PortNotOpenedException ("Serial::getRI");
589  }
590  DWORD dwModemStatus;
591  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
592  THROW (IOException, "Error getting the status of the RI line.");
593  }
594 
595  return (MS_RING_ON & dwModemStatus) != 0;
596 }
597 
598 bool
599 Serial::SerialImpl::getCD()
600 {
601  if (is_open_ == false) {
602  throw PortNotOpenedException ("Serial::getCD");
603  }
604  DWORD dwModemStatus;
605  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
606  // Error in GetCommModemStatus;
607  THROW (IOException, "Error getting the status of the CD line.");
608  }
609 
610  return (MS_RLSD_ON & dwModemStatus) != 0;
611 }
612 
613 void
614 Serial::SerialImpl::readLock()
615 {
616  if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
617  THROW (IOException, "Error claiming read mutex.");
618  }
619 }
620 
621 void
622 Serial::SerialImpl::readUnlock()
623 {
624  if (!ReleaseMutex(read_mutex)) {
625  THROW (IOException, "Error releasing read mutex.");
626  }
627 }
628 
629 void
630 Serial::SerialImpl::writeLock()
631 {
632  if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
633  THROW (IOException, "Error claiming write mutex.");
634  }
635 }
636 
637 void
638 Serial::SerialImpl::writeUnlock()
639 {
640  if (!ReleaseMutex(write_mutex)) {
641  THROW (IOException, "Error releasing write mutex.");
642  }
643 }
644 
645 #endif // #if defined(_WIN32)
646 
parity_t
Definition: serial.h:66
bytesize_t
Definition: serial.h:56
#define THROW(exceptionClass, message)
Definition: serial.h:48
stopbits_t
Definition: serial.h:77
flowcontrol_t
Definition: serial.h:86


serial
Author(s): William Woodall , John Harrison
autogenerated on Thu Jan 9 2020 07:18:58