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


ubiquity_motor
Author(s):
autogenerated on Thu Nov 16 2023 03:30:56