53 # include <sys/time.h>
64 #undef SERIAL_DUMP_DATA
71 : m_dev_name(strdup(dev_name))
72 , m_serial_flags(flags)
75 m_com = INVALID_HANDLE_VALUE;
84 : m_dev_name(strdup(dev_name))
85 , m_serial_flags(flags)
88 m_com = INVALID_HANDLE_VALUE;
101 #if defined _SYSTEM_LINUX_
122 if (tcgetattr(m_file_descr, &m_io_set_old) < 0)
126 "Cannot get serial device m_status '" <<
m_dev_name <<
"'. Status ("
137 io_set_new = m_io_set_old;
141 io_set_new.c_oflag = 0;
142 io_set_new.c_iflag = IGNPAR;
143 io_set_new.c_lflag = 0;
144 io_set_new.c_cc[VMIN] = 1;
145 io_set_new.c_cc[VTIME] = 0;
148 if (tcsetattr(m_file_descr, TCSANOW, &io_set_new) < 0)
152 "Serial(" <<
m_dev_name <<
") Error>> tcsetattr failed. Status ("
164 "Serial(" <<
m_dev_name <<
") setting hardware modem control flags to 0x"
168 int modem_control_flags = 0;
171 modem_control_flags |= TIOCM_DTR;
175 modem_control_flags |= TIOCM_RTS;
178 ioctl(m_file_descr, TIOCMSET, modem_control_flags);
182 #elif defined _SYSTEM_WIN32_
184 m_read_buffer_fill = 0;
189 m_dev_name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
190 if (m_com == INVALID_HANDLE_VALUE)
194 "Serial(" <<
m_dev_name <<
"): ERROR>> open port failed ("
195 << StatusText().c_str() <<
").");
202 if (!SetupComm(m_com, 0x4000, 0x4000))
206 "Serial(" <<
m_dev_name <<
"): ERROR>> SetupComm failed ("
207 << StatusText().c_str() <<
").");
215 memset(&dcb, 0,
sizeof(DCB));
218 if (!GetCommState(m_com, &dcb))
222 "Serial(" <<
m_dev_name <<
"): ERROR>> GetCommState failed ("
223 << StatusText().c_str() <<
").");
233 if (!SetCommState(m_com, &dcb))
237 "Serial(" <<
m_dev_name <<
"): ERROR>> SetCommState failed ("
238 << StatusText().c_str() <<
").");
251 unsigned char* c_data =
static_cast<unsigned char*
>(data);
252 printf(
"Serial::DumpData: ");
253 for (
size_t i = 0; i < length; ++i)
255 printf(
"%02X ",
int(c_data[i]));
270 #if defined _SYSTEM_LINUX_
272 if (m_file_descr < 0)
275 struct termios io_set;
278 if (tcgetattr(m_file_descr, &io_set) < 0)
282 "Serial(" <<
m_dev_name <<
"): Error>> tcgetattr failed. Status ("
290 io_set.c_cflag &= ~CBAUD;
292 io_set.c_cflag |= SerialFlags::cFlags(speed);
295 if (tcsetattr(m_file_descr, TCSANOW, &io_set) < 0)
299 "Serial(" <<
m_dev_name <<
"): Error>> tcsetattr failed. Status ("
316 #ifdef _SYSTEM_DARWIN_
322 #ifdef _SYSTEM_WIN32_
326 if (!PurgeComm(m_com, PURGE_RXCLEAR) || !PurgeComm(m_com, PURGE_TXCLEAR))
330 "Serial(" <<
m_dev_name <<
"): ERROR>> PurgeComm failed ("
331 << StatusText().c_str() <<
").");
337 memset(&dcb, 0,
sizeof(DCB));
340 if (!GetCommState(m_com, &dcb))
344 "Serial(" <<
m_dev_name <<
"): ERROR>> GetCommState failed ("
345 << StatusText().c_str() <<
").");
355 if (!SetCommState(m_com, &dcb))
359 "Serial(" <<
m_dev_name <<
"): ERROR>> SetCommState failed ("
360 << StatusText().c_str() <<
").");
372 #ifdef _SYSTEM_WIN32_
376 if (PurgeComm(m_com, PURGE_RXCLEAR))
378 m_read_buffer_fill = 0;
384 "Serial(" <<
m_dev_name <<
"): ERROR>> PurgeComm failed ("
385 << StatusText().c_str() <<
").");
390 #elif defined _SYSTEM_LINUX_
392 if (tcflush(m_file_descr, TCIFLUSH) != 0)
405 #ifdef _SYSTEM_WIN32_
409 if (PurgeComm(m_com, PURGE_TXCLEAR))
411 m_read_buffer_fill = 0;
417 "Serial(" <<
m_dev_name <<
"): ERROR>> PurgeComm failed ("
418 << StatusText().c_str() <<
").");
423 #elif defined _SYSTEM_LINUX_
425 if (tcflush(m_file_descr, TCOFLUSH) != 0)
438 #if defined _SYSTEM_LINUX_
439 if (m_file_descr < 0)
442 ssize_t bytes_out = 0;
446 if ((bytes_out = ::
write(m_file_descr, (
char*)data, size)) < 0)
451 <<
"): Error on writing. Status (" <<
m_status <<
":"
464 #elif defined _SYSTEM_WIN32_
466 assert(m_com != INVALID_HANDLE_VALUE);
469 if (!WriteFile(m_com, data, size, &bytes_written, NULL))
473 "Serial(" <<
m_dev_name <<
"): ERROR>> could not write data ("
474 << StatusText().c_str() <<
").");
481 # ifdef SERIAL_DUMP_DATA
482 DumpData(data, bytes_written);
492 ssize_t
Serial::read(
void* data, ssize_t size,
unsigned long time,
bool return_on_less_data)
495 auto end_time = std::chrono::high_resolution_clock::now() + std::chrono::microseconds(time);
497 #if defined _SYSTEM_LINUX_
498 if (m_file_descr < 0)
501 std::chrono::duration<double, std::milli> tz;
503 ssize_t bytes_read = 0;
504 ssize_t bytes_read_inc;
506 char* buffer = (
char*)data;
517 tz = end_time - std::chrono::high_resolution_clock::now();
519 if (tz < std::chrono::microseconds(1))
521 tz = std::chrono::microseconds(1);
527 FD_SET(m_file_descr, &fds);
528 timeval select_timeout = {0,
529 std::chrono::duration_cast<std::chrono::microseconds>(tz).count()};
531 if ((select_return = select(FD_SETSIZE, &fds, 0, 0, &select_timeout)) > 0)
534 if (return_on_less_data)
536 if ((bytes_read_inc = ::
read(m_file_descr, &buffer[bytes_read], size - bytes_read)) < 0)
541 <<
":" << strerror(-
m_status) <<
")");
547 if (bytes_read_inc > 0)
549 bytes_read += bytes_read_inc;
551 if (bytes_read == size)
561 if (ioctl(m_file_descr, FIONREAD, &bytes_read_inc) < 0)
565 "Error on ioctl FIONREAD '" <<
m_dev_name <<
"'. Status ("
575 if (bytes_read_inc >= size)
577 if ((bytes_read = ::
read(m_file_descr, buffer, size)) < 0)
582 <<
":" << strerror(-
m_status) <<
")");
597 else if (select_return < 0)
609 while (std::chrono::high_resolution_clock::now() < end_time);
618 #ifdef _SYSTEM_DARWIN_
624 #ifdef _SYSTEM_WIN32_
625 assert(m_com != INVALID_HANDLE_VALUE);
630 COMMTIMEOUTS timeout;
631 timeout.ReadIntervalTimeout = time / 1000;
632 timeout.ReadTotalTimeoutMultiplier = 1;
633 timeout.ReadTotalTimeoutConstant = time / 1000;
634 timeout.WriteTotalTimeoutMultiplier = 1;
635 timeout.WriteTotalTimeoutConstant = MAXDWORD;
636 if (!SetCommTimeouts(m_com, &timeout))
640 "Serial(" <<
m_dev_name <<
"): ERROR>> setting read timeout failed ("
641 << StatusText().c_str() <<
")");
647 if (m_read_buffer_fill <= size &&
m_status == 0)
649 DWORD bytes_received = 0;
650 size_t bytes_remaining = (m_read_buffer_fill < size ? size - m_read_buffer_fill : 0);
651 auto now std::chrono::high_resolution_clock::now();
655 m_com, m_read_buffer + m_read_buffer_fill, bytes_remaining, &bytes_received, NULL))
657 m_read_buffer_fill += bytes_received;
658 if (bytes_remaining > bytes_received)
660 bytes_remaining -= bytes_received;
669 DWORD error = GetLastError();
670 if (error != ERROR_TIMEOUT)
674 "Serial(" <<
m_dev_name <<
"): ERROR>> error during read ("
675 << StatusText().c_str() <<
")");
680 now = std::chrono::high_resolution_clock::now();
681 }
while (
m_status == 0 && !return_on_less_data && bytes_remaining && now < end_time);
683 if (
m_status == 0 && !return_on_less_data && bytes_remaining && now >= end_time)
687 "Serial(" <<
m_dev_name <<
"): ERROR>> error during read ("
688 << StatusText().c_str() <<
")");
695 ssize_t bytes_received;
698 bytes_received = std::min(size, m_read_buffer_fill);
699 memcpy(data, m_read_buffer, bytes_received);
702 for (ssize_t write_index = 0, read_index = bytes_received; read_index < m_read_buffer_fill;
703 ++write_index, ++read_index)
705 m_read_buffer[write_index] = m_read_buffer[read_index];
707 m_read_buffer_fill -= bytes_received;
709 # ifdef SERIAL_DUMP_DATA
710 DumpData(data, bytes_received);
720 #if defined _SYSTEM_LINUX_
722 #elif defined _SYSTEM_WIN32_
723 LPVOID msg_buff = NULL;
724 DWORD res = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
725 FORMAT_MESSAGE_IGNORE_INSERTS,
728 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
735 result = (LPCTSTR)msg_buff;
740 result =
"fatal internal error";
744 return "Plattform not supported!";
750 #ifdef _SYSTEM_LINUX_
751 return m_file_descr >= 0;
752 #elif defined _SYSTEM_WIN32_
753 return m_com != INVALID_HANDLE_VALUE;
762 #ifdef _SYSTEM_LINUX_
763 if (m_file_descr >= 0)
767 if (tcsetattr(m_file_descr, TCSANOW, &m_io_set_old) < 0)
771 "Serial(" <<
m_dev_name <<
") Error>> tcsetattr failed. Status ("
777 if (::
close(m_file_descr) < 0)
781 "Serial>> Error closing serial " <<
m_dev_name <<
". Status ("
793 #ifdef _SYSTEM_WIN32_
794 if (m_com != INVALID_HANDLE_VALUE)
797 m_com = INVALID_HANDLE_VALUE;