--- /dev/null
+##Flags
+
+All flags can have their default values set by modifying `config.h`, additional info and configuration options are also available in the file
+
+ * `--line|-l dev` - device to open, can be specified with `/dev/` or as just the device name
+ * `--verbose|-v` - toggle verbose output
+ * `--speed|-s # | -#` - baudrate, can also be set with just the number
+ * `--rx-speed|-i` - separate baudrate for RX line, same as TX if not set explicitly
+ * `--data|-D bits` - set data bits
+ * `--stop-bits|-S bits` - set stop bits
+ * `--software|-X` - toggle XON/XOFF flow control
+ * `--delay|-d delay` - delay between sending characters in nanoseconds
+ * `--min-chars|-m` - the minimum number of characters to start sending them
+ * `--backspace|-b` - toggle between ASCII `DELETE` and `BACKSPACE` characters
+ * `--echo|-h` - toggle local echo (half-duplex mode)
+ * `--canonical|-c` - toggle canonical mode (text can be edited locally before sending it to the line)
+> If both even and odd parity flags are set, parity is disabled
+ * `--odd|-o` - toggle odd parity
+ * `--even|-e` - toggle even parity
+> If both hardware flow control flags are set, DCD flow control is enabled
+ * `--hardware-rts-cts|-R` - toggle RTS/CTS flow control
+ * `--hardware-dtr-dsr|-r` - toggle DTR/DSR flow control
+
+---
+
+ * `--translation|-t option` - CR and LF translation for data sent
+ * `--input-translation|-T option` - CR and LF translation for data read
+###Options:
+ * `cr-to-lf`
+ * `cr-in-lf` - CR to CRLF
+ * `no-cr`
+ * `lf-to-cr`
+ * `lf-in-cr` - LF to CRLF
+ * `no-lf`
+
+##Interactive use
+
+Special character (`~` by default, may be set in `config.h`) will be escaped if it's the first one in the buffer.
+
+###Commands
+
+ * `.` - drop connection and exit
+ * `b` - toggle backspace character
+ * `h` - toggle local echo
+ * `c` - toggle canonical mode
+ * `s` - set new baudrate
+ * `d` - set new character delay
+ * `t|T` - toggle a translation option for output|input
+ * `w` - write file contents to the line
+ * `p` - send a DCD pulse
}
static struct option longopt[] = {
- {"device", required_argument, NULL, 'l'},
+ {"line", required_argument, NULL, 'l'},
{"speed", required_argument, NULL, 's'},
{"rx-speed", required_argument, NULL, 'i'},
{"echo", no_argument, NULL, 'h'},
case 0:
break;
case 'b':
- backspace = !backspace; break;
+ backspace ^= 1; break;
case 'c':
- canonical = !canonical; break;
+ canonical ^= 1; break;
case 'R':
hard ^= 1; break;
case 'r':
hard ^= 2; break;
case 'X':
- soft = !soft; break;
- case 'd':
- tui = strtoui(optarg, "invalid delay: %s\n", 0);
- if (tui == uintmax)
+ soft ^= 1; break;
+ case 'd':;
+ char* endptr;
+ long t = strtol(optarg, &endptr, 10);
+ if (errno != 0 || *endptr != '\0' || t < 0) {
+ fprintf(stderr, "invalid character delay\n");
goto ustusage;
- chardelay = tui;
+ } else {
+ chardelay = t;
+ }
break;
case 'D':
if (strlen(optarg) != 1 || !(optarg[0] >= '5' && optarg[0] <= '8')) {
case 'o':
parity ^= 2; break;
case 'h':
- half = !half; break;
+ half ^= 1; break;
case 'i':
tui = strtoui(optarg, "invalid rx speed: %s\n", 1);
if (tui == uintmax)
goto ustusage;
ispeed = tui;
- rxspdset = !rxspdset;
+ rxspdset = 1;
break;
case 's':
tui = strtoui(optarg, "invalid speed: %s\n", 1);
ospeed = tui;
break;
case 'S':
- stopb = !stopb; break;
+ stopb ^= 1; break;
case 'l':
if (devset) {
fprintf(stderr, "cannot specify multiple devices\n");
goto ustusage;
}
if (strchr(optarg, '/')) {
- line[0] = '\0';
strcpy(line, optarg);
devset = 1;
} else {
- line[0] = '\0';
sprintf(line, "/dev/%s", optarg);
devset = 1;
}
goto ustusage;
break;
case 'v':
- verbose = !verbose; break;
+ verbose ^= 1; break;
default:
ustusage:
- die(2, "usage: ust [--device|-l dev] [--speed|-s #|-#] [--rx-speed|-i #]\n"
+ die(2, "usage: %s [--line|-l line] [--speed|-s #|-#] [--rx-speed|-i #]\n"
" [--data-bits|-D #] [--stop-bits|-S]"
" [--even|-e] [--odd|-o]\n"
" [--hardware-rtscts|-R]"
" [--canonical|-c] [--echo|-h]\n"
" [--translation|-t tropt]"
" [--input-translation|-T tropt]\n"
- " [--verbose|-v] [--backspace|-b]\n");
+ " [--verbose|-v] [--backspace|-b]\n",
+ argv[0]);
break;
}
}
+
if (!rxspdset)
ispeed = ospeed;
pthread_t readthread, writethread;
pthread_create(&writethread, NULL, writeport, NULL);
pthread_create(&readthread, NULL, readport, NULL);
-
- pthread_join(writethread, NULL);
- pthread_join(readthread, NULL);
- close(fd);
- return 0;
-
}
int
optst->c_cflag |= BOTHER;
optst->c_ispeed = ispeed;
optst->c_ospeed = ospeed;
-
#else
struct termios *optst = (struct termios*)strct;
cfsetispeed(optst, ispeed);
int
openport()
{
+ if (verbose) fprintf(stderr, "opening \"%s\"\n", line);
+
fd = open(line, O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("error opening device");
exit(1);
}
- if (verbose) fprintf(stderr, "opened \"%s\"\n", line);
+ if (verbose) fprintf(stderr, "checking if \"%s\" is a TTY\n", line);
if (!isatty(fd))
die(2, "device \"%s\" is not a TTY\n", line);
-
- if (verbose) fprintf(stderr, "\"%s\" is a TTY\n", line);
int flags = fcntl(fd, F_GETFL, 0);
flags &= ~(O_NONBLOCK | O_NDELAY); /* opened to check with non-blocking mode, now set to blocking */
-
- if (fcntl(fd, F_SETFL, flags) != 0)
+ if (fcntl(fd, F_SETFL, flags) == -1)
die(1, "failed to set the device to blocking mode\n");
- if (gettermattr(fd, &cntrl) != 0)
+ if (gettermattr(fd, &cntrl) == -1)
die(1, "failed to get device attributes\n");
if (verbose) fprintf(stderr, "setting baudrate [RX:%u | TX:%u]\n", ispeed, ospeed);
settermspd(ispeed, ospeed, &cntrl);
- if (settermattr(fd, &cntrl) != 0)
+ if (settermattr(fd, &cntrl) == -1)
die(2,"failed to set baudrate [RX:%u | TX:%u]\n", ispeed, ospeed);
cntrl.c_lflag = 0;
cntrl.c_iflag &= ~(ISTRIP | BRKINT);
-
cntrl.c_cflag &= ~(PARENB | PARODD);
if (verbose) fprintf(stderr, "setting parity [even: %d, odd: %d]\n", parity & 1, (parity & 2) >> 1);
if (parity == 2)
cntrl.c_cflag |= PARENB | PARODD;
- if (settermattr(fd, &cntrl) != 0)
+ if (settermattr(fd, &cntrl) == -1)
die(2, "failed to set parity [even: %d, odd: %d]\n", parity & 1, (parity & 2) >> 1);
if (verbose) {
cntrl.c_cflag |= CRTSCTS;
} else if (hard == 2) {
#ifndef CDTRDSR
- fprintf(stderr, "DTR/DSR flow control is not supported on this platform\nenabling this option does nothing!\n");
+ fprintf(stderr, "DTR/DSR flow control is not supported on this platform\n"
+ "enabling this option does nothing!\n");
#else
cntrl.c_lflag |= CDTRDSR;
#endif
#endif
}
- if (settermattr(fd, &cntrl) != 0)
+ if (settermattr(fd, &cntrl) == -1)
die(2, "failed to set flow control\n");
if (setroptions())
cntrl.c_cflag &= ~CSIZE;
cntrl.c_cflag |= db;
- if (settermattr(fd, &cntrl) != 0)
+ if (settermattr(fd, &cntrl) == -1)
die(2, "failed to set data bits [%c]\n", datab);
if (verbose) fprintf(stderr, "setting stop bits [%d]\n", stopb+1);
else
cntrl.c_cflag &= ~CSTOPB;
- if (settermattr(fd, &cntrl) != 0)
- die(1, "failed to set stop bits\n");
+ if (settermattr(fd, &cntrl) == -1)
+ die(1, "failed to set stop bits [%d]\n", stopb+1);
#ifdef __linux__
ioctl(fd, TCFLSH, TCIOFLUSH);
}
nanosleep(&ts, NULL);
}
-
- free(writebuff); free(scratchw);
- writebuff = NULL; scratchw = NULL;
return NULL;
}
interchck();
+ /* disable stdout buffering */
setvbuf(stdout, NULL, _IONBF, 0);
for (;;) {
}
if (isatty(STDIN_FILENO))
settermattr(STDIN_FILENO, &origterm);
-
- free(readbuff); free(scratchr);
- readbuff = NULL; scratchr = NULL;
return NULL;
}
if ((size + c) > bsize)
c = bsize - size;
- if (scratch[0] == 0) {
+ if (scratch[0] == 0 && offset < 0) {
memmove(&str[0]+1, &str[0], size);
scratch[0] = 1;
}
switch (cmdchar) {
case '.':
- die(0,"\r\n[EOT]\r\n");
+ die(0,"\n[EOT]\n");
break;
case 'b':
if (backspace)