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  }
228  else if (parity_ == parity_even) {
229  dcbSerialParams.Parity = EVENPARITY;
230  }
231  else if (parity_ == parity_odd) {
232  dcbSerialParams.Parity = ODDPARITY;
233  }
234  else if (parity_ == parity_mark) {
235  dcbSerialParams.Parity = MARKPARITY;
236  }
237  else if (parity_ == parity_space) {
238  dcbSerialParams.Parity = SPACEPARITY;
239  }
240  else {
241  throw invalid_argument("invalid parity");
242  }
243 
244  // setup flowcontrol
245  if (flowcontrol_ == flowcontrol_none) {
246  dcbSerialParams.fOutxCtsFlow = false;
247  dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
248  dcbSerialParams.fOutX = false;
249  dcbSerialParams.fInX = false;
250  }
251  if (flowcontrol_ == flowcontrol_software) {
252  dcbSerialParams.fOutxCtsFlow = false;
253  dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
254  dcbSerialParams.fOutX = true;
255  dcbSerialParams.fInX = true;
256  }
257  if (flowcontrol_ == flowcontrol_hardware) {
258  dcbSerialParams.fOutxCtsFlow = true;
259  dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;
260  dcbSerialParams.fOutX = false;
261  dcbSerialParams.fInX = false;
262  }
263 
264  // activate settings
265  if (!SetCommState(fd_, &dcbSerialParams)) {
266  CloseHandle(fd_);
267  THROW(IOException, "Error setting serial port settings.");
268  }
269 
270  // Setup timeouts
271  COMMTIMEOUTS timeouts = { 0 };
272  timeouts.ReadIntervalTimeout = timeout_.inter_byte_timeout;
273  timeouts.ReadTotalTimeoutConstant = timeout_.read_timeout_constant;
274  timeouts.ReadTotalTimeoutMultiplier = timeout_.read_timeout_multiplier;
275  timeouts.WriteTotalTimeoutConstant = timeout_.write_timeout_constant;
276  timeouts.WriteTotalTimeoutMultiplier = timeout_.write_timeout_multiplier;
277  if (!SetCommTimeouts(fd_, &timeouts)) {
278  THROW(IOException, "Error setting timeouts.");
279  }
280 }
281 
282 void
283 Serial::SerialImpl::close()
284 {
285  if (is_open_ == true) {
286  if (fd_ != INVALID_HANDLE_VALUE) {
287  int ret;
288  ret = CloseHandle(fd_);
289  if (ret == 0) {
290  stringstream ss;
291  ss << "Error while closing serial port: " << GetLastError();
292  THROW(IOException, ss.str().c_str());
293  }
294  else {
295  fd_ = INVALID_HANDLE_VALUE;
296  }
297  }
298  is_open_ = false;
299  }
300 }
301 
302 bool
303 Serial::SerialImpl::isOpen() const
304 {
305  return is_open_;
306 }
307 
308 size_t
309 Serial::SerialImpl::available()
310 {
311  if (!is_open_) {
312  return 0;
313  }
314  COMSTAT cs;
315  if (!ClearCommError(fd_, NULL, &cs)) {
316  stringstream ss;
317  ss << "Error while checking status of the serial port: " << GetLastError();
318  THROW(IOException, ss.str().c_str());
319  }
320  return static_cast<size_t>(cs.cbInQue);
321 }
322 
323 bool
324 Serial::SerialImpl::waitReadable(uint32_t /*timeout*/)
325 {
326  THROW(IOException, "waitReadable is not implemented on Windows.");
327  return false;
328 }
329 
330 void
331 Serial::SerialImpl::waitByteTimes(size_t /*count*/)
332 {
333  THROW(IOException, "waitByteTimes is not implemented on Windows.");
334 }
335 
336 size_t
337 Serial::SerialImpl::read(uint8_t *buf, size_t size)
338 {
339  if (!is_open_) {
340  throw PortNotOpenedException("Serial::read");
341  }
342  DWORD bytes_read;
343  if (!ReadFile(fd_, buf, static_cast<DWORD>(size), &bytes_read, NULL)) {
344  stringstream ss;
345  ss << "Error while reading from the serial port: " << GetLastError();
346  THROW(IOException, ss.str().c_str());
347  }
348  return (size_t)(bytes_read);
349 }
350 
351 size_t
352 Serial::SerialImpl::write(const uint8_t *data, size_t length)
353 {
354  if (is_open_ == false) {
355  throw PortNotOpenedException("Serial::write");
356  }
357  DWORD bytes_written;
358  if (!WriteFile(fd_, data, static_cast<DWORD>(length), &bytes_written, NULL)) {
359  stringstream ss;
360  ss << "Error while writing to the serial port: " << GetLastError();
361  THROW(IOException, ss.str().c_str());
362  }
363  return (size_t)(bytes_written);
364 }
365 
366 void
367 Serial::SerialImpl::setPort(const string &port)
368 {
369  port_ = wstring(port.begin(), port.end());
370 }
371 
372 string
373 Serial::SerialImpl::getPort() const
374 {
375  return string(port_.begin(), port_.end());
376 }
377 
378 void
379 Serial::SerialImpl::setTimeout(serial::Timeout &timeout)
380 {
381  timeout_ = timeout;
382  if (is_open_) {
383  reconfigurePort();
384  }
385 }
386 
388 Serial::SerialImpl::getTimeout() const
389 {
390  return timeout_;
391 }
392 
393 void
394 Serial::SerialImpl::setBaudrate(unsigned long baudrate)
395 {
396  baudrate_ = baudrate;
397  if (is_open_) {
398  reconfigurePort();
399  }
400 }
401 
402 unsigned long
403 Serial::SerialImpl::getBaudrate() const
404 {
405  return baudrate_;
406 }
407 
408 void
409 Serial::SerialImpl::setBytesize(serial::bytesize_t bytesize)
410 {
411  bytesize_ = bytesize;
412  if (is_open_) {
413  reconfigurePort();
414  }
415 }
416 
418 Serial::SerialImpl::getBytesize() const
419 {
420  return bytesize_;
421 }
422 
423 void
424 Serial::SerialImpl::setParity(serial::parity_t parity)
425 {
426  parity_ = parity;
427  if (is_open_) {
428  reconfigurePort();
429  }
430 }
431 
433 Serial::SerialImpl::getParity() const
434 {
435  return parity_;
436 }
437 
438 void
439 Serial::SerialImpl::setStopbits(serial::stopbits_t stopbits)
440 {
441  stopbits_ = stopbits;
442  if (is_open_) {
443  reconfigurePort();
444  }
445 }
446 
448 Serial::SerialImpl::getStopbits() const
449 {
450  return stopbits_;
451 }
452 
453 void
454 Serial::SerialImpl::setFlowcontrol(serial::flowcontrol_t flowcontrol)
455 {
456  flowcontrol_ = flowcontrol;
457  if (is_open_) {
458  reconfigurePort();
459  }
460 }
461 
463 Serial::SerialImpl::getFlowcontrol() const
464 {
465  return flowcontrol_;
466 }
467 
468 void
469 Serial::SerialImpl::flush()
470 {
471  if (is_open_ == false) {
472  throw PortNotOpenedException("Serial::flush");
473  }
474  FlushFileBuffers(fd_);
475 }
476 
477 void
478 Serial::SerialImpl::flushInput()
479 {
480  if (is_open_ == false) {
481  throw PortNotOpenedException("Serial::flushInput");
482  }
483  PurgeComm(fd_, PURGE_RXCLEAR);
484 }
485 
486 void
487 Serial::SerialImpl::flushOutput()
488 {
489  if (is_open_ == false) {
490  throw PortNotOpenedException("Serial::flushOutput");
491  }
492  PurgeComm(fd_, PURGE_TXCLEAR);
493 }
494 
495 void
496 Serial::SerialImpl::sendBreak(int /*duration*/)
497 {
498  THROW(IOException, "sendBreak is not supported on Windows.");
499 }
500 
501 void
502 Serial::SerialImpl::setBreak(bool level)
503 {
504  if (is_open_ == false) {
505  throw PortNotOpenedException("Serial::setBreak");
506  }
507  if (level) {
508  EscapeCommFunction(fd_, SETBREAK);
509  }
510  else {
511  EscapeCommFunction(fd_, CLRBREAK);
512  }
513 }
514 
515 void
516 Serial::SerialImpl::setRTS(bool level)
517 {
518  if (is_open_ == false) {
519  throw PortNotOpenedException("Serial::setRTS");
520  }
521  if (level) {
522  EscapeCommFunction(fd_, SETRTS);
523  }
524  else {
525  EscapeCommFunction(fd_, CLRRTS);
526  }
527 }
528 
529 void
530 Serial::SerialImpl::setDTR(bool level)
531 {
532  if (is_open_ == false) {
533  throw PortNotOpenedException("Serial::setDTR");
534  }
535  if (level) {
536  EscapeCommFunction(fd_, SETDTR);
537  }
538  else {
539  EscapeCommFunction(fd_, CLRDTR);
540  }
541 }
542 
543 bool
544 Serial::SerialImpl::waitForChange()
545 {
546  if (is_open_ == false) {
547  throw PortNotOpenedException("Serial::waitForChange");
548  }
549  DWORD dwCommEvent;
550 
551  if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
552  // Error setting communications mask
553  return false;
554  }
555 
556  if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
557  // An error occurred waiting for the event.
558  return false;
559  }
560  else {
561  // Event has occurred.
562  return true;
563  }
564 }
565 
566 bool
567 Serial::SerialImpl::getCTS()
568 {
569  if (is_open_ == false) {
570  throw PortNotOpenedException("Serial::getCTS");
571  }
572  DWORD dwModemStatus;
573  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
574  THROW(IOException, "Error getting the status of the CTS line.");
575  }
576 
577  return (MS_CTS_ON & dwModemStatus) != 0;
578 }
579 
580 bool
581 Serial::SerialImpl::getDSR()
582 {
583  if (is_open_ == false) {
584  throw PortNotOpenedException("Serial::getDSR");
585  }
586  DWORD dwModemStatus;
587  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
588  THROW(IOException, "Error getting the status of the DSR line.");
589  }
590 
591  return (MS_DSR_ON & dwModemStatus) != 0;
592 }
593 
594 bool
595 Serial::SerialImpl::getRI()
596 {
597  if (is_open_ == false) {
598  throw PortNotOpenedException("Serial::getRI");
599  }
600  DWORD dwModemStatus;
601  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
602  THROW(IOException, "Error getting the status of the RI line.");
603  }
604 
605  return (MS_RING_ON & dwModemStatus) != 0;
606 }
607 
608 bool
609 Serial::SerialImpl::getCD()
610 {
611  if (is_open_ == false) {
612  throw PortNotOpenedException("Serial::getCD");
613  }
614  DWORD dwModemStatus;
615  if (!GetCommModemStatus(fd_, &dwModemStatus)) {
616  // Error in GetCommModemStatus;
617  THROW(IOException, "Error getting the status of the CD line.");
618  }
619 
620  return (MS_RLSD_ON & dwModemStatus) != 0;
621 }
622 
623 void
624 Serial::SerialImpl::readLock()
625 {
626  if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
627  THROW(IOException, "Error claiming read mutex.");
628  }
629 }
630 
631 void
632 Serial::SerialImpl::readUnlock()
633 {
634  if (!ReleaseMutex(read_mutex)) {
635  THROW(IOException, "Error releasing read mutex.");
636  }
637 }
638 
639 void
640 Serial::SerialImpl::writeLock()
641 {
642  if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
643  THROW(IOException, "Error claiming write mutex.");
644  }
645 }
646 
647 void
648 Serial::SerialImpl::writeUnlock()
649 {
650  if (!ReleaseMutex(write_mutex)) {
651  THROW(IOException, "Error releasing write mutex.");
652  }
653 }
654 
655 #endif // #if defined(_WIN32)
656 
ROSCPP_DECL uint32_t getPort()
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


xarm_api
Author(s):
autogenerated on Sat May 8 2021 02:51:23