#define DEL '\x7f'
#define EOT '\x4'
#define ESC '\x1b'
+
+#define IXONXOFF (IXON | IXOFF)
+
+#ifdef __linux__
+ #define TERMIOS_STRUCT termios2
+#else
+ #define TERMIOS_STRUCT termios
+#endif
+
#if defined(CCDTR_IFLOW) && defined(CDSR_OFLOW)
#define CDTRDSR (CDTR_IFLOW | CDSR_OFLOW)
#endif
-#define IXONXOFF (IXON | IXOFF)
typedef struct {
char find;
/* including here to access CRLFOpt */
#include "config.h"
-static int gettermattr(int dv, void *strct);
-static int settermattr(int dv, const void *strct);
-static void settermspd(unsigned int lispeed, unsigned int lospeed, const void *strct);
+static int gettermattr(int dv, struct TERMIOS_STRUCT *optst);
+static int settermattr(int dv, const struct TERMIOS_STRUCT *optst);
+static void settermspd(unsigned int lispeed, unsigned int lospeed, struct TERMIOS_STRUCT *optst);
static int openport();
static unsigned int strtoui(const char *str, const char *msg, unsigned int min);
static int troptions(CRLFOpt *options, const char *str);
static void sighandl(int signo);
static void die(int code, const char *msg, ...);
-#ifdef __linux__
- static struct termios2 cntrl, origterm = { 0 }, newterm = { 0 };
-#else
- static struct termios cntrl, origterm = { 0 }, newterm = { 0 };
-#endif
+static struct TERMIOS_STRUCT cntrl, origterm = { 0 }, newterm = { 0 };
static Args bsargs = {DEL, DEL, 0};
-static Args nocrargs = {CR, 0, 0};
-static Args nolfargs = {LF, '\0', 0}; /* null-terminator is for use inside `getcmd()` */
-static Args lfincrargs = {CR, LF, 1};
-static Args crinlfargs = {LF, CR, -1};
-static const unsigned int uintmax = ~(unsigned int)0; /* unsigned -1 to return on error */
+static const Args nocrargs = {CR, 0, 0},
+ nolfargs = {LF, '\0', 0}, /* null-terminator is for use inside `getcmd()` */
+ lfincrargs = {CR, LF, 1},
+ crinlfargs = {LF, CR, -1};
static struct timespec wts;
+static const unsigned int uintmax = ~(unsigned int)0; /* unsigned -1 to return on error */
+static int interactive = 0;
static char *writebuff = NULL;
static char *readbuff = NULL;
static int *scratchr = NULL;
static int *scratchw = NULL;
static int fd = -1;
-static int interactive = 0;
int
-gettermattr(int dv, void *strct)
+gettermattr(int dv, struct TERMIOS_STRUCT *optst)
{
#ifdef __linux__
- struct termios2 *optst = (struct termios2*)strct;
return ioctl(dv, TCGETS2, optst);
#else
- struct termios *optst = (struct termios*)strct;
return tcgetattr(dv, optst);
#endif
}
int
-settermattr(int dv, const void *strct)
+settermattr(int dv, const struct TERMIOS_STRUCT *optst)
{
#ifdef __linux__
- struct termios2 *optst = (struct termios2*)strct;
return ioctl(dv, TCSETS2, optst);
#else
- struct termios *optst = (struct termios*)strct;
return tcsetattr(dv, TCSANOW, optst);
#endif
}
void
-settermspd(unsigned int lispeed, unsigned int lospeed, const void *strct)
+settermspd(unsigned int lispeed, unsigned int lospeed, struct TERMIOS_STRUCT *optst)
{
#ifdef __linux__
- struct termios2 *optst = (struct termios2*)strct;
-
optst->c_cflag &= ~CBAUD;
optst->c_cflag |= BOTHER;
optst->c_ispeed = ispeed;
optst->c_ospeed = ospeed;
#else
- struct termios *optst = (struct termios*)strct;
cfsetispeed(optst, ispeed);
cfsetospeed(optst, ospeed);
#endif
die(1, "failed to lock the device, exiting now\n");
}
}
-
+ /*
+ * Baud
+ */
if (verbose) fprintf(stderr, "setting baudrate [RX:%u | TX:%u]\n", ispeed, ospeed);
settermspd(ispeed, ospeed, &cntrl);
if (settermattr(fd, &cntrl) == -1)
die(2,"failed to set baudrate [RX:%u | TX:%u]\n", ispeed, ospeed);
-
+
+ /*
+ * Parity
+ */
cntrl.c_lflag = 0;
cntrl.c_iflag &= ~(ISTRIP | BRKINT);
cntrl.c_cflag &= ~(PARENB | PARODD);
if (settermattr(fd, &cntrl) == -1)
die(2, "failed to set parity [even: %d, odd: %d]\n", parity & 1, (parity & 2) >> 1);
+
+ /*
+ * Flow control
+ */
if (verbose) {
/* it's so ugly and beautiful at the same time */
int t = (((hard & 1) << 1) & (hard & 2)) >> 1;
if (settermattr(fd, &cntrl) == -1)
die(2, "failed to set flow control\n");
+ /*
+ * CR and LF
+ */
cntrl.c_iflag &= ~(ICRNL | INLCR);
cntrl.c_oflag &= ~(OCRNL | ONLRET | ONLCR);
if (setroptions())
die(2, "failed to set cr-lf translation options\n");
+ /*
+ * Data bits
+ */
if (verbose) fprintf(stderr, "setting data bits [%c]\n", datab);
tcflag_t db = CS8;
if (settermattr(fd, &cntrl) == -1)
die(2, "failed to set data bits [%c]\n", datab);
+ /*
+ * Stop bits
+ */
if (verbose) fprintf(stderr, "setting stop bits [%d]\n", stopb+1);
if (stopb)
cntrl.c_cc[VMIN] = 1;
cntrl.c_cc[VTIME] = 0;
-
+
+ /* flush both hardware buffers */
#ifdef __linux__
ioctl(fd, TCFLSH, TCIOFLUSH);
#else
* but almost all compilers will just truncate the value so it's OK
*/
return (unsigned int)t;
- /* termios's `speed_t` is a typedef for `unsigned int` */
}
int
inline int
termchck(const void *term)
{
- #ifdef __linux__
- struct termios2 *iterm = (struct termios2*)term;
- #define TERMIOS_STRUCT termios2
- #else
- struct termios *iterm = (struct termios*)term;
- #define TERMIOS_STRUCT termios
- #endif
for (size_t i = 0; i < sizeof(struct TERMIOS_STRUCT); i++)
- if (((char*)iterm)[i] != 0)
+ if (((char*)term)[i] != 0)
return 1;
return 0;
writeport(void *unused)
{
Sizes msizes;
- struct timespec ts;
+ struct timespec timeout, ts;
+ timeout.tv_sec = stimeout;
+ timeout.tv_nsec = nstimeout;
ts.tv_sec = swritedelay;
ts.tv_nsec = nswritedelay;
wts.tv_sec = 0;
} else {
write(fd, writebuff, 1);
}
+ } else if (inln == 0 && !interactive) {
+ break;
}
nanosleep(&ts, NULL);
}
+ /* ust kills itself upon receiving a signal so no fancy `nanosleep()` features needed */
+ nanosleep(&timeout, NULL);
+ die(0, "\n[EOF]\n");
return NULL;
}
case EOT: /* FALLTHROUGH */
case '.':
die(0,"\n[EOT]\n");
- break;
case 'b':
if (backspace)
bsargs.input = DEL;
if (argv[i][0] == '-' && argv[i][1] >= '0' && argv[i][1] <= '9') {
asprintf(&t, "-s%s", argv[i] + 1);
if (!t) {
- fprintf(stderr, "cannot convert -# to -s#\n");
+ fprintf(stderr, "%s: cannot convert -# to -s#\n", argv[0]);
break;
}
argv[i] = t;
{"data", required_argument, NULL, 'D'},
{"delay", required_argument, NULL, 'd'},
{"min-chars", required_argument, NULL, 'm'},
+ {"timeout-ns", required_argument, NULL, 'f'},
+ {"timeout-s", required_argument, NULL, 'F'},
{"stop-bits", no_argument, NULL, 'S'},
{"backspace", no_argument, NULL, 'b'},
{"translation", required_argument, NULL, 't'},
unsigned int tui;
int oind, rxspdset, devset, c;
oind = rxspdset = devset = 0;
- while ((c = getopt_long(argc, argv, "bcd:D:ehi:l:m:oRrs:t:T:vX", longopt, &oind)) != -1) {
+ while ((c = getopt_long(argc, argv, "D:F:T:d:f:i:l:m:s:t:RXbcehorv", longopt, &oind)) != -1) {
switch (c) {
case 0:
break;
hard ^= 2; break;
case 'X':
soft ^= 1; break;
- case 'd':;
+ case 'd': /* FALLTHROUGH */
+ case 'f':
+ case 'F':;
char* endptr;
long t;
t = strtol(optarg, &endptr, 10);
if (errno != 0 || *endptr != '\0' || t < 0) {
- fprintf(stderr, "invalid character delay\n");
+ fprintf(stderr, "%s: invalid character delay: %s\n", argv[0], optarg);
goto ustusage;
- } else {
+ } else if (c == 'd') {
chardelay = t;
+ } else if (c == 'f'){
+ nstimeout = t;
+ } else {
+ stimeout = t;
}
break;
case 'D':
if (strlen(optarg) != 1 || !(optarg[0] >= '5' && optarg[0] <= '8')) {
- fprintf(stderr, "invalid number of data bits: %s\n", optarg);
+ fprintf(stderr, "%s: invalid number of data bits: %s\n", argv[0], optarg);
goto ustusage;
} else {
datab = optarg[0];
stopb ^= 1; break;
case 'l':
if (devset) {
- fprintf(stderr, "cannot specify multiple devices\n");
+ fprintf(stderr, "%s: cannot specify multiple devices\n", argv[0]);
goto ustusage;
}
if (strlen(optarg) > 10) {
- fprintf(stderr, "device name too long\n");
+ fprintf(stderr, "%s: device name too long\n", argv[0]);
goto ustusage;
}
if (strchr(optarg, '/')) {
" [--canonical|-c] [--echo|-h]\n"
" [--translation|-t option]"
" [--input-translation|-T option]\n"
- " [--verbose|-v] [--backspace|-b]\n",
+ " [--verbose|-v] [--backspace|-b]"
+ " [--timeout-s|-F #] [--timeout-ns|-f #]",
argv[0]);
break;
}