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;
229 dcbSerialParams.Parity = EVENPARITY;
232 dcbSerialParams.Parity = ODDPARITY;
235 dcbSerialParams.Parity = MARKPARITY;
238 dcbSerialParams.Parity = SPACEPARITY;
241 throw invalid_argument(
"invalid parity");
246 dcbSerialParams.fOutxCtsFlow =
false;
247 dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
248 dcbSerialParams.fOutX =
false;
249 dcbSerialParams.fInX =
false;
252 dcbSerialParams.fOutxCtsFlow =
false;
253 dcbSerialParams.fRtsControl = RTS_CONTROL_DISABLE;
254 dcbSerialParams.fOutX =
true;
255 dcbSerialParams.fInX =
true;
258 dcbSerialParams.fOutxCtsFlow =
true;
259 dcbSerialParams.fRtsControl = RTS_CONTROL_HANDSHAKE;
260 dcbSerialParams.fOutX =
false;
261 dcbSerialParams.fInX =
false;
265 if (!SetCommState(fd_, &dcbSerialParams)) {
267 THROW(IOException,
"Error setting serial port settings.");
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.");
283 Serial::SerialImpl::close()
285 if (is_open_ ==
true) {
286 if (fd_ != INVALID_HANDLE_VALUE) {
288 ret = CloseHandle(fd_);
291 ss <<
"Error while closing serial port: " << GetLastError();
292 THROW(IOException, ss.str().c_str());
295 fd_ = INVALID_HANDLE_VALUE;
303 Serial::SerialImpl::isOpen()
const 309 Serial::SerialImpl::available()
315 if (!ClearCommError(fd_, NULL, &cs)) {
317 ss <<
"Error while checking status of the serial port: " << GetLastError();
318 THROW(IOException, ss.str().c_str());
320 return static_cast<size_t>(cs.cbInQue);
324 Serial::SerialImpl::waitReadable(uint32_t )
326 THROW(IOException,
"waitReadable is not implemented on Windows.");
331 Serial::SerialImpl::waitByteTimes(
size_t )
333 THROW(IOException,
"waitByteTimes is not implemented on Windows.");
337 Serial::SerialImpl::read(uint8_t *buf,
size_t size)
340 throw PortNotOpenedException(
"Serial::read");
343 if (!ReadFile(fd_, buf, static_cast<DWORD>(size), &bytes_read, NULL)) {
345 ss <<
"Error while reading from the serial port: " << GetLastError();
346 THROW(IOException, ss.str().c_str());
348 return (
size_t)(bytes_read);
352 Serial::SerialImpl::write(
const uint8_t *data,
size_t length)
354 if (is_open_ ==
false) {
355 throw PortNotOpenedException(
"Serial::write");
358 if (!WriteFile(fd_, data, static_cast<DWORD>(length), &bytes_written, NULL)) {
360 ss <<
"Error while writing to the serial port: " << GetLastError();
361 THROW(IOException, ss.str().c_str());
363 return (
size_t)(bytes_written);
367 Serial::SerialImpl::setPort(
const string &port)
369 port_ = wstring(port.begin(), port.end());
373 Serial::SerialImpl::getPort()
const 375 return string(port_.begin(), port_.end());
388 Serial::SerialImpl::getTimeout()
const 394 Serial::SerialImpl::setBaudrate(
unsigned long baudrate)
396 baudrate_ = baudrate;
403 Serial::SerialImpl::getBaudrate()
const 411 bytesize_ = bytesize;
418 Serial::SerialImpl::getBytesize()
const 433 Serial::SerialImpl::getParity()
const 441 stopbits_ = stopbits;
448 Serial::SerialImpl::getStopbits()
const 456 flowcontrol_ = flowcontrol;
463 Serial::SerialImpl::getFlowcontrol()
const 469 Serial::SerialImpl::flush()
471 if (is_open_ ==
false) {
472 throw PortNotOpenedException(
"Serial::flush");
474 FlushFileBuffers(fd_);
478 Serial::SerialImpl::flushInput()
480 if (is_open_ ==
false) {
481 throw PortNotOpenedException(
"Serial::flushInput");
483 PurgeComm(fd_, PURGE_RXCLEAR);
487 Serial::SerialImpl::flushOutput()
489 if (is_open_ ==
false) {
490 throw PortNotOpenedException(
"Serial::flushOutput");
492 PurgeComm(fd_, PURGE_TXCLEAR);
496 Serial::SerialImpl::sendBreak(
int )
498 THROW(IOException,
"sendBreak is not supported on Windows.");
502 Serial::SerialImpl::setBreak(
bool level)
504 if (is_open_ ==
false) {
505 throw PortNotOpenedException(
"Serial::setBreak");
508 EscapeCommFunction(fd_, SETBREAK);
511 EscapeCommFunction(fd_, CLRBREAK);
516 Serial::SerialImpl::setRTS(
bool level)
518 if (is_open_ ==
false) {
519 throw PortNotOpenedException(
"Serial::setRTS");
522 EscapeCommFunction(fd_, SETRTS);
525 EscapeCommFunction(fd_, CLRRTS);
530 Serial::SerialImpl::setDTR(
bool level)
532 if (is_open_ ==
false) {
533 throw PortNotOpenedException(
"Serial::setDTR");
536 EscapeCommFunction(fd_, SETDTR);
539 EscapeCommFunction(fd_, CLRDTR);
544 Serial::SerialImpl::waitForChange()
546 if (is_open_ ==
false) {
547 throw PortNotOpenedException(
"Serial::waitForChange");
551 if (!SetCommMask(fd_, EV_CTS | EV_DSR | EV_RING | EV_RLSD)) {
556 if (!WaitCommEvent(fd_, &dwCommEvent, NULL)) {
567 Serial::SerialImpl::getCTS()
569 if (is_open_ ==
false) {
570 throw PortNotOpenedException(
"Serial::getCTS");
573 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
574 THROW(IOException,
"Error getting the status of the CTS line.");
577 return (MS_CTS_ON & dwModemStatus) != 0;
581 Serial::SerialImpl::getDSR()
583 if (is_open_ ==
false) {
584 throw PortNotOpenedException(
"Serial::getDSR");
587 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
588 THROW(IOException,
"Error getting the status of the DSR line.");
591 return (MS_DSR_ON & dwModemStatus) != 0;
595 Serial::SerialImpl::getRI()
597 if (is_open_ ==
false) {
598 throw PortNotOpenedException(
"Serial::getRI");
601 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
602 THROW(IOException,
"Error getting the status of the RI line.");
605 return (MS_RING_ON & dwModemStatus) != 0;
609 Serial::SerialImpl::getCD()
611 if (is_open_ ==
false) {
612 throw PortNotOpenedException(
"Serial::getCD");
615 if (!GetCommModemStatus(fd_, &dwModemStatus)) {
617 THROW(IOException,
"Error getting the status of the CD line.");
620 return (MS_RLSD_ON & dwModemStatus) != 0;
624 Serial::SerialImpl::readLock()
626 if (WaitForSingleObject(read_mutex, INFINITE) != WAIT_OBJECT_0) {
627 THROW(IOException,
"Error claiming read mutex.");
632 Serial::SerialImpl::readUnlock()
634 if (!ReleaseMutex(read_mutex)) {
635 THROW(IOException,
"Error releasing read mutex.");
640 Serial::SerialImpl::writeLock()
642 if (WaitForSingleObject(write_mutex, INFINITE) != WAIT_OBJECT_0) {
643 THROW(IOException,
"Error claiming write mutex.");
648 Serial::SerialImpl::writeUnlock()
650 if (!ReleaseMutex(write_mutex)) {
651 THROW(IOException,
"Error releasing write mutex.");
655 #endif // #if defined(_WIN32)
ROSCPP_DECL uint32_t getPort()
#define THROW(exceptionClass, message)