]> rtime.felk.cvut.cz Git - sojka/sterm.git/commitdiff
Allow enforcing minimum delay between transmitted characters
authorMichal Sojka <michal.sojka@cvut.cz>
Sat, 4 Jan 2020 15:32:50 +0000 (16:32 +0100)
committerMichal Sojka <michal.sojka@cvut.cz>
Sat, 4 Jan 2020 15:32:50 +0000 (16:32 +0100)
sterm.c
sterm.man

diff --git a/sterm.c b/sterm.c
index 303c28f45b0e8ffa3aaacabc766a3493eece88a7..6d38cd80166f162e19e81fb4a99518d5671bd2be 100644 (file)
--- a/sterm.c
+++ b/sterm.c
@@ -1,7 +1,7 @@
 /*
  * Simple serial terminal
  *
- * Copyright 2014, 2015, 2016, 2017, 2019 Michal Sojka <sojkam1@fel.cvut.cz>
+ * Copyright 2014, 2015, 2016, 2017, 2019, 2020 Michal Sojka <sojkam1@fel.cvut.cz>
  *
  * This program is free software: you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
 #include <getopt.h>
 #include <poll.h>
 #include <stdbool.h>
+#include <stdint.h>
 #include <string.h>
 #include <signal.h>
 #ifdef HAVE_LOCKDEV
 #include <lockdev.h>
 #endif
 #include <sys/file.h>
+#include <time.h>
 #include <errno.h>
 
 #define STRINGIFY(val) #val
@@ -58,6 +60,8 @@
 
 #define VERBOSE(format, ...) do { if (verbose) fprintf(stderr, "sterm: " format, ##__VA_ARGS__); } while (0)
 
+#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y))
+
 bool verbose = false;
 bool exit_on_escape = true;
 
@@ -140,6 +144,7 @@ void usage(const char* argv0)
                "  -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"
                "\n"
                "PULSE is a number specifying the pulse. Absolute value defines the\n"
@@ -202,6 +207,13 @@ void handle_commands(int fd)
        }
 }
 
+static int64_t now_us()
+{
+       struct timespec ts;
+       CHECK(clock_gettime(CLOCK_MONOTONIC, &ts));
+       return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
+}
+
 int main(int argc, char *argv[])
 {
        int fd;
@@ -213,13 +225,14 @@ int main(int argc, char *argv[])
        bool raw = true;
        bool cmd = false;
        int break_dur = -1;
+       int tx_delay_ms = 0;
 
        if ((stdin_tty = isatty(0))) {
                CHECK(tcgetattr(0, &stdin_tio_backup));
                atexit(restore_stdin_term);
        }
 
-       while ((opt = getopt(argc, argv, "b:cnd::er::s:v")) != -1) {
+       while ((opt = getopt(argc, argv, "b:cnd::er::s:vt:")) != -1) {
                switch (opt) {
                case 'b': break_dur = atoi(optarg); break;
                case 'c': cmd = true; break;
@@ -269,6 +282,9 @@ int main(int argc, char *argv[])
                        }
                        break;
                }
+               case 't':
+                       tx_delay_ms = atoi(optarg);
+                       break;
                case 'v':
                        verbose = true;
                        break;
@@ -369,30 +385,55 @@ int main(int argc, char *argv[])
        if (exit_on_escape)
                VERBOSE("Use '<Enter>~.' sequence to exit.\r\n");
 
-       char buf[4096];
+       char buf2dev[4096];
+       int buf_len = 0, buf_idx = 0;
+       int64_t last_tx_us = 0;
        while (1) {
-               int rlen, wlen;
-               int timeout = -1;
+               int timeout = (tx_delay_ms == 0 || buf_len == 0)
+                       ? -1
+                       : MAX(0, tx_delay_ms - (now_us() - last_tx_us) / 1000);
+
                CHECK(poll(fds, 2, timeout));
-               if (fds[STDIN].revents & POLLIN) {
-                       rlen = CHECK(read(STDIN_FILENO, buf, sizeof(buf)));
-                       if (rlen == 0) {
+               if (fds[STDIN].revents & POLLIN && buf_len == 0) {
+                       buf_len = CHECK(read(STDIN_FILENO, buf2dev, sizeof(buf2dev)));
+                       if (buf_len == 0) {
                                VERBOSE("EOF on stdin\r\n");
                                break;
                        }
+                       buf_idx = 0;
                        if (exit_on_escape)
-                               exit_on_escapeseq(buf, rlen);
-                       wlen = CHECK(write(fd, buf, rlen));
-                       if (rlen != wlen) {
-                               fprintf(stderr, "Not all data written to %s (%d/%d)\n", dev, rlen, wlen);
+                               exit_on_escapeseq(buf2dev, buf_len);
+               }
+               if (buf_len > 0) {
+                       int wlen = 0;
+                       bool short_write = false;
+                       if (tx_delay_ms == 0) {
+                               wlen = CHECK(write(fd, buf2dev, buf_len));
+                               short_write = wlen != buf_len;
+
+                       } else {
+                               int64_t now = now_us();
+                               if (now - last_tx_us >= tx_delay_ms * 1000) {
+                                       wlen = CHECK(write(fd, &buf2dev[buf_idx], 1));
+                                       short_write = wlen != 1;
+                                       last_tx_us = now;
+                               }
+                       }
+                       if (short_write) {
+                               fprintf(stderr, "Not all data written to %s (%d/%d)\n", dev, buf_len, wlen);
                                exit(1);
                        }
+                       buf_idx += wlen;
+                       if (buf_idx >= buf_len)
+                               buf_len = 0;
                }
                if (fds[STDIN].revents & POLLHUP) {
                        VERBOSE("HUP on stdin\r\n");
                        break;
                }
                if (fds[DEV].revents & POLLIN) {
+                       char buf[1024];
+                       int rlen, wlen;
                        rlen = CHECK(read(fd, buf, sizeof(buf)));
                        if (rlen == 0) {
                                VERBOSE("EOF on %s\r\n", dev);
index 4c12108af0d1c281c2c83117bf908af225621c35..5f29a626f3b94c25c08dbd2b71cea5013afacd06 100644 (file)
--- a/sterm.man
+++ b/sterm.man
@@ -46,6 +46,12 @@ length of the pulse and its polarity.
 Set serial like baudrate to the given value. Here are few common
 values: 4800, 9600, 19200, 115200. For full list of supported
 baudrates see source files or test what is acceptable.
+.TP
+\fB\-t <ms>\fR
+Enforce minimum delay of MS milliseconds between transmitting any two
+characters to the serial line. This is useful when talking to devices,
+which loose charactes sent at full speed, e.g. after copy&paste
+operation.
 
 .TP
 \fB\-v\fR