X-Git-Url: http://rtime.felk.cvut.cz/gitweb/can-benchmark.git/blobdiff_plain/e6d19b5adde38dac0ab7020fcb4de75abe06ba5e..1c379cb3292ef06cf2c81a890f6af13003c90f3c:/utils/sterm.c diff --git a/utils/sterm.c b/utils/sterm.c index bbd80da..305a985 100644 --- a/utils/sterm.c +++ b/utils/sterm.c @@ -1,10 +1,5 @@ /* - * Simple terminal - * - * This is a minimalist terminal program like minicom or cu. The only - * thing it does is creating a bidirectional connection between - * stdin/stdout and a device (e.g. serial terminal). It can also set - * serial line baudrate and manipulate DTR/RTS modem lines. + * Simple serial terminal * * Copyright 2014 Michal Sojka * @@ -23,6 +18,17 @@ * . */ +/* + * This is a minimalist terminal program like minicom or cu. The only + * thing it does is creating a bidirectional connection between + * stdin/stdout and a device (e.g. serial terminal). It can also set + * serial line baudrate and manipulate DTR/RTS modem lines. + * + * The -d and -r option create short pulse on DTR/RTS. The lines are + * always raised when the device is opened and those options lower the + * lines immediately after opening. + */ + #define _BSD_SOURCE #include #include @@ -44,6 +50,7 @@ #define VERBOSE(format, ...) do { if (verbose) fprintf(stderr, format, ##__VA_ARGS__); } while (0) bool verbose = false; +bool exit_on_escape = true; char template[] = "/var/lock/TMPXXXXXX"; char lockfile[100]; @@ -64,9 +71,52 @@ void restore_stdin_term() void sighandler(int arg) { - exit(0); + exit(0); /* Invoke exit handlers */ +} + +int dtr_rts_arg(const char option) +{ + int val = -1; + + if (optarg) { + switch (optarg[0]) { + case '+': val = +1; break; + case '-': val = -1; break; + default: + fprintf(stderr, "Unknown -%c argument: %s", option, optarg); + exit(1); + } + } + return val; +} + +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 (buf[i] == *state) { + state++; + if (*state == 0) + exit(0); + } else + state = escseq; + } } +void usage(const char* argv0) +{ + fprintf(stderr, "Usage: %s [options] \n", argv0); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -d [+|-] create short positive/negative pulse on DTR\n"); + fprintf(stderr, " -e ignore '~.' escape sequence\n"); + fprintf(stderr, " -n do not switch the device to raw mode\n"); + fprintf(stderr, " -r [+|-] create short positive/negative pulse on RTS\n"); + fprintf(stderr, " -s \n"); + fprintf(stderr, " -v verbose\n"); +} int main(int argc, char *argv[]) { @@ -74,7 +124,6 @@ int main(int argc, char *argv[]) char *dev = NULL; int opt; speed_t speed = 0; - int ret; int dtr = 0, rts = 0; struct termios tio; bool stdin_tty; @@ -85,16 +134,12 @@ int main(int argc, char *argv[]) atexit(restore_stdin_term); } - while ((opt = getopt(argc, argv, "ndrs:v")) != -1) { + while ((opt = getopt(argc, argv, "nd::er::s:v")) != -1) { switch (opt) { - case 'd': - dtr = 1; - break; - case 'n': - raw = false; - case 'r': - rts = 1; - break; + case 'd': dtr = dtr_rts_arg(opt); break; + case 'e': exit_on_escape = false; break; + case 'n': raw = false; break; + case 'r': rts = dtr_rts_arg(opt); break; case 's': { int s = atoi(optarg); switch (s) { @@ -129,7 +174,7 @@ int main(int argc, char *argv[]) verbose = true; break; default: /* '?' */ - fprintf(stderr, "Usage: %s [-s baudrate] [-v] \n", argv[0]); + usage(argv[0]); exit(1); } } @@ -139,6 +184,7 @@ int main(int argc, char *argv[]) if (!dev) { fprintf(stderr, "No device specified\n"); + usage(argv[0]); exit(1); } @@ -158,9 +204,21 @@ int main(int argc, char *argv[]) CHECK(write(tmp, pid, strlen(pid))); close(tmp); snprintf(lockfile, sizeof(lockfile), "/var/lock/LCK..%s", dev + 5); + retry: if (link(template, lockfile) == -1) { - perror(lockfile); - exit(1); + tmp = CHECK(open(lockfile, O_RDONLY)); + CHECK(read(tmp, pid, sizeof(pid))); + close(tmp); + int p = atoi(pid); + char proc[50]; + snprintf(proc, sizeof(proc), "/proc/%d", p); + if (access(proc, F_OK) == 0) { + fprintf(stderr, "%s is used by PID %d\n", dev, p); + exit(1); + } + fprintf(stderr, "Stale lock file %s (PID %d) - removing it!\n", lockfile, p); + CHECK(unlink(lockfile)); + goto retry; } rm_file(0, template); on_exit(rm_file, lockfile); @@ -185,13 +243,13 @@ int main(int argc, char *argv[]) if (dtr || rts) { int status; - tio.c_cflag &= ~HUPCL; + /* tio.c_cflag &= ~HUPCL; */ /* Don't lower DTR/RTS on close */ CHECK(ioctl(fd, TIOCMGET, &status)); - if (dtr == +1) status &= ~TIOCM_DTR; - if (dtr == -1) status |= TIOCM_DTR; - if (rts == +1) status &= ~TIOCM_RTS; - if (rts == -1) status |= TIOCM_RTS; + if (dtr == -1) status &= ~TIOCM_DTR; + if (dtr == +1) status |= TIOCM_DTR; + if (rts == -1) status &= ~TIOCM_RTS; + if (rts == +1) status |= TIOCM_RTS; CHECK(ioctl(fd, TIOCMSET, &status)); } @@ -217,13 +275,15 @@ int main(int argc, char *argv[]) VERBOSE("Connected.\n"); while (1) { int r1, r2; - ret = CHECK(poll(fds, 2, -1)); + CHECK(poll(fds, 2, -1)); if (fds[0].revents & POLLIN) { r1 = CHECK(read(0, buf, sizeof(buf))); if (r1 == 0) { VERBOSE("EOF on stdin\n"); break; } + if (exit_on_escape) + exit_on_escapeseq(buf, r1); r2 = CHECK(write(fd, buf, r1)); if (r1 != r2) { fprintf(stderr, "Not all data written to %s (%d/%d)\n", dev, r1, r2);