]> git.sur5r.net Git - tio/commitdiff
New upstream version 1.47
authorJakob Haufe <sur5r@debian.org>
Sat, 20 Aug 2022 16:31:13 +0000 (16:31 +0000)
committerJakob Haufe <sur5r@debian.org>
Sat, 20 Aug 2022 16:31:13 +0000 (16:31 +0000)
31 files changed:
AUTHORS
NEWS
README.md
TODO
example/tiorc [new file with mode: 0644]
images/tio-demo.gif
man/tio.1.in
man/tio.1.txt [new file with mode: 0644]
meson.build
src/bash-completion/tio.in
src/configfile.c
src/error.c
src/error.h
src/iossiospeed.c [deleted file]
src/log.c
src/main.c
src/meson.build
src/misc.c
src/misc.h
src/options.c
src/options.h
src/print.c
src/print.h
src/setspeed.c [new file with mode: 0644]
src/setspeed.h [new file with mode: 0644]
src/setspeed2.c [deleted file]
src/signals.c
src/socket.c
src/tty.c
src/tty.h
subprojects/libinih.wrap

diff --git a/AUTHORS b/AUTHORS
index 525446a83c774bf7407d6fa5f3126c18392af7da..762ce18fd8a00ad1874c7432d2ec3feb90973651 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -36,5 +36,9 @@ Peter Collingbourne <pcc@google.com>
 g0mb4 <gomba007@gmail.com>
 ZeroMemoryEx on GitHub
 George Joseph <g.devel@wxy78.net>
+Robert Snell <rcsnell@ncf.ca>
+Rui Chen <rui@chenrui.dev>
+Ralph Siemsen <ralphs@netwinder.org>
+Victor Oliveira <rhapsodyv@gmail.com>
 
 Thanks to everyone who has contributed to this project.
diff --git a/NEWS b/NEWS
index 11282e46ae3b631a41c01fb9008c7b516a0196f0..e7305cc435d23a82b20e6354f97e6c4fdc7648c5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,195 @@
 
-=== tio v1.43 ===
+=== tio v1.47 ===
+
+
+
+Changes since tio v1.46:
+
+ * Enable log feature when using --log-filename
+
+   No reason to not assume that the user wants to enable log when the
+   --log-filename is used. This way uses can skip the use of --log to
+   enable log.
+
+ * Enable line buffering of log
+
+   Replace flushing/writing of log at every log write operation with line
+   buffering, meaning log will be written line by line to make it more I/O
+   friendly but still update frequently.
+
+ * Avoid invalid hex character messages when switching hex mode
+
+ * Force flushing of log writes
+
+ * Renamed tty_flush() to tty_sync()
+
+ * Fix sync output to serial port
+
+   Using fsync() on filedescriptors for serial ports can not be relied on.
+   Add use of tcdrain() to make sure data has been written by the serial
+   port before proceeding.
+
+   This fixes a problem with tio sometimes not writing piped input data to
+   the serial port before exiting which results in the pending writes being
+   cancelled / flushed.
+
+ * Clean up tty_flush()
+
+ * Force frequent sync on tty_flush()
+
+ * Update README
+
+ * Update example tiorc
+
+ * Quit from non-interactive mode using ctrl-c
+
+   When piping to tio it will automatically enter "non-interactive" mode
+   which means it will not react to any input key sequences but simple read
+   the input stream and write it to the tty device.
+
+   This also means that ctrl-t q can not be used to quit and so tio would
+   hang forever when used in non-interactive mode.
+
+   This change allows to send the standard termination signal by pressing
+   ctrl-c on tio in non-interactive mode to make it quit.
+
+ * Make sure we flush output buffer to tty when piping to tio
+
+ * Do not return false read error when piping to tio
+
+ * Show error message when reading port settings fail
+
+Victor Oliveira
+
+ * add macports install instructions
+
+
+
+Changes since tio v1.45:
+
+ * Rework toggle and pulse feature to support all lines
+
+   Replace existing toggle and pulse key commands with the following
+   generalized key commands which allows to toggle or pulse all serial port
+   lines:
+
+    ctrl-t g   Toggle serial port line
+    ctrl-t p   Pulse serial port line
+
+   When used, user will be asked which serial line to toggle or pulse.
+
+   Also introduce --line-pulse-duration option for setting specific pulse
+   duration in milliseconds for each serial line using a key value pair
+   format. Each key represents a serial line. The following keys are
+   available: DTR, RTS, CTS, DSR, DCD, RI.
+
+   Example:
+
+    $ tio /dev/ttyUSB0 --line-pulse-duration DTR=200,RTS=300,RI=50
+    
+   Likewise, the pulse duration can also be set via configuration file
+   using the line-pulse-duration variable:
+    
+    line-pulse-duration = DTR=200,RTS=300,RI=50
+
+ * Upgrade inih wrap to r56
+
+ * Optimization
+
+ * Add example configuration file
+
+
+Ralph Siemsen:
+
+ * Fix relative timestamps
+
+   Fix the display of relative timestamps. The hack of subtracting 3600
+   only works if you happen to be in a time zone that is one hour away from
+   UTC. When subtracting two time values, the result is an absolute
+   quantity (interval). These should be displayed as-is; without local time
+   zone nor daylight saving correction. Hence gmtime() instead of
+   localtime().
+
+
+
+Changes since tio v1.44:
+
+ * Introduce bold color option
+
+   Introduce "bold" color option which only apply bold color formatting to
+   existing system color.
+
+   Also make "bold" the default color option.
+
+   Fixes all white issue with black on white tio text.
+
+ * Update README
+
+ * Change 'ctrl-t T' to 'ctrl-t t' for timestamp toggle
+
+ * Add support for remapping prefix key
+
+   Make it possible to remap the prefix key (default: ctrl-t) by setting
+   the prefix-ctrl-key variable in the configuration file.
+
+   Allowed values are in the range a..z.
+
+   Example, to set the prefix key to ctrl-a simply do:
+
+   prefix-ctrl-key = a
+
+ * Add plaintext man page
+
+Rui Chen:
+
+ * docs: add homebrew installation note
+
+ * fix macOS build
+
+ * fix compilation error
+
+
+
+Changes since tio v1.43:
+
+ * Simplify arbitrary baudrate code
+
+ * Cleanup error printing routines
+
+   Clean up so that only the following error related printing functions are
+   used: tio_error_printf(), tio_error_printf_silent(),
+   tio_warning_printf().
+
+   A session mode switch is introduced for error printing so that it will
+   print error messages with better formatting depending on in or out of
+   session.
+
+ * Update README
+
+ * Clean up man page
+
+ * Add support for space parity
+
+ * Rename EOL delay to Output line delay
+
+ * Replace -U,--upcase with mapping flag OLTU
+
+ * Simplify tty_write()
+
+Robert Snell:
+
+ * Additional commands: EOL delay, lower to upper translation, added mark parity
+
+   Added command line options:
+   -O, --eol-delay to have a separate delay for end of line
+   -U, --upper to enable translation of lower case alpha to upper case
+
+   Added ability to set mark parity.
+   Added ctrl-t U key sequence to allow enable/disable lower case alpha to
+   upper case during a session.
+   Updated Man page with command line options, ctrl-t sequences and
+   configuration file options.
+   Updated README.md, with above information.
 
 
 
index 93d747ed11f41c14269f11b864c62c471c4ca25d..a79bc159285e5809808b6b602ba1d6056372c453 100644 (file)
--- a/README.md
+++ b/README.md
@@ -27,16 +27,17 @@ when used in combination with [tmux](https://tmux.github.io).
 ## 2. Features
 
  * Easily connect to serial TTY devices
- * Automatic connect
+ * Automatic connect and reconnect
  * Support for arbitrary baud rates
- * List available serial devices
+ * List available serial devices by ID
  * Show RX/TX statistics
  * Toggle serial lines
- * Pulse the DTR line
+ * Pulse serial lines with configurable pulse duration
  * Local echo support
- * Remap special characters (nl, cr-nl, bs, etc.)
+ * Map characters (nl, cr-nl, bs, lowercase to uppercase, etc.)
  * Line timestamps
- * Support for delayed output
+ * Support for delayed output per character
+ * Support for delayed output per line
  * Hexadecimal mode
  * Log to file
  * Autogeneration of log filename
@@ -46,47 +47,51 @@ when used in combination with [tmux](https://tmux.github.io).
  * Pipe input and/or output
  * Bash completion
  * Color support
+ * Remapping of prefix key
  * Man page documentation
 
 ## 3. Usage
 
+For more usage details please see the man page documentation
+[here](man/tio.1.txt).
+
 ### 3.1 Command-line
 
 The command-line interface is straightforward as reflected in the output from
 'tio --help':
 ```
-    Usage: tio [<options>] <tty-device|sub-config>
-
-    Connect to tty device directly or via sub-configuration.
-
-    Options:
-      -b, --baudrate <bps>             Baud rate (default: 115200)
-      -d, --databits 5|6|7|8           Data bits (default: 8)
-      -f, --flow hard|soft|none        Flow control (default: none)
-      -s, --stopbits 1|2               Stop bits (default: 1)
-      -p, --parity odd|even|none       Parity (default: none)
-      -o, --output-delay <ms>          Character output delay (default: 0)
-          --dtr-pulse-duration <ms>    DTR pulse duration (default: 100)
-      -n, --no-autoconnect             Disable automatic connect
-      -e, --local-echo                 Enable local echo
-      -t, --timestamp                  Enable line timestamp
-          --timestamp-format <format>  Set timestamp format (default: 24hour)
-      -L, --list-devices               List available serial devices
-      -l, --log                        Enable log to file
-          --log-file <filename>        Set log filename
-          --log-strip                  Strip control characters and escape sequences
-      -m, --map <flags>                Map special characters
-      -c, --color 0..255|none|list     Colorize tio text (default: 15)
-      -S, --socket <socket>            Redirect I/O to file or network socket
-      -x, --hexadecimal                Enable hexadecimal mode
-      -v, --version                    Display version
-      -h, --help                       Display help
-
-    Options and sub-configurations may be set via configuration file.
-
-    In session, press ctrl-t q to quit.
-
-    See the man page for more details.
+  Usage: tio [<options>] <tty-device|sub-config>
+
+  Connect to tty device directly or via sub-configuration.
+
+  Options:
+    -b, --baudrate <bps>                   Baud rate (default: 115200)
+    -d, --databits 5|6|7|8                 Data bits (default: 8)
+    -f, --flow hard|soft|none              Flow control (default: none)
+    -s, --stopbits 1|2                     Stop bits (default: 1)
+    -p, --parity odd|even|none|mark|space  Parity (default: none)
+    -o, --output-delay <ms>                Output character delay (default: 0)
+    -O, --output-line-delay <ms>           Output line delay (default: 0)
+        --line-pulse-duration <duration>   Set line pulse duration
+    -n, --no-autoconnect                   Disable automatic connect
+    -e, --local-echo                       Enable local echo
+    -t, --timestamp                        Enable line timestamp
+        --timestamp-format <format>        Set timestamp format (default: 24hour)
+    -L, --list-devices                     List available serial devices
+    -l, --log                              Enable log to file
+        --log-file <filename>              Set log filename
+        --log-strip                        Strip control characters and escape sequences
+    -m, --map <flags>                      Map characters
+    -c, --color 0..255|bold|none|list      Colorize tio text (default: bold)
+    -S, --socket <socket>                  Redirect I/O to file or network socket
+    -x, --hexadecimal                      Enable hexadecimal mode
+    -v, --version                          Display version
+    -h, --help                             Display help
+
+  Options and sub-configurations may be set via configuration file.
+
+  See the man page for more details.
+
 ```
 
 By default tio automatically connects to the provided TTY device if present.
@@ -126,20 +131,21 @@ ctrl-t ? to list the available key commands.
 [20:19:12.040]  ctrl-t ?   List available key commands
 [20:19:12.040]  ctrl-t b   Send break
 [20:19:12.040]  ctrl-t c   Show configuration
-[20:19:12.040]  ctrl-t d   Toggle DTR line
-[20:19:12.040]  ctrl-t D   Pulse DTR line
 [20:19:12.040]  ctrl-t e   Toggle local echo mode
+[20:19:12.040]  ctrl-t g   Toggle serial port line
 [20:19:12.040]  ctrl-t h   Toggle hexadecimal mode
 [20:19:12.040]  ctrl-t l   Clear screen
 [20:19:12.040]  ctrl-t L   Show line states
+[20:19:12.040]  ctrl-t p   Pulse serial port line
 [20:19:12.040]  ctrl-t q   Quit
-[20:19:12.040]  ctrl-t r   Toggle RTS line
 [20:19:12.041]  ctrl-t s   Show statistics
-[20:19:12.041]  ctrl-t t   Send ctrl-t key code
 [20:19:12.041]  ctrl-t T   Toggle line timestamp mode
+[20:19:12.041]  ctrl-t U   Toggle conversion to uppercase
 [20:19:12.041]  ctrl-t v   Show version
 ```
 
+If needed, the prefix key (ctrl-t) can be remapped via configuration file.
+
 ### 3.3 Configuration file
 
 Options can be set via the configuration file first found in any of the
@@ -161,7 +167,6 @@ databits = 8
 parity = none
 stopbits = 1
 color = 10
-dtr-pulse-duration = 50
 
 [rpi3]
 tty = /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
@@ -169,6 +174,7 @@ baudrate = 115200
 no-autoconnect = enable
 log = enable
 log-file = rpi3.log
+line-pulse-duration = DTR=200,RTS=150
 color = 12
 
 [usb devices]
@@ -186,10 +192,11 @@ Or by pattern match:
 $ tio usb12
 ```
 
+Another configuration file example is available [here](example/tiorc).
 
 ## 4. Installation
 
-### 4.1 Installation using package manager
+### 4.1 Installation using package manager (Linux)
 
 Packages for various GNU/Linux distributions are available. Please consult your
 package manager tool to find and install tio.
@@ -197,18 +204,28 @@ package manager tool to find and install tio.
 If you would like to see tio included in your favorite distribution, please
 reach out to their package maintainers team.
 
-### 4.2 Installation using snap
+### 4.2 Installation using snap (Linux)
 
 Install latest stable version:
 ```
     $ snap install tio
 ```
-Install bleeding edge:
+
+### 4.3 Installation using brew (MacOS, Linux)
+
+If you have [brew](http://brew.sh) installed:
+```
+    $ brew install tio
+```
+
+### 4.4 Installation using MacPorts (MacOS)
+
+If you have [MacPorts](https://www.macports.org) installed:
 ```
-    $ snap install tio --edge
+    $ sudo port install tio
 ```
 
-### 4.3 Installation from source
+### 4.5 Installation from source
 
 The latest source releases can be found [here](https://github.com/tio/tio/releases).
 
@@ -221,8 +238,8 @@ Install steps:
 
 See meson\_options.txt for tio specific build options.
 
-Note: Please do no try to install from source if you are not familiar with
-how to build stuff using meson.
+Note: It is recommended to only try to install from source if you are familiar
+with how to build stuff using meson.
 
 
 ## 5. Contributing
diff --git a/TODO b/TODO
index dda518087eb909280688a93ed64d29374ebb1670..7801868f53db4c1445e1f9459b58b8bfff810542 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,24 +1,19 @@
 
- * Improve error/warning messaging when parsing configuration file
-
- * Refactor and consolidate arbitrary set speed function into one file for all platforms
-
- * Consider reworking line toggle and line pulse featueres in case requests are made to apply them to more lines:
-
-     ctrl-t g Toggle serial line
-     
-     Which would then make tio ask which line to toggle:
-     
-     [20:50:11.691] Please enter which line number to toggle?
-     [20:50:11.691] DTR(0) RTS(1) CTS(2) DSR(3) DCD(4) RI(5)
-     
-     ctrl-t p Pulse serial line
-     
-     [20:50:11.691] Please enter which line number to pulse?
-     [20:50:11.691] DTR(0) RTS(1) CTS(2) DSR(3) DCD(4) RI(5)
-     
-     command-line:
-     --line-pulse-duration="DTR=60,RTS=50,CTS=40,DSR=30,DCD=20,RI=10"
-     
-     config file:
-     line-pulse-duration="DTR=60,RTS=50,CTS=40,DSR=30,DCD=20,RI=10"
+ * Split I/O feature
+
+   Allow to split input and output so that it is possible to manage these independently.
+
+   The general idea is to redirect the output stream on the socket port number
+   specified but then redirect the input stream on the same port number + 1.
+
+   Example:
+
+   tio /dev/ttyUSB0 --socket inet:4444,split-io
+
+   Will result in output stream being hosted on port 4444 and input stream hosted on port 4445.
+
+   For file sockets something similar can be arranged:
+
+   tio /dev/ttyUSB0 --socket unix:/tmp/tio-socket-0,split-io
+
+   Will result in output stream being hosted via /tmp/tio-socket-0 and input stream hosted via /tmp/tio-socket-0_input
diff --git a/example/tiorc b/example/tiorc
new file mode 100644 (file)
index 0000000..a1340e3
--- /dev/null
@@ -0,0 +1,46 @@
+###############################
+# tio - https://tio.github.io #
+###############################
+
+# Example configuration file
+
+# Defaults
+baudrate = 115200
+databits = 8
+flow = none
+stopbits = 1
+parity = none
+prefix-ctrl-key = t
+output-delay = 0
+output-line-delay = 0
+no-autoconnect = disable
+hexadecimal = disable
+timestamp = disable
+color = bold
+
+# Sub-configuraions
+
+[rpi3]
+baudrate = 115200
+tty = /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A6009HU3-if00-port0
+socket = unix:/tmp/tio-socket-0
+color = 9
+
+[am64-evm]
+baudrate = 115200
+tty = /dev/serial/by-id/usb-Silicon_Labs_CP2105_Dual_USB_to_UART_Bridge_Controller_01093176-if01-port0
+line-pulse-duration = DTR=200,RTS=300,RI=50
+color = 10
+
+[tincan]
+baudrate = 9600
+tty = /dev/serial/by-id/usb-TinCanTools_Flyswatter2_FS20000-if00-port0
+log = enable
+log-file = tincan.log
+log-strip = enable
+color = 11
+
+[usb devices]
+pattern = usb([0-9]*)
+tty = /dev/ttyUSB%s
+color = 12
index 3e468bd235a154a8c4c36336c9ee9bbbbe66899d..7e12336e0b11047627796cb441b979aab5ba338d 100644 (file)
Binary files a/images/tio-demo.gif and b/images/tio-demo.gif differ
index 7132e6484aeb3e624709e75442fd759bd303a5e5..48623b23264dbee49b30044c883faee0b1d0d682 100644 (file)
@@ -10,10 +10,9 @@ tio \- a simple serial device I/O tool
 
 .SH "DESCRIPTION"
 .PP
-.B tio
-is a simple serial device tool which features a straightforward command-line
-and configuration file interface to easily connect to serial TTY devices for
-basic I/O operations.
+\fBtio\fR is a simple serial device tool which features a straightforward
+command-line and configuration file interface to easily connect to serial TTY
+devices for basic I/O operations.
 
 .SH "OPTIONS"
 
@@ -34,29 +33,58 @@ Set flow control (default: none).
 
 Set stop bits (default: 1).
 .TP
-.BR \-p ", " "\-\-parity odd" | even | none
+.BR \-p ", " "\-\-parity odd" | even | none | mark | space
 
 Set parity (default: none).
+
+Note: With \fBmark\fR parity the parity bit is always 0. With \fBspace\fR
+parity the parity bit is always 1. Not all platforms support \fBmark\fR and
+\fBspace\fR parity.
+
 .TP
 .BR \-o ", " "\-\-output\-delay " \fI<ms>
 
 Set output delay [ms] inserted between each sent character (default: 0).
 
 .TP
-.BR "    \-\-dtr\-pulse\-duration " \fI<ms>
+.BR \-O ", " "\-\-output\-line\-delay " \fI<ms>
+
+Set output delay [ms] inserted between each sent line (default: 0).
+
+.TP
+.BR "    \-\-line\-pulse\-duration " \fI<duration>
+
+Set the pulse duration [ms] of each serial port line using the following key
+valur pair format in the duration field: <key>=<value>
+
+Each key represents a serial line. The following keys are available:
+
+.RS
+.TP 12n
+.IP "\fBDTR - Data Terminal Ready"
+.IP "\fBRTS - Request To Send"
+.IP "\fBCTS - Clear To Send"
+.IP "\fBDSR - Data Set Ready"
+.IP "\fBDCD - Data Carrier Detect"
+.IP "\fBRI  - Ring Indicator"
+.P
+If defining more than one key value pair, the pairs must be comma separated.
 
-Set the duration [ms] of the DTR pulse (default: 100).
+The default pulse duration for each line is 100 ms.
+.RE
 
 .TP
 .BR \-n ", " \-\-no\-autoconnect
 
 Disable automatic connect.
 
-By default tio automatically connects to the provided device if present. If the device is not present, it will wait for it to appear and then connect. If the connection is lost (eg. device disconnects), it will wait for the device to reappear and then reconnect.
+By default tio automatically connects to the provided device if present. If the
+device is not present, it will wait for it to appear and then connect. If the
+connection is lost (eg. device disconnects), it will wait for the device to
+reappear and then reconnect.
 
-However, if the
-.B \-\-no\-autoconnect
-option is provided, tio will exit if the device is not present or an established connection is lost.
+However, if the \fB\-\-no\-autoconnect\fR option is provided, tio will exit if
+the device is not present or an established connection is lost.
 
 .TP
 .BR \-e ", " "\-\-local\-echo
@@ -84,8 +112,7 @@ Set timestamp format to any of the following timestamp formats:
 .IP "\fBiso8601"
 ISO8601 format ("YYYY-MM-DDThh:mm:ss.sss")
 .PP
-Default format is
-.B 24hour
+Default format is \fB24hour\fR
 .RE
 
 .TP
@@ -96,7 +123,10 @@ List available serial devices.
 .TP
 .BR \-l ", " \-\-log
 
-Enable log to file. If no filename is provided the filename will be automatically generated.
+Enable log to file.
+
+If no filename is provided the filename will be
+automatically generated.
 
 .TP
 .BR "    \-\-log-file \fI<filename>
@@ -111,23 +141,27 @@ Strip control characters and escape sequences from log.
 .TP
 .BR \-m ", " "\-\-map " \fI<flags>
 
-Map (replace, translate) special characters on input or output. The following mapping flags are supported:
+Map (replace, translate) characters on input or output. The following mapping
+flags are supported:
+
 .RS
 .TP 12n
 .IP "\fBICRNL"
-Map CR to NL on input (unless IGNCR is set).
+Map CR to NL on input (unless IGNCR is set)
 .IP "\fBIGNCR"
-Ignore CR on input.
+Ignore CR on input
 .IP "\fBINLCR"
-Map NL to CR on input.
+Map NL to CR on input
 .IP "\fBINLCRNL"
-Map NL to CR-NL on input.
+Map NL to CR-NL on input
 .IP "\fBOCRNL"
-Map CR to NL on output.
+Map CR to NL on output
 .IP "\fBODELBS"
-Map DEL to BS on output.
+Map DEL to BS on output
 .IP "\fBONLCRNL"
-Map NL to CR-NL on output.
+Map NL to CR-NL on output
+.IP "\fBOLTU"
+Map lowercase characters to uppercase on output
 .P
 If defining more than one flag, the flags must be comma separated.
 .RE
@@ -138,20 +172,23 @@ If defining more than one flag, the flags must be comma separated.
 Enable hexadecimal mode.
 
 .TP
-.BR \-c ", " "\-\-color " \fI0..255|none|list
+.BR \-c ", " "\-\-color " \fI0..255|bold|none|list
 
-Colorize tio text using ANSI color code value ranging from 0 to 255 or use "none" for no color.
+Colorize tio text using ANSI color code value ranging from 0 to 255 or use
+"none" for no color or use "bold" to apply bold formatting to existing system
+color.
 
 Use "list" to print a list of available ANSI color codes.
 
-Default value is 15.
+Default value is "bold".
 
 .TP
 .BR \-S ", " "\-\-socket \fI<socket>\fR\fB
 
-Redirect I/O to socket. Any input from clients connected to the socket is sent on the serial port as if entered at the terminal where tio is running (except that
-.B ctrl-t
-sequences are not recognized), and any input from the serial port is multiplexed to the terminal and all connected clients.
+Redirect I/O to socket. Any input from clients connected to the socket is sent
+on the serial port as if entered at the terminal where tio is running (except
+that \fBctrl-t\fR sequences are not recognized), and any input from the serial
+port is multiplexed to the terminal and all connected clients.
 
 Sockets remain open while the serial port is disconnected, and writes will block.
 
@@ -182,7 +219,7 @@ Display help.
 .SH "KEYS"
 .PP
 .TP 16n
-In session, the following key sequences are intercepted as tio commands:
+In session, the following key sequences, a prefix key (default: ctrl-t) followed by a command key, are intercepted as tio commands:
 .IP "\fBctrl-t ?"
 List available key commands
 .IP "\fBctrl-t b"
@@ -191,37 +228,42 @@ Send serial break (triggers SysRq on Linux, etc.)
 Show configuration (baudrate, databits, etc.)
 .IP "\fBctrl-t e"
 Toggle local echo mode
+.IP "\fBctrl-t g"
+Toggle serial port line
 .IP "\fBctrl-t h"
 Toggle hexadecimal mode
 .IP "\fBctrl-t l"
 Clear screen
+.IP "\fBctrl-t L"
+Show line states (DTR, RTS, CTS, DSR, DCD, RI)
+.IP "\fBctrl-t p"
+Pulse serial port line
 .IP "\fBctrl-t q"
 Quit
 .IP "\fBctrl-t s"
 Show TX/RX statistics
 .IP "\fBctrl-t t"
-Send ctrl-t key code
-.IP "\fBctrl-t L"
-Show line states (DTR, RTS, CTS, DSR, DCD, RI)
-.IP "\fBctrl-t d"
-Toggle DTR
-.IP "\fBctrl-t D"
-Pulse DTR
-.IP "\fBctrl-t r"
-Toggle RTS
+Toggle line timestamp mode
+.IP "\fBctrl-t U"
+Toggle conversion to uppercase on output
 .IP "\fBctrl-t v"
 Show version
 
 .SH "HEXADECIMAL MODE"
-.TP
+.PP
 In hexadecimal mode each incoming byte is printed out as a hexadecimal value.
-.TP
-Bytes can be sent in this mode by typing the \fBtwo-character hexadecimal\fR representation of the value, e.g.: to send \fI0xA\fR you must type \fI0a\fR or \fI0A\fR.
+
+.PP
+Bytes can be sent in this mode by typing the \fBtwo-character hexadecimal\fR
+representation of the value, e.g.: to send \fI0xA\fR you must type \fI0a\fR or
+\fI0A\fR.
 
 .SH "CONFIGURATION FILE"
 .PP
-.TP 16n
-Options can be set via configuration file using the INI format. tio uses the configuration file first found in the following locations in the order listed:
+Options can be set via configuration file using the INI format. \fBtio\fR uses
+the configuration file first found in the following locations in the order
+listed:
+
 .PP
 .I $XDG_CONFIG_HOME/tio/tiorc
 .PP
@@ -229,23 +271,24 @@ Options can be set via configuration file using the INI format. tio uses the con
 .PP
 .I $HOME/.tiorc
 
-.TP
-Labels can be used to group settings into named sub-configurations which can be activated from the command-line when starting tio.
+.PP
+Labels can be used to group settings into named sub-configurations which can be
+activated from the command-line when starting tio.
 
-.TP
-.TP
-tio will try to match the user input to a sub-configuration by name or by pattern to get the tty and other options.
+.PP
+\fBtio\fR will try to match the user input to a sub-configuration by name or by
+pattern to get the tty and other options.
 
-.TP
+.PP
 Options without any label change the default options.
 
-.TP
+.PP
 Any options set via command-line will override options set in the configuration file.
 
-.TP
+.PP
 The following configuration file options are available:
 
-.TP 20n
+.TP 21n
 .IP "\fBpattern"
 Pattern matching user input. This pattern can be an extended regular expression with a single group.
 .IP "\fBtty"
@@ -261,9 +304,11 @@ Set stop bits
 .IP "\fBparity"
 Set parity
 .IP "\fBoutput-delay"
-Set output delay
-.IP "\fBdtr-pulse-duration"
-Set DTR pulse duration
+Set output character delay
+.IP "\fBoutput-line-delay"
+Set output line delay
+.IP "\fBline-pulse-duration"
+Set line pulse duration
 .IP "\fBno-autoconnect"
 Disable automatic connect
 .IP "\fBlog"
@@ -279,13 +324,15 @@ Enable line timestamp
 .IP "\fBtimestamp-format"
 Set timestamp format
 .IP "\fBmap"
-Map special characters on input or output
+Map characters on input or output
 .IP "\fBcolor"
 Colorize tio text using ANSI color code ranging from 0 to 255
 .IP "\fBhexadecimal"
 Enable hexadecimal mode
 .IP "\fBsocket"
 Set socket to redirect I/O to
+.IP "\fBprefix-ctrl-key"
+Set prefix ctrl key (a..z, default: t)
 
 .SH "CONFIGURATION FILE EXAMPLES"
 
@@ -301,7 +348,7 @@ databits = 8
 parity = none
 stopbits = 1
 color = 10
-dtr-pulse-duration = 50
+line-pulse-duration = DTR=200,RTS=400
 .ec
 .fi
 .RE
@@ -419,7 +466,12 @@ Then, use netcat to connect to the shared tty session over network (assuming tio
 $ nc -N 10.0.0.42 4444
 
 .TP
-Pipe data from file to the serial device:
+Pipe command to the serial device:
+
+$ echo "ls -la" | tio /dev/serial/by\-id/usb\-FTDI_TTL232R-3V3_FTGQVXBL\-if00\-port0
+.TP
+Likewise, to pipe data from file to the serial device:
 
 $ cat data.bin | tio /dev/serial/by\-id/usb\-FTDI_TTL232R-3V3_FTGQVXBL\-if00\-port0
 
diff --git a/man/tio.1.txt b/man/tio.1.txt
new file mode 100644 (file)
index 0000000..dc1072a
--- /dev/null
@@ -0,0 +1,390 @@
+tio(1)                                                        User Commands                                                        tio(1)
+
+NAME
+       tio - a simple serial device I/O tool
+
+SYNOPSIS
+       tio [<options>] <tty-device|sub-config>
+
+DESCRIPTION
+       tio  is  a simple serial device tool which features a straightforward command-line and configuration file interface to easily con‐
+       nect to serial TTY devices for basic I/O operations.
+
+OPTIONS
+       -b, --baudrate <bps>
+
+              Set baud rate [bps] (default: 115200).
+
+       -d, --databits 5|6|7|8
+
+              Set data bits (default: 8).
+
+       -f, --flow hard|soft|none
+
+              Set flow control (default: none).
+
+       -s, --stopbits 1|2
+
+              Set stop bits (default: 1).
+
+       -p, --parity odd|even|none|mark|space
+
+              Set parity (default: none).
+
+              Note: With mark parity the parity bit is always 0. With space parity the parity bit is always 1. Not all platforms  support
+              mark and space parity.
+
+       -o, --output-delay <ms>
+
+              Set output delay [ms] inserted between each sent character (default: 0).
+
+       -O, --output-line-delay <ms>
+
+              Set output delay [ms] inserted between each sent line (default: 0).
+
+           --line-pulse-duration <duration>
+
+              Set  the  pulse  duration  [ms]  of  each serial port line using the following key valur pair format in the duration field:
+              <key>=<value>
+
+              Each key represents a serial line. The following keys are available:
+
+              DTR - Data Terminal Ready
+
+              RTS - Request To Send
+
+              CTS - Clear To Send
+
+              DSR - Data Set Ready
+
+              DCD - Data Carrier Detect
+
+              RI  - Ring Indicator
+
+              If defining more than one key value pair, the pairs must be comma separated.
+
+              The default pulse duration for each line is 100 ms.
+
+       -n, --no-autoconnect
+
+              Disable automatic connect.
+
+              By default tio automatically connects to the provided device if present. If the device is not present, it will wait for  it
+              to appear and then connect. If the connection is lost (eg. device disconnects), it will wait for the device to reappear and
+              then reconnect.
+
+              However, if the --no-autoconnect option is provided, tio will exit if the device is not present or an  established  connec‐
+              tion is lost.
+
+       -e, --local-echo
+
+              Enable local echo.
+
+       -t, --timestamp
+
+              Enable line timestamp.
+
+           --timestamp-format <format>
+
+              Set timestamp format to any of the following timestamp formats:
+
+              24hour          24-hour format ("hh:mm:ss.sss")
+
+              24hour-start    24-hour format relative to start time
+
+              24hour-delta    24-hour format relative to previous timestamp
+
+              iso8601         ISO8601 format ("YYYY-MM-DDThh:mm:ss.sss")
+
+              Default format is 24hour
+
+       -L, --list-devices
+
+              List available serial devices.
+
+       -l, --log
+
+              Enable log to file.
+
+              If no filename is provided the filename will be automatically generated.
+
+           --log-file <filename>
+
+              Set log filename.
+
+           --log-strip
+
+              Strip control characters and escape sequences from log.
+
+       -m, --map <flags>
+
+              Map (replace, translate) characters on input or output. The following mapping flags are supported:
+
+              ICRNL       Map CR to NL on input (unless IGNCR is set)
+
+              IGNCR       Ignore CR on input
+
+              INLCR       Map NL to CR on input
+
+              INLCRNL     Map NL to CR-NL on input
+
+              OCRNL       Map CR to NL on output
+
+              ODELBS      Map DEL to BS on output
+
+              ONLCRNL     Map NL to CR-NL on output
+
+              OLTU        Map lowercase characters to uppercase on output
+
+              If defining more than one flag, the flags must be comma separated.
+
+       -x, --hexadecimal
+
+              Enable hexadecimal mode.
+
+       -c, --color 0..255|bold|none|list
+
+              Colorize  tio text using ANSI color code value ranging from 0 to 255 or use "none" for no color or use "bold" to apply bold
+              formatting to existing system color.
+
+              Use "list" to print a list of available ANSI color codes.
+
+              Default value is "bold".
+
+       -S, --socket <socket>
+
+              Redirect I/O to socket. Any input from clients connected to the socket is sent on the serial port as if entered at the ter‐
+              minal  where tio is running (except that ctrl-t sequences are not recognized), and any input from the serial port is multi‐
+              plexed to the terminal and all connected clients.
+
+              Sockets remain open while the serial port is disconnected, and writes will block.
+
+              Various socket types are supported using the following prefixes in the socket field:
+
+              unix:<filename>     Unix Domain Socket (file)
+
+              inet:<port>         Internet Socket (network)
+
+              inet6:<port>        Internet IPv6 Socket (network)
+
+              If port is 0 or no port is provided default port 3333 is used.
+
+              At present there is a hardcoded limit of 16 clients connected at one time.
+
+       -v, --version
+
+              Display program version.
+
+       -h, --help
+
+              Display help.
+
+KEYS
+       In session, the following key sequences, a prefix key (default: ctrl-t) followed by a command key, are  intercepted  as  tio  com‐
+       mands:
+
+       ctrl-t ?        List available key commands
+
+       ctrl-t b        Send serial break (triggers SysRq on Linux, etc.)
+
+       ctrl-t c        Show configuration (baudrate, databits, etc.)
+
+       ctrl-t e        Toggle local echo mode
+
+       ctrl-t g        Toggle serial port line
+
+       ctrl-t h        Toggle hexadecimal mode
+
+       ctrl-t l        Clear screen
+
+       ctrl-t L        Show line states (DTR, RTS, CTS, DSR, DCD, RI)
+
+       ctrl-t p        Pulse serial port line
+
+       ctrl-t q        Quit
+
+       ctrl-t s        Show TX/RX statistics
+
+       ctrl-t t        Toggle line timestamp mode
+
+       ctrl-t U        Toggle conversion to uppercase on output
+
+       ctrl-t v        Show version
+
+HEXADECIMAL MODE
+       In hexadecimal mode each incoming byte is printed out as a hexadecimal value.
+
+       Bytes  can  be  sent  in this mode by typing the two-character hexadecimal representation of the value, e.g.: to send 0xA you must
+       type 0a or 0A.
+
+CONFIGURATION FILE
+       Options can be set via configuration file using the INI format. tio uses the configuration file first found in the following loca‐
+       tions in the order listed:
+
+       $XDG_CONFIG_HOME/tio/tiorc
+
+       $HOME/.config/tio/tiorc
+
+       $HOME/.tiorc
+
+       Labels can be used to group settings into named sub-configurations which can be activated from the command-line when starting tio.
+
+       tio will try to match the user input to a sub-configuration by name or by pattern to get the tty and other options.
+
+       Options without any label change the default options.
+
+       Any options set via command-line will override options set in the configuration file.
+
+       The following configuration file options are available:
+
+       pattern              Pattern matching user input. This pattern can be an extended regular expression with a single group.
+
+       tty                  tty device to open. If it contains a "%s" it is substituted with the first group match.
+
+       baudrate             Set baud rate
+
+       databits             Set data bits
+
+       flow                 Set flow control
+
+       stopbits             Set stop bits
+
+       parity               Set parity
+
+       output-delay         Set output character delay
+
+       output-line-delay    Set output line delay
+
+       line-pulse-duration  Set line pulse duration
+
+       no-autoconnect       Disable automatic connect
+
+       log                  Enable log to file
+
+       log-file             Set log filename
+
+       log-strip            Enable strip of control and escape sequences from log
+
+       local-echo           Enable local echo
+
+       timestamp            Enable line timestamp
+
+       timestamp-format     Set timestamp format
+
+       map                  Map characters on input or output
+
+       color                Colorize tio text using ANSI color code ranging from 0 to 255
+
+       hexadecimal          Enable hexadecimal mode
+
+       socket               Set socket to redirect I/O to
+
+       prefix-ctrl-key      Set prefix ctrl key (a..z, default: t)
+
+CONFIGURATION FILE EXAMPLES
+       To change the default configuration simply set options like so:
+
+              # Defaults
+              baudrate = 9600
+              databits = 8
+              parity = none
+              stopbits = 1
+              color = 10
+              line-pulse-duration = DTR=200,RTS=400
+
+       Named sub-configurations can be added via labels:
+
+              [rpi3]
+              tty = /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
+              baudrate = 115200
+              color = 11
+
+       Activate the sub-configuration by name:
+
+              $ tio rpi3
+
+       Which is equivalent to:
+
+              $ tio -b 115200 -c 11 /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
+
+       A sub-configuration can also be activated by its pattern which supports regular expressions:
+
+              [usb device]
+              pattern = usb([0-9]*)
+              tty = /dev/ttyUSB%s
+              baudrate = 115200
+
+       Activate the sub-configuration by pattern match:
+
+              $ tio usb12
+
+       Which is equivalent to:
+
+              $ tio -b 115200 /dev/ttyUSB12
+
+       It is also possible to combine use of sub-configuration and command-line options. For example:
+
+              $ tio -l -t usb12
+
+EXAMPLES
+       Typical use is without options:
+
+              $ tio /dev/ttyUSB0
+
+       Which corresponds to the commonly used default options:
+
+              $ tio -b 115200 -d 8 -f none -s 1 -p none /dev/ttyUSB0
+
+       It is recommended to connect serial tty devices by ID:
+
+              $ tio /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
+
+       Using  serial  devices by ID ensures that tio automatically reconnects to the correct serial device if it is disconnected and then
+       reconnected.
+
+       Redirect serial device I/O to Unix file socket for scripting:
+
+              $ tio -S unix:/tmp/tmux-socket0 /dev/ttyUSB0
+
+       Then, to issue a command via the file socket simply do:
+
+              $ echo "ls -la" | nc -UN /tmp/tmux-socket0 > /dev/null
+
+       Or use the expect command to script an interaction:
+
+              #!/usr/bin/expect -f
+
+              set timeout -1
+              log_user 0
+
+              spawn nc -UN /tmp/tio-socket0
+              set uart $spawn_id
+
+              send -i $uart "date\n"
+              expect -i $uart "prompt> "
+              send -i $uart "ls -la\n"
+              expect -i $uart "prompt> "
+
+       Redirect device I/O to network file socket for remote tty sharing:
+
+              $ tio --socket inet:4444 /dev/ttyUSB0
+
+       Then, use netcat to connect to the shared tty session over network (assuming tio is hosted on IP 10.0.0.42):
+
+              $ nc -N 10.0.0.42 4444
+
+       Pipe command to the serial device:
+
+              $ echo "ls -la" | tio /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
+
+       Likewise, to pipe data from file to the serial device:
+
+              $ cat data.bin | tio /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
+
+WEBSITE
+       Visit https://tio.github.io
+
+AUTHOR
+       Created by Martin Lund <martin.lund@keep-it-simple.com>.
+
+tio 1.46                                                        2022-07-15                                                         tio(1)
index 60d139a92a6218c11df9369a931c7547fc9f9db2..6f11ea41c5d9b2eea3ed91b4c2ae5fcdbe9410da 100644 (file)
@@ -1,12 +1,12 @@
 project('tio', 'c',
-    version : '1.43',
+    version : '1.47',
     license : [ 'GPL-2'],
     meson_version : '>= 0.53.2',
     default_options : [ 'warning_level=2', 'buildtype=release', 'c_std=gnu99' ]
 )
 
 # The tag date of the project_version(), update when the version bumps.
-version_date = '2022-07-09'
+version_date = '2022-07-23'
 
 # Test for dynamic baudrate configuration interface
 compiler = meson.get_compiler('c')
index 320601c9d9acde6ce1c2412d2ec2d3fb638a87fb..3d87cb690f28d91604e62fcecf34250b3f9b3ca6 100644 (file)
@@ -16,7 +16,8 @@ _tio()
           -s --stopbits \
           -p --parity \
           -o --output-delay \
-             --dtr-pulse-duration \
+          -o --output-line-delay \
+             --line-pulse-duration \
           -n --no-autoconnect \
           -e --local-echo \
           -l --log \
@@ -56,11 +57,15 @@ _tio()
             return 0
             ;;
         -o | --output-delay)
-            COMPREPLY=( $(compgen -W "1 10 100" -- ${cur}) )
+            COMPREPLY=( $(compgen -W "1 10 100" -- ${cur}) )
             return 0
             ;;
-        --dtr-pulse-duration)
-            COMPREPLY=( $(compgen -W "10 50 100 500" -- ${cur}) )
+        -O | --output-line-delay)
+            COMPREPLY=( $(compgen -W "1 10 100" -- ${cur}) )
+            return 0
+            ;;
+        --line-pulse-duration)
+            COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
             return 0
             ;;
         -n | --no-autoconnect)
@@ -75,11 +80,11 @@ _tio()
             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
             return 0
             ;;
-        -l | --log-file)
+        --log-file)
             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
             return 0
             ;;
-        -l | --log-strip)
+        --log-strip)
             COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
             return 0
             ;;
index 84c76d2168358cf1392b277b436fac1301e704c4..b8a16492ea2513f5b3c57813a3c8aa383b1914db 100644 (file)
@@ -58,7 +58,7 @@ static int get_match(const char *input, const char *pattern, char **match)
     if (ret)
     {
         regerror(ret, &re, err, sizeof(err));
-        fprintf(stderr, "regex error: %s", err);
+        tio_error_printf("Regex failure: %s", err);
         return ret;
     }
 
@@ -124,9 +124,13 @@ static int data_handler(void *user, const char *section, const char *name,
         {
             option.output_delay = atoi(value);
         }
-        else if (!strcmp(name, "dtr-pulse-duration"))
+        else if (!strcmp(name, "output-line-delay"))
         {
-            option.dtr_pulse_duration = atoi(value);
+            option.output_line_delay = atoi(value);
+        }
+        else if (!strcmp(name, "line-pulse-duration"))
+        {
+            line_pulse_duration_option_parse(value);
         }
         else if (!strcmp(name, "no-autoconnect"))
         {
@@ -215,12 +219,16 @@ static int data_handler(void *user, const char *section, const char *name,
                 // Ignore
                 return 0;
             }
-
-            if (!strcmp(value, "none"))
+            else if (!strcmp(value, "none"))
             {
                 option.color = -1; // No color
                 return 0;
             }
+            else if (!strcmp(value, "bold"))
+            {
+                option.color = 256; // Bold
+                return 0;
+            }
 
             option.color = atoi(value);
             if ((option.color < 0) || (option.color > 255))
@@ -233,6 +241,15 @@ static int data_handler(void *user, const char *section, const char *name,
             asprintf(&c->socket, "%s", value);
             option.socket = c->socket;
         }
+        else if (!strcmp(name, "prefix-ctrl-key"))
+        {
+            if (ctrl_key_code(value[0]) > 0)
+            {
+                option.prefix_code = ctrl_key_code(value[0]);
+                option.prefix_key = value[0];
+            }
+        }
+
     }
     return 0;
 }
@@ -326,7 +343,7 @@ void config_file_parse(void)
     c = malloc(sizeof(struct config_t));
     if (!c)
     {
-        fprintf(stderr, "Error: Insufficient memory allocation");
+        tio_error_printf("Insufficient memory allocation");
         exit(EXIT_FAILURE);
     } 
     memset(c, 0, sizeof(struct config_t));
@@ -351,7 +368,7 @@ void config_file_parse(void)
     ret = ini_parse(c->path, data_handler, NULL);
     if (ret < 0)
     {
-        fprintf(stderr, "Error: Unable to parse configuration file (%d)", ret);
+        tio_error_printf("Unable to parse configuration file (%d)", ret);
         exit(EXIT_FAILURE);
     }
     free(c->section_name);
@@ -364,7 +381,7 @@ void config_file_parse(void)
         ret = ini_parse(c->path, section_name_search_handler, NULL);
         if (!c->section_name)
         {
-            debug_printf("Unable to match user input to configuration section (%d)", ret);
+            tio_debug_printf("Unable to match user input to configuration section (%d)", ret);
             return;
         }
     }
@@ -373,7 +390,7 @@ void config_file_parse(void)
     ret = ini_parse(c->path, data_handler, NULL);
     if (ret < 0)
     {
-        fprintf(stderr, "Error: Unable to parse configuration file (%d)", ret);
+        tio_error_printf("Unable to parse configuration file (%d)", ret);
         exit(EXIT_FAILURE);
     }
 
index 8e25a8cde26d5d32e5d19cdad5a65601dc0d3b5d..4e0142fc8f639beb56d00f7e3bf1f752d2226488 100644 (file)
  * 02110-1301, USA.
  */
 
+#define __STDC_WANT_LIB_EXT2__ 1   // To access vasprintf
+
 #include "config.h"
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
 #include <string.h>
 #include <errno.h>
 #include "options.h"
 #include "print.h"
 #include "error.h"
 
-char error[2][1000];
+static char error[2][1000];
+static bool in_session = false;
+
+void error_enter_session_mode(void)
+{
+  in_session = true;
+}
+
+void error_printf_(const char *format, ...)
+{
+  va_list args;
+  char *line;
+
+  va_start(args, format);
+  vasprintf(&line, format, args);
+
+  if (in_session)
+  {
+    if (print_tainted)
+    {
+      putchar('\n');
+    }
+    ansi_error_printf("[%s] %s", current_time(), line);
+  }
+  else
+  {
+    fprintf(stderr, "%s\n", line);
+  }
+
+  va_end(args);
+
+  print_tainted = false;
+  free(line);
+}
+
+void tio_error_printf(const char *format, ...)
+{
+  va_list args;
+
+  va_start(args, format);
+  vsnprintf(error[0], 1000, format, args);
+  va_end(args);
+}
+
+void tio_error_printf_silent(const char *format, ...)
+{
+  va_list args;
+
+  va_start(args, format);
+  vsnprintf(error[1], 1000, format, args);
+  va_end(args);
+}
 
 void error_exit(void)
 {
   if (error[0][0] != 0)
   {
     /* Print error */
-    tio_error_printf("Error: %s", error[0]);
+    error_printf_("Error: %s", error[0]);
   }
   else if ((error[1][0] != 0) && (option.no_autoconnect))
   {
     /* Print silent error */
-    tio_error_printf("Error: %s", error[1]);
+    error_printf_("Error: %s", error[1]);
   }
 }
index a7c9d4564eb05744483823d3039dc68ad61c740b..109d0022e79664458a4687820e82395183b0f376 100644 (file)
@@ -24,6 +24,7 @@
 #define TIO_SUCCESS 0
 #define TIO_ERROR   1
 
-extern char error[2][1000];
-
+void tio_error_printf(const char *format, ...);
+void tio_error_printf_silent(const char *format, ...);
 void error_exit(void);
+void error_enter_session_mode(void);
diff --git a/src/iossiospeed.c b/src/iossiospeed.c
deleted file mode 100644 (file)
index 8fa0d5f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * tio - a simple serial terminal I/O tool
- *
- * Copyright (c) 2017  Martin Lund
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include <sys/ioctl.h>
-#include <IOKit/serial/ioss.h>
-
-int iossiospeed(int fd, int baudrate)
-{
-  return ioctl(fd, IOSSIOSPEED, (char *)&baudrate);
-}
index b1577ec6604829e2f1f0edc604318eef1eef3998..aa868470e2e2bef1dd78cc1a379705189dcba84d 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -76,8 +76,8 @@ void log_open(const char *filename)
         exit(EXIT_FAILURE);
     }
 
-    // Enable full buffering
-    setvbuf(fp, file_buffer, _IOFBF, BUFSIZ);
+    // Enable line buffering
+    setvbuf(fp, file_buffer, _IOLBF, BUFSIZ);
 }
 
 bool log_strip(char c)
@@ -188,7 +188,7 @@ void log_exit(void)
 
     if (log_error)
     {
-        error_printf("Could not open log file %s (%s)", option.log_filename, strerror(errno));
+        tio_error_printf("Could not open log file %s (%s)", option.log_filename, strerror(errno));
     }
     else if (option.log)
     {
index 519e8d962cce14b6f87a1206c78bb485f6820b79..7f31645ddb229bd48577ce5cc6e8127fc13b1bb4 100644 (file)
@@ -88,11 +88,18 @@ int main(int argc, char *argv[])
     /* Initialize ANSI text formatting (colors etc.) */
     print_init_ansi_formatting();
 
+    /* Change error printing mode */
+    error_enter_session_mode();
+
     /* Print launch hints */
     tio_printf("tio v%s", VERSION);
     if (interactive_mode)
     {
-        tio_printf("Press ctrl-t q to quit");
+        tio_printf("Press ctrl-%c q to quit", option.prefix_key);
+    } else
+    {
+        tio_printf("Non-interactive mode enabled");
+        tio_printf("Press ctrl-c to quit");
     }
 
     /* Open socket */
@@ -102,7 +109,7 @@ int main(int argc, char *argv[])
     }
 
     /* Connect to tty device */
-    if ((option.no_autoconnect) || (!interactive_mode))
+    if (option.no_autoconnect)
     {
         status = tty_connect();
     }
index 38d300ad43d87f597aafa631bc0763ad91e1398b..464f4f3ea9ab8f40cd5cbed03db346f76ee44a02 100644 (file)
@@ -13,7 +13,8 @@ tio_sources = [
   'print.c',
   'configfile.c',
   'signals.c',
-  'socket.c'
+  'socket.c',
+  'setspeed.c'
 ]
 
 tio_dep = dependency('inih', required: true,
@@ -23,12 +24,10 @@ tio_dep = dependency('inih', required: true,
 tio_c_args = ['-Wno-unused-result']
 
 if enable_setspeed2
-  tio_sources += 'setspeed2.c'
   tio_c_args += '-DHAVE_TERMIOS2'
 endif
 
 if enable_iossiospeed
-  tio_sources += 'iossiospeed.c'
   tio_c_args += '-DHAVE_IOSSIOSPEED'
 endif
 
index 7e8ffbddba16a6ff258a2e4c7394651e708abadb..c519c4610bf68b408dd9319c644b7b43708167c1 100644 (file)
@@ -62,15 +62,13 @@ char *current_time(void)
         case TIMESTAMP_24HOUR_START:
             // "hh:mm:ss.sss" (24 hour format relative to start time)
             timersub(&tv_now, &tv_start, &tv);
-            tv.tv_sec -= 3600; // Why is this needed??
-            tm = localtime(&tv.tv_sec);
+            tm = gmtime(&tv.tv_sec);
             len = strftime(time_string, sizeof(time_string), "%H:%M:%S", tm);
             break;
         case TIMESTAMP_24HOUR_DELTA:
             // "hh:mm:ss.sss" (24 hour format relative to previous time stamp)
             timersub(&tv_now, &tv_previous, &tv);
-            tv.tv_sec -= 3600; // Why is this needed??
-            tm = localtime(&tv.tv_sec);
+            tm = gmtime(&tv.tv_sec);
             len = strftime(time_string, sizeof(time_string), "%H:%M:%S", tm);
             break;
         case TIMESTAMP_ISO8601:
@@ -99,6 +97,11 @@ void delay(long ms)
 {
     struct timespec ts;
 
+    if (ms <= 0)
+    {
+        return;
+    }
+
     ts.tv_sec = ms / 1000;
     ts.tv_nsec = (ms % 1000) * 1000000;
 
@@ -120,3 +123,13 @@ long string_to_long(char *string)
 
     return result;
 }
+
+int ctrl_key_code(unsigned char key)
+{
+    if ((key >= 'a') && (key <= 'z'))
+    {
+        return key & ~0x60;
+    }
+
+    return -1;
+}
index 734cd9b07f86fd056f4170e58aaed026d5bbc32e..23208a653b860a9a061c61e79885b19610370303 100644 (file)
@@ -26,3 +26,4 @@
 char * current_time(void);
 void delay(long ms);
 long string_to_long(char *string);
+int ctrl_key_code(unsigned char key);
index 00a21c478bc422a6c0c166746eb74f56b2aa4480..49646745359c755c4394b5994bcd04dc9b209314 100644 (file)
@@ -42,7 +42,7 @@ enum opt_t
     OPT_TIMESTAMP_FORMAT,
     OPT_LOG_FILE,
     OPT_LOG_STRIP,
-    OPT_DTR_PULSE_DURATION,
+    OPT_LINE_PULSE_DURATION,
 };
 
 /* Default options */
@@ -55,7 +55,13 @@ struct option_t option =
     .stopbits = 1,
     .parity = "none",
     .output_delay = 0,
+    .output_line_delay = 0,
     .dtr_pulse_duration = 100,
+    .rts_pulse_duration = 100,
+    .cts_pulse_duration = 100,
+    .dsr_pulse_duration = 100,
+    .dcd_pulse_duration = 100,
+    .ri_pulse_duration = 100,
     .no_autoconnect = false,
     .log = false,
     .log_filename = NULL,
@@ -64,8 +70,10 @@ struct option_t option =
     .timestamp = TIMESTAMP_NONE,
     .socket = NULL,
     .map = "",
-    .color = 15,
+    .color = 256, // Bold
     .hex_mode = false,
+    .prefix_code = 20, // ctrl-t
+    .prefix_key = 't',
 };
 
 void print_help(char *argv[])
@@ -75,32 +83,31 @@ void print_help(char *argv[])
     printf("Connect to tty device directly or via sub-configuration.\n");
     printf("\n");
     printf("Options:\n");
-    printf("  -b, --baudrate <bps>             Baud rate (default: 115200)\n");
-    printf("  -d, --databits 5|6|7|8           Data bits (default: 8)\n");
-    printf("  -f, --flow hard|soft|none        Flow control (default: none)\n");
-    printf("  -s, --stopbits 1|2               Stop bits (default: 1)\n");
-    printf("  -p, --parity odd|even|none       Parity (default: none)\n");
-    printf("  -o, --output-delay <ms>          Output delay (default: 0)\n");
-    printf("      --dtr-pulse-duration <ms>    DTR pulse duration (default: 100)\n");
-    printf("  -n, --no-autoconnect             Disable automatic connect\n");
-    printf("  -e, --local-echo                 Enable local echo\n");
-    printf("  -t, --timestamp                  Enable line timestamp\n");
-    printf("      --timestamp-format <format>  Set timestamp format (default: 24hour)\n");
-    printf("  -L, --list-devices               List available serial devices\n");
-    printf("  -l, --log                        Enable log to file\n");
-    printf("      --log-file <filename>        Set log filename\n");
-    printf("      --log-strip                  Strip control characters and escape sequences\n");
-    printf("  -m, --map <flags>                Map special characters\n");
-    printf("  -c, --color 0..255|none|list     Colorize tio text (default: 15)\n");
-    printf("  -S, --socket <socket>            Redirect I/O to file or network socket\n");
-    printf("  -x, --hexadecimal                Enable hexadecimal mode\n");
-    printf("  -v, --version                    Display version\n");
-    printf("  -h, --help                       Display help\n");
+    printf("  -b, --baudrate <bps>                   Baud rate (default: 115200)\n");
+    printf("  -d, --databits 5|6|7|8                 Data bits (default: 8)\n");
+    printf("  -f, --flow hard|soft|none              Flow control (default: none)\n");
+    printf("  -s, --stopbits 1|2                     Stop bits (default: 1)\n");
+    printf("  -p, --parity odd|even|none|mark|space  Parity (default: none)\n");
+    printf("  -o, --output-delay <ms>                Output character delay (default: 0)\n");
+    printf("  -O, --output-line-delay <ms>           Output line delay (default: 0)\n");
+    printf("      --line-pulse-duration <duration>   Set line pulse duration\n");
+    printf("  -n, --no-autoconnect                   Disable automatic connect\n");
+    printf("  -e, --local-echo                       Enable local echo\n");
+    printf("  -t, --timestamp                        Enable line timestamp\n");
+    printf("      --timestamp-format <format>        Set timestamp format (default: 24hour)\n");
+    printf("  -L, --list-devices                     List available serial devices\n");
+    printf("  -l, --log                              Enable log to file\n");
+    printf("      --log-file <filename>              Set log filename\n");
+    printf("      --log-strip                        Strip control characters and escape sequences\n");
+    printf("  -m, --map <flags>                      Map characters\n");
+    printf("  -c, --color 0..255|bold|none|list      Colorize tio text (default: bold)\n");
+    printf("  -S, --socket <socket>                  Redirect I/O to file or network socket\n");
+    printf("  -x, --hexadecimal                      Enable hexadecimal mode\n");
+    printf("  -v, --version                          Display version\n");
+    printf("  -h, --help                             Display help\n");
     printf("\n");
     printf("Options and sub-configurations may be set via configuration file.\n");
     printf("\n");
-    printf("In session, press ctrl-t q to quit.\n");
-    printf("\n");
     printf("See the man page for more details.\n");
 }
 
@@ -161,6 +168,63 @@ enum timestamp_t timestamp_option_parse(const char *arg)
     return timestamp;
 }
 
+void line_pulse_duration_option_parse(const char *arg)
+{
+    bool token_found = true;
+    char *token = NULL;
+    char *buffer = strdup(arg);
+
+    while (token_found == true)
+    {
+        if (token == NULL)
+        {
+            token = strtok(buffer,",");
+        }
+        else
+        {
+            token = strtok(NULL, ",");
+        }
+
+        if (token != NULL)
+        {
+            char keyname[10];
+            unsigned int value;
+            sscanf(token, "%10[^=]=%d", keyname, &value);
+
+            if (!strcmp(keyname, "DTR"))
+            {
+                option.dtr_pulse_duration = value;
+            }
+            else if (!strcmp(keyname, "RTS"))
+            {
+                option.rts_pulse_duration = value;
+            }
+            else if (!strcmp(keyname, "CTS"))
+            {
+                option.cts_pulse_duration = value;
+            }
+            else if (!strcmp(keyname, "DSR"))
+            {
+                option.dsr_pulse_duration = value;
+            }
+            else if (!strcmp(keyname, "DCD"))
+            {
+                option.dcd_pulse_duration = value;
+            }
+            else if (!strcmp(keyname, "RI"))
+            {
+                option.ri_pulse_duration = value;
+            }
+        }
+        else
+        {
+            token_found = false;
+        }
+    }
+    free(buffer);
+
+}
+
 void options_print()
 {
     tio_printf(" TTY device: %s", option.tty_device);
@@ -172,8 +236,15 @@ void options_print()
     tio_printf(" Local echo: %s", option.local_echo ? "enabled" : "disabled");
     tio_printf(" Timestamp: %s", timestamp_state_to_string(option.timestamp));
     tio_printf(" Output delay: %d", option.output_delay);
+    tio_printf(" Output line delay: %d", option.output_line_delay);
     tio_printf(" DTR pulse duration: %d", option.dtr_pulse_duration);
     tio_printf(" Auto connect: %s", option.no_autoconnect ? "disabled" : "enabled");
+    tio_printf(" Pulse duration: DTR=%d RTS=%d CTS=%d DSR=%d DCD=%d RI=%d", option.dtr_pulse_duration,
+                                                                            option.rts_pulse_duration,
+                                                                            option.cts_pulse_duration,
+                                                                            option.dsr_pulse_duration,
+                                                                            option.dcd_pulse_duration,
+                                                                            option.ri_pulse_duration);
     if (option.map[0] != 0)
         tio_printf(" Map flags: %s", option.map);
     if (option.log)
@@ -196,35 +267,36 @@ void options_parse(int argc, char *argv[])
     {
         static struct option long_options[] =
         {
-            {"baudrate",         required_argument, 0, 'b'                  },
-            {"databits",         required_argument, 0, 'd'                  },
-            {"flow",             required_argument, 0, 'f'                  },
-            {"stopbits",         required_argument, 0, 's'                  },
-            {"parity",           required_argument, 0, 'p'                  },
-            {"output-delay",     required_argument, 0, 'o'                  },
-            {"dtr-pulse-duration",   required_argument, 0, OPT_DTR_PULSE_DURATION   },
-            {"no-autoconnect",   no_argument,       0, 'n'                  },
-            {"local-echo",       no_argument,       0, 'e'                  },
-            {"timestamp",        no_argument,       0, 't'                  },
-            {"timestamp-format", required_argument, 0, OPT_TIMESTAMP_FORMAT },
-            {"list-devices",     no_argument,       0, 'L'                  },
-            {"log",              no_argument,       0, 'l'                  },
-            {"log-file",         required_argument, 0, OPT_LOG_FILE         },
-            {"log-strip",        no_argument,       0, OPT_LOG_STRIP        },
-            {"socket",           required_argument, 0, 'S'                  },
-            {"map",              required_argument, 0, 'm'                  },
-            {"color",            required_argument, 0, 'c'                  },
-            {"hexadecimal",      no_argument,       0, 'x'                  },
-            {"version",          no_argument,       0, 'v'                  },
-            {"help",             no_argument,       0, 'h'                  },
-            {0,                  0,                 0,  0                   }
+            {"baudrate",            required_argument, 0, 'b'                    },
+            {"databits",            required_argument, 0, 'd'                    },
+            {"flow",                required_argument, 0, 'f'                    },
+            {"stopbits",            required_argument, 0, 's'                    },
+            {"parity",              required_argument, 0, 'p'                    },
+            {"output-delay",        required_argument, 0, 'o'                    },
+            {"output-line-delay" ,  required_argument, 0, 'O'                    },
+            {"line-pulse-duration", required_argument, 0, OPT_LINE_PULSE_DURATION},
+            {"no-autoconnect",      no_argument,       0, 'n'                    },
+            {"local-echo",          no_argument,       0, 'e'                    },
+            {"timestamp",           no_argument,       0, 't'                    },
+            {"timestamp-format",    required_argument, 0, OPT_TIMESTAMP_FORMAT   },
+            {"list-devices",        no_argument,       0, 'L'                    },
+            {"log",                 no_argument,       0, 'l'                    },
+            {"log-file",            required_argument, 0, OPT_LOG_FILE           },
+            {"log-strip",           no_argument,       0, OPT_LOG_STRIP          },
+            {"socket",              required_argument, 0, 'S'                    },
+            {"map",                 required_argument, 0, 'm'                    },
+            {"color",               required_argument, 0, 'c'                    },
+            {"hexadecimal",         no_argument,       0, 'x'                    },
+            {"version",             no_argument,       0, 'v'                    },
+            {"help",                no_argument,       0, 'h'                    },
+            {0,                     0,                 0,  0                     }
         };
 
         /* getopt_long stores the option index here */
         int option_index = 0;
 
         /* Parse argument using getopt_long */
-        c = getopt_long(argc, argv, "b:d:f:s:p:o:netLlS:m:c:xvh", long_options, &option_index);
+        c = getopt_long(argc, argv, "b:d:f:s:p:o:O:netLlS:m:c:xvh", long_options, &option_index);
 
         /* Detect the end of the options */
         if (c == -1)
@@ -266,8 +338,12 @@ void options_parse(int argc, char *argv[])
                 option.output_delay = string_to_long(optarg);
                 break;
 
-            case OPT_DTR_PULSE_DURATION:
-                option.dtr_pulse_duration = string_to_long(optarg);
+            case 'O':
+                option.output_line_delay = string_to_long(optarg);
+                break;
+
+            case OPT_LINE_PULSE_DURATION:
+                line_pulse_duration_option_parse(optarg);
                 break;
 
             case 'n':
@@ -296,6 +372,7 @@ void options_parse(int argc, char *argv[])
                 break;
 
             case OPT_LOG_FILE:
+                option.log = true;
                 option.log_filename = optarg;
                 break;
 
@@ -322,17 +399,21 @@ void options_parse(int argc, char *argv[])
                     }
                     exit(EXIT_SUCCESS);
                 }
-
-                if (!strcmp(optarg, "none"))
+                else if (!strcmp(optarg, "none"))
+                {
+                    option.color = -1; // No color
+                    break;
+                }
+                else if (!strcmp(optarg, "bold"))
                 {
-                    option.color = -1;
+                    option.color = 256; // Bold
                     break;
                 }
 
                 option.color = string_to_long(optarg);
                 if ((option.color < 0) || (option.color > 255))
                 {
-                    printf("Error: Invalid color code\n");
+                    tio_error_printf("Invalid color code");
                     exit(EXIT_FAILURE);
                 }
                 break;
@@ -368,23 +449,23 @@ void options_parse(int argc, char *argv[])
 
     /* Assume first non-option is the tty device name */
     if (strcmp(option.tty_device, ""))
-           optind++;
+            optind++;
     else if (optind < argc)
         option.tty_device = argv[optind++];
 
     if (strlen(option.tty_device) == 0)
     {
-        printf("Error: Missing tty device or sub-configuration name\n");
+        tio_error_printf("Missing tty device or sub-configuration name");
         exit(EXIT_FAILURE);
     }
 
     /* Print any remaining command line arguments (unknown options) */
     if (optind < argc)
     {
-        printf("Error: Unknown argument ");
+        fprintf(stderr, "Error: Unknown argument ");
         while (optind < argc)
             printf("%s ", argv[optind++]);
-        printf("\n");
+        fprintf(stderr, "\n");
         exit(EXIT_FAILURE);
     }
 }
index b005a1ae91fce3ee3e5208fbcea0c5aa81cd44f0..ed8a4fa0fb2194a3474029ca1284f693e5d99e97 100644 (file)
@@ -48,7 +48,13 @@ struct option_t
     int stopbits;
     char *parity;
     int output_delay;
-    int dtr_pulse_duration;
+    int output_line_delay;
+    unsigned int dtr_pulse_duration;
+    unsigned int rts_pulse_duration;
+    unsigned int cts_pulse_duration;
+    unsigned int dsr_pulse_duration;
+    unsigned int dcd_pulse_duration;
+    unsigned int ri_pulse_duration;
     bool no_autoconnect;
     bool log;
     bool log_strip;
@@ -59,6 +65,8 @@ struct option_t
     const char *socket;
     int color;
     bool hex_mode;
+    unsigned char prefix_code;
+    unsigned char prefix_key;
 };
 
 extern struct option_t option;
@@ -66,3 +74,5 @@ extern struct option_t option;
 void options_print();
 void options_parse(int argc, char *argv[]);
 void options_parse_final(int argc, char *argv[]);
+
+void line_pulse_duration_option_parse(const char *arg);
index 68e663c1f6c5547e50e7cadeae849880b7884baa..359c0785ff04e155bdb8070788af3c02a6d118e8 100644 (file)
@@ -39,6 +39,14 @@ void print_normal(char c)
 
 void print_init_ansi_formatting()
 {
-  // Set bold text with user defined ANSI color
-  sprintf(ansi_format, "\e[1;38;5;%dm", option.color);
+  if (option.color == 256)
+  {
+    // Set bold text with no color changes
+    sprintf(ansi_format, "\e[1m");
+  }
+  else
+  {
+    // Set bold text with user defined ANSI color
+    sprintf(ansi_format, "\e[1;38;5;%dm", option.color);
+  }
 }
index 53c7eea05d86ea3003ee9dfa1e65afa71c23f88a..c212a7c875cd82bdc04cc40a87f0745eebad8e99 100644 (file)
@@ -42,7 +42,7 @@ extern char ansi_format[];
 #define ansi_error_printf(format, args...) \
 { \
   if (option.color < 0) \
-    fprintf (stdout, "\r" format "\r\n", ## args); \
+    fprintf (stderr, "\r" format "\r\n", ## args); \
   else \
     fprintf (stderr, "\r%s" format ANSI_RESET "\r\n", ansi_format, ## args); \
   fflush(stderr); \
@@ -56,7 +56,7 @@ extern char ansi_format[];
     fprintf (stdout, "%s" format ANSI_RESET, ansi_format, ## args); \
 }
 
-#define warning_printf(format, args...) \
+#define tio_warning_printf(format, args...) \
 { \
   if (print_tainted) \
     putchar('\n'); \
@@ -74,28 +74,14 @@ extern char ansi_format[];
   print_tainted = false; \
 }
 
-#define tio_error_printf(format, args...) \
-{ \
-  if (print_tainted) \
-    putchar('\n'); \
-  ansi_error_printf("[%s] " format, current_time(), ## args); \
-  print_tainted = false; \
-}
-
-#define error_printf(format, args...) \
-  snprintf(error[0], 1000, format, ## args);
-
-#define error_printf_silent(format, args...) \
-  snprintf(error[1], 1000, format, ## args);
-
 #ifdef DEBUG
-#define debug_printf(format, args...) \
+#define tio_debug_printf(format, args...) \
   fprintf (stdout, "[debug] " format, ## args)
-#define debug_printf_raw(format, args...) \
+#define tio_debug_printf_raw(format, args...) \
   fprintf (stdout, "" format, ## args)
 #else
-#define debug_printf(format, args...)
-#define debug_printf_raw(format, args...)
+#define tio_debug_printf(format, args...)
+#define tio_debug_printf_raw(format, args...)
 #endif
 
 void print_hex(char c);
diff --git a/src/setspeed.c b/src/setspeed.c
new file mode 100644 (file)
index 0000000..745bd4b
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * tio - a simple serial terminal I/O tool
+ *
+ * Copyright (c) 2017-2022  Martin Lund
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <errno.h>
+
+#ifdef HAVE_TERMIOS2
+#define termios asmtermios
+#include <sys/ioctl.h>
+#undef termios
+#include <asm-generic/ioctls.h>
+#include <asm-generic/termbits.h>
+
+#elif HAVE_IOSSIOSPEED
+#include <sys/ioctl.h>
+#include <IOKit/serial/ioss.h>
+#endif
+
+
+#ifdef HAVE_TERMIOS2
+int setspeed(int fd, int baudrate)
+{
+    struct termios2 tio;
+    int status;
+
+    status = ioctl(fd, TCGETS2, &tio);
+
+    // Set baudrate speed using termios2 interface
+    tio.c_cflag &= ~CBAUD;
+    tio.c_cflag |= BOTHER;
+    tio.c_ispeed = baudrate;
+    tio.c_ospeed = baudrate;
+
+    status = ioctl(fd, TCSETS2, &tio);
+
+    return status;
+}
+
+#elif HAVE_IOSSIOSPEED
+int setspeed(int fd, int baudrate)
+{
+    return ioctl(fd, IOSSIOSPEED, (char *)&baudrate);
+}
+
+#else
+int setspeed(int fd, int baudrate)
+{
+    errno = EINVAL;
+    return -1;
+}
+#endif
diff --git a/src/setspeed.h b/src/setspeed.h
new file mode 100644 (file)
index 0000000..c201f6e
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * tio - a simple serial terminal I/O tool
+ *
+ * Copyright (c) 2022  Martin Lund
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#pragma once
+
+int setspeed(int fd, int baudrate);
diff --git a/src/setspeed2.c b/src/setspeed2.c
deleted file mode 100644 (file)
index 64ecb4a..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * tio - a simple serial terminal I/O tool
- *
- * Copyright (c) 2017-2022  Martin Lund
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#define termios asmtermios
-#include <sys/ioctl.h>
-#undef termios
-#include <asm-generic/ioctls.h>
-#include <asm-generic/termbits.h>
-
-int setspeed2(int fd, int baudrate)
-{
-    struct termios2 tio;
-    int status;
-
-    status = ioctl(fd, TCGETS2, &tio);
-
-    // Set baudrate speed using termios2 interface
-    tio.c_cflag &= ~CBAUD;
-    tio.c_cflag |= BOTHER;
-    tio.c_ispeed = baudrate;
-    tio.c_ospeed = baudrate;
-
-    status = ioctl(fd, TCSETS2, &tio);
-
-    return status;
-}
index 364de8ba4f232c43beeb3127fc39ff6119574dc1..02ccbbe5b71c1ae6d112fe05caa87f8880955b73 100644 (file)
 #include "error.h"
 #include "print.h"
 #include "misc.h"
+#include "tty.h"
 
 static void signal_handler(int signum)
 {
-    UNUSED(signum);
-    tio_printf("Received hangup signal!");
+    switch (signum)
+    {
+        case SIGHUP:
+            tio_printf("Received SIGHUP signal!");
+            break;
+        case SIGINT:
+            tio_printf("Received SIGINT signal!");
+            break;
+    }
     exit(EXIT_FAILURE);
 }
 
 void signal_handlers_install(void)
 {
     signal(SIGHUP, signal_handler);
+    signal(SIGINT, signal_handler);
 }
index 13c204b8f473b751603159af40a07e1ef209abfe..c21904f15dd327cb2b200f7560cf5094d951b7f7 100644 (file)
@@ -94,13 +94,13 @@ void socket_configure(void)
 
         if (strlen(socket_filename()) == 0)
         {
-            error_printf("Missing socket filename");
+            tio_error_printf("Missing socket filename");
             exit(EXIT_FAILURE);
         }
 
         if (strlen(socket_filename()) > sizeof(sockaddr_unix.sun_path) - 1)
         {
-            error_printf("Socket file path %s too long", option.socket);
+            tio_error_printf("Socket file path %s too long", option.socket);
             exit(EXIT_FAILURE);
         }
     }
@@ -113,7 +113,7 @@ void socket_configure(void)
 
         if (port_number < 0)
         {
-            error_printf("Invalid port number: %d", port_number);
+            tio_error_printf("Invalid port number: %d", port_number);
             exit(EXIT_FAILURE);
         }
     }
@@ -126,14 +126,14 @@ void socket_configure(void)
 
         if (port_number < 0)
         {
-            error_printf("Invalid port number: %d", port_number);
+            tio_error_printf("Invalid port number: %d", port_number);
             exit(EXIT_FAILURE);
         }
     }
 
     if (socket_family == AF_UNSPEC)
     {
-        error_printf("%s: Invalid socket scheme, must be prefixed with 'unix:', 'inet:', or 'inet6:'", option.socket);
+        tio_error_printf("%s: Invalid socket scheme, must be prefixed with 'unix:', 'inet:', or 'inet6:'", option.socket);
         exit(EXIT_FAILURE);
     }
  
@@ -165,7 +165,7 @@ void socket_configure(void)
             break;
 
         default:
-            error_printf("Invalid socket family (%d)", socket_family);
+            tio_error_printf("Invalid socket family (%d)", socket_family);
             exit(EXIT_FAILURE);
             break;
     }
@@ -174,21 +174,21 @@ void socket_configure(void)
     sockfd = socket(socket_family, SOCK_STREAM, 0);
     if (sockfd < 0)
     {
-        error_printf("Failed to create socket (%s)", strerror(errno));
+        tio_error_printf("Failed to create socket (%s)", strerror(errno));
         exit(EXIT_FAILURE);
     }
 
     /* Bind */
     if (bind(sockfd, sockaddr_p, socklen) < 0)
     {
-        error_printf("Failed to bind to socket (%s)", strerror(errno));
+        tio_error_printf("Failed to bind to socket (%s)", strerror(errno));
         exit(EXIT_FAILURE);
     }
 
     /* Listen */
     if (listen(sockfd, MAX_SOCKET_CLIENTS) < 0)
     {
-        error_printf("Failed to listen on socket (%s)", strerror(errno));
+        tio_error_printf("Failed to listen on socket (%s)", strerror(errno));
         exit(EXIT_FAILURE);
     }
 
@@ -218,7 +218,7 @@ void socket_write(char input_char)
         {
             if (write(clientfds[i], &input_char, 1) <= 0)
             {
-                error_printf_silent("Failed to write to socket (%s)", strerror(errno));
+                tio_error_printf_silent("Failed to write to socket (%s)", strerror(errno));
                 close(clientfds[i]);
                 clientfds[i] = -1;
             }
@@ -289,7 +289,7 @@ bool socket_handle_input(fd_set *rdfs, char *output_char)
             }
             if (status < 0)
             {
-                error_printf_silent("Failed to read from socket (%s)", strerror(errno));
+                tio_error_printf_silent("Failed to read from socket (%s)", strerror(errno));
                 close(clientfds[i]);
                 clientfds[i] = -1;
                 continue;
index 4c0998860672639895cc66302a4a603f3b3316bc..43cfb9125cb32981fafc13ee22d61ca7a70f7810 100644 (file)
--- a/src/tty.c
+++ b/src/tty.c
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <sys/types.h>
 #include "log.h"
 #include "error.h"
 #include "socket.h"
-
-#ifdef HAVE_TERMIOS2
-extern int setspeed2(int fd, int baudrate);
-#endif
-
-#ifdef HAVE_IOSSIOSPEED
-extern int iossiospeed(int fd, int baudrate);
-#endif
+#include "setspeed.h"
 
 #ifdef __APPLE__
 #define PATH_SERIAL_DEVICES "/dev/"
@@ -63,6 +57,41 @@ extern int iossiospeed(int fd, int baudrate);
 #define PATH_SERIAL_DEVICES "/dev/serial/by-id/"
 #endif
 
+#ifndef CMSPAR
+#define CMSPAR   010000000000
+#endif
+
+#define KEY_0 0x30
+#define KEY_1 0x31
+#define KEY_2 0x32
+#define KEY_3 0x33
+#define KEY_4 0x34
+#define KEY_5 0x35
+#define KEY_QUESTION 0x3f
+#define KEY_B 0x62
+#define KEY_C 0x63
+#define KEY_E 0x65
+#define KEY_G 0x67
+#define KEY_H 0x68
+#define KEY_L 0x6C
+#define KEY_P 0x70
+#define KEY_Q 0x71
+#define KEY_S 0x73
+#define KEY_T 0x74
+#define KEY_U 0x55
+#define KEY_V 0x76
+#define KEY_SHIFT_L 0x4C
+
+#define NORMAL 0
+#define HEX 1
+
+enum line_mode_t
+{
+    LINE_OFF,
+    LINE_TOGGLE,
+    LINE_PULSE
+};
+
 bool interactive_mode = true;
 
 static struct termios tio, tio_old, stdout_new, stdout_old, stdin_new, stdin_old;
@@ -76,6 +105,7 @@ static bool map_i_nl_crnl = false;
 static bool map_o_cr_nl = false;
 static bool map_o_nl_crnl = false;
 static bool map_o_del_bs = false;
+static bool map_o_ltu = false;
 static char hex_chars[2];
 static unsigned char hex_char_index = 0;
 static char tty_buffer[BUFSIZ*2];
@@ -120,22 +150,23 @@ inline static unsigned char char_to_nibble(char c)
     }
 }
 
-void tty_flush(int fd)
+void tty_sync(int fd)
 {
     ssize_t count;
 
-    do
+    while (tty_buffer_count > 0)
     {
         count = write(fd, tty_buffer, tty_buffer_count);
         if (count < 0)
         {
             // Error
-            debug_printf("Write error while flushing tty buffer (%s)", strerror(errno));
+            tio_debug_printf("Write error while flushing tty buffer (%s)", strerror(errno));
             break;
         }
         tty_buffer_count -= count;
+        fsync(fd);
+        tcdrain(fd);
     }
-    while (tty_buffer_count > 0);
 
     // Reset
     tty_buffer_write_ptr = tty_buffer;
@@ -144,31 +175,52 @@ void tty_flush(int fd)
 
 ssize_t tty_write(int fd, const void *buffer, size_t count)
 {
-    ssize_t bytes_written = 0;
+    ssize_t retval = 0, bytes_written = 0;
+    size_t i;
+
+    if (map_o_ltu)
+    {
+        // Convert lower case to upper case
+        for (i = 0; i<count; i++)
+        {
+            *((unsigned char*)buffer+i) = toupper(*((unsigned char*)buffer+i));
+        }
+    }
 
-    if (option.output_delay)
+    if (option.output_delay || option.output_line_delay)
     {
         // Write byte by byte with output delay
-        for (size_t i=0; i<count; i++)
+        for (i=0; i<count; i++)
         {
-            ssize_t retval = write(fd, buffer, 1);
+            retval = write(fd, buffer, 1);
             if (retval < 0)
             {
                 // Error
-                debug_printf("Write error (%s)", strerror(errno));
+                tio_debug_printf("Write error (%s)", strerror(errno));
                 break;
             }
             bytes_written += retval;
+
+            if (option.output_line_delay && *(unsigned char*)buffer == '\r')
+            {
+                delay(option.output_line_delay);
+            }
+
             fsync(fd);
-            delay(option.output_delay);
+            tcdrain(fd);
+
+            if (option.output_delay)
+            {
+                delay(option.output_delay);
+            }
         }
     }
     else
     {
-        // Flush tty buffer if too full
+        // Force write of tty buffer if too full
         if ((tty_buffer_count + count) > BUFSIZ)
         {
-            tty_flush(fd);
+            tty_sync(fd);
         }
 
         // Copy bytes to tty write buffer
@@ -195,7 +247,7 @@ static void output_hex(char c)
         ssize_t status = tty_write(fd, &hex_value, 1);
         if (status < 0)
         {
-            warning_printf("Could not write to tty device");
+            tio_warning_printf("Could not write to tty device");
         }
         else
         {
@@ -204,28 +256,67 @@ static void output_hex(char c)
     }
 }
 
-static void toggle_line(const char *line_name, int mask)
+static void toggle_line(const char *line_name, int mask, enum line_mode_t line_mode)
 {
     int state;
 
-    if (ioctl(fd, TIOCMGET, &state) < 0)
-    {
-        warning_printf("Could not get line state (%s)", strerror(errno));
-    }
-    else
+    if (line_mode == LINE_TOGGLE)
     {
-        if (state & mask)
+        // Toggle line
+        if (ioctl(fd, TIOCMGET, &state) < 0)
         {
-            state &= ~mask;
-            tio_printf("set %s to LOW", line_name);
+            tio_warning_printf("Could not get line state (%s)", strerror(errno));
         }
         else
         {
-            state |= mask;
-            tio_printf("set %s to HIGH", line_name);
+            if (state & mask)
+            {
+                state &= ~mask;
+                tio_printf("Setting %s to LOW", line_name);
+            }
+            else
+            {
+                state |= mask;
+                tio_printf("Setting %s to HIGH", line_name);
+            }
+            if (ioctl(fd, TIOCMSET, &state) < 0)
+                tio_warning_printf("Could not set line state (%s)", strerror(errno));
+        }
+    } else if (line_mode == LINE_PULSE)
+    {
+        int duration = 0;
+        // Pulse line
+        toggle_line(line_name, mask, LINE_TOGGLE);
+        switch (mask)
+        {
+            case TIOCM_DTR:
+                duration = option.dtr_pulse_duration;
+                break;
+            case TIOCM_RTS:
+                duration = option.rts_pulse_duration;
+                break;
+            case TIOCM_CTS:
+                duration = option.cts_pulse_duration;
+                break;
+            case TIOCM_DSR:
+                duration = option.dsr_pulse_duration;
+                break;
+            case TIOCM_CD:
+                duration = option.dcd_pulse_duration;
+                break;
+            case TIOCM_RI:
+                duration = option.ri_pulse_duration;
+                break;
+            default:
+                duration = 0;
+                break;
         }
-        if (ioctl(fd, TIOCMSET, &state) < 0)
-            warning_printf("Could not set line state (%s)", strerror(errno));
+        if (duration > 0)
+        {
+            tio_printf("Waiting %d ms", duration);
+            delay(duration);
+        }
+        toggle_line(line_name, mask, LINE_TOGGLE);
     }
 }
 
@@ -234,16 +325,55 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
     char unused_char;
     bool unused_bool;
     int state;
+    static enum line_mode_t line_mode = LINE_OFF;
 
     /* Ignore unused arguments */
     if (output_char == NULL)
+    {
         output_char = &unused_char;
+    }
 
     if (forward == NULL)
+    {
         forward = &unused_bool;
+    }
+
+    if (line_mode)
+    {
+        // Handle line toggle number action
+        *forward = false;
+        switch (input_char)
+        {
+            case KEY_0:
+                toggle_line("DTR", TIOCM_DTR, line_mode);
+                break;
+            case KEY_1:
+                toggle_line("RTS", TIOCM_RTS, line_mode);
+                break;
+            case KEY_2:
+                toggle_line("CTS", TIOCM_CTS, line_mode);
+                break;
+            case KEY_3:
+                toggle_line("DSR", TIOCM_DSR, line_mode);
+                break;
+            case KEY_4:
+                toggle_line("DCD", TIOCM_CD, line_mode);
+                break;
+            case KEY_5:
+                toggle_line("RI", TIOCM_RI, line_mode);
+                break;
+            default:
+                tio_warning_printf("Invalid line number");
+                break;
+        }
+
+        line_mode = LINE_OFF;
+
+        return;
+    }
 
     /* Handle escape key commands */
-    if (previous_char == KEY_CTRL_T)
+    if (previous_char == option.prefix_code)
     {
         /* Do not forward input char to output by default */
         *forward = false;
@@ -252,27 +382,26 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
         {
             case KEY_QUESTION:
                 tio_printf("Key commands:");
-                tio_printf(" ctrl-t ?   List available key commands");
-                tio_printf(" ctrl-t b   Send break");
-                tio_printf(" ctrl-t c   Show configuration");
-                tio_printf(" ctrl-t d   Toggle DTR line");
-                tio_printf(" ctrl-t D   Pulse DTR line");
-                tio_printf(" ctrl-t e   Toggle local echo mode");
-                tio_printf(" ctrl-t h   Toggle hexadecimal mode");
-                tio_printf(" ctrl-t l   Clear screen");
-                tio_printf(" ctrl-t L   Show line states");
-                tio_printf(" ctrl-t q   Quit");
-                tio_printf(" ctrl-t r   Toggle RTS line");
-                tio_printf(" ctrl-t s   Show statistics");
-                tio_printf(" ctrl-t t   Send ctrl-t key code");
-                tio_printf(" ctrl-t T   Toggle line timestamp mode");
-                tio_printf(" ctrl-t v   Show version");
+                tio_printf(" ctrl-%c ?   List available key commands", option.prefix_key);
+                tio_printf(" ctrl-%c b   Send break", option.prefix_key);
+                tio_printf(" ctrl-%c c   Show configuration", option.prefix_key);
+                tio_printf(" ctrl-%c e   Toggle local echo mode", option.prefix_key);
+                tio_printf(" ctrl-%c g   Toggle serial port line", option.prefix_key);
+                tio_printf(" ctrl-%c h   Toggle hexadecimal mode", option.prefix_key);
+                tio_printf(" ctrl-%c l   Clear screen", option.prefix_key);
+                tio_printf(" ctrl-%c L   Show line states", option.prefix_key);
+                tio_printf(" ctrl-%c p   Pulse serial port line", option.prefix_key);
+                tio_printf(" ctrl-%c q   Quit", option.prefix_key);
+                tio_printf(" ctrl-%c s   Show statistics", option.prefix_key);
+                tio_printf(" ctrl-%c t   Toggle line timestamp mode", option.prefix_key);
+                tio_printf(" ctrl-%c U   Toggle conversion to uppercase on output", option.prefix_key);
+                tio_printf(" ctrl-%c v   Show version", option.prefix_key);
                 break;
 
             case KEY_SHIFT_L:
                 if (ioctl(fd, TIOCMGET, &state) < 0)
                 {
-                    warning_printf("Could not get line state (%s)", strerror(errno));
+                    tio_warning_printf("Could not get line state (%s)", strerror(errno));
                     break;
                 }
                 tio_printf("Line states:");
@@ -283,18 +412,29 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
                 tio_printf(" DCD: %s", (state & TIOCM_CD) ? "HIGH" : "LOW");
                 tio_printf(" RI : %s", (state & TIOCM_RI) ? "HIGH" : "LOW");
                 break;
-            case KEY_D:
-                toggle_line("DTR", TIOCM_DTR);
-                break;
 
-            case KEY_SHIFT_D:
-                toggle_line("DTR", TIOCM_DTR);
-                delay(option.dtr_pulse_duration);
-                toggle_line("DTR", TIOCM_DTR);
+            case KEY_G:
+                tio_printf("Please enter which serial line number to toggle:");
+                tio_printf(" DTR (0)");
+                tio_printf(" RTS (1)");
+                tio_printf(" CTS (2)");
+                tio_printf(" DSR (3)");
+                tio_printf(" DCD (4)");
+                tio_printf(" RI  (5)");
+                // Process next input character as part of the line toggle step
+                line_mode = LINE_TOGGLE;
                 break;
 
-            case KEY_R:
-                toggle_line("RTS", TIOCM_RTS);
+            case KEY_P:
+                tio_printf("Please enter which serial line number to pulse:");
+                tio_printf(" DTR (0)");
+                tio_printf(" RTS (1)");
+                tio_printf(" CTS (2)");
+                tio_printf(" DSR (3)");
+                tio_printf(" DCD (4)");
+                tio_printf(" RI  (5)");
+                // Process next input character as part of the line pulse step
+                line_mode = LINE_PULSE;
                 break;
 
             case KEY_B:
@@ -345,12 +485,6 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
                 break;
 
             case KEY_T:
-                /* Send ctrl-t key code upon ctrl-t t sequence */
-                *output_char = KEY_CTRL_T;
-                *forward = true;
-                break;
-
-            case KEY_SHIFT_T:
                 option.timestamp += 1;
                 switch (option.timestamp)
                 {
@@ -375,6 +509,10 @@ void handle_command_sequence(char input_char, char previous_char, char *output_c
                 }
                 break;
 
+            case KEY_U:
+                map_o_ltu = !map_o_ltu;
+                break;
+
             case KEY_V:
                 tio_printf("tio v%s", VERSION);
                 break;
@@ -398,7 +536,7 @@ void stdin_configure(void)
     /* Save current stdin settings */
     if (tcgetattr(STDIN_FILENO, &stdin_old) < 0)
     {
-        error_printf("Saving current stdin settings failed");
+        tio_error_printf("Saving current stdin settings failed");
         exit(EXIT_FAILURE);
     }
 
@@ -416,7 +554,7 @@ void stdin_configure(void)
     status = tcsetattr(STDIN_FILENO, TCSANOW, &stdin_new);
     if (status == -1)
     {
-        error_printf("Could not apply new stdin settings (%s)", strerror(errno));
+        tio_error_printf("Could not apply new stdin settings (%s)", strerror(errno));
         exit(EXIT_FAILURE);
     }
 
@@ -440,7 +578,7 @@ void stdout_configure(void)
     /* Save current stdout settings */
     if (tcgetattr(STDOUT_FILENO, &stdout_old) < 0)
     {
-        error_printf("Saving current stdio settings failed");
+        tio_error_printf("Saving current stdio settings failed");
         exit(EXIT_FAILURE);
     }
 
@@ -450,6 +588,12 @@ void stdout_configure(void)
     /* Reconfigure stdout (RAW configuration) */
     cfmakeraw(&stdout_new);
 
+    /* Allow ^C / SIGINT (to allow termination when piping to tio) */
+    if (!interactive_mode)
+    {
+        stdout_new.c_lflag |= ISIG;
+    }
+
     /* Control characters */
     stdout_new.c_cc[VTIME] = 0; /* Inter-character timer unused */
     stdout_new.c_cc[VMIN]  = 1; /* Blocking read until 1 character received */
@@ -458,7 +602,7 @@ void stdout_configure(void)
     status = tcsetattr(STDOUT_FILENO, TCSANOW, &stdout_new);
     if (status == -1)
     {
-        error_printf("Could not apply new stdout settings (%s)", strerror(errno));
+        tio_error_printf("Could not apply new stdout settings (%s)", strerror(errno));
         exit(EXIT_FAILURE);
     }
 
@@ -500,7 +644,7 @@ void tty_configure(void)
             standard_baudrate = false;
             break;
 #else
-            error_printf("Invalid baud rate");
+            tio_error_printf("Invalid baud rate");
             exit(EXIT_FAILURE);
 #endif
     }
@@ -511,7 +655,7 @@ void tty_configure(void)
         status = cfsetispeed(&tio, baudrate);
         if (status == -1)
         {
-            error_printf("Could not configure input speed (%s)", strerror(errno));
+            tio_error_printf("Could not configure input speed (%s)", strerror(errno));
             exit(EXIT_FAILURE);
         }
 
@@ -519,7 +663,7 @@ void tty_configure(void)
         status = cfsetospeed(&tio, baudrate);
         if (status == -1)
         {
-            error_printf("Could not configure output speed (%s)", strerror(errno));
+            tio_error_printf("Could not configure output speed (%s)", strerror(errno));
             exit(EXIT_FAILURE);
         }
     }
@@ -541,7 +685,7 @@ void tty_configure(void)
             tio.c_cflag |= CS8;
             break;
         default:
-            error_printf("Invalid data bits");
+            tio_error_printf("Invalid data bits");
             exit(EXIT_FAILURE);
     }
 
@@ -563,7 +707,7 @@ void tty_configure(void)
     }
     else
     {
-        error_printf("Invalid flow control");
+        tio_error_printf("Invalid flow control");
         exit(EXIT_FAILURE);
     }
 
@@ -577,7 +721,7 @@ void tty_configure(void)
             tio.c_cflag |= CSTOPB;
             break;
         default:
-            error_printf("Invalid stop bits");
+            tio_error_printf("Invalid stop bits");
             exit(EXIT_FAILURE);
     }
 
@@ -596,9 +740,21 @@ void tty_configure(void)
     {
         tio.c_cflag &= ~PARENB;
     }
+    else if ( strcmp("mark", option.parity) == 0)
+    {
+        tio.c_cflag |= PARENB;
+        tio.c_cflag |= PARODD;
+        tio.c_cflag |= CMSPAR;
+    }
+    else if ( strcmp("space", option.parity) == 0)
+    {
+        tio.c_cflag |= PARENB;
+        tio.c_cflag &= ~PARODD;
+        tio.c_cflag |= CMSPAR;
+    }
     else
     {
-        error_printf("Invalid parity");
+        tio_error_printf("Invalid parity");
         exit(EXIT_FAILURE);
     }
 
@@ -654,6 +810,10 @@ void tty_configure(void)
             {
                 map_o_nl_crnl = true;
             }
+            else if (strcmp(token, "OLTU") == 0)
+            {
+                map_o_ltu = true;
+            }
             else
             {
                 printf("Error: Unknown mapping flag %s\n", token);
@@ -681,51 +841,56 @@ void tty_wait_for_device(void)
     /* Loop until device pops up */
     while (true)
     {
-        if (first)
-        {
-            /* Don't wait first time */
-            tv.tv_sec = 0;
-            tv.tv_usec = 1;
-            first = false;
-        }
-        else
+        if (interactive_mode)
         {
-            /* Wait up to 1 second */
-            tv.tv_sec = 1;
-            tv.tv_usec = 0;
-        }
+            /* In interactive mode, while waiting for tty device, we need to
+             * read from stdin to react on input key commands. */
+            if (first)
+            {
+                /* Don't wait first time */
+                tv.tv_sec = 0;
+                tv.tv_usec = 1;
+                first = false;
+            }
+            else
+            {
+                /* Wait up to 1 second for input */
+                tv.tv_sec = 1;
+                tv.tv_usec = 0;
+            }
 
-        FD_ZERO(&rdfs);
-        FD_SET(STDIN_FILENO, &rdfs);
-        maxfd = MAX(STDIN_FILENO, socket_add_fds(&rdfs, false));
+            FD_ZERO(&rdfs);
+            FD_SET(STDIN_FILENO, &rdfs);
+            maxfd = MAX(STDIN_FILENO, socket_add_fds(&rdfs, false));
 
-        /* Block until input becomes available or timeout */
-        status = select(maxfd + 1, &rdfs, NULL, NULL, &tv);
-        if (status > 0)
-        {
-            if (FD_ISSET(STDIN_FILENO, &rdfs))
+            /* Block until input becomes available or timeout */
+            status = select(maxfd + 1, &rdfs, NULL, NULL, &tv);
+            if (status > 0)
             {
-                /* Input from stdin ready */
-
-                /* Read one character */
-                status = read(STDIN_FILENO, &input_char, 1);
-                if (status <= 0)
+                if (FD_ISSET(STDIN_FILENO, &rdfs))
                 {
-                    error_printf("Could not read from stdin");
-                    exit(EXIT_FAILURE);
-                }
+                    /* Input from stdin ready */
+
+                    /* Read one character */
+                    status = read(STDIN_FILENO, &input_char, 1);
+                    if (status <= 0)
+                    {
+                        tio_error_printf("Could not read from stdin");
+                        exit(EXIT_FAILURE);
+                    }
 
-                /* Handle commands */
-                handle_command_sequence(input_char, previous_char, NULL, NULL);
+                    /* Handle commands */
+                    handle_command_sequence(input_char, previous_char, NULL, NULL);
 
-                previous_char = input_char;
+                    previous_char = input_char;
+                }
+                socket_handle_input(&rdfs, NULL);
+            }
+            else if (status == -1)
+            {
+                tio_error_printf("select() failed (%s)", strerror(errno));
+                exit(EXIT_FAILURE);
             }
-            socket_handle_input(&rdfs, NULL);
-        }
-        else if (status == -1)
-        {
-            error_printf("select() failed (%s)", strerror(errno));
-            exit(EXIT_FAILURE);
         }
 
         /* Test for accessible device file */
@@ -737,10 +902,18 @@ void tty_wait_for_device(void)
         }
         else if (last_errno != errno)
         {
-            warning_printf("Could not open tty device (%s)", strerror(errno));
+            tio_warning_printf("Could not open tty device (%s)", strerror(errno));
             tio_printf("Waiting for tty device..");
             last_errno = errno;
         }
+
+        if (!interactive_mode)
+        {
+            /* In non-interactive mode we do not need to handle input key
+             * commands so we simply sleep 1 second between checking for
+             * presence of tty device */
+            sleep(1);
+        }
     }
 }
 
@@ -789,7 +962,7 @@ void forward_to_tty(int fd, char output_char)
         status = tty_write(fd, crlf, 2);
         if (status < 0)
         {
-            warning_printf("Could not write to tty device");
+            tio_warning_printf("Could not write to tty device");
         }
 
         tx_total += 2;
@@ -807,7 +980,7 @@ void forward_to_tty(int fd, char output_char)
             status = tty_write(fd, &output_char, 1);
             if (status < 0)
             {
-                warning_printf("Could not write to tty device");
+                tio_warning_printf("Could not write to tty device");
             }
 
             /* Update transmit statistics */
@@ -832,14 +1005,14 @@ int tty_connect(void)
     fd = open(option.tty_device, O_RDWR | O_NOCTTY | O_NONBLOCK);
     if (fd < 0)
     {
-        error_printf_silent("Could not open tty device (%s)", strerror(errno));
+        tio_error_printf_silent("Could not open tty device (%s)", strerror(errno));
         goto error_open;
     }
 
     /* Make sure device is of tty type */
     if (!isatty(fd))
     {
-        error_printf("Not a tty device");
+        tio_error_printf("Not a tty device");
         exit(EXIT_FAILURE);;
     }
 
@@ -847,7 +1020,7 @@ int tty_connect(void)
     status = flock(fd, LOCK_EX | LOCK_NB);
     if ((status == -1) && (errno == EWOULDBLOCK))
     {
-        error_printf("Device file is locked by another process");
+        tio_error_printf("Device file is locked by another process");
         exit(EXIT_FAILURE);
     }
 
@@ -879,13 +1052,14 @@ int tty_connect(void)
     /* Save current port settings */
     if (tcgetattr(fd, &tio_old) < 0)
     {
+        tio_error_printf_silent("Could not get port settings (%s)", strerror(errno));
         goto error_tcgetattr;
     }
 
 #ifdef HAVE_IOSSIOSPEED
     if (!standard_baudrate)
     {
-        /* OS X wants these fields left alone. We'll set baudrate with iossiospeed below. */
+        /* OS X wants these fields left alone before setting arbitrary baud rate */
         tio.c_ispeed = tio_old.c_ispeed;
         tio.c_ospeed = tio_old.c_ospeed;
     }
@@ -902,31 +1076,19 @@ int tty_connect(void)
     status = tcsetattr(fd, TCSANOW, &tio);
     if (status == -1)
     {
-        error_printf_silent("Could not apply port settings (%s)", strerror(errno));
+        tio_error_printf_silent("Could not apply port settings (%s)", strerror(errno));
         goto error_tcsetattr;
     }
 
-#ifdef HAVE_TERMIOS2
+    /* Set arbitrary baudrate (only works on supported platforms) */
     if (!standard_baudrate)
     {
-        if (setspeed2(fd, option.baudrate) != 0)
+        if (setspeed(fd, option.baudrate) != 0)
         {
-            error_printf_silent("Could not set baudrate speed (%s)", strerror(errno));
+            tio_error_printf_silent("Could not set baudrate speed (%s)", strerror(errno));
             goto error_setspeed;
         }
     }
-#endif
-
-#ifdef HAVE_IOSSIOSPEED
-    if (!standard_baudrate)
-    {
-        if (iossiospeed(fd, option.baudrate) != 0)
-        {
-            error_printf_silent("Could not set baudrate speed (%s)", strerror(errno));
-            goto error_setspeed;
-        }
-    }
-#endif
 
     /* Input loop */
     while (true)
@@ -949,7 +1111,7 @@ int tty_connect(void)
                 if (bytes_read <= 0)
                 {
                     /* Error reading - device is likely unplugged */
-                    error_printf_silent("Could not read from tty device");
+                    tio_error_printf_silent("Could not read from tty device");
                     goto error_read;
                 }
 
@@ -1012,11 +1174,17 @@ int tty_connect(void)
             {
                 /* Input from stdin ready */
                 ssize_t bytes_read = read(STDIN_FILENO, input_buffer, BUFSIZ);
-                if (bytes_read <= 0)
+                if (bytes_read < 0)
                 {
-                    error_printf_silent("Could not read from stdin");
+                    tio_error_printf_silent("Could not read from stdin (%s)", strerror(errno));
                     goto error_read;
                 }
+                else if (bytes_read == 0)
+                {
+                    /* Reached EOF (when piping to stdin) */
+                    tty_sync(fd);
+                    exit(EXIT_SUCCESS);
+                }
 
                 /* Process input byte by byte */
                 for (int i=0; i<bytes_read; i++)
@@ -1029,8 +1197,8 @@ int tty_connect(void)
 
                     if (interactive_mode)
                     {
-                        /* Do not forward ctrl-t key */
-                        if (input_char == KEY_CTRL_T)
+                        /* Do not forward prefix key */
+                        if (input_char == option.prefix_code)
                         {
                             forward = false;
                         }
@@ -1041,11 +1209,11 @@ int tty_connect(void)
                         /* Save previous key */
                         previous_char = input_char;
 
-                        if (print_mode == HEX)
+                        if ((print_mode == HEX) && (forward))
                         {
                             if (!is_valid_hex(input_char))
                             {
-                                warning_printf("Invalid hex character: '%d' (0x%02x)", input_char, input_char);
+                                tio_warning_printf("Invalid hex character: '%d' (0x%02x)", input_char, input_char);
                                 forward = false;
                             }
                         }
@@ -1057,7 +1225,7 @@ int tty_connect(void)
                     }
                 }
 
-                tty_flush(fd);
+                tty_sync(fd);
             }
             else
             {
@@ -1068,21 +1236,19 @@ int tty_connect(void)
                     forward_to_tty(fd, output_char);
                 }
 
-                tty_flush(fd);
+                tty_sync(fd);
             }
         }
         else if (status == -1)
         {
-            error_printf("Error: select() failed (%s)", strerror(errno));
+            tio_error_printf("select() failed (%s)", strerror(errno));
             exit(EXIT_FAILURE);
         }
     }
 
     return TIO_SUCCESS;
 
-#if defined (HAVE_TERMIOS2) || defined (HAVE_IOSSIOSPEED)
 error_setspeed:
-#endif
 error_tcsetattr:
 error_tcgetattr:
 error_read:
index a47c8b9fd2562c6010659c4f0356e7fc30c818f8..14d1779dcb5cff66d825c6f78af23fe34acb4dc6 100644 (file)
--- a/src/tty.h
+++ b/src/tty.h
 
 #include <stdbool.h>
 
-#define KEY_QUESTION 0x3f
-#define KEY_B 0x62
-#define KEY_C 0x63
-#define KEY_E 0x65
-#define KEY_H 0x68
-#define KEY_L 0x6C
-#define KEY_Q 0x71
-#define KEY_S 0x73
-#define KEY_T 0x74
-#define KEY_SHIFT_T 0x54
-#define KEY_CTRL_T 0x14
-#define KEY_V 0x76
-#define KEY_D 0x64
-#define KEY_SHIFT_D 0x44
-#define KEY_R 0x72
-#define KEY_SHIFT_L 0x4C
-
-#define NORMAL 0
-#define HEX 1
-
 extern bool interactive_mode;
 
 void stdout_configure(void);
index c9d1760190ca3bd295f1c2cdf90ff5faed772645..8a7447c6fff8998bd570f9cb9e9cb06d7fd8b62a 100644 (file)
@@ -1,4 +1,4 @@
 [wrap-git]
 directory=libinih
 url=https://github.com/benhoyt/inih.git
-revision=r55
+revision=r56