91 options.c_cflag |= ( CLOCAL
94 options.c_iflag &= ~( IGNBRK
105 options.c_oflag &= ~OPOST;
106 options.c_lflag &= ~(ECHO
115 switch (jevois::serial::baudrate::get())
117 case 4000000: rate = B4000000;
break;
118 case 3500000: rate = B3500000;
break;
119 case 3000000: rate = B3000000;
break;
120 case 2500000: rate = B2500000;
break;
121 case 2000000: rate = B2000000;
break;
122 case 1500000: rate = B1500000;
break;
123 case 1152000: rate = B1152000;
break;
124 case 1000000: rate = B1000000;
break;
125 case 921600: rate = B921600;
break;
126 case 576000: rate = B576000;
break;
127 case 500000: rate = B500000;
break;
128 case 460800: rate = B460800;
break;
129 case 230400: rate = B230400;
break;
130 case 115200: rate = B115200;
break;
131 case 57600: rate = B57600;
break;
132 case 38400: rate = B38400;
break;
133 case 19200: rate = B19200;
break;
134 case 9600: rate = B9600;
break;
135 case 4800: rate = B4800;
break;
136 case 2400: rate = B2400;
break;
137 case 1200: rate = B1200;
break;
138 case 600: rate = B600;
break;
139 case 300: rate = B300;
break;
140 case 110: rate = B110;
break;
141 case 0: rate = B0;
break;
142 default:
SERTHROW(
"Invalid baud rate " <<jevois::serial::baudrate::get());
145 cfsetispeed(&options, rate);
146 cfsetospeed(&options, rate);
149 std::string
const format = jevois::serial::format::get();
150 if (format.length() != 3)
SERTHROW(
"Incorrect format string: " << format);
153 options.c_cflag &= ~CSIZE;
157 case '5': options.c_cflag |= CS5;
break;
158 case '6': options.c_cflag |= CS6;
break;
159 case '7': options.c_cflag |= CS7;
break;
160 case '8': options.c_cflag |= CS8;
break;
161 default:
SERTHROW(
"Invalid charbits: " << format[0] <<
" (should be 5..8)");
165 options.c_cflag &= ~(PARENB | PARODD);
170 case 'E': options.c_cflag |= PARENB;
break;
171 case 'O': options.c_cflag |= (PARENB | PARODD);
break;
172 default:
SERTHROW(
"Invalid parity: " << format[1] <<
" (should be N,E,O)");
176 options.c_cflag &= ~CSTOPB;
180 case '2': options.c_cflag |= CSTOPB;
break;
181 default:
SERTHROW(
"Invalid stopbits: " << format[2] <<
" (should be 1..2)");
185 options.c_cflag &= ~CRTSCTS;
186 options.c_iflag &= ~(IXON | IXANY | IXOFF);
188 if (jevois::serial::flowsoft::get()) options.c_iflag |= (IXON | IXANY | IXOFF);
189 if (jevois::serial::flowhard::get()) options.c_cflag |= CRTSCTS;
192 if (tcsetattr(itsDev, TCSANOW, &options) == -1)
SERTHROW(
"Failed to set port options");
196 LINFO(
"Serial driver [" << instanceName() <<
"] ready on " << jevois::serial::devname::get());
202 std::lock_guard<std::mutex> _(itsMtx);
206 if (tcsetattr(itsDev, TCSANOW, &itsSavedState) == -1)
LERROR(
"Failed to restore serial port state -- IGNORED");
215 std::lock_guard<std::mutex> _(itsMtx);
217 int flags = fcntl(itsDev, F_GETFL, 0);
218 if (flags == -1)
SERFATAL(
"Cannot get flags");
219 if (blocking) flags &= (~O_NONBLOCK);
else flags |= O_NONBLOCK;
220 if (fcntl(itsDev, F_SETFL, flags) == -1)
SERFATAL(
"Cannot set flags");
226 if (tcgetattr(itsDev, &options) == -1)
SERFATAL(
"Failed to get options");
227 options.c_cc[VMIN] = 0;
228 options.c_cc[VTIME] = timeout.count() / 100;
229 if (tcsetattr(itsDev, TCSANOW, &options) == -1)
SERFATAL(
"Failed to set port options");
236 std::lock_guard<std::mutex> _(itsMtx);
238 struct termios tty, old;
240 if (tcgetattr(itsDev, &tty) == -1 || tcgetattr(itsDev, &old) == -1)
SERFATAL(
"Failed to get attributes");
242 cfsetospeed(&tty, B0);
243 cfsetispeed(&tty, B0);
245 if (tcsetattr(itsDev, TCSANOW, &tty) == -1)
SERFATAL(
"Failed to set attributes");
247 std::this_thread::sleep_for(dur);
249 if (tcsetattr(itsDev, TCSANOW, &old) == -1)
SERFATAL(
"Failed to restore attributes");
255 std::lock_guard<std::mutex> _(itsMtx);
258 tcsendbreak(itsDev, 0);
264 if (itsErrno.load()) { tryReconnect();
if (itsErrno.load())
return false; }
266 std::lock_guard<std::mutex> _(itsMtx);
272 int n = ::read(itsDev,
reinterpret_cast<char *
>(&c), 1);
276 if (errno == EAGAIN)
return false;
279 else if (n == 0)
return false;
281 switch (jevois::serial::linestyle::get())
283 case jevois::serial::LineStyle::LF:
284 if (c ==
'\n') { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
285 else itsPartialString += c;
288 case jevois::serial::LineStyle::CR:
289 if (c ==
'\r') { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
290 else itsPartialString += c;
293 case jevois::serial::LineStyle::CRLF:
294 if (c ==
'\n') { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
295 else if (c !=
'\r') itsPartialString += c;
298 case jevois::serial::LineStyle::Zero:
299 if (c == 0x00) { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
300 else itsPartialString += c;
303 case jevois::serial::LineStyle::Sloppy:
304 if (c ==
'\r' || c ==
'\n' || c == 0x00 || c == 0xd0)
306 if (itsPartialString.empty() ==
false)
307 { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
309 else itsPartialString += c;
319 if (itsErrno.load()) { tryReconnect();
if (itsErrno.load())
return; }
321 std::string fullstr(str);
323 switch (jevois::serial::linestyle::get())
325 case jevois::serial::LineStyle::CR: fullstr +=
'\r';
break;
326 case jevois::serial::LineStyle::LF: fullstr +=
'\n';
break;
327 case jevois::serial::LineStyle::CRLF: fullstr +=
"\r\n";
break;
328 case jevois::serial::LineStyle::Zero: fullstr +=
'\0';
break;
329 case jevois::serial::LineStyle::Sloppy: fullstr +=
"\r\n";
break;
332 std::lock_guard<std::mutex> _(itsMtx);
333 writeInternal(fullstr.c_str(), fullstr.length());
337void jevois::Serial::writeInternal(
void const * buffer,
const int nbytes,
bool nodrop)
343 int ndone = 0;
char const * b =
reinterpret_cast<char const *
>(buffer);
344 while (ndone < nbytes)
346 int n = ::write(itsDev, b + ndone, nbytes - ndone);
347 if (n == -1 && errno != EAGAIN)
SERFATAL(
"Write error");
350 if (n > 0) ndone += n;
351 if (ndone < nbytes) tcdrain(itsDev);
354 else if (drop::get())
357 int ndone = 0;
char const * b =
reinterpret_cast<char const *
>(buffer);
int iter = 0;
358 while (ndone < nbytes && iter++ < 10)
360 int n = ::write(itsDev, b + ndone, nbytes - ndone);
361 if (n == -1 && errno != EAGAIN)
SERFATAL(
"Write error");
364 if (n > 0) { ndone += n; iter = 0; }
365 if (ndone < nbytes) std::this_thread::sleep_for(std::chrono::milliseconds(5));
367 if (ndone < nbytes)
SERFATAL(
"Timeout (host disconnect or overflow) -- SOME DATA LOST");
372 int ndone = 0;
char const * b =
reinterpret_cast<char const *
>(buffer);
int iter = 0;
373 while (ndone < nbytes && iter++ < 50)
375 int n = ::write(itsDev, b + ndone, nbytes - ndone);
376 if (n == -1 && errno != EAGAIN)
SERFATAL(
"Write error");
379 if (n > 0) ndone += n;
380 if (ndone < nbytes) std::this_thread::sleep_for(std::chrono::milliseconds(2));
387 std::this_thread::sleep_for(std::chrono::milliseconds(100));
390 ++itsWriteOverflowCounter;
if (itsWriteOverflowCounter > 100) itsWriteOverflowCounter = 0;
391 if (itsWriteOverflowCounter == 1)
392 throw std::overflow_error(
"Serial write overflow: need to reduce amount ot serial writing");
396 else itsWriteOverflowCounter = 0;
403 std::lock_guard<std::mutex> _(itsMtx);
406 if (tcflush(itsDev, TCIFLUSH) != 0)
LDEBUG(
"Serial flush error -- IGNORED");
421 std::lock_guard<std::mutex> _(itsMtx);
423 std::ifstream fil(abspath, std::ios::in | std::ios::binary);
424 if (fil.is_open() ==
false)
throw std::runtime_error(
"Could not read file " + abspath);
427 fil.seekg(0, fil.end);
size_t num = fil.tellg(); fil.seekg(0, fil.beg);
429 std::string startstr =
"JEVOIS_FILEGET " + std::to_string(num) +
'\n';
430 writeInternal(startstr.c_str(), startstr.length(),
true);
433 size_t const bufsiz = std::min(num,
size_t(1024 * 1024));
char buffer[1024 * 1024];
436 size_t got = std::min(bufsiz, num); fil.read(buffer, got);
if (!fil) got = fil.gcount();
437 writeInternal(buffer, got,
true);
445 std::ofstream fil(abspath, std::ios::out | std::ios::binary);
446 if (fil.is_open() ==
false)
throw std::runtime_error(
"Could not write file " + abspath);
449 std::string lenstr;
int timeout = 1000;
450 while (readSome(lenstr) ==
false)
452 std::this_thread::sleep_for(std::chrono::milliseconds(2));
454 if (timeout == 0)
throw std::runtime_error(
"Timeout waiting for file length for " + abspath);
458 throw std::runtime_error(
"Incorrect header while receiving file " + abspath);
461 if (vec.size() != 2)
throw std::runtime_error(
"Incorrect header fields while receiving file " + abspath);
463 size_t num = std::stoul(vec[1]);
466 std::lock_guard<std::mutex> _(itsMtx);
467 size_t const bufsiz = std::min(num,
size_t(1024 * 1024));
char buffer[1024 * 1024];
470 int got = ::read(itsDev, buffer, bufsiz);
471 if (got == -1 && errno != EAGAIN)
throw std::runtime_error(
"Serial: Read error");
475 fil.write(buffer, got);
478 else std::this_thread::sleep_for(std::chrono::milliseconds(2));