11 using std::stringstream;
12 using std::invalid_argument;
24 _prefix_port_if_needed(
const wstring &input)
26 static wstring windows_com_port_prefix = L
"\\\\.\\";
27 if (input.compare(windows_com_port_prefix) != 0)
29 return windows_com_port_prefix + input;
33 Serial::SerialImpl::SerialImpl (
const string &port,
unsigned long baudrate,
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)
41 read_mutex = CreateMutex(NULL,
false, NULL);
42 write_mutex = CreateMutex(NULL,
false, NULL);
43 if (port_.empty () ==
false)
47 Serial::SerialImpl::~SerialImpl ()
50 CloseHandle(read_mutex);
51 CloseHandle(write_mutex);
55 Serial::SerialImpl::open ()
58 throw invalid_argument (
"Empty port is invalid.");
60 if (is_open_ ==
true) {
61 throw SerialException (
"Serial port already open.");
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,
72 FILE_ATTRIBUTE_NORMAL,
75 if (fd_ == INVALID_HANDLE_VALUE) {
76 DWORD errno_ = GetLastError();
79 case ERROR_FILE_NOT_FOUND:
81 ss <<
"Specified port, " << this->
getPort() <<
", does not exist.";
82 THROW (IOException, ss.str().c_str());
84 ss <<
"Unknown error opening the serial port: " << errno;
85 THROW (IOException, ss.str().c_str());
94 Serial::SerialImpl::reconfigurePort ()
96 if (fd_ == INVALID_HANDLE_VALUE) {
98 THROW (IOException,
"Invalid file descriptor, is the serial port open?");
101 DCB dcbSerialParams = {0};
103 dcbSerialParams.DCBlength=
sizeof(dcbSerialParams);
105 if (!GetCommState(fd_, &dcbSerialParams)) {
107 THROW (IOException,
"Error getting the serial port state.");
113 case 0: dcbSerialParams.BaudRate = CBR_0;
break;
116 case 50: dcbSerialParams.BaudRate = CBR_50;
break;
119 case 75: dcbSerialParams.BaudRate = CBR_75;
break;
122 case 110: dcbSerialParams.BaudRate = CBR_110;
break;
125 case 134: dcbSerialParams.BaudRate = CBR_134;
break;
128 case 150: dcbSerialParams.BaudRate = CBR_150;
break;
131 case 200: dcbSerialParams.BaudRate = CBR_200;
break;
134 case 300: dcbSerialParams.BaudRate = CBR_300;
break;
137 case 600: dcbSerialParams.BaudRate = CBR_600;
break;
140 case 1200: dcbSerialParams.BaudRate = CBR_1200;
break;
143 case 1800: dcbSerialParams.BaudRate = CBR_1800;
break;
146 case 2400: dcbSerialParams.BaudRate = CBR_2400;
break;
149 case 4800: dcbSerialParams.BaudRate = CBR_4800;
break;
152 case 7200: dcbSerialParams.BaudRate = CBR_7200;
break;
155 case 9600: dcbSerialParams.BaudRate = CBR_9600;
break;
158 case 14400: dcbSerialParams.BaudRate = CBR_14400;
break;
161 case 19200: dcbSerialParams.BaudRate = CBR_19200;
break;
164 case 28800: dcbSerialParams.BaudRate = CBR_28800;
break;
167 case 57600: dcbSerialParams.BaudRate = CBR_57600;
break;
170 case 76800: dcbSerialParams.BaudRate = CBR_76800;
break;
173 case 38400: dcbSerialParams.BaudRate = CBR_38400;
break;
176 case 115200: dcbSerialParams.BaudRate = CBR_115200;
break;
179 case 128000: dcbSerialParams.BaudRate = CBR_128000;
break;
182 case 153600: dcbSerialParams.BaudRate = CBR_153600;
break;
185 case 230400: dcbSerialParams.BaudRate = CBR_230400;
break;
188 case 256000: dcbSerialParams.BaudRate = CBR_256000;
break;
191 case 460800: dcbSerialParams.BaudRate = CBR_460800;
break;
194 case 921600: dcbSerialParams.BaudRate = CBR_921600;
break;
198 dcbSerialParams.BaudRate = baudrate_;
203 dcbSerialParams.ByteSize = 8;
205 dcbSerialParams.ByteSize = 7;
207 dcbSerialParams.ByteSize = 6;
209 dcbSerialParams.ByteSize = 5;
211 throw invalid_argument (
"invalid char len");
215 dcbSerialParams.StopBits = ONESTOPBIT;
217 dcbSerialParams.StopBits = ONE5STOPBITS;
219 dcbSerialParams.StopBits = TWOSTOPBITS;
221 throw invalid_argument (
"invalid stop bit");
225 dcbSerialParams.Parity = NOPARITY;
227 dcbSerialParams.Parity = EVENPARITY;
229 dcbSerialParams.Parity = ODDPARITY;
231 dcbSerialParams.Parity = MARKPARITY;
233 dcbSerialParams.Parity = SPACEPARITY;
235 throw invalid_argument (
"invalid parity");
240 dcbSerialParams.fOutxCtsFlow =
false;
241 dcbSerialParams.fRtsControl = 0x00;
242 dcbSerialParams.fOutX =
false;
243 dcbSerialParams.fInX =
false;
246 dcbSerialParams.fOutxCtsFlow =
false;
247 dcbSerialParams.fRtsControl = 0x00;
248 dcbSerialParams.fOutX =
true;
249 dcbSerialParams.fInX =
true;
252 dcbSerialParams.fOutxCtsFlow =
true;
253 dcbSerialParams.fRtsControl = 0x03;
254 dcbSerialParams.fOutX =
false;
255 dcbSerialParams.fInX =
false;
259 if (!SetCommState(fd_, &dcbSerialParams)){
261 THROW (IOException,
"Error setting serial port settings.");
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.");
277 Serial::SerialImpl::close ()
279 if (is_open_ ==
true) {
280 if (fd_ != INVALID_HANDLE_VALUE) {
282 ret = CloseHandle(fd_);
285 ss <<
"Error while closing serial port: " << GetLastError();
286 THROW (IOException, ss.str().c_str());
288 fd_ = INVALID_HANDLE_VALUE;
296 Serial::SerialImpl::isOpen ()
const
302 Serial::SerialImpl::available ()
308 if (!ClearCommError(fd_, NULL, &cs)) {
310 ss <<
"Error while checking status of the serial port: " << GetLastError();
311 THROW (IOException, ss.str().c_str());
313 return static_cast<size_t>(cs.cbInQue);
317 Serial::SerialImpl::waitReadable (uint32_t
timeout)
319 THROW (IOException,
"waitReadable is not implemented on Windows.");
324 Serial::SerialImpl::waitByteTimes (
size_t count)
326 THROW (IOException,
"waitByteTimes is not implemented on Windows.");
330 Serial::SerialImpl::read (uint8_t *buf,
size_t size)
333 throw PortNotOpenedException (
"Serial::read");
336 if (!ReadFile(fd_, buf,
static_cast<DWORD
>(size), &bytes_read, NULL)) {
338 ss <<
"Error while reading from the serial port: " << GetLastError();
339 THROW (IOException, ss.str().c_str());
341 return (
size_t) (bytes_read);
345 Serial::SerialImpl::write (
const uint8_t *data,
size_t length)
347 if (is_open_ ==
false) {
348 throw PortNotOpenedException (
"Serial::write");
351 if (!WriteFile(fd_, data,
static_cast<DWORD
>(length), &bytes_written, NULL)) {
353 ss <<
"Error while writing to the serial port: " << GetLastError();
354 THROW (IOException, ss.str().c_str());
356 return (
size_t) (bytes_written);
360 Serial::SerialImpl::setPort (
const string &port)
362 port_ = wstring(port.begin(), port.end());
366 Serial::SerialImpl::getPort ()
const
368 return string(port_.begin(), port_.end());
381 Serial::SerialImpl::getTimeout ()
const
387 Serial::SerialImpl::setBaudrate (
unsigned long baudrate)
389 baudrate_ = baudrate;
396 Serial::SerialImpl::getBaudrate ()
const
404 bytesize_ = bytesize;
411 Serial::SerialImpl::getBytesize ()
const
426 Serial::SerialImpl::getParity ()
const
434 stopbits_ = stopbits;
441 Serial::SerialImpl::getStopbits ()
const
449 flowcontrol_ = flowcontrol;
456 Serial::SerialImpl::getFlowcontrol ()
const
462 Serial::SerialImpl::flush ()
464 if (is_open_ ==
false) {
465 throw PortNotOpenedException (
"Serial::flush");
467 FlushFileBuffers (fd_);
471 Serial::SerialImpl::flushInput ()
473 THROW (IOException,
"flushInput is not supported on Windows.");
477 Serial::SerialImpl::flushOutput ()
479 THROW (IOException,
"flushOutput is not supported on Windows.");
483 Serial::SerialImpl::sendBreak (
int duration)
485 THROW (IOException,
"sendBreak is not supported on Windows.");
489 Serial::SerialImpl::setBreak (
bool level)
491 if (is_open_ ==
false) {
492 throw PortNotOpenedException (
"Serial::setBreak");
495 EscapeCommFunction (fd_, SETBREAK);
497 EscapeCommFunction (fd_, CLRBREAK);
502 Serial::SerialImpl::setRTS (
bool level)
504 if (is_open_ ==
false) {
505 throw PortNotOpenedException (
"Serial::setRTS");
508 EscapeCommFunction (fd_, SETRTS);
510 EscapeCommFunction (fd_, CLRRTS);
515 Serial::SerialImpl::setDTR (
bool level)
517 if (is_open_ ==
false) {
518 throw PortNotOpenedException (
"Serial::setDTR");
521 EscapeCommFunction (fd_, SETDTR);
523 EscapeCommFunction (fd_, CLRDTR);
528 Serial::SerialImpl::waitForChange ()
530 if (is_open_ ==
false) {
531 throw PortNotOpenedException (
"Serial::waitForChange");
535 if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
540 if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
550 Serial::SerialImpl::getCTS ()
552 if (is_open_ ==
false) {
553 throw PortNotOpenedException (
"Serial::getCTS");
556 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
557 THROW (IOException,
"Error getting the status of the CTS line.");
560 return (MS_CTS_ON & dwModemStatus) != 0;
564 Serial::SerialImpl::getDSR ()
566 if (is_open_ ==
false) {
567 throw PortNotOpenedException (
"Serial::getDSR");
570 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
571 THROW (IOException,
"Error getting the status of the DSR line.");
574 return (MS_DSR_ON & dwModemStatus) != 0;
578 Serial::SerialImpl::getRI()
580 if (is_open_ ==
false) {
581 throw PortNotOpenedException (
"Serial::getRI");
584 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
585 THROW (IOException,
"Error getting the status of the RI line.");
588 return (MS_RING_ON & dwModemStatus) != 0;
592 Serial::SerialImpl::getCD()
594 if (is_open_ ==
false) {
595 throw PortNotOpenedException (
"Serial::getCD");
598 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
600 THROW (IOException,
"Error getting the status of the CD line.");
603 return (MS_RLSD_ON & dwModemStatus) != 0;
607 Serial::SerialImpl::readLock()
609 if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
610 THROW (IOException,
"Error claiming read mutex.");
615 Serial::SerialImpl::readUnlock()
617 if (!ReleaseMutex(read_mutex)) {
618 THROW (IOException,
"Error releasing read mutex.");
623 Serial::SerialImpl::writeLock()
625 if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
626 THROW (IOException,
"Error claiming write mutex.");
631 Serial::SerialImpl::writeUnlock()
633 if (!ReleaseMutex(write_mutex)) {
634 THROW (IOException,
"Error releasing write mutex.");
638 #endif // #if defined(_WIN32)