+void exit_on_escapeseq(const char *buf, int len)
+{
+ static const char escseq[] = "\r~.";
+ static const char *state = escseq+1;
+ int i;
+ for (i = 0; i < len; i++) {
+ if (is_cpr_control_seq(buf[i]))
+ continue;
+ if (buf[i] == *state) {
+ state++;
+ if (*state == 0)
+ exit(0);
+ } else {
+ state = escseq;
+ if (buf[i] == *state)
+ state++;
+ }
+ }
+}
+
+void print_usage_and_exit(const char* argv0, int exit_code)
+{
+ fprintf(exit_code == 0 ? stdout : stderr, "Usage: %s [options] <device>\n", argv0);
+ fprintf(exit_code == 0 ? stdout : stderr,
+ "Options:\n"
+ " -b <duration> send break signal\n"
+ " -c enter command mode\n"
+ " -d[PULSE] make pulse on DTR\n"
+ " -e ignore '~.' escape sequence\n"
+ " -h, --help print help and exit\n"
+ " -n do not switch stdin TTY to raw mode\n"
+ " -r[PULSE] make pulse on RTS\n"
+ " -s <baudrate>\n"
+ " -t <ms> minimum delay between two transmitted characters\n"
+ " -v verbose mode\n"
+ " -V, --version print version and exit\n"
+ "\n"
+ "PULSE is a number specifying the pulse. Absolute value defines the\n"
+ "length of the pulse in milliseconds, sign determines the polarity of\n"
+ "the pulse. Alternatively, PULSE can be either '+' or '-', which\n"
+ "corresponds to '+1' or '-1'.\n"
+ );
+ exit(exit_code);
+}
+
+void pulse(int fd, int dtr, int rts)
+{
+ int status, ms = 0;
+ /* tio.c_cflag &= ~HUPCL; */ /* Don't lower DTR/RTS on close */
+
+ CHECK(ioctl(fd, TIOCMGET, &status));
+ if (dtr > 0) { status &= ~TIOCM_DTR; ms = +dtr; }
+ if (dtr < 0) { status |= TIOCM_DTR; ms = -dtr; }
+ if (rts > 0) { status &= ~TIOCM_RTS; ms = +rts; }
+ if (rts < 0) { status |= TIOCM_RTS; ms = -rts; }
+ CHECK(ioctl(fd, TIOCMSET, &status));
+
+ usleep(ms*1000);
+
+ if (dtr < 0) { status &= ~TIOCM_DTR; }
+ if (dtr > 0) { status |= TIOCM_DTR; }
+ if (rts < 0) { status &= ~TIOCM_RTS; }
+ if (rts > 0) { status |= TIOCM_RTS; }
+ CHECK(ioctl(fd, TIOCMSET, &status));
+}
+
+void handle_commands(int fd)
+{
+ char command[100];
+ bool go = false;
+
+ while (!go) {
+ char *p1 = NULL;
+ int num;
+ if (fgets(command, sizeof(command), stdin) == NULL) {
+ if (!feof(stdin))
+ perror("Command read");
+ exit(1);
+ }
+ if (sscanf(command, "dtr %ms", &p1) == 1)
+ pulse(fd, dtr_rts_arg('d', p1), 0);
+ else if (sscanf(command, "rts %ms", &p1) == 1)
+ pulse(fd, 0, dtr_rts_arg('r', p1));
+ else if (sscanf(command, "break %d", &num) == 1)
+ CHECK(tcsendbreak(fd, num));
+ else if (strcmp(command, "go\n") == 0)
+ break;
+ else if (strcmp(command, "exit\n") == 0)
+ exit(0);
+ else {
+ fprintf(stderr, "Unknown command: %s\n", command);
+ exit(1);
+ }
+
+ free(p1);
+ }
+}
+
+static int64_t now_us()
+{
+ struct timespec ts;
+ CHECK(clock_gettime(CLOCK_MONOTONIC, &ts));
+ return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+}