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;
34 Serial::SerialImpl::SerialImpl (
const string &port,
unsigned long baudrate,
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)
42 if (port_.empty () ==
false)
44 read_mutex = CreateMutex(NULL,
false, NULL);
45 write_mutex = CreateMutex(NULL,
false, NULL);
48 Serial::SerialImpl::~SerialImpl ()
51 CloseHandle(read_mutex);
52 CloseHandle(write_mutex);
56 Serial::SerialImpl::open ()
59 throw invalid_argument (
"Empty port is invalid.");
61 if (is_open_ ==
true) {
62 throw SerialException (
"Serial port already open.");
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,
73 FILE_ATTRIBUTE_NORMAL,
76 if (fd_ == INVALID_HANDLE_VALUE) {
77 DWORD create_file_err = GetLastError();
79 switch (create_file_err) {
80 case ERROR_FILE_NOT_FOUND:
82 ss <<
"Specified port, " << this->getPort() <<
", does not exist.";
83 THROW (IOException, ss.str().c_str());
85 ss <<
"Unknown error opening the serial port: " << create_file_err;
86 THROW (IOException, ss.str().c_str());
95 Serial::SerialImpl::reconfigurePort ()
97 if (fd_ == INVALID_HANDLE_VALUE) {
99 THROW (IOException,
"Invalid file descriptor, is the serial port open?");
102 DCB dcbSerialParams = {0};
104 dcbSerialParams.DCBlength=
sizeof(dcbSerialParams);
106 if (!GetCommState(fd_, &dcbSerialParams)) {
108 THROW (IOException,
"Error getting the serial port state.");
114 case 0: dcbSerialParams.BaudRate = CBR_0;
break;
117 case 50: dcbSerialParams.BaudRate = CBR_50;
break;
120 case 75: dcbSerialParams.BaudRate = CBR_75;
break;
123 case 110: dcbSerialParams.BaudRate = CBR_110;
break;
126 case 134: dcbSerialParams.BaudRate = CBR_134;
break;
129 case 150: dcbSerialParams.BaudRate = CBR_150;
break;
132 case 200: dcbSerialParams.BaudRate = CBR_200;
break;
135 case 300: dcbSerialParams.BaudRate = CBR_300;
break;
138 case 600: dcbSerialParams.BaudRate = CBR_600;
break;
141 case 1200: dcbSerialParams.BaudRate = CBR_1200;
break;
144 case 1800: dcbSerialParams.BaudRate = CBR_1800;
break;
147 case 2400: dcbSerialParams.BaudRate = CBR_2400;
break;
150 case 4800: dcbSerialParams.BaudRate = CBR_4800;
break;
153 case 7200: dcbSerialParams.BaudRate = CBR_7200;
break;
156 case 9600: dcbSerialParams.BaudRate = CBR_9600;
break;
159 case 14400: dcbSerialParams.BaudRate = CBR_14400;
break;
162 case 19200: dcbSerialParams.BaudRate = CBR_19200;
break;
165 case 28800: dcbSerialParams.BaudRate = CBR_28800;
break;
168 case 57600: dcbSerialParams.BaudRate = CBR_57600;
break;
171 case 76800: dcbSerialParams.BaudRate = CBR_76800;
break;
174 case 38400: dcbSerialParams.BaudRate = CBR_38400;
break;
177 case 115200: dcbSerialParams.BaudRate = CBR_115200;
break;
180 case 128000: dcbSerialParams.BaudRate = CBR_128000;
break;
183 case 153600: dcbSerialParams.BaudRate = CBR_153600;
break;
186 case 230400: dcbSerialParams.BaudRate = CBR_230400;
break;
189 case 256000: dcbSerialParams.BaudRate = CBR_256000;
break;
192 case 460800: dcbSerialParams.BaudRate = CBR_460800;
break;
195 case 921600: dcbSerialParams.BaudRate = CBR_921600;
break;
199 dcbSerialParams.BaudRate = baudrate_;
204 dcbSerialParams.ByteSize = 8;
206 dcbSerialParams.ByteSize = 7;
208 dcbSerialParams.ByteSize = 6;
210 dcbSerialParams.ByteSize = 5;
212 throw invalid_argument (
"invalid char len");
216 dcbSerialParams.StopBits = ONESTOPBIT;
218 dcbSerialParams.StopBits = ONE5STOPBITS;
220 dcbSerialParams.StopBits = TWOSTOPBITS;
222 throw invalid_argument (
"invalid stop bit");
226 dcbSerialParams.Parity = NOPARITY;
228 dcbSerialParams.Parity = EVENPARITY;
230 dcbSerialParams.Parity = ODDPARITY;
232 dcbSerialParams.Parity = MARKPARITY;
234 dcbSerialParams.Parity = SPACEPARITY;
236 throw invalid_argument (
"invalid parity");
241 dcbSerialParams.fOutxCtsFlow =
false;
242 dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
243 dcbSerialParams.fOutX =
false;
244 dcbSerialParams.fInX =
false;
247 dcbSerialParams.fOutxCtsFlow =
false;
248 dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
249 dcbSerialParams.fOutX =
true;
250 dcbSerialParams.fInX =
true;
253 dcbSerialParams.fOutxCtsFlow =
true;
254 dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;
255 dcbSerialParams.fOutX =
false;
256 dcbSerialParams.fInX =
false;
260 if (!SetCommState(fd_, &dcbSerialParams)){
262 THROW (IOException,
"Error setting serial port settings.");
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.");
278 Serial::SerialImpl::close ()
280 if (is_open_ ==
true) {
281 if (fd_ != INVALID_HANDLE_VALUE) {
283 ret = CloseHandle(fd_);
286 ss <<
"Error while closing serial port: " << GetLastError();
287 THROW (IOException, ss.str().c_str());
289 fd_ = INVALID_HANDLE_VALUE;
297 Serial::SerialImpl::isOpen ()
const 303 Serial::SerialImpl::available ()
309 if (!ClearCommError(fd_, NULL, &cs)) {
311 ss <<
"Error while checking status of the serial port: " << GetLastError();
312 THROW (IOException, ss.str().c_str());
314 return static_cast<size_t>(cs.cbInQue);
318 Serial::SerialImpl::waitReadable (uint32_t )
320 THROW (IOException,
"waitReadable is not implemented on Windows.");
325 Serial::SerialImpl::waitByteTimes (
size_t )
327 THROW (IOException,
"waitByteTimes is not implemented on Windows.");
331 Serial::SerialImpl::read (uint8_t *buf,
size_t size)
334 throw PortNotOpenedException (
"Serial::read");
337 if (!ReadFile(fd_, buf, static_cast<DWORD>(size), &bytes_read, NULL)) {
339 ss <<
"Error while reading from the serial port: " << GetLastError();
340 THROW (IOException, ss.str().c_str());
342 return (
size_t) (bytes_read);
346 Serial::SerialImpl::write (
const uint8_t *data,
size_t length)
348 if (is_open_ ==
false) {
349 throw PortNotOpenedException (
"Serial::write");
352 if (!WriteFile(fd_, data, static_cast<DWORD>(length), &bytes_written, NULL)) {
354 ss <<
"Error while writing to the serial port: " << GetLastError();
355 THROW (IOException, ss.str().c_str());
357 return (
size_t) (bytes_written);
361 Serial::SerialImpl::setPort (
const string &port)
363 port_ = wstring(port.begin(), port.end());
367 Serial::SerialImpl::getPort ()
const 369 return string(port_.begin(), port_.end());
382 Serial::SerialImpl::getTimeout ()
const 388 Serial::SerialImpl::setBaudrate (
unsigned long baudrate)
390 baudrate_ = baudrate;
397 Serial::SerialImpl::getBaudrate ()
const 405 bytesize_ = bytesize;
412 Serial::SerialImpl::getBytesize ()
const 427 Serial::SerialImpl::getParity ()
const 435 stopbits_ = stopbits;
442 Serial::SerialImpl::getStopbits ()
const 450 flowcontrol_ = flowcontrol;
457 Serial::SerialImpl::getFlowcontrol ()
const 463 Serial::SerialImpl::flush ()
465 if (is_open_ ==
false) {
466 throw PortNotOpenedException (
"Serial::flush");
468 FlushFileBuffers (fd_);
472 Serial::SerialImpl::flushInput ()
474 if (is_open_ ==
false) {
475 throw PortNotOpenedException(
"Serial::flushInput");
477 PurgeComm(fd_, PURGE_RXCLEAR);
481 Serial::SerialImpl::flushOutput ()
483 if (is_open_ ==
false) {
484 throw PortNotOpenedException(
"Serial::flushOutput");
486 PurgeComm(fd_, PURGE_TXCLEAR);
490 Serial::SerialImpl::sendBreak (
int )
492 THROW (IOException,
"sendBreak is not supported on Windows.");
496 Serial::SerialImpl::setBreak (
bool level)
498 if (is_open_ ==
false) {
499 throw PortNotOpenedException (
"Serial::setBreak");
502 EscapeCommFunction (fd_, SETBREAK);
504 EscapeCommFunction (fd_, CLRBREAK);
509 Serial::SerialImpl::setRTS (
bool level)
511 if (is_open_ ==
false) {
512 throw PortNotOpenedException (
"Serial::setRTS");
515 EscapeCommFunction (fd_, SETRTS);
517 EscapeCommFunction (fd_, CLRRTS);
522 Serial::SerialImpl::setDTR (
bool level)
524 if (is_open_ ==
false) {
525 throw PortNotOpenedException (
"Serial::setDTR");
528 EscapeCommFunction (fd_, SETDTR);
530 EscapeCommFunction (fd_, CLRDTR);
535 Serial::SerialImpl::waitForChange ()
537 if (is_open_ ==
false) {
538 throw PortNotOpenedException (
"Serial::waitForChange");
542 if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
547 if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
557 Serial::SerialImpl::getCTS ()
559 if (is_open_ ==
false) {
560 throw PortNotOpenedException (
"Serial::getCTS");
563 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
564 THROW (IOException,
"Error getting the status of the CTS line.");
567 return (MS_CTS_ON & dwModemStatus) != 0;
571 Serial::SerialImpl::getDSR ()
573 if (is_open_ ==
false) {
574 throw PortNotOpenedException (
"Serial::getDSR");
577 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
578 THROW (IOException,
"Error getting the status of the DSR line.");
581 return (MS_DSR_ON & dwModemStatus) != 0;
585 Serial::SerialImpl::getRI()
587 if (is_open_ ==
false) {
588 throw PortNotOpenedException (
"Serial::getRI");
591 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
592 THROW (IOException,
"Error getting the status of the RI line.");
595 return (MS_RING_ON & dwModemStatus) != 0;
599 Serial::SerialImpl::getCD()
601 if (is_open_ ==
false) {
602 throw PortNotOpenedException (
"Serial::getCD");
605 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
607 THROW (IOException,
"Error getting the status of the CD line.");
610 return (MS_RLSD_ON & dwModemStatus) != 0;
614 Serial::SerialImpl::readLock()
616 if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
617 THROW (IOException,
"Error claiming read mutex.");
622 Serial::SerialImpl::readUnlock()
624 if (!ReleaseMutex(read_mutex)) {
625 THROW (IOException,
"Error releasing read mutex.");
630 Serial::SerialImpl::writeLock()
632 if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
633 THROW (IOException,
"Error claiming write mutex.");
638 Serial::SerialImpl::writeUnlock()
640 if (!ReleaseMutex(write_mutex)) {
641 THROW (IOException,
"Error releasing write mutex.");
645 #endif // #if defined(_WIN32)
#define THROW(exceptionClass, message)