25 #include <sys/types.h>
36 if (itsDev != -1) ::close(itsDev);
41 if (tcgetattr(itsDev, &itsSavedState) == -1)
LFATAL(
"Failed to save current state");
47 termios options = { };
48 if (tcgetattr(itsDev, &options) == -1)
LFATAL(
"Failed to get options");
51 options.c_cflag |= ( CLOCAL
54 options.c_iflag &= ~( IGNBRK
65 options.c_oflag &= ~OPOST;
66 options.c_lflag &= ~(ECHO
77 case 4000000:
rate = B4000000;
break;
78 case 3500000:
rate = B3500000;
break;
79 case 3000000:
rate = B3000000;
break;
80 case 2500000:
rate = B2500000;
break;
81 case 2000000:
rate = B2000000;
break;
82 case 1500000:
rate = B1500000;
break;
83 case 1152000:
rate = B1152000;
break;
84 case 1000000:
rate = B1000000;
break;
85 case 921600:
rate = B921600;
break;
86 case 576000:
rate = B576000;
break;
87 case 500000:
rate = B500000;
break;
88 case 460800:
rate = B460800;
break;
89 case 230400:
rate = B230400;
break;
90 case 115200:
rate = B115200;
break;
91 case 57600:
rate = B57600;
break;
92 case 38400:
rate = B38400;
break;
93 case 19200:
rate = B19200;
break;
94 case 9600:
rate = B9600;
break;
95 case 4800:
rate = B4800;
break;
96 case 2400:
rate = B2400;
break;
97 case 1200:
rate = B1200;
break;
98 case 600:
rate = B600;
break;
99 case 300:
rate = B300;
break;
100 case 110:
rate = B110;
break;
101 case 0:
rate = B0;
break;
105 cfsetispeed(&options,
rate);
106 cfsetospeed(&options,
rate);
113 options.c_cflag &= ~CSIZE;
117 case '5': options.c_cflag |= CS5;
break;
118 case '6': options.c_cflag |= CS6;
break;
119 case '7': options.c_cflag |= CS7;
break;
120 case '8': options.c_cflag |= CS8;
break;
121 default:
LFATAL(
"Invalid charbits: " <<
format[0] <<
" (should be 5..8)");
125 options.c_cflag &= ~(PARENB | PARODD);
130 case 'E': options.c_cflag |= PARENB;
break;
131 case 'O': options.c_cflag |= (PARENB | PARODD);
break;
132 default:
LFATAL(
"Invalid parity: " <<
format[1] <<
" (should be N,E,O)");
136 options.c_cflag &= ~CSTOPB;
140 case '2': options.c_cflag |= CSTOPB;
break;
141 default:
LFATAL(
"Invalid stopbits: " <<
format[2] <<
" (should be 1..2)");
145 options.c_cflag &= ~CRTSCTS;
146 options.c_iflag &= ~(IXON | IXANY | IXOFF);
152 if (tcsetattr(itsDev, TCSANOW, &options) == -1)
LFATAL(
"Failed to set port options");
162 if (tcsetattr(itsDev, TCSANOW, &itsSavedState) == -1)
LERROR(
"Failed to restore serial port state -- IGNORED");
171 std::lock_guard<std::mutex> _(itsMtx);
173 int flags = fcntl(itsDev, F_GETFL, 0);
174 if (flags == -1)
LFATAL(
"Cannot get flags");
175 if (blocking) flags &= (~O_NONBLOCK);
else flags |= O_NONBLOCK;
176 if (fcntl(itsDev, F_SETFL, flags) == -1)
LFATAL(
"Cannot set flags");
182 if (tcgetattr(itsDev, &options) == -1)
LFATAL(
"Failed to get options");
183 options.c_cc[VMIN] = 0;
184 options.c_cc[VTIME] = timeout.count() / 100;
185 if (tcsetattr(itsDev, TCSANOW, &options) == -1)
LFATAL(
"Failed to set port options");
192 std::lock_guard<std::mutex> _(itsMtx);
194 struct termios tty, old;
196 if (tcgetattr(itsDev, &tty) == -1 || tcgetattr(itsDev, &old) == -1)
LFATAL(
"Failed to get attributes");
198 cfsetospeed(&tty, B0);
199 cfsetispeed(&tty, B0);
201 if (tcsetattr(itsDev, TCSANOW, &tty) == -1)
LFATAL(
"Failed to set attributes");
203 std::this_thread::sleep_for(dur);
205 if (tcsetattr(itsDev, TCSANOW, &old) == -1)
LFATAL(
"Failed to restore attributes");
211 std::lock_guard<std::mutex> _(itsMtx);
214 tcsendbreak(itsDev, 0);
220 std::lock_guard<std::mutex> _(itsMtx);
222 int n = ::read(itsDev, buffer, nbytes);
224 if (n == -1)
throw std::runtime_error(
"Serial: Read error");
225 if (n == 0)
throw std::runtime_error(
"Serial: Read timeout");
233 std::lock_guard<std::mutex> _(itsMtx);
235 int n = ::read(itsDev, buffer, nbytes);
239 if (errno == EAGAIN)
return false;
240 else throw std::runtime_error(
"Serial: Read error");
243 if (n == 0)
return false;
251 std::lock_guard<std::mutex> _(itsMtx);
257 int n = ::read(itsDev,
reinterpret_cast<char *
>(&c), 1);
261 if (errno == EAGAIN)
return false;
262 else throw std::runtime_error(
"Serial: Read error");
265 if (n == 0)
return false;
269 case jevois::serial::LineStyle::LF:
270 if (c ==
'\n') { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
271 else itsPartialString += c;
274 case jevois::serial::LineStyle::CR:
275 if (c ==
'\r') { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
276 else itsPartialString += c;
279 case jevois::serial::LineStyle::CRLF:
280 if (c ==
'\n') { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
281 else if (c !=
'\r') itsPartialString += c;
284 case jevois::serial::LineStyle::Zero:
285 if (c == 0x00) { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
286 else itsPartialString += c;
289 case jevois::serial::LineStyle::Sloppy:
290 if (c ==
'\r' || c ==
'\n' || c == 0x00 || c == 0xd0)
292 if (itsPartialString.empty() ==
false)
293 { str = std::move(itsPartialString); itsPartialString.clear();
return true; }
295 else itsPartialString += c;
304 std::lock_guard<std::mutex> _(itsMtx);
305 return readStringInternal();
309 std::string jevois::Serial::readStringInternal()
311 std::string str;
unsigned char c;
315 int n = ::read(itsDev,
reinterpret_cast<char *
>(&c), 1);
319 if (errno == EAGAIN) std::this_thread::sleep_for(std::chrono::milliseconds(2));
320 else throw std::runtime_error(
"Serial: Read error");
323 std::this_thread::sleep_for(std::chrono::milliseconds(2));
328 case jevois::serial::LineStyle::LF:
if (c ==
'\n')
return str;
else str += c;
break;
330 case jevois::serial::LineStyle::CR:
if (c ==
'\r')
return str;
else str += c;
break;
332 case jevois::serial::LineStyle::CRLF:
if (c ==
'\n')
return str;
else if (c !=
'\r') str += c;
break;
334 case jevois::serial::LineStyle::Zero:
if (c == 0x00)
return str;
else str += c;
break;
336 case jevois::serial::LineStyle::Sloppy:
337 if (c ==
'\r' || c ==
'\n' || c == 0x00 || c == 0xd0) {
if (str.empty() ==
false)
return str; }
348 std::string fullstr(str);
352 case jevois::serial::LineStyle::CR: fullstr +=
'\r';
break;
353 case jevois::serial::LineStyle::LF: fullstr +=
'\n';
break;
354 case jevois::serial::LineStyle::CRLF: fullstr +=
"\r\n";
break;
355 case jevois::serial::LineStyle::Zero: fullstr +=
'\0';
break;
356 case jevois::serial::LineStyle::Sloppy: fullstr +=
"\r\n";
break;
359 this->write(fullstr.c_str(), fullstr.length());
365 std::lock_guard<std::mutex> _(itsMtx);
366 writeInternal(buffer, nbytes);
370 void jevois::Serial::writeInternal(
void const * buffer,
const int nbytes,
bool nodrop)
376 int ndone = 0;
char const * b =
reinterpret_cast<char const *
>(buffer);
377 while (ndone < nbytes)
379 int n = ::write(itsDev, b + ndone, nbytes - ndone);
380 if (n == -1 && errno != EAGAIN)
throw std::runtime_error(
"Serial: Write error");
383 if (n > 0) ndone += n;
384 if (ndone < nbytes) tcdrain(itsDev);
390 int ndone = 0;
char const * b =
reinterpret_cast<char const *
>(buffer);
int iter = 0;
391 while (ndone < nbytes && iter++ < 50)
393 int n = ::write(itsDev, b + ndone, nbytes - ndone);
394 if (n == -1 && errno != EAGAIN)
throw std::runtime_error(
"Serial: Write error");
397 if (n > 0) ndone += n;
398 if (ndone < nbytes) { tcdrain(itsDev); std::this_thread::sleep_for(std::chrono::milliseconds(5)); }
404 int ndone = 0;
char const * b =
reinterpret_cast<char const *
>(buffer);
int iter = 0;
405 while (ndone < nbytes && iter++ < 50)
407 int n = ::write(itsDev, b + ndone, nbytes - ndone);
408 if (n == -1 && errno != EAGAIN)
throw std::runtime_error(
"Serial: Write error");
411 if (n > 0) ndone += n;
412 if (ndone < nbytes) { tcdrain(itsDev); std::this_thread::sleep_for(std::chrono::milliseconds(2)); }
419 std::this_thread::sleep_for(std::chrono::milliseconds(100));
424 ++itsWriteOverflowCounter;
if (itsWriteOverflowCounter > 100) itsWriteOverflowCounter = 0;
425 if (itsWriteOverflowCounter == 1)
426 throw std::overflow_error(
"Serial write overflow: need to reduce amount ot serial writing");
430 else itsWriteOverflowCounter = 0;
437 std::lock_guard<std::mutex> _(itsMtx);
439 int ndone = 0;
char const * b =
reinterpret_cast<char const *
>(buffer);
int iter = 0;
440 while (ndone < nbytes && iter++ < 50)
442 int n = ::write(itsDev, b + ndone, nbytes - ndone);
443 if (n == -1 && errno != EAGAIN)
throw std::runtime_error(
"Serial: Write error");
444 if (n > 0) ndone += n;
450 if (tcflush(itsDev, TCOFLUSH) != 0)
LDEBUG(
"Serial flushOut error -- IGNORED");
457 std::lock_guard<std::mutex> _(itsMtx);
460 if (tcflush(itsDev, TCIFLUSH) != 0)
LDEBUG(
"Serial flush error -- IGNORED");
475 std::lock_guard<std::mutex> _(itsMtx);
477 std::ifstream fil(abspath, std::ios::in | std::ios::binary);
478 if (fil.is_open() ==
false)
throw std::runtime_error(
"Could not read file " + abspath);
481 fil.seekg(0, fil.end);
size_t num = fil.tellg(); fil.seekg(0, fil.beg);
483 std::string startstr =
"JEVOIS_FILEGET " +
std::to_string(num) +
'\n';
484 writeInternal(startstr.c_str(), startstr.length(),
true);
487 size_t const bufsiz = std::min(num,
size_t(1024 * 1024));
char buffer[1024 * 1024];
490 size_t got = std::min(bufsiz, num); fil.read(buffer, got);
if (!fil) got = fil.gcount();
491 writeInternal(buffer, got,
true);
499 std::lock_guard<std::mutex> _(itsMtx);
501 std::ofstream fil(abspath, std::ios::out | std::ios::binary);
502 if (fil.is_open() ==
false)
throw std::runtime_error(
"Could not write file " + abspath);
505 std::string
const lenstr = readStringInternal();
507 throw std::runtime_error(
"Incorrect header while receiving file " + abspath);
510 if (vec.size() != 2)
throw std::runtime_error(
"Incorrect header fields while receiving file " + abspath);
512 size_t num = std::stoul(vec[1]);
515 size_t const bufsiz = std::min(num,
size_t(1024 * 1024));
char buffer[1024 * 1024];
518 int got = ::read(itsDev, buffer, bufsiz);
519 if (got == -1 && errno != EAGAIN)
throw std::runtime_error(
"Serial: Read error");
523 fil.write(buffer, got);
526 else std::this_thread::sleep_for(std::chrono::milliseconds(2));