Compare commits

...

978 commits

Author SHA1 Message Date
Jakob Haufe
6fb3a64ba2 Fix license in meson.build
- Make license here match LICENSE
- According to meson docs, it should not be an array
2026-01-22 12:41:01 +01:00
aiotter
3af4c5591e Fix redundant output on macOS 2025-08-07 17:18:29 +02:00
John Barbero Unenge
cce94b9d92 Add --complete-profiles to help printout and man pages 2025-06-17 16:30:31 +02:00
ii8
86f48a2fb6 Overhaul Lua API
Lua API moved into a tio library table and names adjusted to Lua stdlib style.
Regex in expect() replaced with Lua patterns so binary data can be handled.
New tio.alwaysecho variable allows enabling and disabling echo to console.
Read and write functions now manage complex retry and timeout logic internally,
giving the user a simple "nil if fail" API like the rest of Lua.
exit() was removed, os.exit() already exists in the Lua standard library.
2025-06-14 15:09:21 +02:00
Martin Lund
381c0b7823 Update codeql to v3 2025-06-14 07:03:17 +02:00
Martin Lund
8f33cff6ea Disable compiler warning on unused result 2025-05-31 19:43:11 +02:00
Keith Barratt
9d00cd3492 Fix device description-Linux
This commit only effects Linux.

The description field of the `device_list`, populated by
`tty_search_for_serial_devices()`, was either incorrect or less than ideal
for CDC ACM virtual com ports. For instance:
    (i) Some devices incorrectly have the description field populated by
    the 'product' property of USB hub they are connected via.
    (ii) Other devices have description fields populated with the interface,
    e.g. CDC, when there is a 'product' property available that would give a
    clearer description.

To solve these issues, we first prioritise searching for the 'product' property
of the device over the 'interface' property. We also look for the
'product' property in an additional directory.
2025-05-30 17:20:06 +02:00
Martin Lund
3e0b2d861d Fix Ubuntu workflow 2025-05-30 17:18:21 +02:00
ii8
a1217af4c6 Fix string truncation bug in scripting api 2025-05-25 21:13:43 +02:00
Martin Lund
58bf5c5008 Update tio man page 2025-05-25 19:46:18 +02:00
Maximilian Seesslen
7e61a34df3 Added timestamp format "epoch-usec"
This timestamp format will print the seconds since epoch along with
subdivision in microseconds.

Example:
 [1748009585.087083] tio v3.9-8-g2fb788f-dirty
 [1748009585.087156] Press ctrl-t q to quit
 [1748009585.087683] Connected to /dev/ttyUSB0
2025-05-23 16:36:39 +02:00
Hideaki Tai
2fb788f817 fix: lua script stops output if it includes null terminate 2025-05-06 17:28:53 +02:00
Martin Lund
f887756a71 meson: Enable compiler warnings on unused result and global shadows 2025-04-29 17:44:08 +02:00
Robert Lipe
5d915134a3 Fix --auto new and --auto latest on MacOS. (redo)
Git is being dumb about
67c071633d This PR is identical to that one and will supercede it.

Fix --auto new and --auto latest on MacOS.

'device_list' was both a global (eww!) and a local inside
tty_search_for_serial_devices(). The local got set and
returned, so it looked sane, but the caller used the global
instead of the return value of the function it had just
called, meaning (global) device_list was NULL while
(ignored, local) device_list held a perfectly lovely
linked list.

Tested:
tio --auto new waits for a new device to appare and connects
tio --latest will connect to the most recently attached device
  which, in most worlds, is the most recently enumerated USB
  device, conveniently skipping all the bluetooth nonsense.
  If the lone USB device is disconnected, it then connects to
  one of those, meaning you really do have to restart tio.
2025-04-29 17:05:24 +02:00
Robert Lipe
7516dff802 Add missing build piece. 2025-04-24 17:55:26 +02:00
Robert Lipe
03ef931fb2 - Implemented getPropertyString(), getDeviceLocation(), tty_search_for_serial_devices()
for MacOS
- Added error handling and memory management
- Improved code readability and consistency
- Updated coding style to match project conventions

- Added robust error checking for CoreFoundation property retrieval
- Implemented more defensive memory allocation and type checking
- Switched to using callout device key for more reliable device discovery
- Added single-line block bracing consistent with project style
- Improved comments and code formatting

- Used `kIOCalloutDeviceKey` instead of `kIODialinDeviceKey` for device path retrieval
- Enhanced type checking for CoreFoundation objects
- Simplified memory management and error handling
- Added additional logging and error reporting

- Verified functionality on MacOS 10.11 and 10.15. Tested with ESP32-P4 and ESP32-BOX

Resolves potential device discovery and memory management issues in the MacOS serial device detection code.
2025-04-24 17:55:26 +02:00
Martin Lund
437881f0ed Update AUTHORS 2025-04-23 08:17:11 +02:00
David Ordnung
c736b1e353 Input ICRCRNL mapping to avoid using INLCRNL with ICRNL 2025-04-23 08:09:22 +02:00
Martin Lund
d682e98a66 codeql: Build using ubuntu-22.04 2025-04-16 10:47:39 +02:00
Martin Lund
bdfe87e1cb Update date 2025-04-13 13:31:06 +02:00
Martin Lund
5c2ced1093 Update NEWS 2025-04-13 13:27:50 +02:00
Martin Lund
f87f470415 Fix pattern matching memory corruption 2025-04-13 13:25:25 +02:00
Martin Lund
2e86718973 Add typos.toml 2025-04-13 08:28:01 +02:00
Martin Lund
013aebcc05 Update NEWS 2025-04-12 09:02:22 +02:00
Martin Lund
b33045189f Update plain text man page 2025-04-12 08:57:25 +02:00
Martin Lund
600c3d7563 Update version date 2025-04-12 08:55:40 +02:00
Martin Lund
ebce2d4ee9 Bump version 2025-04-12 08:55:11 +02:00
Martin Lund
16b7aee42f Update NEWS 2025-04-12 08:54:50 +02:00
Martin Lund
d33e275ca3 Update AUTHORS 2025-03-23 07:04:47 +01:00
Samuel Holland
da4074c9a5 Don't add null characters to the expect buffer
They prevent regexec() from seeing the remainder of the buffer.
2025-03-23 07:02:56 +01:00
Martin Lund
f716d2ccdd Update TODO 2025-03-13 15:44:12 +01:00
V
7567e08227 Disable stdout buffering globally
This makes it possible to pipe output to other programs cleanly.
2025-03-11 20:46:14 +01:00
Martin Lund
6aca9ffee5 Update AUTHORS 2025-03-10 16:17:56 +01:00
Lubov66
f5740dbf31 docs: edited the license date 2025-03-10 16:12:53 +01:00
Lubov66
d163afc6b1 Update README.md 2025-03-10 11:37:32 +01:00
Lubov66
1b60dd1ae7 Update README.md 2025-03-10 11:07:03 +01:00
Martin Lund
795ef28f79 Update TODO 2025-02-25 16:16:24 +01:00
Martin Lund
8e155c9276 Update TODO 2025-02-23 16:26:28 +01:00
Martin Lund
6831ad0eae Fix parsing of timestamp options 2025-02-15 20:27:53 +01:00
Martin Lund
8f7bf2fd2c codeql: Upgrade to upload-artifact@v4 2025-02-08 02:58:02 +01:00
Martin Lund
f389f11669 Update plaintext man page 2025-01-26 16:41:24 +01:00
Martin Lund
37994b3cc5 Add character mapping examples 2025-01-25 15:09:07 +01:00
Jakob Haufe
27f8f2c4e6 Manpage: Fix backslash encoding
Literal backslash needs to be written as \e.
2024-12-01 14:32:56 +01:00
Martin Lund
01e637cdf4 Update NEWS 2024-11-30 12:40:48 +01:00
Martin Lund
1b2a0ea130 Update version date 2024-11-30 12:12:09 +01:00
Martin Lund
b8135ea639 Rename git version to simply version 2024-11-30 11:37:27 +01:00
Martin Lund
c49faa7337 Clean up lua API
Rename modem_send() to send()
Rename send to write()
2024-11-30 11:09:43 +01:00
Martin Lund
4511d74a9e Update AUTHORS 2024-11-07 22:17:26 +01:00
Keith Hill
afd82f7ac4 + Add system timestamps to lua read() and new lua read_line() per global options
+ Add missing timestamp-format epoch
+ Update send_ to use fsync and tcdrain like normal tty_sync does
+ Rework read_line to save partial line at timeout
+ Simplified read_line to reduce cyclomatic complexity

+ renamed example files read.lua and read_line.lua
+ moved #define READ_LINE_SIZE to top of file
+ renamed g_linebuf to linebuf, and moved it into read_line as a static variable
2024-11-07 21:45:06 +01:00
Martin Lund
db3f109c7d Zero initialize buffer in read_string() 2024-11-07 18:05:32 +01:00
Martin Lund
ab678e6c88 Use version from git 2024-10-25 19:35:13 +02:00
Martin Lund
330e99381e Fix memory leak in base62_encode() 2024-10-25 18:26:59 +02:00
Martin Lund
7e314b2cc3 Update TODO 2024-10-17 18:53:36 +02:00
Martin Lund
4fb034858a Update AUTHORS 2024-10-15 17:22:34 +02:00
Martin Lund
d494b9d3ac Update README 2024-09-25 20:51:40 +02:00
konosubakonoakua
4034d0ad51 Update readme.md
Update readme.md issue part

Update readme.md issue part
2024-09-25 17:34:06 +02:00
Martin Lund
9fec689117 Fix name declaration conflict with socket send() 2024-09-15 05:57:31 +02:00
Martin Lund
6c4b92270e Add clang-format spec 2024-09-07 09:31:31 +02:00
Martin Lund
a22b270749 Bump version 2024-08-31 09:23:19 +02:00
Martin Lund
9f27ce5899 Update version date 2024-08-31 09:09:34 +02:00
Martin Lund
27f9b9f2e8 Update NEWS 2024-08-31 09:06:28 +02:00
Martin Lund
2e7da862c8 Cleanup 2024-08-24 13:21:41 +02:00
Martin Lund
bb2b4e30b2 Update AUTHORS 2024-08-24 12:37:12 +02:00
Steve Marple
f47467271f Add "epoch" timestamp option
Add an option that prints the timestamp as the number of seconds since
the Unix epoch.
2024-08-24 12:35:30 +02:00
Martin Lund
cdc773100c Update AUTHORS 2024-08-19 20:40:05 +02:00
Tomka Gergely
a3b67d3eb6 The log-directory options is not read from the configuration file. 2024-08-19 20:37:18 +02:00
Martin Lund
ef12ed62df Remove unnecessary sync in line input mode
This caused a problem for some highly timing sensitive modem read-eval-print
loops because the input line and line termination characters (cr/nl) would be
shifted out on the UART with too big delay inbetween because of two
syncs.
2024-08-06 20:48:43 +02:00
Martin Lund
2f6b3796f2 Bump version 2024-07-25 00:12:23 +02:00
Martin Lund
6163bc392b Fix socket send call on platforms without MSG_NOSIGNAL
To fix build issue encountered on MacOS Catalina but may apply to other
platforms.
2024-07-20 08:25:49 +02:00
Martin Lund
475bc29cc8 Update plain text man page 2024-07-19 09:39:41 +02:00
Martin Lund
c4f5269c83 Update version date 2024-07-19 09:39:13 +02:00
Martin Lund
13ad59ac12 Update README 2024-07-19 09:37:57 +02:00
Martin Lund
2259244eb2 Update NEWS 2024-07-19 09:27:23 +02:00
Martin Lund
725423c50c Add configuration file include directive
To include the contents of another configuration file simply do e.g.:

[include raspberrypi.conf]

Also, included file can include other files which can include other
files etc.

This feature is useful for managing many configuration files and sharing
configuration files with others.
2024-07-19 08:49:49 +02:00
Martin Lund
14963032c3 Update TODO 2024-07-15 20:05:28 +02:00
Martin Lund
e1fe232254 Fix shadow variable 2024-07-13 18:36:03 +02:00
Martin Lund
9cafcbcab5 Update README 2024-07-13 17:17:14 +02:00
Martin Lund
f4076258f1 Update man page 2024-07-13 17:09:26 +02:00
Martin Lund
866b5bcb30 Mention how to list key commands in help output 2024-07-13 16:49:19 +02:00
Martin Lund
289bbfd393 Update AUTHORS 2024-07-13 15:14:24 +02:00
Heinrich Schuchardt
68a64ac554 Print correct 'Done' timestamp for X- and Y-modem transfers
Closes: #268

Call tio_printf() after completing xymodem_send().

Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
2024-07-13 15:10:39 +02:00
Martin Lund
0a95da00f1 Typo fixes 2024-07-11 17:00:37 +02:00
Martin Lund
32d97683f8 Update TODO 2024-07-10 13:27:12 +02:00
Martin Lund
c3654486c7 Fix hex output mode when using normal input mode
In this combination of modes the input character was not forwarded to
the tty device. This fix makes sure it is forwarded.
2024-07-10 13:11:28 +02:00
Martin Lund
b5184012c4 Update AUTHORS 2024-07-10 01:48:13 +02:00
Robert Lipe
fc0c6f61d2 Recompute listing_device_name_length_max for MacOS case, too. 2024-07-10 01:46:32 +02:00
Martin Lund
53bb2a6ad1 Fix uptime on MacOS
On MacOS the birth time is apparently not available so we use
modification time instead.
2024-07-09 22:12:42 +02:00
Martin Lund
da9f7a6540 Improve warning upon failing connect
Add device path to warning when connect fails.
2024-07-09 21:06:22 +02:00
Martin Lund
2a1dae6336 Fix crashy search_reset() on macOS 2024-07-09 16:44:10 +02:00
Martin Lund
ada2db0739 Clean up shadow variable 2024-07-02 19:20:59 +02:00
Martin Lund
14ee38a0d9 Clean up readline code 2024-07-02 19:13:14 +02:00
Martin Lund
2c700a90b0 Code cleanup 2024-07-02 19:11:40 +02:00
Martin Lund
da04c2c444 Improve listing of long device names 2024-07-02 17:41:49 +02:00
Martin Lund
5f70b75e90 Fix listing of serial devices on macOS 2024-07-01 23:11:58 +02:00
Martin Lund
02cac07a77 Bump version 2024-06-29 12:33:55 +02:00
Martin Lund
a3a6b5127f Update NEWS 2024-06-29 12:22:35 +02:00
Martin Lund
ef6fa8030e Update version date 2024-06-29 12:19:54 +02:00
Martin Lund
561376696b Clarify input and output direction of map flags 2024-06-29 12:17:57 +02:00
Martin Lund
d34fa1c1ad Rename mapping flag MSB2LSB to IMSB2LSB
This is the correct naming since we are changing the input bit order on
input from the serial device.
2024-06-29 12:14:34 +02:00
Martin Lund
9022f51ea5 Update NEWS 2024-06-28 11:51:40 +02:00
Martin Lund
4723cc3f4e Add OIGNCR mapping flag
Ignores CR on output to serial device.
2024-06-27 20:09:25 +02:00
Martin Lund
8c471105fe Fix line input mode ignoring characters ABCD 2024-06-27 18:54:19 +02:00
Martin Lund
b9902bbd78 Fix tainted print 2024-06-27 18:43:16 +02:00
Jakob Haufe
c5afd86b9a Fix typos 2024-06-15 17:16:23 +02:00
Martin Lund
b756d2e1f1 Bump version 2024-06-15 16:46:20 +02:00
Martin Lund
5c7d81b900 Update version date 2024-06-15 16:21:16 +02:00
Martin Lund
7e9574f98d Update NEWS 2024-06-15 16:20:44 +02:00
Martin Lund
053ae53f19 Update configuration output 2024-06-15 16:00:58 +02:00
Martin Lund
8f77ad5830 Clean up script run interaction text 2024-06-15 15:58:08 +02:00
Martin Lund
be4fc0908f Fix unbounded writes 2024-06-15 15:06:10 +02:00
Martin Lund
6ec2ac19d0 Add history and editing feature to line input mode
Use up and down arrow keys to navigate history.

Use left and right arrow keys to move cursor back and forth.

We try mimic the behaviour of GNU readline which we can not use because
we also need to react to key commands.
2024-06-15 14:31:23 +02:00
Martin Lund
bed34a0b9a Reuse socket address
To avoid having to wait for socket timeout when restarting server.
2024-06-11 15:18:38 +02:00
Martin Lund
134038c1ce Fix line input mode
Fix so that ABCD are no longer ignored.
2024-06-09 13:03:59 +02:00
Martin Lund
003b2e37d4 Make sure ICRNL, IGNCR, INLCR take effect 2024-06-02 23:35:36 +02:00
Martin Lund
8014ef68c0 Cleanup parsing of mapping flags 2024-06-02 14:26:39 +02:00
Vyacheslav Patkov
563c4fa6ea Show current mappings in the configuration printout 2024-06-02 13:22:33 +02:00
Vyacheslav Patkov
d1d6b45e8e Use "ctrl-t m" to change mappings interactively 2024-06-02 13:22:33 +02:00
Vyacheslav Patkov
f148a1413c Prompt for Lua script or shell command in interactive session 2024-06-01 16:23:51 +02:00
Martin Lund
bb3636e2d5 Update TODO 2024-05-30 12:17:00 +02:00
Martin Lund
133789517a Add group write permission to xymodem received file 2024-05-29 09:26:08 +02:00
Martin Lund
7e0bd980f2 Fix missing open() flags in xymodem_receive() 2024-05-29 01:41:14 +02:00
Martin Lund
883acbaa4b Update AUTHORS 2024-05-29 01:24:02 +02:00
Eliot Alan Foss
d10e762a7d Added support to receive XMODEM-CRC files from the connected serial port. 2024-05-29 01:23:00 +02:00
Martin Lund
94e40d82f3 Update README 2024-05-27 12:02:41 +02:00
Martin Lund
9315cf6a55 Update README 2024-05-27 10:10:36 +02:00
Martin Lund
eb9726bbcc Update AUTHORS 2024-05-22 18:54:44 +02:00
Martin Lund
4014fc4b3e Update README 2024-05-17 11:59:10 +02:00
Martin Lund
ccc01433b7 Include correct header for poll() 2024-05-16 19:16:17 +02:00
Martin Lund
ee3687430b Bump version 2024-05-15 09:16:13 +02:00
Martin Lund
6f6038ebcd Update plain text man page 2024-05-15 08:35:45 +02:00
Martin Lund
0921796054 Update version date 2024-05-15 08:35:16 +02:00
Martin Lund
dba4690a88 Update NEWS 2024-05-15 00:13:34 +02:00
Martin Lund
b3aac7b182 Update plain text man page 2024-05-15 00:13:03 +02:00
Martin Lund
5b5248929e Force destructive backspace when using local echo
Only takes effect in normal output mode.
2024-05-14 23:22:05 +02:00
Martin Lund
8f45d6f688 Fix local-echo in configuration file 2024-05-14 22:20:59 +02:00
Martin Lund
37f8b4fd1b Update workflow name 2024-05-13 14:07:14 +02:00
Martin Lund
5f5a8a9cdd Update README 2024-05-13 14:01:44 +02:00
Martin Lund
3f616a47c8 Fix includes 2024-05-13 11:04:09 +02:00
Martin Lund
694524cb6f Run CodeQL on push 2024-05-13 11:01:24 +02:00
Martin Lund
747ac62733 Fix includes 2024-05-13 10:57:27 +02:00
Martin Lund
c76a4d0172 Fix includes 2024-05-12 08:57:59 +02:00
Martin Lund
d2dd9f5a5b Update README 2024-05-11 16:44:12 +02:00
Martin Lund
ae9c8edbca Clean up includes 2024-05-11 10:50:01 +02:00
Martin Lund
f71ffeabb7 Force socket write operation to ignore any signals 2024-05-10 14:29:05 +02:00
Martin Lund
6ebd50ab85 Bump version 2024-05-08 13:37:43 +02:00
Martin Lund
241ff93bf4 Man page cleanup 2024-05-08 13:37:05 +02:00
Martin Lund
2d17624ddb Update version date 2024-05-08 13:05:47 +02:00
Martin Lund
ce70f43113 Update man page 2024-05-08 13:04:08 +02:00
Martin Lund
f825363606 Update NEWS 2024-05-08 13:00:44 +02:00
Martin Lund
86f1b3881d Fix shadow variable 2024-05-08 10:31:32 +02:00
Martin Lund
c2f910ffe3 Bump version 2024-05-07 21:49:23 +02:00
Martin Lund
9066523229 Do not print error when using --list with broken config file 2024-05-07 19:08:10 +02:00
Martin Lund
016c81291e Clean up completion script 2024-05-07 14:48:57 +02:00
Martin Lund
e75e19eb00 Add option '--exec <command>' for running shell command
Runs shell command with I/O redirected to device.
2024-05-07 14:38:31 +02:00
Martin Lund
545d473220 Make sure all error output is directed to stderr 2024-05-07 14:21:43 +02:00
Martin Lund
873bd6973d Fix shadow variables 2024-05-07 09:50:07 +02:00
Martin Lund
9320f54a73 Update plaintext man page 2024-05-07 09:19:51 +02:00
Martin Lund
68e2042fd6 Update man page 2024-05-07 09:12:15 +02:00
Martin Lund
b490233988 Fix build on older GNU/Linux systems without statx 2024-05-05 21:02:28 +02:00
Martin Lund
c2ef2fced5 Add codefactor.io shield 2024-05-04 14:07:55 +02:00
Martin Lund
3a75b098d1 Add new build shields to README 2024-05-04 13:35:40 +02:00
Martin Lund
242a2ea843 Fix line ending in --list output 2024-05-04 13:16:28 +02:00
Martin Lund
ce736c267a Update README 2024-05-03 18:25:17 +02:00
Martin Lund
c88cd3c5f3 Print location of configuratin file in --list output 2024-05-03 18:23:53 +02:00
Martin Lund
59940b3311 Update README 2024-05-03 15:45:39 +02:00
Martin Lund
05785e82b3 Update README 2024-05-03 15:39:52 +02:00
Martin Lund
50253a6a77 Update README 2024-05-03 15:36:53 +02:00
Martin Lund
13f3bedb2f Update README 2024-05-03 15:31:05 +02:00
Martin Lund
6310a9fabc Fix alignment of profile listing 2024-05-03 15:26:55 +02:00
Martin Lund
eb087713a4 Update README 2024-05-03 15:26:11 +02:00
Martin Lund
3e81f36dce Update version date 2024-05-03 14:20:57 +02:00
Martin Lund
fe4e47219e Update NEWS 2024-05-03 14:18:03 +02:00
Martin Lund
ec8f63f06d Improve --list feature on non-linux platform 2024-05-03 14:12:47 +02:00
Martin Lund
5ec33f5d4d Update doc 2024-05-03 11:57:26 +02:00
Martin Lund
adafa00b87 Update NEWS 2024-05-03 11:38:00 +02:00
Martin Lund
31647a934c List available profiles in --list output 2024-05-03 11:35:48 +02:00
Martin Lund
e9c96c5456 Update NEWS 2024-05-03 10:47:01 +02:00
Martin Lund
3b3fca2e8b Always message when saving log file 2024-05-03 10:45:49 +02:00
Martin Lund
a53a4f44de Update NEWS 2024-05-03 10:36:14 +02:00
Martin Lund
60caede5dd Add support for using TID as device in config file 2024-05-03 10:32:33 +02:00
Martin Lund
eae7f8f8d7 Update NEWS 2024-05-03 10:02:44 +02:00
Martin Lund
04dfa682c9 Fix use of invalid flag with regexec() 2024-05-03 09:19:21 +02:00
Martin Lund
62a4a93dec Fix potential buffer overflow in match_and_replace() 2024-05-03 08:39:58 +02:00
Martin Lund
7aa2d3fee2 Fix profile autocompletion 2024-05-03 02:12:12 +02:00
Martin Lund
22bcfdc29f Remove inih dependency from CI builds 2024-05-02 23:44:26 +02:00
Martin Lund
0e9dbcbc77 Replace use of stat() with fstat()
For better security.
2024-05-02 22:30:47 +02:00
Martin Lund
68c78222e1 Fix hexN output mode 2024-05-02 21:50:48 +02:00
Martin Lund
22b4f451ea Update pattern matching example 2024-05-02 20:42:10 +02:00
Martin Lund
15ba034ce5 Fix submenu response when invalid key hit 2024-05-02 19:38:14 +02:00
Martin Lund
17bb6edfd2 Bump version 2024-05-02 18:52:52 +02:00
Martin Lund
65c5a068d8 Replace inih with glib key file parser
After including the use of glib we might as well replace inih
with the glib key file parser.

All configuraiton file parsing has been reworked and also the options
parsing has been cleaned up, resulting in better and stricter
configuration file and option value checks.

Compared to old, configuration files now requires any default
configurations to be put in a group/section named [default].

Configuration file keywords such as "enable", "disable", "on",
"off", "yes", "no", "0", "1" have been retired. Now only "true" and
"false" apply to boolean configuration options. This is done to simplify
things and avoid any confusion.

The pattern option feature has been reworked so now the user can now
access the full match string and any matching subexpression using the
%mN syntax.

For example:

[usb devices]
pattern = usb([0-9]*)
device = /dev/ttyUSB%m1

Then when using tio:
$ tio usb12

   %m0 = 'usb12'  // Full match string
   %m1 = 12       // First match subexpression

Which results in device = /dev/ttyUSB12
2024-05-02 18:35:37 +02:00
Martin Lund
68d3b845b2 Remove CircleCI
Replaced with github workflow CI.
2024-04-30 13:40:07 +02:00
Martin Lund
22f030ebb8 Add github workflow for Ubuntu build 2024-04-30 13:35:46 +02:00
Rui Chen
f5703ff107 remove verbose for meson install and use system glib and pkg-config
Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-04-30 10:02:19 +02:00
Rui Chen
3b77eb35cf fix: add build patch for FNM_EXTMATCH
run into the following build failure

```
cc -Isrc/tio.p -Isrc -I../src -I/opt/homebrew/Cellar/glib/2.80.0_2/include/glib-2.0 -I/opt/homebrew/Cellar/glib/2.80.0_2/lib/glib-2.0/include -I/opt/homebrew/opt/gettext/include -I/opt/homebrew/Cellar/pcre2/10.43/include -I/opt/homebrew/Cellar/inih/58/include -I/opt/homebrew/include/lua -fdiagnostics-color=always -Wall -Winvalid-pch -Wextra -std=gnu99 -O3 -Wno-unused-result -DHAVE_IOSSIOSPEED -MD -MQ src/tio.p/misc.c.o -MF src/tio.p/misc.c.o.d -o src/tio.p/misc.c.o -c ../src/misc.c
../src/misc.c:201:38: error: use of undeclared identifier 'FNM_EXTMATCH'
        if (fnmatch(pattern, string, FNM_EXTMATCH) == 0)
                                     ^
1 error generated.
```

Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-04-30 10:02:19 +02:00
Rui Chen
054326454b feat: add macos workflow
Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-04-30 10:02:19 +02:00
Rui Chen
b763f1289b fix: add macos build patch for fs_get_creation_time
Signed-off-by: Rui Chen <rui@chenrui.dev>
2024-04-29 20:21:51 +02:00
Martin Lund
8ead9337d1 Enable extended pattern matching
So that the exclude options can also work as include using special
pattern syntax.

For example, to only include /dev/ttyUSB* devices simply do:

$ tio --exclude-devices=!(/dev/ttyUSB*) --list

See the man page of fnmatch() for all available extended pattern
options.
2024-04-29 19:36:44 +02:00
Martin Lund
d8fb141bc4 Update lua read() description 2024-04-29 16:47:00 +02:00
Martin Lund
a698799a7d Update man page 2024-04-29 16:22:01 +02:00
Martin Lund
5e3722a10e Update man page 2024-04-29 16:09:37 +02:00
Martin Lund
c16a2a1f94 Update README 2024-04-29 16:05:14 +02:00
Martin Lund
e2960c3f82 Update README 2024-04-29 16:00:12 +02:00
Martin Lund
08404e700f Update NEWS 2024-04-29 15:48:00 +02:00
Martin Lund
6d77201ba0 Simplify lua line manipulation API
Collapses lua high(), low(), toggle(), config_high(), config_low(),
config_apply() into one simple function:

set{<line>=<state>, ...}

Line can be any of DTR, RTS, CTS, DSR, CD, RI.

State is high, low, or toggle.

Example:
script = set{DTR=high, RTS=low}; msleep(100); set{DTR=low, RTS=high}; msleep(100); set{RTS=low}

Notice the use of {} instad of () when calling the set function. This is
required to pass parameters by name in lua.
2024-04-29 15:20:53 +02:00
Martin Lund
eef0a15194 Unshadow variable 2024-04-29 01:49:44 +02:00
Martin Lund
6895c05321 Update README 2024-04-28 18:23:08 +02:00
Martin Lund
c453728ab5 Update README 2024-04-28 17:26:10 +02:00
Martin Lund
273afb73f4 Update README 2024-04-28 17:22:26 +02:00
Martin Lund
84dd4c3685 Update README 2024-04-28 14:47:07 +02:00
Martin Lund
33eae0c30d Update script API 2024-04-28 14:46:41 +02:00
Martin Lund
9bc93991e7 Update NEWS 2024-04-27 23:51:01 +02:00
Martin Lund
ed70a587ec Update NEWS 2024-04-27 19:30:24 +02:00
Martin Lund
fe2973522e Fix shadow variable 2024-04-27 19:11:37 +02:00
Martin Lund
f5f62ee02d Disable DEC Special Graphics at exit if vt100
If a vt100 terminal receives the Shift In character '\016' it will
enable the 7 bit DEC Special Graphics character set used for line drawing.

For most users this can happen due to line noise from the tty device and
will likely mess up your terminal even after tio exits.

To better handle this we want to make sure that tio disables this mode
by sending the Shift Out character '\017' at exit.

This mechanism will only activate if environment variable TERM assumes
value "vt100".
2024-04-27 17:32:48 +02:00
Martin Lund
cd160250a6 Cleanup 2024-04-27 17:13:06 +02:00
Martin Lund
588ac3e8ac Update TODO 2024-04-27 15:45:34 +02:00
Martin Lund
76de9b890e Update README 2024-04-27 15:33:22 +02:00
Martin Lund
42ff234204 Add hexN output mode
Adds support for hexN mode where N is a number in the range 1 to 4096
which defines how many hex values will be printed before a line break.

In short, it defines the width of the hex output.

In this mode, if timestamps are enabled they will be added to each hex
line.
2024-04-27 15:25:34 +02:00
Martin Lund
4113a072c2 Make sure to reset tainted state 2024-04-27 14:41:08 +02:00
Martin Lund
232cbee697 Rename sub-config to profile
Because better naming.
2024-04-27 09:13:33 +02:00
Martin Lund
1b77ed783b Update README 2024-04-27 02:30:22 +02:00
Martin Lund
41b8e4f99c Update README 2024-04-27 02:03:12 +02:00
Martin Lund
c61d56935b Fix excludes pattern matching 2024-04-27 01:31:43 +02:00
Martin Lund
6e779a0520 Use lua io.write() instead of print()
io.write() gives better output control as print() is hardcoded to always
print a newline.
2024-04-27 00:48:38 +02:00
Martin Lund
d8fbd607d4 Update README 2024-04-26 22:58:24 +02:00
Martin Lund
01f3c391f0 Update README 2024-04-26 22:54:25 +02:00
Martin Lund
5bbdf3b9f8 Update README 2024-04-26 22:38:55 +02:00
Martin Lund
b4741de50c Bump version 2024-04-26 22:28:27 +02:00
Martin Lund
d19ba1c492 Add new ways to manage serial devices
* Rename --list-devices to --list

 * Rename --no-autoconnect to --no-reconnect

 * Switch -l and -L options

   * -l now lists available serial devices

   * -L enables log to file

 * Add option --auto-connect <strategy>

   * Supported strategies:

     * "new" - Waits to connect first new appearing serial device

     * "latest" - Connects to latest registered serial device

     * "direct" - Connect directly to specified serial device (default)

 * Add options to exclude serial devices from auto connect strategy by
   pattern

   * Supported exclude options:

     * --exclude-devices <pattern>

       Example: '--exclude-devices "/dev/ttyUSB2,/dev/ttyS?"'

     * --exclude-drivers <pattern>

       Example: '--exclude-drivers "cdc_acm"'

     * --exclude-tids <pattern>

       Example: '--exclude-tids "yW07,bCC2"'

     * Patterns support '*' and '?'

 * Connect to same port/device combination via unique topology ID (TID)

   * Topology ID is a 4 digit base62 encoded hash of a device topology
     string coming from the Linux kernel. This means that whenever you
     plug in the same e.g. USB serial port device to the same USB hub
     port connected via the exact same hub topology all the way to your
     computer, you will get the same unique TID.

   * Useful for stable reconnections when serial device has no serial
     device by ID

   * For now, only tested on Linux.

 * Reworked and improved listing of serial devices to show serial devices:

   * By device

     * Including TID, uptime, driver, and description.

     * Sorted by uptime (newest device listed last)

   * By unique topology ID

   * By ID

   * By path

 * Add script interface 'list = tty_search()' for searching for serial
   devices.
2024-04-26 22:19:22 +02:00
Martin Lund
ae76f8f58d Clean up timestamp enum definition 2024-04-20 15:02:43 +02:00
Martin Lund
b05f38abd0 Add missing options to show configuration 2024-04-20 14:51:45 +02:00
Martin Lund
51bfa68bdd Text cleanup 2024-04-20 14:03:38 +02:00
Martin Lund
fa4207ddfd Update description of mute option 2024-04-19 20:14:22 +02:00
Martin Lund
3ca6a66d9b Add lua read_string() function 2024-04-19 17:10:36 +02:00
Martin Lund
f1c5394570 Don't forget to log output in lua expect() 2024-04-19 16:57:27 +02:00
Martin Lund
0105346a11 Cleanup 2024-04-19 16:56:30 +02:00
Martin Lund
96fafc5fb4 Generalize automatic login example for Linux 2024-04-19 14:44:54 +02:00
Davis C
29546bb13a Updated login example with new expect logic 2024-04-19 14:41:30 +02:00
Martin Lund
b0e9fa02e8 Fix log output in hex output mode 2024-04-18 18:55:08 +02:00
Martin Lund
f257b7fba5 Update README 2024-04-18 16:23:41 +02:00
Martin Lund
6fff4939e4 Add timeout based timestamps in hex output mode
This change reintroduces timestamping in hex output mode but based on
timeout instead of new lines which made no sense. This means that
timestamps will only be printed when timeout time has elapsed with no
output activity from serial device.

Adds option --timestamp-timeout <ms> for setting the timeout value in
milliseconds.

Defaults to 200 ms.
2024-04-18 15:52:45 +02:00
Martin Lund
a8e0d2693d Do not echo CR in line input and hex output mode 2024-04-18 14:44:39 +02:00
Martin Lund
c440da2ea8 Improve switched messages 2024-04-18 13:35:09 +02:00
Martin Lund
f1144ca5cc Cleanup 2024-04-18 13:29:06 +02:00
Martin Lund
3cc2d90fda Extend lua expect() to also return matched string 2024-04-17 23:38:21 +02:00
Martin Lund
48c9e8a9a9 Update AUTHORS 2024-04-17 18:30:53 +02:00
Martin Lund
f4c4387e05 Add automatic login script example 2024-04-17 18:27:46 +02:00
Martin Lund
a1987b61b4 Organize examples directory 2024-04-17 18:24:33 +02:00
Martin Lund
f8924182d3 Update TODO 2024-04-17 18:15:51 +02:00
Davis C
d0e95c5fba Reset buffer size at start of expect 2024-04-17 18:13:00 +02:00
Davis C
1cefb7b6bc Revert "Added reset_buffer()"
This reverts commit ee56d1280d.
2024-04-17 18:13:00 +02:00
Davis C
794c5202f4 Added reset_buffer() 2024-04-17 18:13:00 +02:00
Davis C
98653566a8 Return 1 when expect matches 2024-04-17 18:13:00 +02:00
Martin Lund
a605533213 Fix local echo in line mode 2024-04-17 16:17:20 +02:00
Martin Lund
1e20948d83 Fix line input mode
Do not forward input characters to tty device before a line is input via
carriage return.
2024-04-16 19:38:45 +02:00
Martin Lund
4801816357 Introduce basic line input mode 2024-04-16 17:42:34 +02:00
Martin Lund
d60363a64c Cleanup global variable name shadowing 2024-04-15 11:21:36 +02:00
Martin Lund
5c45150f58 Bump version 2024-04-14 18:43:58 +02:00
Martin Lund
d3993da6d4 Update AUTHORS 2024-04-14 18:05:01 +02:00
Martin Lund
00f3ea9b7f Update NEWS 2024-04-14 18:04:51 +02:00
Martin Lund
e8114ca0a4 Update version date 2024-04-14 18:04:31 +02:00
Martin Lund
de0a7c547f Rework resolve_config_file() 2024-04-14 12:52:28 +02:00
Martin Lund
76a7a56e85 Rework line_pulse_duration_option_parse()
Introduce proper sscanf() checks.
2024-04-14 11:43:23 +02:00
Martin Lund
9744fcafcf Rework rs485_parse_config()
Introduce proper sscanf() checks.
2024-04-14 11:30:39 +02:00
Martin Lund
c4878a90d7 Clean up file descriptor name shadowing 2024-04-14 10:42:22 +02:00
Martin Lund
ae461dc296 Add missing header guard 2024-04-14 10:23:43 +02:00
Martin Lund
10eedd4ad2 Update README 2024-04-14 02:32:25 +02:00
Martin Lund
fa41771e65 Update README 2024-04-14 01:50:50 +02:00
Martin Lund
a1a4dc4642 Update plain text man page 2024-04-14 01:42:43 +02:00
Martin Lund
7dbb806311 Upgrade inih subproject 2024-04-14 01:08:37 +02:00
Martin Lund
97537853a8 Remove options --response-wait, --response-timeout
Remove options and rework input handling so it is possible to do the
same thing but via script which is much more flexible.

These options were always a bit of a hardcoded solution. With the new
script expect feature we can wait for any type of response.

For example, pipe command to serial device and wait for line response within 1 second:

$ echo "*IDN?" | tio /dev/ttyACM0 --script "expect('\r\n', 1000)" --mute
2024-04-13 23:18:25 +02:00
Martin Lund
e1e3e298bf Add lua exit(code) 2024-04-13 16:46:00 +02:00
Martin Lund
c5dac4fd33 pdate README 2024-04-13 15:48:32 +02:00
Martin Lund
51300cc4f0 Add timeout feature to expect() 2024-04-13 15:30:14 +02:00
Martin Lund
3ad090caf7 Update README 2024-04-13 00:56:41 +02:00
Martin Lund
fba73f98db Update README 2024-04-13 00:11:44 +02:00
Martin Lund
2db87ede53 Update README 2024-04-12 22:21:35 +02:00
Martin Lund
fca76a017d Fix text alignment 2024-04-12 21:15:36 +02:00
Martin Lund
7915c1a445 Update README 2024-04-12 18:51:17 +02:00
Martin Lund
6c75ec553d Update README 2024-04-12 18:36:31 +02:00
Martin Lund
fc54df1f22 Add lua expect(string)
Add simple expect functionality.

The expect(string) function will wait for input from the tty device and
only return when there is a string match. Regular expressions are
supported.

Example:

script = expect('password:'); send('my_password\n')
2024-04-12 18:20:33 +02:00
Martin Lund
0afae5d3ee Update text 2024-04-12 13:03:51 +02:00
Martin Lund
e028544cd0 Update plain text man page 2024-04-12 00:24:01 +02:00
Martin Lund
5eb649278a Clean up man page 2024-04-12 00:23:04 +02:00
Martin Lund
418a43d96e Add lua send(string) 2024-04-12 00:08:45 +02:00
Martin Lund
00c8124a0a Add lua modem_send(file,protocol) 2024-04-11 21:20:50 +02:00
Martin Lund
78f96bd32c Fix xymodem error print outs 2024-04-10 20:13:44 +02:00
Martin Lund
d8fb1ab0ca Rework x/y-modem transfer command
Remove ctrl-t X optin and instead introduce submenu to ctrl-t x option
for picking which xmodem protocol to use.
2024-04-10 19:56:21 +02:00
Martin Lund
a208c9908a Update README 2024-04-10 15:05:29 +02:00
Martin Lund
2b6a79b9f0 Cleanup options 2024-04-10 15:04:47 +02:00
Martin Lund
2fff4d36d0 Add independent input and output mode
Replaces -x, --hexadecimal option with --intput-mode and --output-mode
so it is possible to select hex or normal mode for both input and output
independently.

To obtain same behaviour as -x, --hexadecimal use the following
configuration:

input-mode = hex
output-mode = hex
2024-04-10 14:40:18 +02:00
HiFiPhile
fd6a246908 Add manpage. 2024-04-09 14:58:17 +02:00
HiFiPhile
901e00bba3 Poll on serial port read instead of delay. 2024-04-09 14:58:17 +02:00
Mengsk
eea46a2005 Add Xmodem-CRC support. 2024-04-09 14:58:17 +02:00
Martin Lund
2ee1f5c224 Update README 2024-04-07 12:40:47 +02:00
Martin Lund
3e50191107 Add tty line configuration script API
On some platforms calling high()/low() to switch line states result in
costly system calls whick makes it impossible to swith two or more tty
lines simultaneously.

To help solve this timing issue we introduce a tty line state
configuration API which can be used instead of using
high()/low().

Using config_low(line) and config_high(line) one can set up a new line
state configuration for multiple lines and then use config_apply() to
finally apply the configuration. This will result in only one system
call to instruct the serial port drive to switch all the configured line
states which should help ensure that the lines are switched
simultaneously.

Example:

script = config_high(DTR); config_low(RTS); config_apply()
2024-04-06 09:34:25 +02:00
Martin Lund
4369d5b66f Add ONULBRK mapping flag
Add ONULBRK mapping to map nul (zero) to send break signal on output.

This is useful if one needs to e.g. send the break signal to the tty
device when connected via socket.
2024-04-05 13:55:51 +02:00
Martin Lund
70913fe120 Add --log-directory option
For specifying directory path in which to save automatically named log
files.
2024-04-04 12:31:55 +02:00
Martin Lund
83f826349b Update codeql config 2024-04-02 03:52:54 +02:00
Martin Lund
00f57c9992 Update circleCI 2024-04-01 15:55:03 +02:00
Martin Lund
0becfa3274 Add Lua scripting feature
Add support for running Lua scripts that can manipulate the tty control
lines. Script is activated automatically on connect or manually via in
session key command.

The Lua scripting feature opens up for many posibilities in the future
such as adding expect like functionality to easily and programatically
interact with the connected device.
2024-04-01 15:37:40 +02:00
Martin Lund
6fee8514f4 Invert line states to reflect true electrical level 2024-03-30 16:31:45 +01:00
Martin Lund
10255d52d0 Update AUTHORS 2024-03-24 11:21:42 +01:00
Mingjie Shen
6720da3b88 Check return values of sscanf()
Failing to check that a call to 'sscanf' actually writes to an output
variable can lead to unexpected behavior at reading time.
2024-03-24 11:03:51 +01:00
Jakob Haufe
ed4ac0c797 Support NO_COLOR env variable as per no-color.org 2024-03-06 13:38:59 +01:00
Martin Lund
d45c9b1a22 Update TODO 2024-03-01 12:28:51 +01:00
Martin Lund
91459c2490 Update AUTHORS 2024-02-19 16:51:24 +01:00
Martin Lund
593f9495f4 Add support for disabling prefix key handling
To disable prefix key input handing simply set prefix-ctrl-key to
'none'.

Based on original patch from Sebastian Krahmer.
2024-02-19 16:51:02 +01:00
Martin Lund
6c520090c6 Add meson man pages install option
Defaults to installing man pages.
2024-02-13 13:49:29 +01:00
Martin Lund
67640d4a00 Update AUTHORS 2024-02-12 22:25:07 +01:00
Fredrik Svedberg
58c9489b92 Add map FF to ESC-c on input
Added map of form feed to ESC-c on input for terminals that
do not clear screen on ^L but do on ESC-c.
2024-02-12 22:22:20 +01:00
Brian
553b67e406
Add CodeQL Workflow for Code Security Analysis (#220)
* Add CodeQL Workflow for Code Security Analysis

Add CodeQL Workflow for Code Security Analysis

This pull request introduces a CodeQL workflow to enhance the security analysis of our repository. CodeQL is a powerful static analysis tool that helps identify and mitigate security vulnerabilities in our codebase. By integrating this workflow into our GitHub Actions, we can proactively identify and address potential issues before they become security threats.

We added a new CodeQL workflow file (.github/workflows/codeql.yml) that
- Runs on every push and pull request to the main branch.
- Excludes queries with a high false positive rate or low-severity findings.
- Does not display results for third-party code, focusing only on our own codebase.

Testing:
To validate the functionality of this workflow, we have run several test scans on the codebase and reviewed the results. The workflow successfully compiles the project, identifies issues, and provides actionable insights while reducing noise by excluding certain queries and third-party code.

Deployment:
Once this pull request is merged, the CodeQL workflow will be active and automatically run on every push and pull request to the main branch. To view the results of these code scans, please follow these steps:
1. Under the repository name, click on the Security tab.
2. In the left sidebar, click Code scanning alerts.

Additional Information:
- You can further customize the workflow to adapt to your specific needs by modifying the workflow file.
- For more information on CodeQL and how to interpret its results, refer to the GitHub documentation and the CodeQL documentation.

Signed-off-by: Brian <bayuan@purdue.edu>

* Add CodeQL Workflow for Code Security Analysis

Add CodeQL Workflow for Code Security Analysis

This pull request introduces a CodeQL workflow to enhance the security analysis of our repository. CodeQL is a powerful static analysis tool that helps identify and mitigate security vulnerabilities in our codebase. By integrating this workflow into our GitHub Actions, we can proactively identify and address potential issues before they become security threats.

We added a new CodeQL workflow file (.github/workflows/codeql.yml) that
- Runs on every pull request (functionality to run on every push to main branches is included as a comment for convenience).
- Runs daily.
- Excludes queries with a high false positive rate or low-severity findings.
- Does not display results for git submodules, focusing only on our own codebase.

Testing:
To validate the functionality of this workflow, we have run several test scans on the codebase and reviewed the results. The workflow successfully compiles the project, identifies issues, and provides actionable insights while reducing noise by excluding certain queries and third-party code.

Deployment:
Once this pull request is merged, the CodeQL workflow will be active and automatically run on every push and pull request to the main branch. To view the results of these code scans, please follow these steps:
1. Under the repository name, click on the Security tab.
2. In the left sidebar, click Code scanning alerts.

Additional Information:
- You can further customize the workflow to adapt to your specific needs by modifying the workflow file.
- For more information on CodeQL and how to interpret its results, refer to the GitHub documentation and the CodeQL documentation (https://codeql.github.com/ and https://codeql.github.com/docs/).

Signed-off-by: Brian <bayuan@purdue.edu>

* Add CodeQL Workflow for Code Security Analysis

Add CodeQL Workflow for Code Security Analysis

This pull request introduces a CodeQL workflow to enhance the security analysis of our repository. CodeQL is a powerful static analysis tool that helps identify and mitigate security vulnerabilities in our codebase. By integrating this workflow into our GitHub Actions, we can proactively identify and address potential issues before they become security threats.

We added a new CodeQL workflow file (.github/workflows/codeql.yml) that
- Runs on every pull request (functionality to run on every push to main branches is included as a comment for convenience).
- Runs daily.
- Excludes queries with a high false positive rate or low-severity findings.
- Does not display results for git submodules, focusing only on our own codebase.

Testing:
To validate the functionality of this workflow, we have run several test scans on the codebase and reviewed the results. The workflow successfully compiles the project, identifies issues, and provides actionable insights while reducing noise by excluding certain queries and third-party code.

Deployment:
Once this pull request is merged, the CodeQL workflow will be active and automatically run on every push and pull request to the main branch. To view the results of these code scans, please follow these steps:
1. Under the repository name, click on the Security tab.
2. In the left sidebar, click Code scanning alerts.

Additional Information:
- You can further customize the workflow to adapt to your specific needs by modifying the workflow file.
- For more information on CodeQL and how to interpret its results, refer to the GitHub documentation and the CodeQL documentation (https://codeql.github.com/ and https://codeql.github.com/docs/).

Signed-off-by: Brian <bayuan@purdue.edu>

* Add CodeQL Workflow for Code Security Analysis

Add CodeQL Workflow for Code Security Analysis

This pull request introduces a CodeQL workflow to enhance the security analysis of our repository. CodeQL is a powerful static analysis tool that helps identify and mitigate security vulnerabilities in our codebase. By integrating this workflow into our GitHub Actions, we can proactively identify and address potential issues before they become security threats.

We added a new CodeQL workflow file (.github/workflows/codeql.yml) that
- Runs on every pull request (functionality to run on every push to main branches is included as a comment for convenience).
- Runs daily.
- Excludes queries with a high false positive rate or low-severity findings.
- Does not display results for git submodules, focusing only on our own codebase.

Testing:
To validate the functionality of this workflow, we have run several test scans on the codebase and reviewed the results. The workflow successfully compiles the project, identifies issues, and provides actionable insights while reducing noise by excluding certain queries and third-party code.

Deployment:
Once this pull request is merged, the CodeQL workflow will be active and automatically run on every push and pull request to the main branch. To view the results of these code scans, please follow these steps:
1. Under the repository name, click on the Security tab.
2. In the left sidebar, click Code scanning alerts.

Additional Information:
- You can further customize the workflow to adapt to your specific needs by modifying the workflow file.
- For more information on CodeQL and how to interpret its results, refer to the GitHub documentation and the CodeQL documentation (https://codeql.github.com/ and https://codeql.github.com/docs/).

Signed-off-by: Brian <bayuan@purdue.edu>

* Update codeql-buildscript.sh

---------

Signed-off-by: Brian <bayuan@purdue.edu>
2024-02-07 00:31:35 +01:00
Sylvain LAFRASSE
4269ec835d Fix double call of tty_disconnect() on macOS/Darwin. 2024-01-12 12:11:24 +01:00
Martin Lund
e572255fd2 Fix file descriptor handling on MacOS 2024-01-11 20:36:17 +01:00
Martin Lund
bfefd04b55 Update README 2023-12-10 21:43:11 +01:00
Jakob Haufe
ed66c72ca1
Fix troff warning (#216)
.eo/.ec sections seemingly need explicit empty lines using .sp

Otherwise, troff complains:

troff:<standard input>:535: warning: expected numeric expression, got '\'
troff:<standard input>:538: warning: expected numeric expression, got '\'
troff:<standard input>:541: warning: expected numeric expression, got '\'
2023-12-08 10:43:37 +01:00
Martin Lund
14f598e11e Update README 2023-09-28 12:52:01 +02:00
Martin Lund
7193e6f0c9 Bump version 2023-09-22 16:57:44 +02:00
HiFiPhile
72399c4fe6
CYGWIN: Fix port auto connection. (#211) 2023-09-22 11:53:37 +02:00
Martin Lund
1777206de7 Update plain text man page 2023-09-21 08:47:34 +02:00
Martin Lund
1c32555c2a Update NEWS 2023-09-19 21:48:58 +02:00
Martin Lund
4307e81760 Update AUTHORS 2023-09-19 21:47:55 +02:00
Martin Lund
3d7d9c85b5 Bump version 2023-09-19 21:37:05 +02:00
Martin Lund
02b60e9fb3 Revert "Make quit hint more explicit"
This reverts commit 93e49ab5a2.
2023-09-19 21:21:59 +02:00
Martin Lund
c93922fd36 Update README 2023-09-16 16:10:30 +02:00
Martin Lund
838c110876 Increase header size for ymodem 2023-09-16 15:03:38 +02:00
Martin Lund
a42f3f78d1 Overwrite old stale letters on xmodem filename input
When entering a file name, eg. 'test' it whould output the following
with 2 stale letters of the former input string:

[14:41:58.987] Send file with XMODEM
[14:42:08.015] Sending file 'test'st
[14:42:08.015] Press any key to abort transfer

To avoid this we simply overwrite the 2 stale letters with whitespaces.
2023-09-16 14:51:34 +02:00
Martin Lund
93e49ab5a2 Make quit hint more explicit
To minimize confusion for new users.
2023-09-16 14:13:27 +02:00
Martin Lund
ed0386d2c4 Re-adjust max line size
So it stays within maximum size handled by xmodem.
2023-09-16 13:14:55 +02:00
Martin Lund
63dced047f Update AUTHORS 2023-09-16 12:30:52 +02:00
Martin Lund
cf6e8b963b Clean up whitespaces 2023-09-16 12:27:34 +02:00
Martin Lund
07864a0e78 Increase line buffer size
Just to make sure we accept very long filenames.
2023-09-16 12:25:38 +02:00
Martin Lund
c9c5f03c10 Fix meson source listing 2023-09-16 12:20:34 +02:00
pnrhub
e6ffbd9058
Add xmodem and ymodem file send support (#208)
* Add xmodem and ymodem file send support
---------

Co-authored-by: pnr <pnr@home25.nl>
2023-09-16 12:17:38 +02:00
Martin Lund
812dee8e54
Merge pull request #207 from HiFiPhile/eintr
tty_stdin_input_thread(): write to pipe only if byte_count > 0.
2023-09-14 00:19:39 +02:00
HiFiPhile
d9dc1ff698 tty_stdin_input_thread(): write to pipe only if byte_count > 0. 2023-09-14 00:06:46 +02:00
Martin Lund
c01baca157
Merge pull request #206 from HiFiPhile/eintr
Ignore EINTR error.
2023-09-13 23:30:04 +02:00
HiFiPhile
5c441f22c2 Ignore EINTR error. 2023-09-13 22:45:11 +02:00
Martin Lund
8134cd3486 Update AUTHORS 2023-09-10 13:57:12 +02:00
Martin Lund
46a72d8254
Merge pull request #204 from HiFiPhile/com
CYGWIN: Add support for "COM*" naming.
2023-09-10 13:55:47 +02:00
HiFiPhile
bdca5a27ec CYGWIN: Add support for "COM*" naming. 2023-09-10 13:32:01 +02:00
Martin Lund
3c7c865e59 Update man page 2023-09-07 00:55:52 +02:00
Martin Lund
59cd3a1379 Update README 2023-08-20 23:48:43 +02:00
Martin Lund
98052936b0 Update TODO 2023-08-18 14:20:14 +02:00
Martin Lund
a486ba581b
Merge pull request #200 from weskoerber/fix/log-append-cli
fix: support --log-append in cli options
2023-07-14 09:25:41 +02:00
Wes Koerber
df5379bac5 chore: reorder log-strip and log-append
reorder to maintain consistency with documentation
2023-07-13 20:58:20 -04:00
Wes Koerber
5656381cc3 chore: update readme, bash completion, man page 2023-07-13 20:58:01 -04:00
Wes Koerber
d461751a71 fix: support --log-append in cli options
fixes: #199
2023-07-13 20:49:53 -04:00
Martin Lund
88ef473362 Update NEWS 2023-06-10 13:02:32 +02:00
Martin Lund
d3bd5d8e17 Remove warning when using pattern option 2023-06-09 20:13:39 +02:00
Martin Lund
148a3c1da1 Add --log-append option
Add --log-append option which makes tio append to any existing log file.

This also changes the default behaviour of tio from appending to
overwriting any existing log file. Now you have to use this new option
to make tio append.
2023-04-28 20:50:34 +02:00
Martin Lund
3bedd85e7c Update man page 2023-04-27 10:13:57 +02:00
Martin Lund
ab905d8e0c Update README 2023-04-22 20:41:27 +02:00
Martin Lund
8fe5dde4b8 Fix line termination for response wait feature
The response wait feature waited for a line response, a string
terminated with either CR or NL. However, some devices may send a CR and
then their line content and then NL. This means tio will quit before
receiving and printing the line response. To solve this we simply ignore
the CR character and only consider lines terminated with a NL character.

This should work for all devices as lines are AFAIK always terminated
with either CRNL or a NL.
2023-04-20 17:28:43 +02:00
Martin Lund
b5ca54c56e Update README 2023-04-15 00:19:17 +02:00
Martin Lund
fd1003533c Update AUTHORS 2023-04-15 00:13:26 +02:00
Martin Lund
ec2cf476bb
Merge pull request #194 from somewear-labs/socketInputModes
Support input mapping modes for sockets
2023-04-15 00:09:40 +02:00
Braden Young
afc9e3be5b Move map variables to tty to keep them all in one spot 2023-04-14 15:00:03 -07:00
Braden Young
5651c1c5d7 Configure socket mapping flags from tty parsing logic. Remove duplicate parsing logic in socket 2023-04-14 13:08:48 -07:00
Braden Young
65b3353f57 Support input mapping modes for sockets 2023-04-14 11:18:27 -07:00
Martin Lund
791b1df27e Merge branch 'master' of https://github.com/tio/tio 2023-04-08 20:02:39 +02:00
Martin Lund
f5c8d5233c Add tio icon to README 2023-04-08 20:02:32 +02:00
Martin Lund
5635f30135
Merge pull request #192 from jsoref/spelling
Spelling
2023-04-04 06:39:53 +02:00
Josh Soref
cbb8ad8362 spelling: timestamp
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-04-03 17:40:32 -04:00
Josh Soref
b540f16734 spelling: interactive
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-04-03 17:40:32 -04:00
Josh Soref
2f3583ebde spelling: configurations
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-04-03 17:40:32 -04:00
Josh Soref
36e4c672a7 spelling: being
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-04-03 17:40:32 -04:00
Josh Soref
cee560dd8b spelling: autoconf
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-04-03 17:40:32 -04:00
Josh Soref
fcf760f0d7 spelling: arguments
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-04-03 17:40:32 -04:00
Josh Soref
a6f1b8d546 spelling: adds
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
2023-04-03 17:40:32 -04:00
Martin Lund
4f509594d8 Update README 2023-03-31 13:14:11 +02:00
Martin Lund
4008969ca7
Merge pull request #191 from Habbie/setspeed-warning-unused
avoid "warning: unused parameter" on setspeed stub
2023-03-20 21:09:06 +01:00
Peter van Dijk
c16e004757 avoid "warning: unused parameter" on setspeed stub 2023-03-20 20:00:50 +00:00
Martin Lund
309a2abfd4 Update AUTHORS 2023-03-11 02:15:56 +01:00
Martin Lund
269974c244
Merge pull request #189 from Habbie/haiku
use right /dev/ path on Haiku
2023-03-11 02:09:04 +01:00
Peter van Dijk
0cdc3ce045 use right /dev/ path on Haiku 2023-03-10 23:58:52 +00:00
Martin Lund
f6905b4213 Update tty device listing configuration
Cleanup and add FreeBSD tty device listing support.
2023-02-28 17:57:10 +01:00
Martin Lund
725faa5455 Update AUTHORS 2023-01-30 16:14:37 +01:00
Martin Lund
e1774664dd
Merge pull request #188 from bhass1/readme_snap_classic
Update README with details on snap confinement
2023-01-30 16:13:29 +01:00
Bill Hass
35c9b40982 Update README with details on snap confinement 2023-01-29 19:34:09 -05:00
Martin Lund
b533312d45 Update README 2023-01-27 21:17:53 +01:00
Martin Lund
c6f319ecb0 Mention which keystrokes are forwarded 2023-01-12 00:08:27 +01:00
Martin Lund
b6672c1704 Update TODO 2023-01-08 22:44:27 +01:00
Martin Lund
ae604d12e2 Update README 2023-01-08 13:58:48 +01:00
Martin Lund
4782faf47f Update plain text man page 2023-01-05 08:23:09 +01:00
Martin Lund
4a1c213409 Update man page 2023-01-05 08:20:44 +01:00
Martin Lund
27b8c1b82a Update TODO 2022-12-25 16:02:47 +01:00
Martin Lund
76eb17e4d4 Bump version 2022-12-17 17:28:28 +01:00
Martin Lund
a2bbab0684 Update plain text man page 2022-12-17 17:11:22 +01:00
Martin Lund
dfe5f827f9 Update NEWS 2022-12-17 17:10:20 +01:00
Martin Lund
ea7f43e60c Update configuration file documentation
Rename .tiorc to .tioconfig, tiorc to config, etc.
2022-12-17 16:59:37 +01:00
Martin Lund
4e9d29c88d Add support for $HOME/.tioconfig
Replaces what used to be $HOME/.tiorc
2022-12-07 04:10:56 +01:00
Martin Lund
6a955b08e1 Update AUTHORS 2022-12-06 18:48:19 +01:00
Martin Lund
20a40edd36
Merge pull request #181 from vpatkov/master
Better error checking in config file, rename the file
2022-12-06 18:37:55 +01:00
Vyacheslav Patkov
42739c0817 Better error checking in config file, rename the file
Accept "true", "enable", "on", "yes", "1" as true values, their
counterparts as false ones. Check integer values for errors and range.
Warn about ignored (e.g. misspelled) options.

Check getenv() return value for NULL.

Rename "tiorc" to "config", as it's a static INI file, not an executable
"run commands".
2022-12-06 20:27:14 +04:00
Martin Lund
2915d26a19 Fix double prefix key regression 2022-12-05 16:27:53 +01:00
Martin Lund
e2e974958e Bump version 2022-12-02 13:42:53 +01:00
Martin Lund
6b084a53b8 Update version tag date 2022-12-02 13:05:00 +01:00
Martin Lund
a21809b090 Update plain text man page 2022-12-02 12:59:51 +01:00
Martin Lund
cd24797961 Update flush command 2022-12-02 12:45:45 +01:00
Martin Lund
f4dc46d002 Update NEWS 2022-12-02 04:12:35 +01:00
Martin Lund
93e6efc001 Add threaded input handling
To make tio more responsive to quit and I/O flush key command when main I/O
thread is blocked on output.
2022-11-28 14:44:32 +01:00
Martin Lund
12f20c84e3 Fix so that is it possible to quit tio in tio etc.
Fix regression so that it is possible to send the prefix key code to the
remote tio session without local tio session reacting to same key code
(quitting etc.).
2022-11-28 14:30:54 +01:00
Martin Lund
419fbdc3fa Add key command to toggle log on/off
Add key command 'ctrl-t f' which will toggle log on/off.

If no log filename has been specified via the 'log-filename' option then
tio will automatically generate a new log filename every time the log
feature is toggled on. Meaning, when toggled multiple times, multiple
log files will be generated.

However, if a log filename has been specified, tio will only write and
append to that same file.
2022-11-23 17:24:54 +01:00
Martin Lund
a4f0d4da53 Add socket input comment 2022-11-21 17:16:14 +01:00
Martin Lund
1aaecef419 Update plain text man page 2022-11-01 11:11:54 +01:00
Martin Lund
6c19cd0750 Bump version 2022-11-01 11:10:49 +01:00
Martin Lund
845e683fc9 Update NEWS 2022-11-01 10:55:41 +01:00
Martin Lund
d3ac8e7b1f Update README 2022-11-01 10:49:02 +01:00
Martin Lund
c6beed8265 Update example tiorc 2022-11-01 10:48:54 +01:00
Martin Lund
7c32e5a21e Update TODO 2022-10-31 14:44:07 +01:00
Martin Lund
73c1129be7 Update README 2022-10-29 16:50:22 +02:00
Martin Lund
374c2ad113 Update example configuration file 2022-10-23 22:29:37 +02:00
Martin Lund
c80f833a06 Add mute feature
This will make tio go fully silent and not print anything.
2022-10-22 08:59:41 +02:00
Martin Lund
784201ea2e Deprecate tty config keyword but keep it around for now 2022-10-19 23:56:31 +02:00
Martin Lund
2cba4b863f Update text 2022-10-19 22:44:10 +02:00
Martin Lund
fba56318f8 Update show config 2022-10-19 22:35:34 +02:00
Martin Lund
48a2298e81 Rename config variable 'tty' to 'device' 2022-10-19 22:29:33 +02:00
Martin Lund
6f9e41152b Update show config 2022-10-19 22:18:25 +02:00
Martin Lund
134fa87a5c Bump version 2022-10-18 16:13:35 +02:00
Martin Lund
eaab692d4d Update NEWS 2022-10-18 15:31:28 +02:00
Martin Lund
a40097f837 Update man page 2022-10-18 15:28:59 +02:00
Martin Lund
b00b0e872f Beautify help 2022-10-17 13:55:00 +02:00
Martin Lund
4768db5311 Update README 2022-10-17 13:31:49 +02:00
Martin Lund
c2aa3489fd Fix error message 2022-10-17 01:12:35 +02:00
Martin Lund
ad9b93dc52 Simplify configfile implementation 2022-10-17 00:23:26 +02:00
Martin Lund
a97b2c00cd Add shell completion of sub-configuration names
Does not work with sub configuration names that contains one or more
white spaces.
2022-10-16 23:02:04 +02:00
Martin Lund
bf7b032649 Bump version 2022-10-15 23:15:01 +02:00
Martin Lund
14fc77ffc1 Update plain text man page 2022-10-15 00:58:47 +02:00
Martin Lund
ca5af47e7b Update tag date 2022-10-15 00:57:35 +02:00
Martin Lund
0850b1938b Update NEWS 2022-10-15 00:56:36 +02:00
Martin Lund
c8aeba7ef8 Fix output line delay
Apply output line delay on lines ending with \n.

On most systems lines ends with \n or \r\n.
2022-10-11 12:12:40 +02:00
Martin Lund
a65b5b0e3a Do not print timestamps in hex mode 2022-09-29 20:50:12 +02:00
Martin Lund
5f14924c96 Improve input mechanism in hex mode
Print the 2 character hex code that you input in hex mode but then
delete it before sending. This way it is easier to keep track of what
you are inputting. It basically mimics the ctrl-shift-u input mechanism
that is used to input unicode.
2022-09-29 20:18:36 +02:00
Martin Lund
0b61aaf451 Update AUTHORS 2022-09-29 20:16:47 +02:00
Martin Lund
acefbbbe6c
Merge pull request #169 from attila-v/feature/bit-order
Add bit reverse order feature
2022-09-29 18:09:08 +02:00
Attila Veghelyi
4924969268 Complete bit reorder feature for release 2022-09-29 17:33:35 +02:00
Attila Veghelyi
5b8f33bd78 Add bit reverse order feature 2022-09-29 15:42:44 +02:00
Martin Lund
ce3101a380 Clean up indentation 2022-09-18 19:20:12 +02:00
Martin Lund
e54a13827b Update example tiorc 2022-09-18 12:35:49 +02:00
Martin Lund
d70af20454 Update README 2022-09-18 12:30:55 +02:00
Martin Lund
f2535e4ea0 Update README 2022-09-17 22:57:55 +02:00
Martin Lund
fb89b79b30 Update man page 2022-09-16 13:47:29 +02:00
Martin Lund
3298ba0f1b Update README 2022-09-16 13:43:51 +02:00
Martin Lund
d06623dd7a Update README 2022-09-16 13:35:23 +02:00
Martin Lund
6c168bcc77 Update README 2022-09-16 13:25:18 +02:00
Martin Lund
512bc410f3 Update README 2022-09-14 19:53:27 +02:00
Martin Lund
52c89ca071 Update README 2022-09-13 17:12:28 +02:00
Martin Lund
33f287e8cf Update README 2022-09-13 17:05:05 +02:00
Martin Lund
167988bf27 Update README 2022-09-13 17:03:59 +02:00
Martin Lund
3e728a223c Update README 2022-09-13 17:01:09 +02:00
Martin Lund
1f19ba1302 Update README 2022-09-13 16:59:34 +02:00
Martin Lund
3fab077a7a Update README 2022-09-13 16:58:28 +02:00
Martin Lund
0131a9a051 Update README 2022-09-13 16:57:15 +02:00
Martin Lund
e7dcd5d034 Update README 2022-09-13 16:56:08 +02:00
Martin Lund
7d597d315b Update README 2022-09-13 16:54:36 +02:00
Martin Lund
0f31f17f5d Update README 2022-09-13 16:43:10 +02:00
Martin Lund
97796395aa Update README 2022-09-13 16:32:25 +02:00
Martin Lund
f43ef9b584 Update README 2022-09-13 16:30:49 +02:00
Martin Lund
529692805c Update README 2022-09-13 16:22:57 +02:00
Martin Lund
76a51a4af3 Update README 2022-09-13 16:19:15 +02:00
Martin Lund
eb95a656b0 Update README 2022-09-13 16:15:58 +02:00
Martin Lund
bf3974c2b6 Update README 2022-09-11 22:31:20 +02:00
Martin Lund
ab885713b9 Add support for sending prefix character to serial device
Do so by inputting prefix key twice, e.g. input ctrl-t ctrl-t to send
ctrl-t character to serial device.
2022-09-11 22:17:29 +02:00
Martin Lund
81607424f8 Update README 2022-09-11 20:13:21 +02:00
Martin Lund
d0926b25ba Bump version 2022-09-11 14:00:45 +02:00
Martin Lund
6618642acf Fix tty path on MSYS/CYGWIN platforms 2022-09-11 13:38:13 +02:00
Martin Lund
47827f094b Fix compilation error on systems without RS-485 support 2022-09-11 12:51:48 +02:00
Martin Lund
137e6111f6 Update README 2022-09-11 11:59:42 +02:00
Martin Lund
61b204aa3d Update plain text man page 2022-09-11 11:58:18 +02:00
Martin Lund
16479c8d86 Cleanup 2022-09-11 11:55:19 +02:00
Martin Lund
278750428c Update plain text man page 2022-09-11 11:47:04 +02:00
Martin Lund
f8c9d6091a Update version date 2022-09-11 11:46:24 +02:00
Martin Lund
75c5261fe5 Update NEWS 2022-09-11 11:43:56 +02:00
Martin Lund
8188bb5b76 Handle stale unix socket file
Delete existing unix socket file if it is tested to be stale, meaning no
one is listening on it.
2022-09-11 11:20:27 +02:00
Martin Lund
0afcef807b Cleanup 2022-09-11 00:57:05 +02:00
Martin Lund
1dc3a3891d Cleanup 2022-09-10 23:31:02 +02:00
Martin Lund
ba2d49d2f7 Consolidate timestamp implementation in one file 2022-09-10 23:29:23 +02:00
Martin Lund
a85cfcf3ef Update README 2022-09-10 23:01:28 +02:00
Martin Lund
6224fe292e Update example 2022-09-10 22:53:27 +02:00
Martin Lund
88588100e4 Update plain text man page 2022-09-10 22:46:58 +02:00
Martin Lund
9cad01791b Update NEWS 2022-09-10 22:45:55 +02:00
Martin Lund
989874ffb8 Cleanup 2022-09-10 22:39:36 +02:00
Martin Lund
dbc9a8e82d Add visual or audible alert support on connect/disconnect
The feature is detailed via the following option:

 --alert none|bell|blink

     Set alert action on connect/disconnect.

     It will sound the bell once or blink once on successful connect.
     Likewise it will sound the bell twice or blink twice on disconnect.

     Default value is "none" for no alert.
2022-09-10 22:33:42 +02:00
Martin Lund
68fc159654 Fix listing of serial devices in MSYS2/Cygwin
We generally try to list serial devices by ID but in the MSYS2/Cygwin
environment serial devices are not available by ID and so we simply list
the basic serial device paths instead.
2022-09-10 19:06:18 +02:00
Martin Lund
3c8d7fa786 Update NEWS 2022-09-10 18:08:05 +02:00
Martin Lund
8afbc1d813 Update README 2022-09-10 18:03:08 +02:00
Martin Lund
ee46686fb6 Add experimental RS-485 support
Many modern RS-485 serial devices such as the ones from FTDI already
operate in RS-485 mode by default and will work with tio out of the box.
However, there are some RS-232/485 devices which need to be switched
from e.g. RS-232 to RS-485 mode to operate accordingly on the physical
level.

This commit implements the switching mechanism and interface required to
enable RS-485 mode. It only works on Linux and with serial devices which
use device drivers that support the Linux RS-485 control interface.

The RS-485 feature is detailed via the following options:

 --rs-485                           Enable RS-485 mode
 --rs-485-config <config>           Set RS-485 configuration

Set the RS-485 configuration using the following key or key value pair
format in the configuration field:

 RTS_ON_SEND=value             Set logical level (0 or 1) for RTS pin when sending
 RTS_AFTER_SEND=value          Set logical level (0 or 1) for RTS pin after sending
 RTS_DELAY_BEFORE_SEND=value   Set RTS delay (ms) before sending
 RTS_DELAY_AFTER_SEND=value    Set RTS delay (ms) after sending
 RX_DURING_TX                  Receive data even while sending data

If defining more than one key or key value pair, they must be comma
separated.

Example use:

 $ tio /dev/ttyUSB0 --rs-485 --rs-r485-config=RTS_DELAY_AFTER_SEND=50,RX_DURING_TX
2022-09-10 17:52:54 +02:00
Martin Lund
a58d406a3c Update list description 2022-09-08 09:32:51 +02:00
Martin Lund
fe6827bc7e Clean up man page 2022-08-30 01:11:27 +02:00
Martin Lund
be7f77e214 Update NEWS 2022-08-23 13:13:40 +02:00
Martin Lund
0dd703e5a2 Remove MacPorts instructions
Remove instructions for MacPorts because the port has no maintainer and
the port build definition is broken (missing dependency on libinih etc.).

It is recommended to use brew instead.
2022-08-23 12:58:58 +02:00
Martin Lund
d2aafc24cc Update README 2022-08-19 15:47:19 +02:00
Martin Lund
c12709f9fe
Merge pull request #166 from pcc/sigpipe
Ignore SIGPIPE signals
2022-08-18 02:50:09 +02:00
Peter Collingbourne
db765bc371 Ignore SIGPIPE signals
If the remote end of a socket is closed between when an input character
is received from the serial port and when it is written to the socket,
tio will receive a SIGPIPE signal when writing the character to the
socket, which will terminate the program. To prevent this, ignore the
signal, which will cause write(2) to return -EPIPE, causing tio to close
the socket.
2022-08-17 16:51:15 -07:00
Martin Lund
1219c6b8c0 Update README 2022-08-16 05:12:39 +02:00
Martin Lund
34e9d028a1 Bump version to v2.0 2022-08-15 20:05:40 +02:00
Martin Lund
e837fd0303 Add line response feature
Add a simple line response feature to make it possible to send e.g. a
command string to your serial device and easily receive and parse a line
response.

This is a convenience feature for simple request/response interaction
based on lines. For more advanced interaction the socket feature should
be used instead.

The line response feature is detailed via the following options:

 -r, --response-wait

Wait for line response then quit. A line is considered any string ending
with either CR or NL character. If no line is received tio will quit
after response timeout.

Any tio text is automatically muted when piping a string to tio while in
response mode to make it easy to parse the response.

 --response-timeout <ms>

Set timeout [ms] of line response (default: 100).

Example:

Sending a string (SCPI command) to a test instrument (Korad PSU) and
print line response:

 $ echo "*IDN?" | tio /dev/ttyACM0 --response-wait
 KORAD KD3305P V4.2 SN:32477045
2022-08-15 19:58:28 +02:00
Martin Lund
a75e04b883 Update man page 2022-08-15 11:00:47 +02:00
Martin Lund
614517bfc4 Update README 2022-08-13 22:50:22 +02:00
Martin Lund
f82d2353d4 Update README 2022-08-08 15:08:34 +02:00
Martin Lund
b3a0917bc9 Update .gitignore 2022-08-06 17:12:49 +02:00
Martin Lund
72eb682267 Cleanup hex mode code 2022-08-06 17:12:16 +02:00
Martin Lund
75aa066bf8 Fix potential sscanf() overflow 2022-08-06 16:54:59 +02:00
Martin Lund
15bef05179 Only print version on '--version' 2022-07-28 21:32:00 +02:00
Martin Lund
a9b7284ba2 Revert "Enable log feature when using --log-filename"
This reverts commit c3116b2b56.

On second thought, this is less appropriate when using the configuration
file. We may want to define the log filename in config file but not
necessarily enable log feature.
2022-07-28 21:23:52 +02:00
Martin Lund
0407436624 Update README 2022-07-27 15:06:32 +02:00
Martin Lund
99c7aa85ed Update TODO 2022-07-25 20:38:04 +02:00
Martin Lund
4598345168 Update TODO 2022-07-25 20:36:38 +02:00
Martin Lund
4952c6ca13 Update TODO 2022-07-25 20:29:06 +02:00
Martin Lund
70f69899fc Cleanup 2022-07-25 12:48:20 +02:00
Martin Lund
1fb0cad7b9 Update README 2022-07-25 11:06:08 +02:00
Martin Lund
dd785f9a30 Update README 2022-07-25 11:04:05 +02:00
Martin Lund
31459f851b Update README 2022-07-25 11:01:31 +02:00
Martin Lund
4c9f28203d Update README 2022-07-25 10:58:46 +02:00
Martin Lund
463415d63b Remove duplicate show config entry of DTR pulse duration 2022-07-24 20:57:34 +02:00
Martin Lund
b5273b2b23 Bump version 2022-07-23 20:05:51 +02:00
Martin Lund
0eb59b09cf Update README 2022-07-23 14:52:58 +02:00
Martin Lund
e8efb621f8 Bump version date 2022-07-23 12:21:48 +02:00
Martin Lund
a133a241d6 Update NEWS 2022-07-23 12:02:35 +02:00
Martin Lund
c3116b2b56 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.
2022-07-23 10:40:35 +02:00
Martin Lund
a13fe254f2 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.
2022-07-23 09:53:12 +02:00
Martin Lund
d28007f0d3 Avoid invalid hex character messages when switching hex mode 2022-07-22 22:03:47 +02:00
Martin Lund
c24cbfcd34 Force flushing of log writes 2022-07-22 17:57:11 +02:00
Martin Lund
f454bdaa3a Cleanup 2022-07-22 16:40:15 +02:00
Martin Lund
b322ecbdcf Renamed tty_flush() to tty_sync() 2022-07-22 16:37:49 +02:00
Martin Lund
de606d51ba 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.
2022-07-22 16:28:38 +02:00
Martin Lund
0cdd69940f Clean up tty_flush() 2022-07-22 00:45:30 +02:00
Martin Lund
443e07ef8a Update README 2022-07-22 00:29:10 +02:00
Martin Lund
dd8b137b15 Force frequent sync on tty_flush() 2022-07-22 00:16:54 +02:00
Martin Lund
2fb1963da2 Update README 2022-07-22 00:02:42 +02:00
Martin Lund
b082b0593b Update example tiorc 2022-07-21 09:01:13 +02:00
Martin Lund
b1102b59e0 Update AUTHORS 2022-07-21 08:56:54 +02:00
Martin Lund
616003a55f Bump version 2022-07-20 20:56:43 +02:00
Martin Lund
6462aac792 Simplify tty_flush() 2022-07-20 20:46:01 +02:00
Martin Lund
5f46136b28 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.
2022-07-20 18:18:16 +02:00
Martin Lund
eadcc7e384 Make sure we flush output buffer to tty when piping to tio 2022-07-20 17:56:43 +02:00
Martin Lund
a0a8dccd51 Do not return false read error when piping to tio 2022-07-20 13:11:11 +02:00
Martin Lund
40c8753151 Show error message when reading port settings fail 2022-07-20 12:25:51 +02:00
Martin Lund
4031636bce Update README 2022-07-20 11:25:58 +02:00
Martin Lund
02637a92ca
Merge pull request #162 from rhapsodyv/patch-1
Add MacPorts install instructions
2022-07-20 11:19:51 +02:00
Victor Oliveira
3bb0ffdeff add macports install instructions
MacPorts support is added by https://github.com/macports/macports-ports/pull/15400
2022-07-19 16:42:53 -03:00
Martin Lund
c57f2c9fba Update README 2022-07-19 18:24:03 +02:00
Martin Lund
e96d289718 Cleanup 2022-07-19 14:54:02 +02:00
Martin Lund
cbff112ec3 Update NEWS 2022-07-19 14:52:21 +02:00
Martin Lund
a01d8b38b1 Update plain text man page 2022-07-19 13:02:29 +02:00
Martin Lund
62c00ce05e Update TODO 2022-07-19 12:57:12 +02:00
Martin Lund
3903880106 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
2022-07-19 12:54:40 +02:00
Martin Lund
35f249394c Update AUTHORS 2022-07-18 19:02:03 +02:00
Ralph Siemsen
34e95bb4a5 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().
2022-07-18 18:58:28 +02:00
Martin Lund
0bbaf4a296 Update plain text man page 2022-07-17 13:54:56 +02:00
Martin Lund
5fd3bf60ba Update man page 2022-07-17 13:14:59 +02:00
Martin Lund
f26abe91b8 Upgrade inih wrap to r56 2022-07-17 13:07:07 +02:00
Martin Lund
110aa1d9dd Update TODO 2022-07-17 09:34:33 +02:00
Martin Lund
fc3e6c40ec Optimization 2022-07-17 09:34:03 +02:00
Martin Lund
4c2d4ed67f Update README 2022-07-17 03:20:56 +02:00
Martin Lund
371a34d23a Add example configuration file 2022-07-16 12:31:53 +02:00
Martin Lund
8b77111bb1 Bump version 2022-07-15 19:56:11 +02:00
Martin Lund
c931d7690d Update plain text man page 2022-07-15 19:55:52 +02:00
Martin Lund
862a3ecadd Bump version date 2022-07-15 19:03:08 +02:00
Martin Lund
7b5529b31f Update NEWS 2022-07-15 19:02:36 +02:00
Martin Lund
019e93a0ed Update AUTHORS 2022-07-15 19:00:19 +02:00
Martin Lund
9733bdf19c 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.
2022-07-15 18:42:03 +02:00
Martin Lund
9db7bb4fbb Update README 2022-07-15 13:45:14 +02:00
Martin Lund
52a1e65bc3 Update plain text man page 2022-07-15 12:41:44 +02:00
Martin Lund
b7ff637667 Update README 2022-07-15 12:30:28 +02:00
Martin Lund
d510c101b4 Change 'ctrl-t T' to 'ctrl-t t' for timestamp toggle 2022-07-15 12:26:36 +02:00
Martin Lund
02729c10b1 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
2022-07-15 12:18:40 +02:00
Martin Lund
1c53af0681 Update TODO 2022-07-14 14:02:17 +02:00
Martin Lund
670c31d6f7 Update README 2022-07-14 13:12:46 +02:00
Martin Lund
eac3dac018 Add plaintext man page 2022-07-14 13:07:28 +02:00
Martin Lund
00ae3b2fbd Update TODO 2022-07-14 11:13:22 +02:00
Martin Lund
98db32b251
Merge pull request #160 from chenrui333/add-homebrew-installation-note
docs: add homebrew installation note
2022-07-14 04:47:21 +02:00
Rui Chen
80977e2f1d
docs: add homebrew installation note
Signed-off-by: Rui Chen <rui@chenrui.dev>
2022-07-13 22:21:39 -04:00
Martin Lund
96a035a56d
Merge pull request #159 from chenrui333/fix-build-issue
fix macOS build
2022-07-14 04:17:03 +02:00
Rui Chen
223f0c5d13
fix compilation error
Signed-off-by: Rui Chen <rui@chenrui.dev>
2022-07-13 22:09:07 -04:00
Martin Lund
e1c7a5c69a Update tio-demo.gif 2022-07-13 19:17:40 +02:00
Martin Lund
44d1812556 Update tio-demo.gif 2022-07-13 19:10:23 +02:00
Martin Lund
b2ab7a69a9 Update tio-demo.gif 2022-07-13 18:44:19 +02:00
Martin Lund
611406c14f Bump version 2022-07-13 16:23:09 +02:00
Martin Lund
dc50b23bec Update README 2022-07-13 16:02:21 +02:00
Martin Lund
3792e10484 Update man page 2022-07-13 15:52:05 +02:00
Martin Lund
ff1ed7ea3f Bump version date 2022-07-13 15:49:51 +02:00
Martin Lund
252545f9e6 Update NEWS 2022-07-13 15:48:55 +02:00
Martin Lund
dfcda015c3 Add missing include 2022-07-12 22:27:42 +02:00
Martin Lund
a23be7f2c2 Simplify arbitrary baudrate code 2022-07-12 12:09:09 +02:00
Martin Lund
ac859f41b9 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.
2022-07-11 23:18:19 +02:00
Martin Lund
73a30a89ef Update README 2022-07-11 21:16:45 +02:00
Martin Lund
c009e19d89 Update README 2022-07-11 18:39:59 +02:00
Martin Lund
0af6c00764 Clean up man page 2022-07-11 15:16:07 +02:00
Martin Lund
360deb3c72 Add support for space parity 2022-07-11 14:55:54 +02:00
Martin Lund
bf972bd2f9 Cleanup 2022-07-11 14:15:54 +02:00
Martin Lund
39af74f263 Rename EOL delay to Output line delay 2022-07-11 14:08:12 +02:00
Martin Lund
8b8dd373a7 Cleanup 2022-07-11 10:51:17 +02:00
Martin Lund
dad6de7ee7 Update man page 2022-07-11 10:19:56 +02:00
Martin Lund
11762b2300 Replace -U,--upcase with mapping flag OLTU 2022-07-11 10:15:12 +02:00
Martin Lund
555e526ce7 Cleanup 2022-07-11 09:18:43 +02:00
Martin Lund
5b82c710f1 Simplify tty_write() 2022-07-11 09:12:56 +02:00
Martin Lund
52446f4d62 Update AUTHORS 2022-07-11 01:19:31 +02:00
Martin Lund
8ccd52e9f3
Merge pull request #155 from MyMiscSWproJ/master
Additional commands: EOL delay, lower to upper translation, added mar…
2022-07-11 01:17:22 +02:00
Robert Snell
8532388b7e Merge branch 'master' of https://github.com/MyMiscSWproJ/tio 2022-07-10 18:51:15 -04:00
Robert Snell
f459a462c5 Fixed indentation in configfile.c, tty.c, options.c 2022-07-10 18:14:29 -04:00
MyMiscSWproJ
232c94eb79
Delete token.txt
should never have been uploaded. Novice mistake.
2022-07-10 14:16:40 -04:00
Robert Snell
1c29aac9fa fixed indentation in configfile.c 2022-07-10 14:06:22 -04:00
Robert Snell
944ee9173b 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.
2022-07-09 21:22:43 -04:00
Martin Lund
dbdb84743f Bump version 2022-07-09 16:00:34 +02:00
Martin Lund
cf0d27e5b6 Bump version date 2022-07-09 15:44:19 +02:00
Martin Lund
290ffb7a41 Update NEWS 2022-07-09 15:40:30 +02:00
Martin Lund
9c498140de Update TODO 2022-07-08 10:19:33 +02:00
Martin Lund
d08758f247 Update AUTHORS 2022-07-07 21:05:45 +02:00
Martin Lund
6503963e4a
Merge pull request #154 from gtjoseph/master_for_upstream
Add Pulse DTR command
2022-07-07 21:02:58 +02:00
George Joseph
f24cee61e7 Add Pulse DTR command
MCUs like the ESP32 can be reset if the serial port DTR line is
pulsed for a short time.  You could just type CTRL-t d CTRL-t d
but that's a little awkward since you have to lift your finger
off the CTRL key to type the Ds.  Now you can just type CTRL-T D.

* Added new command "D" to pulse the DTR line.  I.E.  Toggle its
  state twice with a configurable duration between toggles.

* Added new config/command line option "--dtr-pulse-duration"
  to set the duration between the DTR state toggles.  The default
  is 100ms.
2022-07-07 12:45:29 -06:00
Martin Lund
a717631207 Improve description of socket option 2022-07-07 14:00:56 +02:00
Martin Lund
4e7456a9fc Rename ChangeLog to NEWS 2022-07-07 00:12:23 +02:00
Martin Lund
55f82c9a20 Update tio demo gif 2022-07-06 20:09:27 +02:00
Martin Lund
e5d71a5e51 Update README 2022-07-06 16:28:49 +02:00
Martin Lund
e53b69afbd Update doc 2022-07-06 16:25:15 +02:00
Martin Lund
167a19fcdd Update README 2022-07-06 15:08:35 +02:00
Martin Lund
36e091842e Update README 2022-07-06 14:58:17 +02:00
Martin Lund
736c1ed003 Update README 2022-07-06 14:51:25 +02:00
Martin Lund
028bd34cbe Update README 2022-07-06 14:46:28 +02:00
Martin Lund
dc1b3a3549 Cleanup 2022-07-06 13:40:56 +02:00
Martin Lund
5ed5f0ae7d Update tio demo gif 2022-07-06 13:35:02 +02:00
Martin Lund
72fd2f2980 Fix timestamp configuration state 2022-07-06 13:22:19 +02:00
Martin Lund
8b6a0cf63c Update TODO 2022-07-05 23:28:23 +02:00
Martin Lund
f83e81e5db Fix default timestamp 2022-07-05 18:57:03 +02:00
Martin Lund
6a1d4838da Update bash completion 2022-07-05 17:47:20 +02:00
Martin Lund
683aab1dc7 Do not expose timestamp-format 'none' option
Do not expose the 'none' timestamp-format option. It is and internal
state used when timestamp is disabled.
2022-07-05 17:34:49 +02:00
Martin Lund
d598fa76a7 Fix timestamp miliseconds bug 2022-07-05 17:00:32 +02:00
Martin Lund
a56db8744b Improve error message 2022-07-05 16:49:31 +02:00
Martin Lund
62d9b5fb5c Remove timestamp format warning 2022-07-05 16:37:10 +02:00
Martin Lund
4cb7eaf48d Update man page 2022-07-05 16:16:31 +02:00
Martin Lund
d1733fc090 Update man page 2022-07-05 16:11:57 +02:00
Martin Lund
732c0c3f89 Add '24hour-delta' timestamp option
When enabled this option will timestamp new lines with the time elapsed
since the line before.

This is a very useful feature to identify which events takes the most
time.
2022-07-05 16:05:38 +02:00
Martin Lund
eecfa6485c Bump version 2022-07-04 22:58:34 +02:00
Martin Lund
835effd3e9 Update ChangeLog 2022-07-04 22:42:15 +02:00
Martin Lund
3243dfa55c Update man page 2022-07-04 21:44:54 +02:00
Martin Lund
458ebc251d Update AUTHORS 2022-07-04 21:22:18 +02:00
Martin Lund
bd9ea4a295 Update man page 2022-07-04 20:50:10 +02:00
Martin Lund
eb24e7215b
Merge pull request #152 from sly74fr/feature/macos_socket_build
Add missing 'string.h' include.
2022-07-04 17:56:21 +02:00
Martin Lund
e426323d93 Bump version 2022-07-04 17:49:28 +02:00
Martin Lund
44e99ffcb0
Merge pull request #151 from ZeroMemoryEx/master
handle malloc failure
2022-07-04 17:44:20 +02:00
Sylvain LAFRASSE
16d6807de7 Add missing 'string.h' include. 2022-07-04 17:34:38 +02:00
V2
c10c47343e
Update configfile.c 2022-07-04 16:31:32 +01:00
Martin Lund
daa8cd39f3 Update version date 2022-07-04 17:06:18 +02:00
Martin Lund
5d62c2947b Update ChangeLog 2022-07-04 16:44:32 +02:00
Martin Lund
58568ed630 Update man page 2022-07-04 15:45:28 +02:00
Martin Lund
a3f5f6414b Cleanup 2022-07-04 12:00:24 +02:00
Martin Lund
233152f0db Update README 2022-07-04 09:29:55 +02:00
Martin Lund
1a9b983dcd Update man page 2022-07-03 22:29:26 +02:00
Martin Lund
e61e2d3820 Update README 2022-07-03 19:44:58 +02:00
Martin Lund
b72fae4c87 Cleanup 2022-07-03 18:28:51 +02:00
Martin Lund
5bf7ae6382 Update doc 2022-07-03 14:58:04 +02:00
Martin Lund
2bc8cf4206 Update doc 2022-07-03 13:51:01 +02:00
Martin Lund
5daabf88d9 Update README 2022-07-03 13:21:58 +02:00
Martin Lund
4ca7375cac Update doc 2022-07-03 13:18:52 +02:00
Martin Lund
db88a9d664 Rename --hex-mode to --hexadecimal 2022-07-03 00:47:18 +02:00
Martin Lund
1b91fd9f69 Rename --hex-mode to --hexadecimal 2022-07-01 13:16:14 +02:00
Martin Lund
3553fc765e Update text 2022-06-30 15:20:38 +02:00
Martin Lund
538e81cbe5 Update man page 2022-06-26 00:00:36 +02:00
Martin Lund
4b912981c3 Update README 2022-06-25 13:57:04 +02:00
Martin Lund
0b4dfbe4d3 Update README 2022-06-25 11:06:35 +02:00
Martin Lund
98c96dba52 Enable buffered writing
Read block of bytes from input and process same block for output.  This
will speed things up by reducing I/O overhead.
2022-06-24 17:21:17 +02:00
Martin Lund
d522527c49 Enable buffered reading
Read block of bytes from input and process byte by byte for output. This
will speed things up by reducing I/O overhead.
2022-06-24 17:18:08 +02:00
Martin Lund
4e08c68533 Refactoring 2022-06-24 00:17:45 +02:00
Martin Lund
941e8d5b04 Cleanup 2022-06-23 20:47:07 +02:00
Martin Lund
a947985651 Optimization 2022-06-22 21:27:11 +02:00
Martin Lund
ac25e7434c Cleanup 2022-06-22 11:23:57 +02:00
Martin Lund
a0f3f9d9b7 Cleanup stdout flushing
Flushing is not needed since we disabled buffering of stdout.
2022-06-22 01:03:59 +02:00
Martin Lund
4c611e6767 Cleanup log code 2022-06-22 00:22:18 +02:00
Martin Lund
c82b7e2ecc Cleanup 2022-06-21 22:32:24 +02:00
Martin Lund
3d65e62e52 Simplify stdout_configure() code 2022-06-21 19:28:04 +02:00
Martin Lund
f62e2f972b Simplify stdin_configure() code 2022-06-21 19:19:05 +02:00
Martin Lund
e72a2ede76 Update man page 2022-06-21 12:26:29 +02:00
Martin Lund
d7a95ed383 Update README 2022-06-21 01:14:06 +02:00
Martin Lund
b46dcc46ac Update text 2022-06-17 14:25:50 +02:00
Martin Lund
1bd663086a Update TODO 2022-06-17 12:23:15 +02:00
Martin Lund
1f94fe2c9a Bump version 2022-06-17 12:21:59 +02:00
Martin Lund
09240c9ad7 Update version date 2022-06-17 11:54:01 +02:00
Martin Lund
574d5620b2 Update general tio description 2022-06-17 11:36:23 +02:00
Martin Lund
1f4a50cc9f Update text 2022-06-17 11:27:47 +02:00
Martin Lund
edcd3c3c3d Update ChangeLog 2022-06-17 11:14:13 +02:00
Martin Lund
18de31a4c3 Cleanup man page 2022-06-17 11:00:42 +02:00
Martin Lund
1dabf0fdf5 Add config support for log-strip 2022-06-17 10:59:59 +02:00
Martin Lund
f48402f7ed Add config support for hex-mode 2022-06-17 10:58:55 +02:00
Martin Lund
1b2f445ed9 Rename --hex to --hex-mode 2022-06-17 10:57:29 +02:00
Martin Lund
a826bf4fcb Fix completion for -e, --local-echo 2022-06-17 10:19:21 +02:00
Martin Lund
858b898bbb Ignore newlines in hex output 2022-06-17 10:06:13 +02:00
Martin Lund
4b928a54b2 Fix newline in warning_printf() 2022-06-17 09:56:16 +02:00
Martin Lund
cd1e6529db Fix ansi_printf_raw() in no color mode 2022-06-17 09:46:48 +02:00
Martin Lund
dba77eb912 Enter non-interactive mode when piping to tio
Add support for a non interactive mode which allows other application to
pipe data to tio which then forwards the data to the connected serial
device.

Non ineractive means that tio does not react to interactive key commands
in the incoming stream. This allows users to pipe binary data directly
to the connected serial device.

Example use:

$ cat commands.txt | tio /dev/ttyUSB0
2022-06-16 21:03:53 +02:00
Martin Lund
a37ad26a88 Clean up main 2022-06-16 18:16:41 +02:00
Martin Lund
1636a55b7e Also strip backspace from log
To make log strip feature consistent so that we remove all unprintable
control characters and escape sequences.
2022-06-16 15:44:49 +02:00
Martin Lund
1e8c950e9d Update text 2022-06-16 11:15:32 +02:00
Martin Lund
cd03af190c Merge branch 'nh26223-allow_strip_esc_key' 2022-06-15 22:54:12 +02:00
Martin Lund
256d6b4fc2 Merge branch 'allow_strip_esc_key' of https://github.com/nh26223/tio into nh26223-allow_strip_esc_key 2022-06-15 22:49:22 +02:00
Martin Lund
9333876ac7 Update tio demo gif 2022-06-15 13:25:43 +02:00
Martin Lund
b8b0ec6575 Socket code cleanup 2022-06-14 22:33:58 +02:00
Martin Lund
1debdc98cb Update README 2022-06-14 01:08:54 +02:00
Martin Lund
1b99a103cb Rename log-filename to log-file in config file 2022-06-14 01:07:54 +02:00
Martin Lund
9ab846a30a Bump version 2022-06-14 00:47:03 +02:00
Martin Lund
5708e2187f Update README 2022-06-13 23:05:33 +02:00
Martin Lund
db45326d98 Rename --log-filename to --log-file 2022-06-13 23:04:30 +02:00
Martin Lund
01a58dd319 Update ChangeLog 2022-06-12 04:19:51 +02:00
Martin Lund
63d3232b32 Improve key command response for local echo and timestamp 2022-06-12 04:07:17 +02:00
Martin Lund
318bcbf650 Update README 2022-06-12 02:56:35 +02:00
Martin Lund
18b8f8140d Update ChangeLog 2022-06-12 02:32:43 +02:00
Martin Lund
c66017f287 Fix invalid hex character error message 2022-06-12 02:31:48 +02:00
Martin Lund
92fbe86c49 Update man page 2022-06-12 01:27:23 +02:00
Martin Lund
fcfeb9189c Update man page 2022-06-12 01:16:41 +02:00
Martin Lund
8f7050dd86 Update version date 2022-06-12 01:11:11 +02:00
Martin Lund
f335ff63a9 Update ChangeLog 2022-06-12 01:06:01 +02:00
Martin Lund
b5c3193411 Remove debug 2022-06-12 00:47:26 +02:00
Martin Lund
16c42bb9ae Fix config file memory leak 2022-06-12 00:44:52 +02:00
Martin Lund
94485ec9ac Make sure only matched config section is parsed 2022-06-12 00:44:35 +02:00
Martin Lund
9b55f18c07 Add support for "disable" keyword in config file 2022-06-12 00:42:24 +02:00
Martin Lund
0a892006ea Unify error message formating 2022-06-11 23:36:51 +02:00
Martin Lund
bf749aead4 Cleanup list devices code 2022-06-11 23:14:18 +02:00
Martin Lund
a0d4be068b Fix command-line tty-device|config parsing
Allow user to add options on both sides of the provided config argument.

For example:

 $ tio -b 9600 am64-evm -e

Before, tio only allowed adding arguments after the config argument.

Implemented as simple as possible by introducing two stage option parsing.
2022-06-11 22:56:03 +02:00
Martin Lund
bd5f542959 Update bash completion 2022-06-11 17:11:19 +02:00
Martin Lund
c38ba262d3 Cleanup IPv6 code 2022-06-11 15:16:47 +02:00
Martin Lund
81a3dbd68a Update README 2022-06-11 14:55:16 +02:00
Martin Lund
1117dc603e Update TODO 2022-06-11 14:22:22 +02:00
Martin Lund
17e96d70bc Add support for IPv4 and IPv6 network sockets
Add support for IPv4 and IPv6 network sockets via socket syntax
"inet:<port>" and "inet6:<port>" respectively.

For example, to listen and redirect serial device I/O to a host bound
IPv4 socket simply do:

 $ tio /dev/ttyUSB0 --socket inet:4444

To connect do e.g.:

 $ nc 127.0.0.1 4444

Likewise, for IPv6 do:

 $ tio /dev/ttyUSB0 --socket inet6:4444

To connect do e.g.:

 $ nc ::1 4444

If port is 0 or no port is provided default port 3333 is used.
2022-06-11 14:19:29 +02:00
Martin Lund
ba22191800 Fix tio deleting unix socket file
If tio has a unix file socket open, a second tio instance of tio may
delete the socket file. This change fixes so that it will not be deleted
and tio will instead error and complain about conflicting socket file.
2022-06-11 02:56:44 +02:00
Martin Lund
373dca3d5b Update README 2022-06-08 20:33:13 +02:00
Martin Lund
50478e7df3 Update TODO 2022-06-08 16:21:50 +02:00
Martin Lund
46b5783789 Rework color option
Rework the color option to support setting ANSI color code values
ranging from 0..255 or "none" for no color or "list" to print a list of
available ANSI colors codes.

Also, disables color when piping.
2022-06-08 16:19:47 +02:00
Martin Lund
2519e2081a Update README 2022-06-07 18:43:54 +02:00
Martin Lund
625f32d288 Update README 2022-06-07 18:36:19 +02:00
Martin Lund
1f094b6b68 Update TODO 2022-06-07 18:23:34 +02:00
Martin Lund
e7282731f3
Create FUNDING.yml 2022-06-07 18:20:28 +02:00
Martin Lund
e854ca0efa Update TODO 2022-06-07 18:14:04 +02:00
Martin Lund
77ff1e5269 Remove debug 2022-06-07 10:01:26 +02:00
Martin Lund
14a16908a1 Update README 2022-06-07 07:40:24 +02:00
Martin Lund
0a22142957 Update README 2022-06-07 07:27:11 +02:00
Martin Lund
10199f6053 Update AUTHORS 2022-06-06 21:22:58 +02:00
Martin Lund
54830e3528 Update README 2022-06-06 21:19:09 +02:00
Martin Lund
2109a0063b Update README 2022-06-06 20:32:47 +02:00
Martin Lund
387f47a39c Update README 2022-06-06 20:29:17 +02:00
Martin Lund
989efeae88 Remove print of hex mode status at startup 2022-06-06 20:08:05 +02:00
Martin Lund
d41649afb6 Update bash completion 2022-06-06 19:47:08 +02:00
Martin Lund
6d007d39d7 Remove newline option in hex mode 2022-06-06 19:38:31 +02:00
g0mb4
0b55981e52 Extended hexadecimal mode.
While in hex mode (ctrl-t h) you can output hexadecimal values.
E.g.: to send 0x0A you have to type 0A (always 2 characters).

Added option -x, --hex to start in hexadecimal mode.

Added option --newline-in-hex to interpret newline characters in hex mode.
This is disabled by default, because, in my opinion, hex stream is
fundamentally different from text, so a "new line" is meaningless in this
context.
2022-06-06 19:10:00 +02:00
Martin Lund
7d3b687eb4 Update README 2022-06-06 10:19:37 +02:00
Martin Lund
a5bde2ea51 Update README 2022-06-06 01:40:49 +02:00
Martin Lund
732a768970 Update TODO 2022-06-05 09:29:33 +02:00
Martin Lund
d907834f72 Update README 2022-06-04 22:28:54 +02:00
Martin Lund
5b7191ed7c Fix configfile memory leaks 2022-06-04 20:37:06 +02:00
Martin Lund
8a83d2a973 Update bash completion 2022-06-04 19:24:26 +02:00
Martin Lund
9476422922 Remove command-line option inconsistencies
Optional arguments, as parsed by the getopt_long mechanism, are
inherently inconsistent with how you define required arguments.

To avoid confusion we decide to avoid this inconsistency by replacing
optional options with additional options with required argmuments.
2022-06-04 19:08:05 +02:00
Martin Lund
8d2ad8d82d Update man page 2022-06-04 17:45:19 +02:00
Martin Lund
d43ef3333f Replace '1' with 'enable' in config files 2022-06-04 17:33:36 +02:00
Martin Lund
6b91159fdf Update README 2022-06-04 17:08:16 +02:00
Martin Lund
be2c682da6 Convert errors to warnings 2022-06-02 20:51:23 +02:00
Martin Lund
b0590fb021 Bump version 2022-06-02 10:54:08 +02:00
Martin Lund
ba201c7248 Update version date 2022-06-02 09:36:36 +02:00
Martin Lund
4e89858816 Update ChangeLog 2022-06-02 01:06:37 +02:00
Martin Lund
b0c085debd Revert back to showing help when no arguments 2022-06-02 01:04:24 +02:00
Martin Lund
89574b2469 Mention config file in --help 2022-06-02 00:29:25 +02:00
Martin Lund
fb1fc9b7a1 Update README 2022-06-01 23:46:42 +02:00
Martin Lund
6e0fcd1280 Update ChangeLog 2022-06-01 23:43:21 +02:00
Martin Lund
836c28098c Redirect error messages to stderr 2022-06-01 19:55:44 +02:00
Martin Lund
5b6a106b34 Improve help and man page 2022-06-01 19:26:42 +02:00
Martin Lund
c94e8826fd Fix running without config file 2022-06-01 18:37:11 +02:00
Martin Lund
c96c3c4c83 Fix config file error messages 2022-06-01 18:23:14 +02:00
Martin Lund
c7b27b022f Redirect error messages to stderr 2022-05-24 13:35:27 +02:00
Martin Lund
9bc6e34e82 Add repology packaging status 2022-05-22 20:19:21 +02:00
Martin Lund
9a1afc09c2 Fix parsing of default settings
Default configuration file settings were not parsed in case a section
was matched. Now we make sure that the default (unnamed) settings are
always parsed.
2022-05-15 22:37:59 +02:00
Martin Lund
8da06ebf2c Fix typo 2022-05-15 20:21:58 +02:00
Martin Lund
16cba00c54 Append to existing log file (no truncation) 2022-05-07 16:02:41 +02:00
Martin Lund
2369c0558d
Merge pull request #146 from lexaone/master
fix for using option 'log' without 'log-filename' in config file
2022-05-07 15:54:37 +02:00
lexaone
334ae28c76
fix for using option 'log' without 'log-filename' in config file 2022-05-03 17:44:43 +03:00
Martin Lund
fa91a3fcc4 Update man page 2022-04-21 02:28:53 +02:00
Martin Lund
2e0b0386dc
Merge pull request #144 from pcc/config-section-name
Match user input against config section names if pattern matching was…
2022-04-21 01:29:24 +02:00
Peter Collingbourne
a81c43a01a Match user input against config section names if pattern matching was unsuccessful.
This allows for better config file ergonomics if the user has a diverse
set of serial devices as the name does not need to be specified in
the config file twice.
2022-04-20 15:31:41 -07:00
Martin Lund
b882827b97 Add socket info to show configuration 2022-04-20 19:43:29 +02:00
Martin Lund
b0b0856a8b Print socket info at startup 2022-04-20 19:20:26 +02:00
Martin Lund
7096bc3a96 Fix socket option parsing 2022-04-20 14:59:27 +02:00
Martin Lund
45c32f78a8 Update socket interface documentaton 2022-04-20 12:08:55 +02:00
Martin Lund
af93efb9e4 Bump version 2022-04-19 20:09:02 +02:00
Martin Lund
97a4c415bf Update AUTHORS 2022-04-19 20:08:02 +02:00
Martin Lund
09bb6a34bb
Merge pull request #143 from pcc/socket
Add support for external control via a Unix domain socket.
2022-04-19 20:04:44 +02:00
Peter Collingbourne
fb453160ef Add support for external control via a Unix domain socket.
This feature allows an external program to inject output into and
listen to input from a serial port via a Unix domain socket (path
specified via the -S/--socket command line flag, or the socket
config file option) while tio is running. This is useful for ad-hoc
scripting of serial port interactions while still permitting manual
control. Since many serial devices (at least on Linux) get confused
when opened by multiple processes, and most commands do not know
how to correctly open a serial device, this allows a more convenient
usage model than directly writing to the device node from an external
program.

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
ctrl-t 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.

Example usage 1 (issue a command):

  echo command | nc -UN /path/to/socket > /dev/null

Example usage 2 (use the expect command to script an interaction):

  #!/usr/bin/expect -f

  set timeout -1
  log_user 0

  spawn nc -UN /path/to/socket
  set uart $spawn_id

  send -i $uart "command1\n"
  expect -i $uart "prompt> "
  send -i $uart "command2\n"
  expect -i $uart "prompt> "
2022-04-18 14:06:33 -07:00
Martin Lund
03e41b61a3 Update version date 2022-04-13 18:00:34 +02:00
Martin Lund
78b8c134ea Update ChangeLog 2022-04-13 17:57:30 +02:00
Martin Lund
28c880cdab Remove verbose option
Remove the command-line verbose option but let the ctrl-t c feature
print some of the verbose information (active config path/section).
2022-04-13 16:28:30 +02:00
Martin Lund
11df828f68
Merge pull request #142 from sly74fr/issue/ini_timestamp_parsing
Fix timestamp parsing in INI conf
2022-03-31 14:05:36 +02:00
Sylvain LAFRASSE
c95226cb46 Update verbosity documentation. 2022-03-31 13:59:02 +02:00
Sylvain LAFRASSE
ac77f2dbb9 Add documentation of verbose mode. 2022-03-30 18:11:36 +02:00
Sylvain LAFRASSE
a543fbd7ef Factorize timestamp parsing to be coherent with command line format in configuration file. 2022-03-30 17:11:50 +02:00
Martin Lund
1ec39d1c7b Make libinih a fallback dependency
This means that in case meson does not find libinih it will
automatically clone libinih and include it in the build.

The libinih library is reconfigured to be statically built so that no
shared object will be installed.
2022-03-29 17:54:33 +02:00
Martin Lund
f229ee2f96 Update man page 2022-03-24 22:52:11 +01:00
Martin Lund
8975c445c2 Update README 2022-03-21 20:37:21 +01:00
Martin Lund
c4d14c1d76 Bump version 2022-03-21 11:17:50 +01:00
Martin Lund
c3969ec81a Update ChangeLog 2022-03-21 10:56:34 +01:00
Martin Lund
6c5e748e15 Update version date 2022-03-21 10:55:47 +01:00
Martin Lund
09bcd91bf0 Add support for defaults in config file
If no section name is specified the configuration will be considered the
default one.

This allows to set e.g. a default color code for sections which do not
configure a color code.
2022-03-19 18:37:37 +01:00
Martin Lund
03cf4ef197 Handle SIGHUP
Handle SIGHUP so that the registered exit handlers are called to restore
the terminal back to its orignal state.
2022-03-18 19:19:11 +01:00
Martin Lund
ed97a8dc21 Update man page 2022-03-12 11:20:03 +01:00
Martin Lund
e81e76473a Add color configuration support 2022-03-11 16:09:21 +01:00
Martin Lund
410fc8bffe Bypass unused result warnings 2022-03-11 15:30:33 +01:00
Martin Lund
659336af51 Force dependency on libinih
Configuration file support is considered a mandatory feature.
2022-03-11 15:28:35 +01:00
Martin Lund
8965b7b42c Update headers 2022-03-11 15:15:39 +01:00
Martin Lund
a2b164519f Mostly cosmetic updates 2022-03-11 15:11:43 +01:00
Martin Lund
ea0dd3e602 Update AUTHORS 2022-03-11 14:35:26 +01:00
Martin Lund
745244df06 Update man page 2022-03-11 14:34:33 +01:00
Martin Lund
e9d5a23129 Move string_to_long() to misc.c 2022-03-11 13:33:35 +01:00
Martin Lund
d7b038d4ef Update CircleCI config 2022-03-11 13:26:07 +01:00
Martin Lund
02c0c61e07
Merge pull request #109 from Liambeguin/config-file
Add support for a configuration file
2022-03-11 13:16:17 +01:00
Liam Beguin
25123fefea document configuration file options
Signed-off-by: Liam Beguin <liambeguin@gmail.com>
2022-03-10 10:34:52 -05:00
Liam Beguin
2e5c1ff20c add support for a configuration file
Signed-off-by: Liam Beguin <liambeguin@gmail.com>
2022-03-10 10:34:52 -05:00
Liam Beguin
2795ef6c79 misc: add _unused macro
Some parameters are expected to be unused.
Add a basic macro to mute these compiler warnings.

Signed-off-by: Liam Beguin <liambeguin@gmail.com>
2022-03-09 20:39:48 -05:00
Liam Beguin
04da651f09 options: expose string_to_long()
Expose string_to_long() so that other source files can use it.

Signed-off-by: Liam Beguin <liambeguin@gmail.com>
2022-03-09 20:15:30 -05:00
Martin Lund
0a825d87cf Update tio gif 2022-02-25 07:25:34 +01:00
Martin Lund
b23397caa0 Fix text 2022-02-25 07:16:14 +01:00
Martin Lund
166d36d7d4 Correct text 2022-02-23 15:35:46 +01:00
Martin Lund
3773fddb6a Update README 2022-02-23 15:17:42 +01:00
Martin Lund
950373d10d Update LICENSE date 2022-02-20 08:19:50 +01:00
Martin Lund
39a9c4bbda Remove redundant COPYING file 2022-02-20 08:19:29 +01:00
Martin Lund
e11fcbd2f4 Bump version 2022-02-20 01:09:50 +01:00
Martin Lund
88974852ae Update version_date 2022-02-20 00:51:09 +01:00
Martin Lund
3c12616128 Update ChangeLog 2022-02-20 00:50:32 +01:00
Martin Lund
690fbebfc7 Bump version 2022-02-19 13:24:12 +01:00
Martin Lund
9f2cac4e41 Fix log exit print 2022-02-19 10:00:21 +01:00
Martin Lund
8f63f755da Cleanup color option 2022-02-19 09:45:02 +01:00
Martin Lund
45210bc741 Add support for automatically generated log filename
Automatically generate log filename if none is provided.

The auto generated file name is on the form:
"tio_DEVICE_YYYY-MM-DDTHH:MM:SS.log"
2022-02-19 09:29:33 +01:00
Martin Lund
d8a822a3fb Add support for configurable timestamp format
Also changes default timestamp format from ISO8601 to classic 24-hour
format as this is assumed to be the format that most users would prefer.

And reintroduces strict but optional ISO8601 format.

This feature allows to easily add more timestamp formats in the future.
2022-02-19 02:26:10 +01:00
Martin Lund
47694904cf Update README 2022-02-18 04:44:10 +01:00
Martin Lund
63ef65804f Reintroduce asm-generic/ioctls.h
It is needed for ppc builds.
2022-02-17 05:47:06 +01:00
Martin Lund
7ffeeccdf5 Merge branch 'osx-baudrate' of https://github.com/robey/tio into robey-osx-baudrate 2022-02-16 05:24:35 +01:00
Martin Lund
27f4d31380 Add macro hack to workaround older buggy glibc 2022-02-16 02:26:36 +01:00
Martin Lund
cbfa118a2b Update version_date 2022-02-15 12:05:23 +01:00
Martin Lund
a1afc2bcfa Update ChangeLog 2022-02-15 12:04:09 +01:00
Sylvain LAFRASSE
2d1e0f1233
Fix TTY device listing on Darwin. (#136) 2022-02-15 11:15:39 +01:00
Martin Lund
3d08787142 Fix setspeed2 compilation 2022-02-15 03:47:24 +01:00
Martin Lund
1ae889fdb2 Bump version 2022-02-15 00:58:44 +01:00
Martin Lund
0e62995e6e Only apply color formatting when using color option
To help the color blind who may use custom terminal foreground /
background colors.
2022-02-15 00:48:10 +01:00
Martin Lund
a699561211 Update README 2022-02-14 22:50:47 +01:00
Martin Lund
274cb63197 Add '-c, --color' option
Allow user to select which ANSI color code to use to colorize the tio
text. To successfully set the color the color code must be in the range
0..255.

If color code is negative tio will print all available ANSI colors.

The default color is changed to bold white to make tio defaults usable
for most users, including color blind users.
2022-02-14 22:25:29 +01:00
Martin Lund
32e853e46e Fix setspeed2 check 2022-02-14 21:01:58 +01:00
Martin Lund
75a7e06d5d Fix meson header check string 2022-02-14 20:25:33 +01:00
Martin Lund
2f51e8368f
Merge pull request #135 from sly74fr/feature/macos_meson_build
Fix TCGETS2 search on Darwin.
2022-02-14 20:20:40 +01:00
Sylvain LAFRASSE
6a57695ab3 Fix TCGETS2 search on Darwin. 2022-02-14 14:49:42 +01:00
Martin Lund
883e3b0bea Reintroduce long timestamp format
But make the timestamp format RFC3339 compliant instead. The RFC states:

NOTE: ISO 8601 defines date and time separated by "T".
      Applications using this syntax may choose, for the sake of
      readability, to specify a full-date and full-time separated by
      (say) a space character.

This way we keep the information specified by ISO 8601 but make it more
human readable which is better for the console output.
2022-02-13 19:29:13 +01:00
Martin Lund
32113076d6 Update version year 2022-02-13 18:28:04 +01:00
Martin Lund
3599b84ad2 Update meson c standard 2022-02-13 11:11:46 +01:00
Martin Lund
d4c3751405 Meson cleanup 2022-02-13 11:07:51 +01:00
Martin Lund
f788ae2ca4 Update ChangeLog 2022-02-13 11:03:03 +01:00
Martin Lund
cdfdbee9ee Update README 2022-02-13 10:18:10 +01:00
Martin Lund
1d03313848 Update version_date 2022-02-13 09:39:43 +01:00
Martin Lund
b36b97769a Update README 2022-02-13 08:34:27 +01:00
Martin Lund
137b2823af Update headers 2022-02-13 06:35:03 +01:00
Martin Lund
2375bc0c7b Show auto connect status in show configuration 2022-02-13 05:46:31 +01:00
Martin Lund
ff4b37af53 Update ChangeLog 2022-02-13 05:34:19 +01:00
Martin Lund
5d031a51f9 Cleanup 2022-02-13 02:13:43 +01:00
Martin Lund
0985f70c13 Update AUTHORS 2022-02-13 01:54:59 +01:00
Martin Lund
2ea4b973f0 Use '#pragma once' in all headers 2022-02-13 00:00:17 +01:00
Martin Lund
b6eac3f001 Improve printed output
Get rid of inconsistencies in the printed output (error printing,
colors, etc.).

Prepare for user configurable color.

Cleanup.
2022-02-12 22:47:42 +01:00
Martin Lund
5efd519d2e Update animated gif 2022-02-12 17:02:16 +01:00
Martin Lund
16836de0e5 Update text 2022-02-12 04:27:09 +01:00
Martin Lund
7e74f8cbe0 Update completion script 2022-02-12 03:26:39 +01:00
Martin Lund
bb300293cc Rename option -i to -L 2022-02-10 15:07:14 +01:00
Martin Lund
353ce69130 Update man page hint text 2022-02-10 08:00:49 +01:00
Martin Lund
c0c9fcc00c Shorten timestamp
We do not need the date part of the timestamp. It simply takes up too
much precious line space. In case of logging to file, one can easily
conclude the date from the file date information.
2022-02-10 07:38:17 +01:00
Martin Lund
59c9b867c3 Update README with build status 2022-02-10 05:51:01 +01:00
Martin Lund
64ed36966b Update README 2022-02-10 05:38:59 +01:00
Martin Lund
bfea34a978 Replace Travis with circleCI 2022-02-10 05:33:46 +01:00
Martin Lund
4e2c6725d5 Update README 2022-02-10 05:21:38 +01:00
Martin Lund
e9208d693e Replace autotools with meson
To introduce much simpler build configuration which is also easier to
maintain.
2022-02-10 05:09:32 +01:00
Martin Lund
c01152bb38 Fix man page 2022-02-09 19:49:02 +01:00
Martin Lund
7a2a18232d Add list serial devices feature
For convenience, add a --list-devices option which lists the available
serial devices.
2022-02-08 23:13:34 +01:00
Martin Lund
6310f28d2c Shorten timestamp description 2022-02-08 21:47:55 +01:00
Martin Lund
d35c607d1a Cleanup: Use dot notation for default options struct 2022-02-08 21:38:16 +01:00
Sylvain LAFRASSE
c2024368a0
Add '-t' option description for time stamping. 2022-02-08 12:02:24 +01:00
Sylvain LAFRASSE
c6d996550a
Add description for time stamping. 2022-02-07 17:48:32 +01:00
Sylvain LAFRASSE
4931c30317
Add attila-v for PR #129 (Refine timestamps with milliseconds and ISO-8601 format). 2022-02-07 17:23:20 +01:00
attila-v
65153c0d03
Refine timestamps with milliseconds and ISO-8601 format (#129).
* Show milliseconds too in the timestamp (#114) and log file (#124)
* Change timestamp format to ISO-8601.
Co-authored-by: Attila Veghelyi <aveghelyi@dension.com>
Co-authored-by: Sylvain LAFRASSE <sly74fr@users.noreply.github.com>
2022-02-07 17:18:36 +01:00
Martin Lund
101e32749b Update README 2022-02-07 04:06:36 +01:00
Sylvain LAFRASSE
b46ea8b758
Add Mariusz Midor for PR #80 (Newline: handle booth NL and CR). 2022-02-02 17:39:06 +01:00
Sylvain LAFRASSE
febefa638f
Merge pull request #80 from marmidr/crlf
Newline: handle booth NL and CR
2022-02-02 17:36:01 +01:00
Martin Lund
95389f4dde Add Sylvain as official co-maintainer
Signed-off-by: Martin Lund <martin.lund@keep-it-simple.com>
2021-10-27 13:47:57 +02:00
Robey Pointer
aa9f121a12 add support for high bps on OS X 2021-04-06 15:50:59 -07:00
Martin Lund
3a1fd79fcb
Merge pull request #120 from nh26223/newline_fix_for_hex_mode
Output newline on stdout with hex print mode
2021-01-21 09:50:47 +01:00
Yin Fengwei
c0c21b1814 Allow strip escape sequence characters from log file
The log without escape key stripped is like:

^M[12:47:17] ACRN:\>
^M[12:47:17] ACRN:\>lasdfjklsdjf
^M
^M[12:47:18] Error: Invalid command.
^M[12:47:19] ACRN:\>
^M[12:47:26] ACRN:\>
^M[12:47:26] ACRN:\>sdafkljsdkaljfklsadjflksdjafjsda^H ^H^H...
^M
^M[12:47:31] Error: Invalid command.

After strip escape key, the log is like:

[12:49:18] ACRN:\>
[12:49:19] ACRN:\>
[12:49:19] ACRN:\>ls

[12:49:19] Error: Invalid command.
[12:49:19] ACRN:\>
[12:49:19] ACRN:\>dfaslhj

[12:49:24] Error: Invalid command.

Beside escape key, it also handle backspace key as well.
2021-01-21 12:51:59 +08:00
Yin Fengwei
0f0279bd3f Output newline on stdout with hex print mode
This is to fix the issue #104. The timestamp will always be
printed at the beginning of line:

[10:25:56] Switched to hexadecimal mode
0d 0a 0d [10:25:57] 41 43 52 4e 3a 5c 3e 0d 0a 0d [10:25:58] 41

is changed to:

[12:34:56] 45 72 72 6f 72 3a 20 49 6e 76 61 6c 69 64 20
[12:34:56] 41 43 52 4e 3a 5c 3e
[12:34:56] 41 43 52 4e 3a 5c 3e
[12:34:57] 41 43 52 4e 3a 5c 3e 6c 73
2021-01-21 12:39:51 +08:00
Martin Lund
1079991608 Update AUTHORS 2021-01-18 02:25:54 +01:00
Martin Lund
17fafd9918
Merge pull request #112 from henrikbrixandersen/bash_completion_ttys
Add bash completion of tty devices
2021-01-18 01:19:45 +01:00
Martin Lund
76c04f5015
Merge pull request #111 from henrikbrixandersen/bash_completion_timestamp
Add -t/--timestamp to bash completion script.
2021-01-18 01:18:48 +01:00
Martin Lund
457075629d
Merge pull request #106 from hzeller/make-local-echo-work-with-buffered-output
Local echo: show character by character even if stdout buffered.
2021-01-18 01:17:34 +01:00
Martin Lund
a4da50dbd8
Merge pull request #105 from zagor/show-error
Show error when failing to open a tty
2021-01-18 01:16:41 +01:00
Martin Lund
07639da625
Merge pull request #102 from AlbanBedel/fix-out-of-tree-builds
Fix out of tree builds
2021-01-18 01:16:02 +01:00
Martin Lund
cda42b0dbb
Merge pull request #98 from ffontaine/master
src/setspeed2.c: fix redefinition of termio
2021-01-18 01:14:17 +01:00
Martin Lund
161f613e08
Merge pull request #96 from eerimoq/master
Exit if output speed cannot be set.
2021-01-18 01:13:42 +01:00
Martin Lund
960c3c0f6c
Merge pull request #117 from sur5r/posix-comparison
Make comparison POSIX compliant
2021-01-18 01:11:58 +01:00
Martin Lund
553939e002
Merge pull request #94 from larsks/bug/92-fflush
fflush() after putchar() for print_hex and print_normal
2021-01-18 01:11:19 +01:00
Martin Lund
50e33a1a5b
Merge branch 'master' into bug/92-fflush 2021-01-18 01:11:05 +01:00
Martin Lund
354bd6e185
Merge pull request #93 from larsks/bug/92
Disable line buffering in stdout
2021-01-18 01:09:35 +01:00
Martin Lund
3a1eea216a
Merge pull request #91 from geo-stark/master
add serial lines manual control
2021-01-18 01:08:09 +01:00
Martin Lund
6c86faf6f9
Merge pull request #86 from sly74fr/feature/TimestampsInLogFile_#84
Resolved tio/tio#84: Added timestamps in log file if enabled.
2021-01-18 01:05:12 +01:00
Martin Lund
3195132fa1
Merge pull request #85 from Serkora/leflush
Flush every local echo-ed char
2021-01-18 01:04:27 +01:00
Jakob Haufe
93771ffab8
Make comparison POSIX compliant
String comparison with == is not POSIX compliant and can fail with e.g.
dash.

Fixes https://github.com/tio/tio/issues/115
2020-10-07 10:08:31 +02:00
Henrik Brix Andersen
6aff97100f Add bash completion of tty devices. 2020-08-13 11:35:16 +02:00
Henrik Brix Andersen
6df80fa503 Add -t/--timestamp to bash completion script. 2020-08-13 10:47:54 +02:00
Henner Zeller
31dccd6633 Local echo: show character by character even if stdout buffered.
Signed-off-by: Henner Zeller <h.zeller@acm.org>
2020-05-25 19:59:20 -07:00
Björn Stenberg
71c1d7c540 Show error when failing to open a tty 2020-05-19 16:00:21 +02:00
Alban Bedel
4e5525a48f Fix out of tree builds
Out of tree builds are currently broken because $(top_srcdir)src/include
is not in the search path. In tree builds are working because autconf add
$(top_builddir)/src/include to the search path for the generated config.h.
As $(top_builddir) and $(top_srcdir) are identical during in tree builds
the search path still end up beeing somehow correct.

To fix this add -I$(srcdir)/include to the CPPFLAGS in Makefile.am.
2020-04-06 17:04:07 +02:00
Fabrice Fontaine
7a84120f7b src/setspeed2.c: fix redefinition of termio
Include ioctls.h and termbits.h from asm-generic instead of asm to avoid
the following build failure:

In file included from setspeed2.c:24:0:
/home/naourr/work/instance-0/output-1/host/sparc64-buildroot-linux-gnu/sysroot/usr/include/asm/termbits.h:17:8: error: redefinition of 'struct termio'
 struct termio {
        ^~~~~~
In file included from /home/naourr/work/instance-0/output-1/host/sparc64-buildroot-linux-gnu/sysroot/usr/include/sys/ioctl.h:29:0,
                 from setspeed2.c:22:
/home/naourr/work/instance-0/output-1/host/sparc64-buildroot-linux-gnu/sysroot/usr/include/bits/ioctl-types.h:36:8: note: originally defined here
 struct termio
        ^~~~~~

Fixes:
 - http://autobuild.buildroot.org/results/1a7418b9cd11374a250f7509d5bddcc864375e1c

Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
2019-12-27 21:41:47 +01:00
Erik Moqvist
ad7b11e6e8 Exit if output speed cannot be set. 2019-10-19 17:08:04 +02:00
Lars Kellogg-Stedman
c6af6c0804 fflush() after putchar() for print_hex and print_normal
In order for local echo to work properly, we have to either call
fflush(stdout) after every character or just disable line buffering.
This change calls fflush() after putchar().

Closes #92
2019-10-16 22:48:44 -04:00
Lars Kellogg-Stedman
4d4ee466f7 Disable line buffering in stdout
In order for local echo to work properly, we have to either call
fflush(stdout) after every character or just disable line buffering.
This change uses setbuf(stdout, NULL) to do the latter.

Closes #92
2019-10-08 22:06:05 -04:00
George Stark
5217d9842b dont show line state if ioctl failed 2019-09-19 17:39:01 +03:00
George Stark
04d92740f5 add serial lines manual control 2019-09-19 15:13:38 +03:00
Sylvain LAFRASSE
a84f762106 Resolved tio/tio#84: Added timestamps in log file if enabled. 2019-05-24 10:46:02 +02:00
arichi
fca5429ae7 Flush every local echo char
Flush stdout at every char in case it
happens to be buffered.
2019-05-13 23:53:08 +08:00
Martin Lund
39a8f63640 Add command to show version
The key sequence ctrl-t v will now show the version of tio.
2018-11-27 23:56:34 +01:00
Martin Lund
42eb14dd77 Align format of timestamps 2018-11-27 23:38:21 +01:00
Mariusz Midor
18c2f7847e Newline: handle booth NL and CR
Flag ONLCRNL expects code \n after press Enter, but on some systems \r is send instead.
2018-11-12 19:16:51 +01:00
Martin Lund
2223662ffd Bump version 2018-11-03 16:52:13 +01:00
Martin Lund
69479bdfda Update ChangeLog 2018-11-03 16:51:47 +01:00
Martin Lund
96a3d315d4 Update AUTHORS 2018-11-03 16:44:30 +01:00
Martin Lund
a5d1546024 Minor code style cleanups 2018-11-03 16:40:59 +01:00
Robey Pointer
f96ad43b1f add optional timestamps
with "-t" or "C-t T", toggle a timestamp prefix to each line.
2018-11-01 17:23:57 -07:00
Martin Lund
36691e8bdf Cleanup print macros 2018-10-21 02:14:18 +02:00
Martin Lund
14e70bd718 Flush output
Make sure output is transmitted immediately by flushing the output.
2018-10-21 02:07:55 +02:00
Martin Lund
bc0ae352b2
Merge pull request #78 from jwilk-forks/spelling
Fix typos
2018-09-17 09:58:11 +02:00
Jakub Wilk
ed8460e5be Fix typos 2018-09-17 09:23:45 +02:00
Martin Lund
2ce78b0993 Update AUTHORS 2018-09-04 21:11:15 +02:00
Martin Lund
7b65f413e4
Merge pull request #75 from sly74fr/master
Added macOS compatibility
2018-09-04 21:09:21 +02:00
Sylvain LAFRASSE
3a024ca529 Made O_NONBLOCK flag to open() call specific to macOS only. 2018-09-04 20:56:21 +02:00
Sylvain LAFRASSE
eb70da83ec Added macOS-related details. 2018-09-04 20:00:07 +02:00
Sylvain LAFRASSE
424c816118 Added O_NONBLOCK flag to open() call for macOS (10.13.6) compatibility. 2018-08-31 13:13:58 +02:00
Martin Lund
8db7bb56b5 Bump version 2018-06-26 19:09:31 +02:00
Martin Lund
c03de80e52 Update ChangeLog 2018-06-26 19:07:22 +02:00
Martin Lund
7245cdf240 Update date 2018-06-26 18:58:20 +02:00
Martin Lund
599d54c5bf Update AUTHORS 2018-06-24 16:42:51 +02:00
Martin Lund
0f17e7e0b0
Merge pull request #73 from hzeller/nicer-variables
Clarify the input/output variable names (No-op change)
2018-06-24 16:41:49 +02:00
Martin Lund
8e1e0c9b26
Merge pull request #71 from hzeller/local-echo
Provide local-echo option.
2018-06-24 16:31:21 +02:00
Henner Zeller
9965062fe2 Clarify the input/output variable names (No-op change) 2018-06-24 07:00:17 -07:00
Henner Zeller
776284e251 Organize options the same sequence they are mentiond in cmdline help. 2018-06-24 06:50:05 -07:00
Martin Lund
64f9f3a248
Merge pull request #72 from hzeller/cr-nl
Map CR->NL locally on output instead of using tio.c_oflag |= OCRNL.
2018-06-24 13:17:05 +02:00
Martin Lund
96cec154d4
Merge pull request #70 from hzeller/log-fast
Write to logfile as soon as we have the data, don't buffer.
2018-06-24 13:16:19 +02:00
Henner Zeller
0bc56c8a8f Update README. 2018-06-23 13:58:59 -07:00
Henner Zeller
ab451a984c Map CR->NL locally on output instead of using tio.c_oflag |= OCRNL.
This mostly is intended to have local echo output exactly what is sent
to the remote endpoint.
A nice side-effect is, that it also fixes tty-implementations, that can't
deal with the OCRNL flag on tio.c_oflag.
2018-06-23 13:47:06 -07:00
Henner Zeller
dabd2130a9 Provide local-echo option.
Can be switched on with -e on the command line.
Can be toggled with Ctrl t e while program is running.
2018-06-23 12:37:40 -07:00
Henner Zeller
763a09e172 Write to logfile as soon as we have the data, don't buffer.
Logfiles are important to see what happend, in particular if something
unexpected happened; so we want to make sure that the logfile is flushed
to disk.

Before this change, the logfile was typically written at the end in
a large chunk as the default (large) buffering applied. Now, characters are
written out ASAP, so it is possible to get a live-view with a
tail -f <logfile>
2018-06-23 11:42:23 -07:00
Martin Lund
08fd18e803 Update ChangeLog 2018-04-18 21:01:50 +02:00
Martin Lund
fff867f637 Update README 2018-04-18 20:51:27 +02:00
Martin Lund
b7cdbec8e2 Update man page and bash completion 2018-04-18 20:48:04 +02:00
Martin Lund
7d5e25d368
Update AUTHORS 2018-04-18 10:49:22 +02:00
Martin Lund
038eebdeb3
Merge pull request #68 from zhaozhongchen/master
ONLCRNL: change the method to map NL to CR-NL
2018-04-18 10:44:57 +02:00
qianfan Zhao
58456a7636 ONLCRNL: change the method to map NL to CR-NL
Signed-off-by: qianfan Zhao <qianfanguijin@163.com>
2018-04-18 16:25:59 +08:00
Martin Lund
23ee9bece3 Bump version 2018-01-28 03:50:27 +01:00
Martin Lund
6317dd2f81 Update ChangeLog 2018-01-28 02:23:38 +01:00
Martin Lund
77c19ff152 Add mapping flags INLCRNL and ODELBS
The following new mapping flags are added:

INLCRNL: Map NL to CR-NL on input.
ODELBS: Map DEL to BS on output.

Flags requested and tested by Jan Ciger (janoc).
2017-12-29 14:54:40 +01:00
Martin Lund
60cbc5b368 Bump version 2017-12-14 07:02:36 +01:00
Martin Lund
1fe70f8dba Bump version 2017-12-14 06:42:06 +01:00
Martin Lund
08d8a338bc Update ChangeLog 2017-12-14 06:41:00 +01:00
Martin Lund
1d7efeb561 Update README 2017-12-03 23:36:54 +01:00
Martin Lund
46f5686837 Update AUTHORS 2017-11-27 15:33:40 +01:00
Martin Lund
8c7cf2015a
Merge pull request #65 from arkamar/musl-include
Add missing header file under musl-libc
2017-11-27 14:45:30 +01:00
Martin Lund
b5246be7fa Add snap status to README.md 2017-11-27 14:32:35 +01:00
Petr Vaněk
3306a8dfb1 Add missing header file under musl-libc
Musl's inclusion tree slightly differs from glibc, therefore TCGETS2 is
not reachable through sys/ioctl.h, so asm/ioctls.h needs to be included
too.
2017-11-27 14:27:28 +01:00
Martin Lund
51d316b5d2 Update README.md 2017-11-23 18:01:18 +01:00
Martin Lund
a82e089394 Add README.md to prettify GitHub page 2017-11-23 17:53:46 +01:00
Martin Lund
c6471625d8 Merge branch 'master' of github.com:tio/tio 2017-11-23 17:29:18 +01:00
Martin Lund
7c39176b3a Update README 2017-11-23 17:29:10 +01:00
Martin Lund
1afd3606cc
Merge pull request #64 from jwilk-forks/spelling
Fix grammar and typos
2017-11-21 16:43:38 +01:00
Jakub Wilk
9229e9addb Fix grammar and typos 2017-11-21 16:27:19 +01:00
Martin Lund
59d4604ce6 Add missing header 2017-11-14 21:38:22 +01:00
Martin Lund
e9efa13bc5 Update ChangeLog 2017-11-14 12:52:15 +01:00
Martin Lund
641b7d87ca Update man page 2017-11-13 21:02:14 +01:00
Martin Lund
e646c50019 Add support for setting non-standard baudrates
Support for non-standard baudrate settings will be automatically enabled
if the termios2 interface is detected available. However, to play it
safe, the old and widely supported termios interface will still be used
when setting standard baudrates.
2017-11-13 13:40:15 +01:00
Martin Lund
23bab24890 Update man page 2017-11-11 15:48:19 +01:00
Martin Lund
39ef771e10 Cleanup 2017-11-09 14:38:50 +01:00
Martin Lund
19ad278c2d Update AUTHORS 2017-11-07 12:37:06 +01:00
Martin Lund
9c63885a27 Bump version 2017-11-06 15:47:23 +01:00
79 changed files with 13889 additions and 2182 deletions

5
.clang-format Normal file
View file

@ -0,0 +1,5 @@
BasedOnStyle: llvm
IndentWidth: 4
AllowShortFunctionsOnASingleLine: None
KeepEmptyLinesAtTheStartOfBlocks: false
BreakBeforeBraces: Allman

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
custom: ["https://www.paypal.me/lundmar"]

View file

@ -0,0 +1,7 @@
#!/usr/bin/env bash
pip3 install meson -U
pip3 install ninja -U
sudo apt-get install -y liblua5.2-dev libglib2.0-dev
meson setup build
meson compile -C build

126
.github/workflows/codeql.yml vendored Normal file
View file

@ -0,0 +1,126 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ "main", "master" ]
schedule:
- cron: '0 0 * * *'
pull_request:
branches: '*'
jobs:
analyze:
name: Analyze
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners
# Consider using larger runners for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-22.04' }}
timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby', 'swift' ]
# Use only 'java' to analyze code written in Java, Kotlin or both
# Use only 'javascript' to analyze code written in JavaScript, TypeScript or both
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
submodules: recursive
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
queries: security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift).
# If this step fails, then you should remove it and run the build manually (see below)
#- name: Autobuild
# uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
- run: |
./.github/workflows/codeql-buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"
upload: false
id: step1
# Filter out rules with low severity or high false positve rate
# Also filter out warnings in third-party code
- name: Filter out unwanted errors and warnings
uses: advanced-security/filter-sarif@v1
with:
patterns: |
-**:cpp/path-injection
-**:cpp/world-writable-file-creation
-**:cpp/poorly-documented-function
-**:cpp/potentially-dangerous-function
-**:cpp/use-of-goto
-**:cpp/integer-multiplication-cast-to-long
-**:cpp/comparison-with-wider-type
-**:cpp/leap-year/*
-**:cpp/ambiguously-signed-bit-field
-**:cpp/suspicious-pointer-scaling
-**:cpp/suspicious-pointer-scaling-void
-**:cpp/unsigned-comparison-zero
-**/cmake*/Modules/**
input: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif
output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif
- name: Upload CodeQL results to code scanning
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ steps.step1.outputs.sarif-output }}
category: "/language:${{matrix.language}}"
- name: Upload CodeQL results as an artifact
if: success() || failure()
uses: actions/upload-artifact@v4
with:
name: codeql-results
path: ${{ steps.step1.outputs.sarif-output }}
retention-days: 5
- name: Fail if an error is found
run: |
./.github/workflows/fail_on_error.py \
${{ steps.step1.outputs.sarif-output }}/cpp.sarif

34
.github/workflows/fail_on_error.py vendored Executable file
View file

@ -0,0 +1,34 @@
#!/usr/bin/env python3
import json
import sys
# Return whether SARIF file contains error-level results
def codeql_sarif_contain_error(filename):
with open(filename, 'r') as f:
s = json.load(f)
for run in s.get('runs', []):
rules_metadata = run['tool']['driver']['rules']
if not rules_metadata:
rules_metadata = run['tool']['extensions'][0]['rules']
for res in run.get('results', []):
if 'ruleIndex' in res:
rule_index = res['ruleIndex']
elif 'rule' in res and 'index' in res['rule']:
rule_index = res['rule']['index']
else:
continue
try:
rule_level = rules_metadata[rule_index]['defaultConfiguration']['level']
except IndexError as e:
print(e, rule_index, len(rules_metadata))
else:
if rule_level == 'error':
return True
return False
if __name__ == "__main__":
if codeql_sarif_contain_error(sys.argv[1]):
sys.exit(1)

30
.github/workflows/macos.yml vendored Normal file
View file

@ -0,0 +1,30 @@
name: MacOS build
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
brew install meson ninja lua
- name: Build
run: |
meson setup build
meson compile -C build --verbose
meson install -C build

31
.github/workflows/ubuntu.yml vendored Normal file
View file

@ -0,0 +1,31 @@
name: Ubuntu build
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install dependencies
run: |
sudo apt update
sudo apt install -y bash-completion git meson liblua5.2-dev libglib2.0-dev
- name: Build
run: |
meson setup build --prefix $HOME/opt/tio
meson compile -C build --verbose
meson install -C build

26
.gitignore vendored
View file

@ -1,24 +1,4 @@
*.tar.xz
src/*.o
src/tio
Makefile.in
Makefile
aclocal.m4
autom4te.cache/
configure
compile
depcomp
install-sh
missing
src/Makefile.in
src/Makefile
config.log
config.status
src/.deps/
src/include/config.h
src/include/config.h.in
src/include/config.h.in~
src/include/stamp-h1
/build
/subprojects/libinih
*.swp
/tio-*
/src/bash-completion/tio
.cache

View file

@ -1,3 +0,0 @@
language: c
before_script: ./autogen.sh
script: ./configure && make

2
.typos.toml Normal file
View file

@ -0,0 +1,2 @@
[default]
extend-ignore-words-re = ["tio"]

55
AUTHORS
View file

@ -1,6 +1,9 @@
Maintainer:
Martin Lund <martin.lund@keep-it-simple.com>
Co-maintainer:
Sylvain LAFRASSE <slymacdev@free.fr>
Contributors:
Jesper Larsen <knorr.jesper@gmail.com>
Jeppe Ledet-Pedersen <jlp@gomspace.com>
@ -11,5 +14,57 @@ Nick Østergaard <oe.nick@gmail.com>
Adam Borowski <kilobyte@angband.pl>
Robert Scheck <robert@fedoraproject.org>
Dmitri Goutnik <dg@syrec.org>
Daniel Engberg <daniel.engberg.lists@pyret.net>
Petr Vaněk <pv@excello.cz>
qianfan Zhao <qianfanguijin@163.com>
Henner Zeller <h.zeller@acm.org>
Robey Pointer <robey@afero.io>
Lars Kellogg-Stedman <lars@oddbit.com>
arichi <sergey.korabanov@gmail.com>
George Stark <george-u@yandex.com>
Erik Moqvist <erik.moqvist@gmail.com>
Fabrice Fontaine <fontaine.fabrice@gmail.com>
Alban Bedel <alban.bedel@aerq.com>
Björn Stenberg <bjorn@haxx.se>
Henner Zeller <h.zeller@acm.org>
Henrik Brix Andersen <henrik@brixandersen.dk>
Mariusz Midor <dexlab@o2.pl>
attila-v <attila_v@index.hu>
Yin Fengwei <fengwei.yin@intel.com>
Liam Beguin <liambeguin@gmail.com>
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>
Attila Veghelyi <aveghelyi@dension.com>
Vyacheslav Patkov <slava@patkov.ru>
Bill Hass <billhass@umich.edu>
Peter van Dijk <peter@7bits.nl>
Braden Young <braden@somewearlabs.com>
Wes Koerber <wkoerber@acsd4u.com>
HiFiPhile <admin@hifiphile.com>
Paul Ruizendaal <pnr@planet.nl>
Fredrik Svedberg <fredrik@svedberg.us>
Sebastian <sebastian.krahmer@gmail.com>
Mingjie Shen <shen497@purdue.edu>
Brian <bayuan@purdue.edu>
Davis C <davisclaib@gmail.com>
KhazAkar <damianzrb@zohomail.eu>
Eliot Alan Foss <eliotfoss@gmail.com>
Robert Lipe <robertlipe@gpsbabel.org>
Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Tomka Gergely <tomkatudor@gmail.com>
Steve Marple <stevemarple@googlemail.com>
konosubakonoakua <ailike_meow@qq.com>
Keith Hill <k_hill@unitronlp.com>
Lubov66 <radolevanja@gmail.com>
V <v@anomalous.eu>
Samuel Holland <samuel@sholland.org>
David Ordnung <david.ordnung@googlemail.com>
Thanks to everyone who has contributed to this project.

339
COPYING
View file

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

516
ChangeLog
View file

@ -1,516 +0,0 @@
=== tio v1.26 ===
Changes since tio v1.25:
* Reconfigure stdin
Make stdin behave more raw'ish. In particular, don't
translate CR -> NL on input.
* Add special character map feature
Add a --map option which allows to map special characters, in particular CR and
NL characters which are used in various combinations on varios platforms.
* Cleanup
* Update AUTHORS
* Update README
* Mention website
* Update man page
Changes since tio v1.24:
* Fix error applying new stdout settings
On Fedora 26 tio will quit with the following error message:
"Error: Could not apply new stdout settings (Invalid argument)"
In case of Fedora, it turns out that the new stdout settings used are a
bit too agressive because an empty termios structure is used. To remedy
this we reuse the existing stdout settings and only reconfigure the
specific options we need to make a "raw" stdout configuration.
* Remove unused pkgconfig in configure
* Code cleanup
Remove unused variable.
Changes since tio v1.23:
* Optimize clear screen command
Replaced system call with inline ANSI/VT100 clear screen code sequence
* Fix bash completion installation
Fixed the configure script to avoid that the bash completion script gets
installed outside of the prefix location. The default install location
is now $prefix/share/bash-completion/completions.
Use the configure option '--with-bash-completion-dir=PATH' if you need
to install the bash completion script elsewhere.
Jakub Wilk:
* Add missing commas in conditional sentences
Changes since tio v1.22:
* Update copyright headers
Jakub Wilk:
* Fix typos
Changes since tio v1.21:
* Update man page date
* Update copyright year
* Code cleanup
* Update README and man page
Changes since tio v1.20:
* Add support for hexadecimal mode
A new key command 'ctrl-t h' is introduced which toggles between
hexadecimal mode and normal mode. When in hexadecimal mode data received
will be printed in hexadecimal.
* Do not distribute src/bash_completion/tio
Since the bash completion tio script is now autogenerated from tio.in it
should not be distributed in the tarball.
* Add missing forward flag
* Update AUTHORS file
Adam Borowski:
* 'ctrl-t b' to send serial break.
Jakub Wilk:
* Removed git commit references from ChangeLog
ChangeLog is primary useful for users who don't have the git repository
at hand.
Replace git commit references with version numbers; or if the change
only cleans up another change with no release in between, remove the
changelog item completely.
Changes since tio v1.19:
* Added more error handling of terminal calls
Also removed duplicate terminal flushing calls.
* Revert "Added support for non-standard baud rates"
This reverts a change made in v1.18.
Reverting because supporting non-standard or arbitrary baud rates is
troublesome because the c library provides no means of doing so and even
if bare metal linux kernel interface is used it will not work on all
Linux kernels version.
Changes since tio v1.18:
* Rearranged key commands
Rearranged the key commands:
ctrl-t c (clear screen) is now
ctrl-t l which is similar to the well known shell ctrl-l
ctrl-t i (show settings information) is now
ctrl-t c (show configuration)
Updated man page accordingly.
* Added "ctrl-t c" key command to clear screen
Changes since tio v1.17:
* Updated man page
* Added support for non-standard baud rates
Only enabled when possible, that is, when the BOTHER definition is
available.
It is untested but it should work as described here:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=683826
Some Cypress USB<->serial devices supposedly supports arbitrary speeds.
* Generate baudrate switch cases based on detection
Support a single source of baud rate configuration as discussed in
https://github.com/tio/tio/issues/45 .
To do so, autogeneration of the switch cases which do the baud rate
option value check and configuration/conversion in tty_configure() is
introduced via a single macro.
Just to be safe, this change also enables configure detection of all
baud rates, including the ones previously assumed supported by most/all
systems (POSIX).
* Minor cleanup
* Exit when not a tty device in autoconnect mode
Jakub Wilk:
* Added non-standard baud rates that are defined on FreeBSD
* Capitalized "GitHub" in README
Changes since tio v1.16:
* Compacted tty_configure() a bit
* Fixed automatic baud rate enablement
* Minor cleanups
* Added autodetection of available baud rates
Various platforms support different baud rates.
To avoid adding platform specific handling generic baud rate detection
tests are introduced in the configure script. Successfully detected baud
rates are automatically enabled. This applies to both the C code and the
bash completion script.
Note:
Baud rates below 57600 are defined by POSIX-1 and supported by most
platforms so only baud rate 57600 and above are tested.
* Updated bash-completion
* Fixed printf() format type
* Added Travis build configuration
Jakub Wilk:
* Generated bash completion at configure time
* Reduce code duplication in baud rate detection
* Add support for baud rates 200 and 1800
* Fixed baudrate type
Changes since tio v1.15:
* Updated man page
* Updated README
* Removed obsolete packaging files
* Removed use of deprecated bzero()
Changes since tio v1.14:
* Removed + to remove potential confusion
* Added input digit checks
* Fixed license string
* Introduced tty_configure()
Moved tty configuration actions to tty_configure() in tty.c. This way
options.c is strictly about parsing options nothing else.
* Function names cleanup
* Updated AUTHORS file
Added Nick who created the new tio package for Arch Linux.
* Fixed tx/rx counters type
Jakob Haufe:
* Include config.h before standard headers
Large file support was meant to be enabled in v1.11.
This change enables it for real.
Changes since tio v1.13:
* Fixed tio_printf macro
* Fixed launch hints
Fixed launch hints not being printed in no autoconnect mode.
* Added 'ctrl-t ?' to list available commands
* Fixed log mechanism
To avoid echoing only log what is received from tty device.
* Improved tio output
Added titles and indentation to commands output for clearer separation
when firing commands repeatedly.
Also added print of tio version and quit command hint at launch.
* Cleaned up tio print mechanism
Jakub Wilk:
* Fixed grammar
"allow" is a transitive verb, which requires an object,
so "allow to <verb>" is ungrammatical.
* Fixed typo
Changes since tio v1.12:
* Fixed some error prints
* Fixed error printing for no autoconnect mode
Always print errors but only print silent errors when in no autoconnect
mode.
* Added key command for showing session settings
A new key command "ctrl-t i" is added to allow the user to display the
various session settings information (baudrate, databits, log file, etc.).
This is useful in case you have a running session but have forgotten
what the settings are.
Changes since tio v1.11:
* Consolidated command key handling
* Moved delay mechanism into separate function
* Retired obsolete usleep()
Replaced with nanosleep()
* Added simple tx/rx statistics command (ctrl-t s)
To display the total number of bytes transmitted/received simply perform the
'ctrl-t s' command sequence.
This feature can be useful when eg. trying to detect non-printable
characters.
* Further simplification of key handling
Changed so that the "ctrl-t ctrl-t" sequence is now simply "ctrl-t t" to
send the ctrl-t key code. This is inspired by screen which does similar
to send its command key code (ctrl-a a).
This change also eases adding new key commands if needed.
Updated man page accordingly.
* Cleaned up and simplified key handling
Jakub Wilk:
* Insert output delay only if something was output
Changes since tio v1.10:
* Enabled large file support (LFS)
Added autotools AC_SYS_LARGEFILE to support 64 bit file size handling.
* Updated tio title
Changes since tio v1.9:
* Introduced lock on device file
Tio will now test for and obtain an advisory lock on the tty device file
to prevent starting multiple sessions on the same tty device.
* Updated AUTHORS
Jakub Wilk:
* Treat EOF on stdin as error
Changes since tio v1.8:
* Cleanup of error handling
Introduced consistent way of handling errors and printing error messages.
Also upgraded some warnings to errors.
* Updated localtime() error message
* Cleanup
Jakub Wilk:
* Fix error handling for select()
Previously the error handling code for select() was unreachable.
* Removed unneeded quotes from AM_CFLAGS
* Expanded tabs
* Fixed setting "tainted"
Set "tainted" if and only if any character was read from the device.
Ctrl-t is no longer sent to the device on exit, so the trick to avoid
its echo is not necessary.
Characters read from stdin don't directly affect output, so they
shouldn't enable "tainted".
* Used \r in color_printf()
\033[300D is an unusual way to move the cursor back to column 1.
Use straightforward \r instead.
* Added missing \r\n to warning messages
\n alone is not enough, because the terminal is in raw mode.
Changes since tio v1.7:
* Fixed enablement of compiler warnings
* Fixed log_open() prototype
* Fixed index error wrt ctrl-t detection
* Fixed handling of ctrl-t
Before, when exercising the quit key sequence (ctrl-t + q) the ctrl-t code
(0x14) would be sent.
This is now fixed so that it is not sent.
However, in case it is needed to send ctrl-t to the device it is possible by
simply repeating the ctrl-t.
Meaning, ctrl-t + ctrl-t = ctrl-t sent to device.
* Improved error handling
Fixes a memory leak and avoids aggressive busy looping when problems
accessing tty device.
* Removed redundant log_close() call
* Enabled compiler warnings
Jakub Wilk:
* Stopped copying arguments to fixed-size buffers
Don't needlessly copy command-line arguments into fixed-size buffers.
Previously the program crashed if an overlong pathname was provided on
the command line. Also, some systems (such as GNU Hurd) don't define
MAXPATHLEN at all.
* Added const to log_open() prototype
* Completed the ^g to ^t transition
In v1.7 the escape key was changed from ^g to ^t, but some
code and comments still referred to the old key.
* Used HTTPS for tio.github.io
* Man page beautification
* Bumped date in man page
* Improve man page formatting
Use regular font for metacharacters such as "[]", "," or "|";
use italic font for metavariables.
* Fixed hyphen vs minus vs em-dash confusion in man page
- prints as hyphen;
\- prints as minus sign;
\em prints as em-dash.
Changes since tio v1.6:
* Changed escape key from ^g to ^t
After renaming to "tio" it makes sense to change the escape key
accordingly. Hence, the new escape key is ^t.
Meaning, in session, its now ctrl-t + q to quit.
Jakub Wilk:
* Fixed silly "tio or tio" in man page
* Fixed typo

370
INSTALL
View file

@ -1,370 +0,0 @@
Installation Instructions
*************************
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
Inc.
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Basic Installation
==================
Briefly, the shell command `./configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' in each directory of the package.
It may also create one or more `.h' files containing system-dependent
definitions. Finally, it creates a shell script `config.status' that
you can run in the future to recreate the current configuration, and a
file `config.log' containing compiler output (useful mainly for
debugging `configure').
It can also use an optional file (typically called `config.cache'
and enabled with `--cache-file=config.cache' or simply `-C') that saves
the results of its tests to speed up reconfiguring. Caching is
disabled by default to prevent problems with accidental use of stale
cache files.
If you need to do unusual things to compile the package, please try
to figure out how `configure' could check whether to do them, and mail
diffs or instructions to the address given in the `README' so they can
be considered for the next release. If you are using the cache, and at
some point `config.cache' contains results you don't want to keep, you
may remove or edit it.
The file `configure.ac' (or `configure.in') is used to create
`configure' by a program called `autoconf'. You need `configure.ac' if
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
2. Type `make' to compile the package.
3. Optionally, type `make check' to run any self-tests that come with
the package, generally using the just-built uninstalled binaries.
4. Type `make install' to install the programs and any data files and
documentation. When installing into a prefix owned by root, it is
recommended that the package be configured and built as a regular
user, and only the `make install' phase executed with root
privileges.
5. Optionally, type `make installcheck' to repeat any self-tests, but
this time using the binaries in their final installed location.
This target does not install anything. Running this target as a
regular user, particularly if the prior `make install' required
root privileges, verifies that the installation completed
correctly.
6. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
7. Often, you can also type `make uninstall' to remove the installed
files again. In practice, not all packages have tested that
uninstallation works correctly, even though it is required by the
GNU Coding Standards.
8. Some packages, particularly those that use Automake, provide `make
distcheck', which can by used by developers to test that all other
targets like `make install' and `make uninstall' work correctly.
This target is generally not run by end users.
Compilers and Options
=====================
Some systems require unusual options for compilation or linking that
the `configure' script does not know about. Run `./configure --help'
for details on some of the pertinent environment variables.
You can give `configure' initial values for configuration parameters
by setting variables in the command line or in the environment. Here
is an example:
./configure CC=c99 CFLAGS=-g LIBS=-lposix
*Note Defining Variables::, for more details.
Compiling For Multiple Architectures
====================================
You can compile the package for more than one kind of computer at the
same time, by placing the object files for each architecture in their
own directory. To do this, you can use GNU `make'. `cd' to the
directory where you want the object files and executables to go and run
the `configure' script. `configure' automatically checks for the
source code in the directory that `configure' is in and in `..'. This
is known as a "VPATH" build.
With a non-GNU `make', it is safer to compile the package for one
architecture at a time in the source code directory. After you have
installed the package for one architecture, use `make distclean' before
reconfiguring for another architecture.
On MacOS X 10.5 and later systems, you can create libraries and
executables that work on multiple system types--known as "fat" or
"universal" binaries--by specifying multiple `-arch' options to the
compiler but only a single `-arch' option to the preprocessor. Like
this:
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
CPP="gcc -E" CXXCPP="g++ -E"
This is not guaranteed to produce working output in all cases, you
may have to build one architecture at a time and combine the results
using the `lipo' tool if you have problems.
Installation Names
==================
By default, `make install' installs the package's commands under
`/usr/local/bin', include files under `/usr/local/include', etc. You
can specify an installation prefix other than `/usr/local' by giving
`configure' the option `--prefix=PREFIX', where PREFIX must be an
absolute file name.
You can specify separate installation prefixes for
architecture-specific files and architecture-independent files. If you
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
PREFIX as the prefix for installing programs and libraries.
Documentation and other data files still use the regular prefix.
In addition, if you use an unusual directory layout you can give
options like `--bindir=DIR' to specify different values for particular
kinds of files. Run `configure --help' for a list of the directories
you can set and what kinds of files go in them. In general, the
default for these options is expressed in terms of `${prefix}', so that
specifying just `--prefix' will affect all of the other directory
specifications that were not explicitly provided.
The most portable way to affect installation locations is to pass the
correct locations to `configure'; however, many packages provide one or
both of the following shortcuts of passing variable assignments to the
`make install' command line to change installation locations without
having to reconfigure or recompile.
The first method involves providing an override variable for each
affected directory. For example, `make install
prefix=/alternate/directory' will choose an alternate location for all
directory configuration variables that were expressed in terms of
`${prefix}'. Any directories that were specified during `configure',
but not in terms of `${prefix}', must each be overridden at install
time for the entire installation to be relocated. The approach of
makefile variable overrides for each directory variable is required by
the GNU Coding Standards, and ideally causes no recompilation.
However, some platforms have known limitations with the semantics of
shared libraries that end up requiring recompilation when using this
method, particularly noticeable in packages that use GNU Libtool.
The second method involves providing the `DESTDIR' variable. For
example, `make install DESTDIR=/alternate/directory' will prepend
`/alternate/directory' before all installation names. The approach of
`DESTDIR' overrides is not required by the GNU Coding Standards, and
does not work on platforms that have drive letters. On the other hand,
it does better at avoiding recompilation issues, and works well even
when some directory options were not specified in terms of `${prefix}'
at `configure' time.
Optional Features
=================
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure' the
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Some packages pay attention to `--enable-FEATURE' options to
`configure', where FEATURE indicates an optional part of the package.
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
is something like `gnu-as' or `x' (for the X Window System). The
`README' should mention any `--enable-' and `--with-' options that the
package recognizes.
For packages that use the X Window System, `configure' can usually
find the X include and library files automatically, but if it doesn't,
you can use the `configure' options `--x-includes=DIR' and
`--x-libraries=DIR' to specify their locations.
Some packages offer the ability to configure how verbose the
execution of `make' will be. For these packages, running `./configure
--enable-silent-rules' sets the default to minimal output, which can be
overridden with `make V=1'; while running `./configure
--disable-silent-rules' sets the default to verbose, which can be
overridden with `make V=0'.
Particular systems
==================
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
CC is not installed, it is recommended to use the following options in
order to use an ANSI C compiler:
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
HP-UX `make' updates targets which have the same time stamps as
their prerequisites, which makes it generally unusable when shipped
generated files such as `configure' are involved. Use GNU `make'
instead.
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
a workaround. If GNU CC is not installed, it is therefore recommended
to try
./configure CC="cc"
and if that doesn't work, try
./configure CC="cc -nodtk"
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
directory contains several dysfunctional programs; working variants of
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
in your `PATH', put it _after_ `/usr/bin'.
On Haiku, software installed for all users goes in `/boot/common',
not `/usr/local'. It is recommended to use the following options:
./configure --prefix=/boot/common
Specifying the System Type
==========================
There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of machine the package
will run on. Usually, assuming the package is built to be run on the
_same_ architectures, `configure' can figure that out, but if it prints
a message saying it cannot guess the machine type, give it the
`--build=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name which has the form:
CPU-COMPANY-SYSTEM
where SYSTEM can have one of these forms:
OS
KERNEL-OS
See the file `config.sub' for the possible values of each field. If
`config.sub' isn't included in this package, then this package doesn't
need to know the machine type.
If you are _building_ compiler tools for cross-compiling, you should
use the option `--target=TYPE' to select the type of system they will
produce code for.
If you want to _use_ a cross compiler, that generates code for a
platform different from the build platform, you should specify the
"host" platform (i.e., that on which the generated programs will
eventually be run) with `--host=TYPE'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Defining Variables
==================
Variables not defined in a site shell script can be set in the
environment passed to `configure'. However, some packages may run
configure again during the build, and the customized values of these
variables may be lost. In order to avoid this problem, you should set
them in the `configure' command line, using `VAR=value'. For example:
./configure CC=/usr/local2/bin/gcc
causes the specified `gcc' to be used as the C compiler (unless it is
overridden in the site shell script).
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
an Autoconf limitation. Until the limitation is lifted, you can use
this workaround:
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
`configure' Invocation
======================
`configure' recognizes the following options to control how it
operates.
`--help'
`-h'
Print a summary of all of the options to `configure', and exit.
`--help=short'
`--help=recursive'
Print a summary of the options unique to this package's
`configure', and exit. The `short' variant lists options used
only in the top level, while the `recursive' variant lists options
also present in any nested packages.
`--version'
`-V'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`--cache-file=FILE'
Enable the cache: use and save the results of the tests in FILE,
traditionally `config.cache'. FILE defaults to `/dev/null' to
disable caching.
`--config-cache'
`-C'
Alias for `--cache-file=config.cache'.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made. To
suppress all normal output, redirect it to `/dev/null' (any error
messages will still be shown).
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--prefix=DIR'
Use DIR as the installation prefix. *note Installation Names::
for more details, including other options available for fine-tuning
the installation locations.
`--no-create'
`-n'
Run the configure checks, but stop before creating any output
files.
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

View file

@ -1,4 +1,4 @@
Copyright (c) 2014-2016 Martin Lund <martin.lund@keep-it-simple.com>
Copyright (c) 2014-2025 Martin Lund <martin.lund@keep-it-simple.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License

View file

@ -1 +0,0 @@
SUBDIRS = src man

2510
NEWS Normal file

File diff suppressed because it is too large Load diff

109
README
View file

@ -1,109 +0,0 @@
################################################################################
################# tio - a simple TTY terminal I/O application ##################
################################################################################
1. Introduction
"tio" is a simple TTY terminal application which features a straightforward
commandline interface to easily connect to TTY devices for basic
input/output.
It was created because the author needed a simple no-nonsense TTY
terminal application to easily connect to various terminal TTY devices.
2. Usage
The commandline interface is straightforward as reflected in the output
from 'tio --help':
Usage: tio [<options>] <tty device>
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 even|odd|none Parity (default: none)
-o, --output-delay <ms> Output delay (default: 0)
-n, --no-autoconnect Disable automatic connect
-l, --log <filename> Log to file
-m, --map <flags> Map special characters
-v, --version Display version
-h, --help Display help
In session, press ctrl-t q to quit.
The only option which requires a bit of elaboration is perhaps the
--no-autoconnect option.
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 connection is lost.
Tio features full bash autocompletion support.
Tio also supports various key commands. Press ctrl-t ? to list the
available key commands.
See the tio man page for more details.
3. Download
The latest release tarball is available at https://tio.github.io
4. Installation
4.1 Installation from source:
$ ./configure
$ make
$ make install
See INSTALL file for more installation details.
4.2 Installation using package:
Tio comes prepackaged for various GNU/Linux distributions. Visit
https://tio.github.io for package installation details.
5. Contributing
Tio is open source. Any contributions (bug fixes, doc, ideas, etc.) are
welcome. Visit the tio GitHub page to access latest source code, create
pull requests, add issues etc..
GitHub: https://github.com/tio/tio
6. Support
Submit bug reports via GitHub: https://github.com/tio/tio/issues
7. Website
Visit https://tio.github.io
8. License
Tio is GPLv2+. See COPYING file for license details.
9. Authors
Created by Martin Lund <martin.lund@keep-it-simple.com>
See the AUTHORS file for full list of authors.

574
README.md Normal file
View file

@ -0,0 +1,574 @@
[![tio](images/tio-icon.png)]()
# tio - a serial device I/O tool
[![](https://img.shields.io/github/actions/workflow/status/tio/tio/ubuntu.yml?label=Ubuntu)](https://github.com/tio/tio/actions/workflows/ubuntu.yml)
[![](https://img.shields.io/github/actions/workflow/status/tio/tio/macos.yml?label=MacOS)](https://github.com/tio/tio/actions/workflows/macos.yml)
[![](https://github.com/tio/tio/actions/workflows/codeql.yml/badge.svg)](https://github.com/tio/tio/actions/workflows/codeql.yml)
[![](https://img.shields.io/codefactor/grade/github/tio/tio)](https://www.codefactor.io/repository/github/tio/tio)
[![](https://img.shields.io/github/v/release/tio/tio?sort=semver)](https://github.com/tio/tio/releases)
[![](https://img.shields.io/repology/repositories/tio)](https://repology.org/project/tio/versions)
## 1. Introduction
tio is a 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.
<p align="center">
<img src="images/tio-demo.gif">
</p>
### 1.1 Motivation
To make a simpler serial device tool for working with serial TTY devices with
less focus on classic terminal/modem features and more focus on the needs of
embedded developers and hackers.
tio was originally created as an alternative to
[screen](https://www.gnu.org/software/screen) for connecting to serial devices
when used in combination with [tmux](https://tmux.github.io).
## 2. Features
* Easily connect to serial TTY devices
* Sensible defaults (115200 8n1)
* Automatic connection management
* Automatic detection of serial ports
* Automatic reconnect
* Automatically connect to first new appearing serial device
* Automatically connect to latest registered serial device
* Connect to same port/device combination via unique topology ID (TID)
* Useful for reconnecting when serial device has no serial device by ID
* Support for non-standard baud rates
* Support for mark and space parity
* X-modem (1K/CRC) and Y-modem file upload
* Support for RS-485 mode
* List available serial devices
* By device
* Including topology ID, uptime, driver, description
* Sorted by uptime (newest device listed last)
* By ID
* By path
* Show RX/TX statistics
* Toggle serial lines
* Pulse serial lines with configurable pulse duration
* Local echo support
* Remapping of characters (nl, cr-nl, bs, lowercase to uppercase, etc.)
* Switchable independent input and output
* Normal mode
* Hex mode (output supports variable width)
* Line mode (input only)
* Timestamp support
* Per line in normal output mode
* Output timeout timestamps in hex output mode
* Support for delayed output
* Per character
* Per line
* Log to file
* Automatic naming of log file (default)
* Configurable directory for saving automatic named log files
* Manual naming of log file
* Overwrite (default) or append to log file
* Strip control characters and escape sequences
* Configuration file support
* Support for configuration profiles
* Activate configuration profiles by name or pattern
* Support for including other configuration files
* Redirect I/O of shell command to serial device
* Redirect I/O to UNIX socket or IPv4/v6 network socket
* Useful for scripting or TTY sharing
* Pipe input and/or output
* Bash completion on options, serial device names, and profile names
* Configurable tio message text color
* Supports NO_COLOR env variable as per [no-color.org](https://no-color.org)
* Visual or audible alert on connect/disconnect
* Remapping of prefix key
* Lua scripting support for automation
* Run script manually or automatically at connect (once/always/never)
* Simple expect/send like functionality with support for regular expressions
* Manipulate port modem lines (useful for microcontroller reset/boot etc.)
* Send files via x/y-modem protocol
* Search for serial devices
* Man page documentation
* Plays nicely with [tmux](https://tmux.github.io) and similar terminal multiplexers
## 3. Usage
For more usage details please see the man page documentation
[here](https://raw.githubusercontent.com/tio/tio/master/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|profile|tid>
Connect to TTY device directly or via configuration profile or topology ID.
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
-a, --auto-connect new|latest|direct Automatic connect strategy (default: direct)
--exclude-devices <pattern> Exclude devices by pattern
--exclude-drivers <pattern> Exclude drivers by pattern
--exclude-tids <pattern> Exclude topology IDs by pattern
-n, --no-reconnect Do not reconnect
-e, --local-echo Enable local echo
--input-mode normal|hex|line Select input mode (default: normal)
--output-mode normal|hex|hexN Select output mode (default: normal)
-t, --timestamp Enable line timestamp
--timestamp-format <format> Set timestamp format (default: 24hour)
--timestamp-timeout <ms> Set timestamp timeout (default: 200)
-l, --list List available serial devices, TIDs, and profiles
-L, --log Enable log to file
--log-file <filename> Set log filename
--log-directory <path> Set log directory path for automatic named logs
--log-append Append to log file
--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 socket
--rs-485 Enable RS-485 mode
--rs-485-config <config> Set RS-485 configuration
--alert bell|blink|none Alert on connect/disconnect (default: none)
--mute Mute tio messages
--script <string> Run script from string
--script-file <filename> Run script from file
--script-run once|always|never Run script on connect (default: always)
--exec <command> Execute shell command with I/O redirected to device
-v, --version Display version
-h, --help Display help
Options and profiles may be set via configuration file.
In session you can press ctrl-t ? to list available key commands.
See the man page for more details.
```
By default tio automatically connects to the provided TTY device. If the device
is not present, tio will wait for it to appear and then connect. If the
connection is lost (e.g. device is unplugged), it will wait for the device to
reappear and then reconnect. However, if the `--no-reconnect` option is
provided, tio will exit if the device is not present or an established
connection is lost.
#### 3.1.1 Examples
Typical use is without options:
```
$ tio /dev/ttyUSB0
```
Which corresponds to the commonly used default options:
```
$ tio --baudrate 115200 --databits 8 --flow none --stopbits 1 --parity none /dev/ttyUSB0
```
List available serial devices:
```
$ tio --list
Device TID Uptime [s] Driver Description
----------------- ---- ------------- ---------------- --------------------------
/dev/ttyS4 BaaB 19526.576 port 16550A UART
/dev/ttyS5 eV0Z 19525.845 port 16550A UART
/dev/ttyUSB1 bCC2 1023.274 ftdi_sio TTL232R-3V3
/dev/ttyUSB0 SPpw 978.527 ftdi_sio TTL232RG-VREG3V3
/dev/ttyACM0 i5q4 2.079 cdc_acm ST-Link VCP Ctrl
By-id
--------------------------------------------------------------------------------
/dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTCHUV56-if00-port0
/dev/serial/by-id/usb-FTDI_TTL232RG-VREG3V3_FT1NELUB-if00-port0
/dev/serial/by-id/usb-STMicroelectronics_STLINK-V3_004900343438510234313939-if02
By-path
--------------------------------------------------------------------------------
/dev/serial/by-path/pci-0000:00:14.0-usb-0:8.1.3.1.4:1.0-port0
/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:8.1.3.1.4:1.0-port0
/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:6.4:1.0-port0
/dev/serial/by-path/pci-0000:00:14.0-usb-0:6.4:1.0-port0
/dev/serial/by-path/pci-0000:00:14.0-usbv2-0:6.3:1.2
/dev/serial/by-path/pci-0000:00:14.0-usb-0:6.3:1.2
Configuration profiles (/home/lundmar/.config/tio/config)
--------------------------------------------------------------------------------
rpi3 stm32 esp32 am64-evm
imx8mp-evk nucleo-h743zi2 usb-devices
```
It is recommended to connect serial TTY devices by ID:
```
$ tio /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTCHUV56-if00-port0
```
Note: Using serial devices by ID helps ensure that tio automatically reconnects
to the same serial device when reattached, even when it enumerates differently.
If no serial device by ID is available it is recommended to connect via
topology ID (TID):
```
$ tio bCC2
```
Note: The TID is unique and will stay the same as long as your USB serial port
device plugs into the same USB topology (same ports, same hubs, same
connections, etc.). This way it is possible for tio to successfully reconnect
to the same device.
Connect automatically to first new appearing serial device:
```
$ tio --auto-connect new
```
Connect automatically to latest registered serial device:
```
$ tio --auto-connect latest
```
It is possible to use exclude options to affect which serial devices are
involved in the automatic connection strategy:
```
$ tio --auto-connect new --exclude-devices "/dev/ttyACM?,/dev/ttyUSB2"
```
And to exclude drivers by pattern:
```
$ tio --auto-connect new --exclude-drivers "cdc_acm,ftdi_sio"
```
Note: Pattern matching supports '*' and '?'. Use comma separation to define
multiple patterns.
To include drivers by specific pattern simply negate the exclude option:
```
$ tio --auto-connect new --exclude-drivers !("cp2102")
```
Log to file with autogenerated filename:
```
$ tio --log /dev/ttyUSB0
```
Log to file with specific filename:
```
$ tio --log --log-file my-log.txt
```
Enable ISO8601 timestamps per line:
```
$ tio --timestamp --timestamp-format iso8601 /dev/ttyUSB0
```
Output to hex with width 16:
```
$ tio --output-mode hex16 /dev/ttyUSB0
```
Redirect I/O to IPv4 network socket on port 4242:
```
$ tio --socket inet:4242 /dev/ttyUSB0
```
Map NL to CR-NL on input from device and DEL to BS on output to device:
```
$ tio --map INLCRNL,ODELBS /dev/ttyUSB0
```
Pipe data to the serial device:
```
$ cat data.bin | tio /dev/ttyUSB0
```
Manipulate modem lines on connect:
```
$ tio --script "tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{DTR=toggle,RTS=toggle}" /dev/ttyUSB0
```
Pipe command to serial device and wait for line response within 1 second:
```
$ echo "*IDN?" | tio /dev/ttyACM0 --script "tio.expect('\r\n', 1000)" --mute
KORAD KD3305P V4.2 SN:32475045
```
### 3.2 Key commands
Various in session key commands are supported. When tio is started, press
ctrl-t ? to list the available key commands.
```
[15:02:53.269] Key commands:
[15:02:53.269] ctrl-t ? List available key commands
[15:02:53.269] ctrl-t b Send break
[15:02:53.269] ctrl-t c Show configuration
[15:02:53.269] ctrl-t e Toggle local echo mode
[15:02:53.269] ctrl-t f Toggle log to file
[15:02:53.269] ctrl-t F Flush data I/O buffers
[15:02:53.269] ctrl-t g Toggle serial port line
[15:02:53.269] ctrl-t i Toggle input mode
[15:02:53.269] ctrl-t l Clear screen
[15:02:53.269] ctrl-t L Show line states
[15:02:53.269] ctrl-t m Change mapping of characters on input or output
[15:02:53.269] ctrl-t o Toggle output mode
[15:02:53.269] ctrl-t p Pulse serial port line
[15:02:53.269] ctrl-t q Quit
[15:02:53.269] ctrl-t r Run script
[15:02:53.269] ctrl-t R Execute shell command with I/O redirected to device
[15:02:53.269] ctrl-t s Show statistics
[15:02:53.269] ctrl-t t Toggle line timestamp mode
[15:02:53.269] ctrl-t v Show version
[15:02:53.269] ctrl-t x Send file via Xmodem
[15:02:53.269] ctrl-t y Send file via Ymodem
[15:02:53.269] ctrl-t ctrl-t Send ctrl-t character
```
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
following locations in the order listed:
- $XDG_CONFIG_HOME/tio/config
- $HOME/.config/tio/config
- $HOME/.tioconfig
The configuration file supports profiles using named sections which can be
activated via the command-line by name or pattern. A profile specifies which
TTY device to connect to and other options.
### 3.3.1 Example
Example configuration file:
```
[default]
baudrate = 115200
databits = 8
parity = none
stopbits = 1
color = 10
[rpi3]
device = /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
no-reconnect = true
log = true
log-file = rpi3.log
line-pulse-duration = DTR=200,RTS=150
color = 11
[svf2]
device = /dev/ttyUSB0
baudrate = 9600
script = tio.expect("login: "); tio.write("root\n"); tio.expect("Password: "); tio.write("root\n")
color = 12
[esp32]
device = /dev/serial/by-id/usb-0403_6014-if00-port0
script = tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{DTR=low,RTS=high}; tio.msleep(100); tio.set{RTS=low}
script-run = once
color = 13
[usb-devices]
pattern = ^usb([0-9]*)
device = /dev/ttyUSB%m1
color = 14
```
To use a specific profile by name simply start tio like so:
```
$ tio rpi3
```
Or by pattern match:
```
$ tio usb12
```
Another more elaborate configuration file example is available [here](examples/config/config).
### 3.4 Lua script API
Tio suppots Lua scripting to easily automate interaction with the tty device.
In addition to the standard Lua API tio makes the following functions
and variables available:
#### `tio.expect(pattern, timeout)`
Waits for the Lua pattern to match or timeout before continuing.
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
Returns the captures from the pattern or `nil` on timeout.
#### `tio.read(size, timeout)`
Read up to `size` bytes from serial device. If timeout is 0 or not provided it
will wait forever until data is ready to read.
Returns a string up to `size` bytes long on success and `nil` on timeout.
#### `tio.readline(timeout)`
Read line from serial device. If timeout is 0 or not provided it will wait
forever until data is ready to read.
Returns a string on success and `nil` on timeout. On timeout a partially read
line may be returned as a second return value.
#### `tio.write(string)`
Write string to serial device.
Returns the `tio` table.
#### `tio.send(file, protocol)`
Send file using x/y-modem protocol.
Protocol can be any of `XMODEM_1K`, `XMODEM_CRC`, `YMODEM`.
#### `tio.ttysearch()`
Search for serial devices.
Returns a table of number indexed tables, one for each serial device found.
Each of these tables contains the serial device information accessible via the
following string indexed elements "path", "tid", "uptime", "driver",
"description".
Returns `nil` if no serial devices are found.
#### `tio.set{line=state, ...}`
Set state of one or multiple tty modem lines.
Line can be any of `DTR`, `RTS`, `CTS`, `DSR`, `CD`, `RI`
State is `high`, `low`, or `toggle`.
#### `tio.sleep(seconds)`
Sleep for seconds.
#### `tio.msleep(ms)`
Sleep for milliseconds.
#### `tio.alwaysecho`
A boolean value, defaults to `true`.
If `tio.alwaysecho` is `false`, the result of `tio.read`, `tio.readline` or
`tio.expect` will only be returned from the function and not logged or printed.
If `tio.alwaysecho` is set to `true`, reading functions also emit a single
timestamp to stdout and log file per `options.timestamp` and `options.log`.
## 4. Installation
### 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.
If you would like to see tio included in your favorite distribution, please
reach out to its package maintainers team.
### 4.2 Installation using snap (Linux)
Install latest stable version:
```
$ snap install tio --classic
```
Note: Classic confinement is currently required due to limitations of the snapcraft framework.
See [Issue #187](https://github.com/tio/tio/issues/187) for discussion.
### 4.3 Installation using brew (MacOS, Linux)
If you have [brew](http://brew.sh) installed:
```
$ brew install tio
```
### 4.4 Installation using MSYS2 (Windows)
If you have [MSYS2](https://www.msys2.org) installed:
```
$ pacman -S tio
```
### 4.5 Installation from source
The latest source releases can be found [here](https://github.com/tio/tio/releases).
Before running the install steps make sure you have glib and lua libraries installed. For example:
```
$ sudo apt install libglib2.0-dev liblua5.2-dev
```
Install steps:
```
$ meson setup build
$ meson compile -C build
$ meson install -C build
```
See meson\_options.txt for tio specific build options.
Note: The meson install steps may differ depending on your specific system.
### 4.6 Known issues
Getting permission access errors trying to open your serial device?
Add your user to the group which allows serial device access permanently. For example, to add your user to the 'dialout' group do:
```bash
sudo usermod -a -G dialout <username>
```
Switch to the "dialout" group, temporary but immediately for this session.
```bash
newgrp dialout
```
## 5. Contributing
This is an open source project - all contributions (bug reports, code, doc,
ideas, etc.) are welcome.
Please use the github issue tracker and pull request features.
Also, if you find this free open source software useful please feel free to
consider making a donation of your choice:
[![Donate](images/paypal.png)](https://www.paypal.me/lundmar)
## 6. Support
Submit bug reports via GitHub: https://github.com/tio/tio/issues
## 7. Website
Visit [tio.github.io](https://tio.github.io)
## 8. License
tio is GPLv2+. See LICENSE file for more details.
## 9. Authors
Maintained by Martin Lund \<martin.lund@keep-it-simple.com>
See the AUTHORS file for full list of contributors.

111
TODO Normal file
View file

@ -0,0 +1,111 @@
* Add release support for arm and x86 binary tarballs
* Support input and input mapping from lua scripts
* Add option to send file raw (no modem protocol)
* Add loopback option
Send received serial input back to output (for testing etc.)
* Add loopback support between two serial ports
Useful for traffic monitoring
* Add mapping feature for printing non-printable characters
* Porting layer to support native win32 builds.
Some of the work that needs to be done:
All posix functions need to be platform independent, go though file by file:
termios.h
unistd.h has very limited functions
ENV different in config_file_resolve
errno
sys/ioctl.h
sys/poll.h
socket, may need a new thread
Serial, RS485, character mapping
Communication pipe
Port enumerate, all devices of the same type have the same name (eg. USB
Serial Device for ttyACM) -> which makes regex not meaningful (kind of a
good thing since libtre in Mingw has too much dependencies makes binary too
big)
* Support traditional hex output format such as:
00000000 74 65 73 74 20 74 65 73 74 20 74 65 73 74 20 74 |test test test t|
00000010 65 73 74 64 66 0a 61 0a 66 61 0a 66 0a 61 73 66 |estdf.a.fa.f.asf|
00000020 64 61 64 73 66 61 73 66 64 61 73 64 66 61 64 73 |dadsfasfdasdfads|
00000030 66 0a 61 73 64 66 61 64 73 66 61 73 64 66 61 73 |f.asdfadsfasdfas|
00000040 64 66 0a 61 73 64 66 61 64 73 66 61 73 64 66 61 |df.asdfadsfasdfa|
00000050 73 64 66 66 64 61 73 64 66 0a 0a 31 32 33 31 0a |sdffdasdf..1231.|
00000060 65 32 31 64 73 77 65 64 0a 0a |e21dswed..|
0000006a
* Add support for activity based time stamping in normal output mode
Already supported in hex output mode.
* Allow tio to connect to socket
After some more consideration I think it makes sense to support connecting to a
socket as that will make tio be able to both serve a serial port via a socket
and connect to it - it will be an end to end solution. In short we will be able
to do the following:
Host serial port on socket (existing feature):
$ tio --socket unix:/tmp/tio-socket-0 /dev/ttyUSB0
Connect to same socket (new feature):
$ tio unix:/tmp/tio-socket-0
Besides a bit of refactoring the following required changes spring to mind:
* Socket mode and type of socket should be activated via device name prefix. For example:
* UNIX socket: tio unix:<filename>
* TCPv4 socket: tio inet:<ip>:<port>
* TCPv6 socket: tio inet6:<ip>:<port>
* If no port number defined default to 3333
* Mapping flags INLCR, IGNCR, ICRNL needs implementation for socket mode
* Error messages should just say "device" instead of "tty device" etc.
* Remove other tty'isms (tty_write() should be device_write() etc.)
* In session key commands that do not work in socket mode should either not be listed or print an error messages if used.
* All non-tty features should continue work (auto-connect etc.)
* Shell completion script update
* Man page update
* 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
* Websocket support
Extend the socket feature to redirect serial I/O to websocket on e.g. port
1234 like so:
$ tio --socket ws:1234
Use libwesockets to implement feature.

View file

@ -1 +0,0 @@
autoreconf --force -v --install

View file

@ -1,91 +0,0 @@
AC_PREREQ([2.68])
AC_INIT([tio], [1.26], [], [tio], [https://tio.github.io])
AC_CONFIG_HEADERS([src/include/config.h])
AM_INIT_AUTOMAKE([1.11 foreign dist-xz no-dist-gzip -Wall -Werror])
AM_SILENT_RULES([yes])
AC_PROG_CC
AC_LANG([C])
AC_PROG_INSTALL
AC_SYS_LARGEFILE
# Handle bash completion
AC_ARG_WITH([bash-completion-dir],
AS_HELP_STRING([--with-bash-completion-dir[=PATH]],
[Install the bash auto-completion script in this directory. @<:@default=yes@:>@]),
[],
[with_bash_completion_dir=yes])
if test "x$with_bash_completion_dir" = "xyes"; then
BASH_COMPLETION_DIR="${datadir}/bash-completion/completions"
else
BASH_COMPLETION_DIR="$with_bash_completion_dir"
fi
AC_SUBST([BASH_COMPLETION_DIR])
AM_CONDITIONAL([ENABLE_BASH_COMPLETION],[test "x$with_bash_completion_dir" != "xno"])
# TIO_CHECK_BAUDRATE(N)
AC_DEFUN(
[TIO_CHECK_BAUDRATE],
[
AC_CHECK_DECL([B$1], [tio_have_decl=1], [tio_have_decl=0], [[#include <termios.h>]])
AS_IF([test $tio_have_decl = 1], [
AC_SUBST([BAUDRATES], ["$BAUDRATES $1"])
AC_SUBST([BAUDRATE_CASES], ["$BAUDRATE_CASES case $1: baudrate = B$1; break;"])]
)
]
)
# TIO_CHECK_BAUDRATES(N1, N2, ...)
AC_DEFUN(
[TIO_CHECK_BAUDRATES],
[m4_foreach([n], [$@], [TIO_CHECK_BAUDRATE(m4_normalize(n))])]
)
# Check for available terminal I/O speeds
BAUDRATES=
BAUDRATE_CASES=
TIO_CHECK_BAUDRATES(
0,
50,
75,
110,
134,
150,
200,
300,
600,
1200,
1800,
2400,
4800,
7200,
9600,
14400,
19200,
28800,
38400,
57600,
76800,
115200,
230400,
460800,
500000,
576000,
921600,
1000000,
1152000,
1500000,
2000000,
2500000,
3000000,
3500000,
4000000
)
AC_DEFINE_UNQUOTED([AUTOCONF_BAUDRATE_CASES],[$BAUDRATE_CASES],[Switch cases for detected baud rates])
AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([src/Makefile])
AC_CONFIG_FILES([src/bash-completion/tio])
AC_CONFIG_FILES([man/Makefile])
AC_OUTPUT

78
examples/config/config Normal file
View file

@ -0,0 +1,78 @@
###############################
# tio - https://tio.github.io #
###############################
# Example tio configuration file
#
# Place file in any of the following locations:
# $XDG_CONFIG_HOME/tio/config
# $HOME/.config/tio/config
# $HOME/.tioconfig
[default]
baudrate = 115200
databits = 8
flow = none
stopbits = 1
parity = none
output-delay = 0
output-line-delay = 0
auto-connect = direct
no-reconnect = false
local-echo = false
input-mode = normal
output-mode = normal
timestamp = false
log = false
log-append = false
log-strip = false
color = bold
rs-485 = false
alert = none
script-run = always
prefix-ctrl-key = t
# Configuration profiles
[rpi3]
baudrate = 115200
device = /dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A6009HU3-if00-port0
socket = unix:/tmp/tio-socket-0
color = 9
[am64-evm]
baudrate = 115200
device = /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
alert = bell
color = 10
[tincan]
baudrate = 9600
device = /dev/serial/by-id/usb-TinCanTools_Flyswatter2_FS20000-if00-port0
log = true
log-file = tincan.log
log-strip = true
color = 11
[usb-devices]
pattern = ^usb([0-9]*)
device = /dev/ttyUSB%m1
color = 12
[rs-485-device]
device = /dev/ttyUSB0
rs-485 = true
rs-485-config = RTS_ON_SEND=1,RTS_AFTER_SEND=1,RTS_DELAY_BEFORE_SEND=60,RTS_DELAY_AFTER_SEND=80,RX_DURING_TX
color = 13
[esp32]
device = /dev/ttyUSB0
color = 14
script = tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{DTR=low,RTS=high}; tio.msleep(100); tio.set{RTS=low}
script-run = always
[buspirate]
device = /dev/ttyACM0
map = INLCRNL,ODELBS
color = 15

View file

@ -0,0 +1,28 @@
local logins = {
["foo"] = {
username = "foouser",
password = "foopass",
},
["bar"] = {
username = "baruser",
password = "barpass",
},
["baz"] = {
username = "bazuser",
password = "bazpass",
},
}
local hostname = tio.expect("^(%g+) login:", 10)
if hostname then
local login = logins[hostname]
if (nil ~= login) then
tio.write(login.username .. "\n")
tio.expect("Password:")
tio.write(login.password .. "\n")
else
io.write("\r\nDon't know login info for " .. hostname .. "\r\n")
end
else
io.write("\r\nDidn't find a login prompt\r\n")
end

View file

@ -0,0 +1,5 @@
tio.set{DTR=high, RTS=low}
tio.msleep(100)
tio.set{DTR=low, RTS=high}
tio.msleep(100)
tio.set{RTS=toggle}

14
examples/lua/read.lua Normal file
View file

@ -0,0 +1,14 @@
tio.read(1000, 6000) -- initial config
tio.write("\n")
tio.msleep(100)
tio.read(650, 60) -- main menu
tio.write("S") -- S menu
tio.msleep(30)
tio.read(650, 60)
tio.write("t") -- Parallel Value Table
tio.read(650, 60)
while true do
tio.msleep(1000)
tio.write("t")
tio.read(650, 50) -- repeat PVT forever
end

View file

@ -0,0 +1,15 @@
tio.read(1000, 8000) -- read initial config
tio.write("\n")
tio.read(650, 100) -- main menu
tio.write("S") -- S menu
repeat
str = tio.readline(25)
until str == nil
while true do
tio.write("t") -- query PV table
tio.msleep(880)
repeat
str = tio.readline(60)
tio.msleep(60)
until str == nil
end

View file

@ -0,0 +1,13 @@
io.write("Searching... ")
local device = tio.ttysearch()
io.write("done\r\n")
for i in ipairs(device) do
io.write("\r\n" .. device[i]["path"] .. "\r\n")
io.write(" tid = " .. device[i]["tid"] .. "\r\n")
io.write(" uptime = " .. device[i]["uptime"] .. "\r\n")
io.write(" driver = " .. device[i]["driver"] .. "\r\n")
io.write(" description = " .. device[i]["description"] .. "\r\n")
end

BIN
images/paypal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
images/tio-demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

BIN
images/tio-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1 +0,0 @@
dist_man_MANS = tio.1

15
man/meson.build Normal file
View file

@ -0,0 +1,15 @@
mandir = join_paths(get_option('prefix'), get_option('mandir'))
man1dir = join_paths(mandir, 'man1')
conf = configuration_data()
conf.set('version', meson.project_version())
conf.set('version_date', version_date)
manpage = configure_file(
input: files('tio.1.in'),
output: 'tio.1',
configuration: conf)
install_man(
manpage,
install_dir: man1dir)

133
man/tio.1
View file

@ -1,133 +0,0 @@
.TH "tio" "1" "October 2017"
.SH "NAME"
tio \- a simple TTY terminal I/O application
.SH "SYNOPSIS"
.PP
.B tio
.RI "[" <options> "] " "<tty-device>"
.SH "DESCRIPTION"
.PP
.B tio
is a simple TTY terminal application which features a straightforward
commandline interface to easily connect to TTY devices for basic input/output.
.SH "OPTIONS"
.TP
.BR \-b ", " "\-\-baudrate " \fI<bps>
Set baud rate [bps] (default: 115200).
.TP
.BR \-d ", " "\-\-databits 5" | 6 | 7 | 8
Set data bits (default: 8).
.TP
.BR \-f ", " "\-\-flow hard" | soft | none
Set flow control (default: none).
.TP
.BR \-s ", " "\-\-stopbits 1" | 2
Set stop bits (default: 1).
.TP
.BR \-p ", " "\-\-parity odd" | even | none
Set parity (default: none).
.TP
.BR \-o ", " "\-\-output\-delay " \fI<ms>
Set output delay [ms] inserted between each transmitted character (default: 0).
.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.
However, if the
.B \-\-no\-autoconnect
option is provided, tio will exit if the device is not present or an established connection is lost.
.TP
.BR \-l ", " "\-\-log " \fI<filename>
Log to file.
.TP
.BR \-m ", " "\-\-map " \fI<flags>
Map (replace, translate) special characters on input or output. The following mapping flags are supported:
.RS
.TP 8n
.IP "\fBINLCR"
Translate NL to CR on input.
.IP "\fBIGNCR"
Ignore carriage return on input.
.IP "\fBICRNL"
Translate carriage return to newline on input (unless IGNCR is set).
.IP "\fBONLCR"
Map NL to CR-NL on output.
.IP "\fBOCRNL"
Map CR to NL on output.
.P
If defining more than one flag, the flags must be comma separated.
.RE
.TP
.BR \-v ", " \-\-version
Display program version.
.TP
.BR \-h ", " \-\-help
Display help.
.SH "KEYS"
.PP
.TP 16n
In session, the following key sequences are intercepted as tio commands:
.IP "\fBctrl-t ?"
List available key commands
.IP "\fBctrl-t b"
Send serial break (triggers SysRq on Linux, etc.)
.IP "\fBctrl-t c"
Show configuration (baudrate, databits, etc.)
.IP "\fBctrl-t h"
Toggle hexadecimal mode
.IP "\fBctrl-t l"
Clear screen
.IP "\fBctrl-t q"
Quit
.IP "\fBctrl-t s"
Show statistics (total number of bytes transmitted/received)
.IP "\fBctrl-t t"
Send ctrl-t key code
.SH "EXAMPLES"
.TP
Typical use is without options. For example:
tio /dev/ttyUSB0
.TP
Which corresponds to the commonly used options:
tio \-b 115200 \-d 8 \-f none \-s 1 \-p none /dev/ttyUSB0
.TP
It is recommended to connect serial tty devices by id. For example:
tio /dev/serial/by\-id/usb\-FTDI_TTL232R-3V3_FTGQVXBL\-if00\-port0
.PP
Using serial devices by id ensures that tio automatically reconnects to the
correct serial device if the device is disconnected and then reconnected.
.SH "WEBSITE"
.PP
Visit https://tio.github.io
.SH "AUTHOR"
.PP
Written by Martin Lund <martin.lund@keep\-it\-simple.com>.

781
man/tio.1.in Normal file
View file

@ -0,0 +1,781 @@
.TH "tio" "1" "@version_date@" "tio @version@" "User Commands"
.SH "NAME"
tio \- a serial device I/O tool
.SH "SYNOPSIS"
.PP
.B tio
.RI "[" <options> "] " "<tty-device|profile|tid>"
.SH "DESCRIPTION"
.PP
\fBtio\fR is a 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"
.TP
.BR \-b ", " "\-\-baudrate " \fI<bps>
Set baud rate [bps] (default: 115200).
.TP
.BR \-d ", " "\-\-databits " 5 | 6 | 7 | 8
Set data bits (default: 8).
.TP
.BR \-f ", " "\-\-flow " hard | soft | none
Set flow control (default: none).
.TP
.BR \-s ", " "\-\-stopbits " 1 | 2
Set stop bits (default: 1).
.TP
.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 \-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
value pair format in the duration field: <key>=<value>
Each key represents a serial line. The following keys are available:
.RS
.TP 8n
.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.
The default pulse duration for each line is 100 ms.
.RE
.TP
.BR "\-a, \-\-auto\-connect new|latest|direct"
Automatically connect to serial device according to one of the following
strategies:
.RS
.TP 10n
.IP "\fBnew"
Automatically connect to first new appearing serial device.
.IP "\fBlatest"
Automatically connect to latest registered serial device.
.IP "\fBdirect"
Connect directly to specified TTY device.
.P
All the listed strategies automatically reconnects according to strategy if
device is not available or connection is lost.
.P
Default value is "direct".
.RE
.TP
.BR " \-\-exclude\-devices \fI<pattern>"
Exclude devices by pattern ('*' and '?' supported).
.TP
.BR " \-\-exclude\-drivers \fI<pattern>"
Exclude drivers by pattern ('*' and '?' supported).
.TP
.BR " \-\-exclude\-tids \fI<pattern>"
Exclude topology IDs by pattern ('*' and '?' supported).
.TP
.BR \-n ", " \-\-no\-reconnect
Do not reconnect.
This means that tio will exit if it fails to connect to device or an
established connection is lost.
.TP
.BR \-e ", " "\-\-local\-echo
Enable local echo.
.TP
.BR \-t ", " \-\-timestamp
Enable line timestamp.
.TP
.BR " \-\-timestamp\-format \fI<format>"
Set timestamp format to any of the following timestamp formats:
.RS
.TP 16n
.IP "\fB24hour"
24-hour format ("hh:mm:ss.sss")
.IP "\fB24hour-start"
24-hour format relative to start time
.IP "\fB24hour-delta"
24-hour format relative to previous timestamp
.IP "\fBiso8601"
ISO8601 format ("YYYY-MM-DDThh:mm:ss.sss")
.IP "\fBepoch"
Seconds since Unix epoch (1970-01-01)
.IP "\fBepoch-usec"
Seconds since Unix epoch (1970-01-01) with subdivision in microseconds
.PP
Default format is \fB24hour\fR
.RE
.TP
.BR " \-\-timestamp\-timeout \fI<ms>"
Set timestamp timeout value in milliseconds.
This value only takes effect in hex output mode where timestamps are only
printed after elapsed timeout time of no output activity from tty device.
Default value is 200.
.TP
.BR \-l ", " \-\-list
List available targets (serial devices, TIDs, configuration profiles).
.TP
.BR \-L ", " \-\-log
Enable log to file.
The log file will be automatically named using the following format
tio_TARGET_YYYY-MM-DDTHH:MM:SS.log. Target being the command line target such
as tty-device, tid, or configuration profile.
The filename can be manually set using the \-\-log-file option.
.TP
.BR " \-\-log\-file \fI<filename>
Set log filename.
.TP
.BR " \-\-log\-directory \fI<path>
Set log directory path in which to save automatically named log files.
.TP
.BR " \-\-log\-append
Append to log file.
.TP
.BR " \-\-log-strip
Strip control characters and escape sequences from log.
.TP
.BR \-m ", " "\-\-map " \fI<flags>
Map (replace, translate) characters on input to the serial device or output
from the serial device. The following mapping flags are supported:
.RS
.TP 12n
.IP "\fBICRNL"
Map CR to NL on input (unless IGNCR is set)
.IP "\fBIGNCR"
Ignore CR on input
.IP "\fBIFFESCC"
Map FF to ESC-c on input
.IP "\fBINLCR"
Map NL to CR on input
.IP "\fBINLCRNL"
Map NL to CR-NL on input
.IP "\fBICRCRNL"
Map CR to CR-NL on input
.IP "\fBIMSB2LSB"
Map MSB bit order to LSB on input
.IP "\fBOCRNL"
Map CR to NL on output
.IP "\fBODELBS"
Map DEL to BS on output
.IP "\fBONLCRNL"
Map NL to CR-NL on output
.IP "\fBOLTU"
Map lowercase characters to uppercase on output
.IP "\fBONULBRK"
Map nul (zero) to send break signal on output
.IP "\fBOIGNCR"
Ignore CR on output
.P
If defining more than one flag, the flags must be comma separated.
.RE
.TP
.BR " \-\-input\-mode " normal|hex|line
Set input mode.
In normal mode input characters are sent immediately as they are typed.
In hex input mode bytes can be sent by typing the \fBtwo-character
hexadecimal\fR representation of the 1 byte value, e.g.: to send \fI0xA\fR you
must type \fI0a\fR or \fI0A\fR.
In line input mode input characters are sent when you press enter. The only
editing feature supported in this mode is backspace.
Default value is "normal".
.TP
.BR " \-\-output\-mode " normal|hex|hexN
Set output mode.
In hex mode each incoming byte is printed out as a 1 byte hex value.
In hexN mode, N is a number less than or equal to 4096 which defines how many
hex values will be printed before a line break.
Default value is "normal".
.TP
.BR \-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".
.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 \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.
Various socket types are supported using the following prefixes in the socket field:
.RS
.TP 20n
.IP "\fBunix:<filename>"
Unix Domain Socket (file)
.IP "\fBinet:<port>"
Internet Socket (network)
.IP "\fBinet6:<port>"
Internet IPv6 Socket (network)
.P
If port is 0 or no port is provided default port 3333 is used.
.P
At present there is a hardcoded limit of 16 clients connected at one time.
.RE
.TP
.BR " \-\-rs\-485"
Enable RS-485 mode.
.TP
.BR " \-\-rs\-485\-config " \fI<config>
Set the RS-485 configuration using the following key or key value pair format in
the configuration field:
.RS
.TP 30n
.IP \fBRTS_ON_SEND=value
Set logical level (0 or 1) for RTS pin when sending
.IP \fBRTS_AFTER_SEND=value
Set logical level (0 or 1) for RTS pin after sending
.IP \fBRTS_DELAY_BEFORE_SEND=value
Set RTS delay (ms) before sending
.IP \fBRTS_DELAY_AFTER_SEND=value
Set RTS delay (ms) after sending
.IP \fBRX_DURING_TX
Receive data even while sending data
.P
If defining more than one key or key value pair, they must be comma separated.
.RE
.TP
.BR "\-\-alert none|bell|blink"
Set alert action on connect/disconnect.
It will sound the bell once or blink once on successful connect. Likewise it
will sound the bell twice or blink twice on disconnect.
Default value is "none".
.TP
.BR "\-\-mute"
Mute tio messages.
.TP
.BR "\-\-script \fI<string>
Run script from string.
.TP
.BR "\-\-script\-file \fI<filename>
Run script from file with filename.
.TP
.BR "\-\-script\-run once|always|never"
Run script on connect once, always, or never.
Default value is "always".
.TP
.BR "\-\-exec \fI<command>
Execute shell command with I/O redirected to device
.TP
.BR "\-\-complete-profiles
Prints profiles (for shell completion)
.TP
.BR \-v ", " \-\-version
Display program version.
.TP
.BR \-h ", " \-\-help
Display help.
.SH "KEY COMMANDS"
.PP
.TP 16n
In session, all key strokes are forwarded to the serial device except the following key sequence: a prefix key (default: ctrl-t) followed by a command key. These sequences are intercepted as key commands:
.IP "\fBctrl-t ?"
List available key commands
.IP "\fBctrl-t b"
Send serial break (triggers SysRq on Linux, etc.)
.IP "\fBctrl-t c"
Show configuration (baudrate, databits, etc.)
.IP "\fBctrl-t e"
Toggle local echo mode
.IP "\fBctrl-t f"
Toggle log to file
.IP "\fBctrl-t F"
Flush data I/O buffers (discard data written but not transmitted and data received but not read)
.IP "\fBctrl-t g"
Toggle serial port line
.IP "\fBctrl-t i"
Toggle input mode
.IP "\fBctrl-t l"
Clear screen
.IP "\fBctrl-t L"
Show line states (DTR, RTS, CTS, DSR, DCD, RI)
.IP "\fBctrl-t m"
Change mapping of characters on input or output
.IP "\fBctrl-t o"
Toggle output mode
.IP "\fBctrl-t p"
Pulse serial port line
.IP "\fBctrl-t q"
Quit
.IP "\fBctrl-t r"
Run script
.IP "\fBctrl-t R"
Execute shell command with I/O redirected to device
.IP "\fBctrl-t s"
Show TX/RX statistics
.IP "\fBctrl-t t"
Toggle line timestamp mode
.IP "\fBctrl-t v"
Show version
.IP "\fBctrl-t x"
Send file using the XMODEM-1K or XMODEM-CRC protocol (prompts for file name and protocol)
.IP "\fBctrl-t y"
Send file using the YMODEM protocol (prompts for file name)
.IP "\fBctrl-t ctrl-t"
Send ctrl-t character
.SH "SCRIPT API"
.PP
Tio suppots Lua scripting to easily automate interaction with the tty device.
In addition to the standard Lua API tio makes the following functions
and variables available:
.TP 6n
.IP "\fBtio.expect(pattern, timeout)"
Waits for the Lua pattern to match or timeout before continuing.
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
Returns the captures from the pattern or nil on timeout.
.IP "\fBtio.read(size, timeout)"
Read up to size bytes from serial device. If timeout is 0 or not provided it
will wait forever until data is ready to read.
Returns a string up to size bytes long on success and nil on timeout.
.IP "\fBtio.readline(timeout)"
Read line from serial device. If timeout is 0 or not provided it will wait
forever until data is ready to read.
Returns a string on success and nil on timeout. On timeout a partially read
line may be returned as a second return value.
.IP "\fBtio.write(string)"
Write string to serial device.
Returns the tio table.
.IP "\fBtio.send(file, protocol)"
Send file using x/y-modem protocol.
Protocol can be any of XMODEM_1K, XMODEM_CRC, YMODEM.
.IP "\fBtio.ttysearch()"
Search for serial devices.
Returns a table of number indexed tables, one for each serial device found.
Each of these tables contains the serial device information accessible via the
following string indexed elements "path", "tid", "uptime", "driver",
"description".
Returns nil if no serial devices are found.
.IP "\fBtio.set{line=state, ...}"
Set state of one or multiple tty modem lines.
Line can be any of DTR, RTS, CTS, DSR, CD, RI
State is high, low, or toggle.
.IP "\fBtio.sleep(seconds)"
Sleep for seconds.
.IP "\fBtio.msleep(ms)"
Sleep for milliseconds.
.IP "\fBtio.alwaysecho"
A boolean value, defaults to true.
If tio.alwaysecho is false, the result of tio.read, tio.readline or tio.expect
will only be returned from the function and not logged or printed.
If tio.alwaysecho is set to true, reading functions also emit a single
timestamp to stdout and log file per options.timestamp and options.log.
.SH "CONFIGURATION FILE"
.PP
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/config
.PP
.I $HOME/.config/tio/config
.PP
.I $HOME/.tioconfig
.PP
Labels can be used to group settings into named configuration profiles which
can be activated from the command-line when starting tio.
.PP
\fBtio\fR will try to match the user input to a configuration profile by name or by
pattern to get the TTY device and other options.
.PP
Options without any label change the default options.
.PP
Any options set via command-line will override options set in the configuration file.
.PP
The following configuration file options are available:
.TP 25n
.IP "\fBpattern"
Pattern matching user input. This pattern can be an extended regular expression with a single group.
.IP "\fBdevice"
TTY device to open. If it contains a "%s" it is substituted with the first group match.
.IP "\fBbaudrate"
Set baud rate
.IP "\fBdatabits"
Set data bits
.IP "\fBflow"
Set flow control
.IP "\fBstopbits"
Set stop bits
.IP "\fBparity"
Set parity
.IP "\fBoutput-delay"
Set output character delay
.IP "\fBoutput-line-delay"
Set output line delay
.IP "\fBline-pulse-duration"
Set line pulse duration
.IP "\fBno-reconnect"
Do not reconnect
.IP "\fBlog"
Enable log to file
.IP "\fBlog-file"
Set log filename
.IP "\fBlog-directory"
Set log directory path in which to save automatically named log files.
.IP "\fBlog-append"
Append to log file
.IP "\fBlog-strip"
Enable strip of control and escape sequences from log
.IP "\fBlocal-echo"
Enable local echo
.IP "\fBtimestamp"
Enable line timestamp
.IP "\fBtimestamp-format"
Set timestamp format
.IP "\fBtimestamp-timeout"
Set timestamp timeout
.IP "\fBmap"
Map characters on input or output
.IP "\fBcolor"
Colorize tio text using ANSI color code ranging from 0 to 255
.IP "\fBinput-mode"
Set input mode
.IP "\fBoutput-mode"
Set output mode
.IP "\fBsocket"
Set socket to redirect I/O to
.IP "\fBprefix-ctrl-key"
Set prefix ctrl key (a..z or 'none', default: t)
.IP "\fBrs-485"
Enable RS-485 mode
.IP "\fBrs-485-config"
Set RS-485 configuration
.IP "\fBalert"
Set alert action on connect/disconnect
.IP "\fBmute"
Mute tio messages
.IP "\fBscript"
Run script from string
.IP "\fBscript-file"
Run script from file
.IP "\fBscript-run"
Run script on connect
.IP "\fBexec"
Execute shell command with I/O redirected to device
.PP
It is possible to include the content of other configuration files using the
include directive like so: "[include <file>]".
.SH "CONFIGURATION FILE EXAMPLES"
.TP
To change the default configuration simply set options like so:
.RS
.nf
.eo
[default]
baudrate = 9600
databits = 8
parity = none
stopbits = 1
color = 10
line-pulse-duration = DTR=200,RTS=400
.ec
.fi
.RE
.TP
Named configuration profiles can be added via labels:
.RS
.nf
.eo
[rpi3]
device = /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
baudrate = 115200
color = 11
.ec
.fi
.RE
.TP
Activate the configuration profile by name:
$ tio rpi3
.TP
Which is equivalent to:
$ tio -b 115200 -c 11 /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
.TP
A configuration profile can also be activated by its pattern which supports regular expressions:
.RS
.nf
.eo
[usb-devices]
pattern = ^usb([0-9]*)
device = /dev/ttyUSB%m1
baudrate = 115200
.ec
.fi
.RE
.TP
Activate the configuration profile by pattern match:
$ tio usb12
.TP
Which becomes equivalent to:
$ tio -b 115200 /dev/ttyUSB12
.TP
It is also possible to combine use of configuration profile and command-line options. For example:
$ tio -l -t usb12
.SH "EXAMPLES"
.TP
Typical use is without options:
$ tio /dev/ttyUSB0
.TP
Which corresponds to the commonly used default options:
$ tio \-b 115200 \-d 8 \-f none \-s 1 \-p none /dev/ttyUSB0
.TP
It is recommended to connect serial TTY devices by ID:
$ tio /dev/serial/by\-id/usb\-FTDI_TTL232R-3V3_FTGQVXBL\-if00\-port0
.PP
Using serial devices by ID ensures that tio automatically reconnects to the
correct serial device if it is disconnected and then reconnected.
.TP
Redirect serial device I/O to Unix file socket for scripting:
$ tio -S unix:/tmp/tio-socket0 /dev/ttyUSB0
.TP
Then, to issue a command via the file socket simply do:
$ echo "ls -la" | nc -UN /tmp/tio-socket0 > /dev/null
.TP
Or use the expect command to script an interaction:
.RS
.nf
.eo
#!/usr/bin/expect -f
.sp
set timeout -1
log_user 0
.sp
spawn nc -UN /tmp/tio-socket0
set uart $spawn_id
.sp
send -i $uart "date\n"
expect -i $uart "prompt> "
send -i $uart "ls -la\n"
expect -i $uart "prompt> "
.ec
.fi
.RE
.TP
It is also possible to use tio's own simpler expect/send script functionality to e.g. automate logins:
$ tio --script 'tio.expect("login: "); tio.write("root\\n"); tio.expect("Password: "); tio.write("root\\n")' /dev/ttyUSB0
.TP
Redirect device I/O to network file socket for remote TTY sharing:
$ tio --socket inet:4444 /dev/ttyUSB0
.TP
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
.TP
Pipe command to the serial device:
$ echo "ls -la" | tio /dev/serial/by\-id/usb\-FTDI_TTL232R-3V3_FTGQVXBL\-if00\-port0
.TP
Pipe command to serial device and wait for line response within 1 second:
$ echo "*IDN?" | tio /dev/ttyACM0 --script "tio.expect('\\r\\n', 1000)" --mute
.TP
.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
.TP
Map NL to CR-NL on input from device and DEL to BS on output to device:
$ tio --map INLCRNL,ODELBS /dev/ttyUSB0
.TP
Enable RS-485 mode:
$ tio --rs-485 --rs-485-config=RTS_ON_SEND=1,RX_DURING_TX /dev/ttyUSB0
.TP
Manipulate DTR and RTS lines upon first connect to reset connected microcontroller:
$ tio --script "tio.set{DTR=high,RTS=low}; tio.msleep(100); tio.set{RTS=toggle}" --script-run once /dev/ttyUSB0
.SH "WEBSITE"
.PP
Visit https://tio.github.io
.SH "AUTHOR"
.PP
Maintained by Martin Lund <martin.lund@keep\-it\-simple.com>.

625
man/tio.1.txt Normal file
View file

@ -0,0 +1,625 @@
tio(1) User Commands tio(1)
NAME
tio - a serial device I/O tool
SYNOPSIS
tio [<options>] <tty-device|profile|tid>
DESCRIPTION
tio is a 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.
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 value 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.
-a, --auto-connect new|latest|direct
Automatically connect to serial device according to one of the following strategies:
new Automatically connect to first new appearing serial device.
latest Automatically connect to latest registered serial device.
direct Connect directly to specified TTY device.
All the listed strategies automatically reconnects according to strategy if device is not available or connection is lost.
Default value is "direct".
--exclude-devices <pattern>
Exclude devices by pattern ('*' and '?' supported).
--exclude-drivers <pattern>
Exclude drivers by pattern ('*' and '?' supported).
--exclude-tids <pattern>
Exclude topology IDs by pattern ('*' and '?' supported).
-n, --no-reconnect
Do not reconnect.
This means that tio will exit if it fails to connect to device or an established connection 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")
epoch Seconds since Unix epoch (1970-01-01)
epoch-usec Seconds since Unix epoch (1970-01-01) with subdivision microseconds
Default format is 24hour
--timestamp-timeout <ms>
Set timestamp timeout value in milliseconds.
This value only takes effect in hex output mode where timestamps are only printed after elapsed timeout time of no output activity from tty device.
Default value is 200.
-l, --list
List available targets (serial devices, TIDs, configuration profiles).
-L, --log
Enable log to file.
The log file will be automatically named using the following format tio_TARGET_YYYY-MM-DDTHH:MM:SS.log. Target being the command line target such as tty-device, tid, or configuration profile.
The filename can be manually set using the --log-file option.
--log-file <filename>
Set log filename.
--log-directory <path>
Set log directory path in which to save automatically named log files.
--log-append
Append to log file.
--log-strip
Strip control characters and escape sequences from log.
-m, --map <flags>
Map (replace, translate) characters on input to the serial device or output from the serial device. The following mapping flags are supported:
ICRNL Map CR to NL on input (unless IGNCR is set)
IGNCR Ignore CR on input
IFFESCC Map FF to ESC-c on input
INLCR Map NL to CR on input
INLCRNL Map NL to CR-NL on input
ICRCRNL Map CR to CR-NL on input
IMSB2LSB Map MSB bit order to LSB 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
ONULBRK Map nul (zero) to send break signal on output
OIGNCR Ignore CR on output
If defining more than one flag, the flags must be comma separated.
--input-mode normal|hex|line
Set input mode.
In normal mode input characters are sent immediately as they are typed.
In hex input mode bytes can be sent by typing the two-character hexadecimal representation of the 1 byte value, e.g.: to send 0xA you must type 0a or 0A.
In line input mode input characters are sent when you press enter. The only editing feature supported in this mode is backspace.
Default value is "normal".
--output-mode normal|hex|hexN
Set output mode.
In hex mode each incoming byte is printed out as a 1 byte hex value.
In hexN mode, N is a number less than or equal to 4096 which defines how many hex values will be printed before a line break.
Default value is "normal".
-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 terminal 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.
--rs-485
Enable RS-485 mode.
--rs-485-config <config>
Set the RS-485 configuration using the following key or key value pair format in the configuration field:
RTS_ON_SEND=value Set logical level (0 or 1) for RTS pin when sending
RTS_AFTER_SEND=value Set logical level (0 or 1) for RTS pin after sending
RTS_DELAY_BEFORE_SEND=value Set RTS delay (ms) before sending
RTS_DELAY_AFTER_SEND=value Set RTS delay (ms) after sending
RX_DURING_TX Receive data even while sending data
If defining more than one key or key value pair, they must be comma separated.
--alert none|bell|blink
Set alert action on connect/disconnect.
It will sound the bell once or blink once on successful connect. Likewise it will sound the bell twice or blink twice on disconnect.
Default value is "none".
--mute
Mute tio messages.
--script <string>
Run script from string.
--script-file <filename>
Run script from file with filename.
--script-run once|always|never
Run script on connect once, always, or never.
Default value is "always".
--exec <command>
Execute shell command with I/O redirected to device
--complete-profiles
Prints profiles (for shell completion)
-v, --version
Display program version.
-h, --help
Display help.
KEY COMMANDS
In session, all key strokes are forwarded to the serial device except the following key sequence: a prefix key (default: ctrl-t) followed by a command key. These sequences are intercepted as key commands:
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 f Toggle log to file
ctrl-t F Flush data I/O buffers (discard data written but not transmitted and data received but not read)
ctrl-t g Toggle serial port line
ctrl-t i Toggle input mode
ctrl-t l Clear screen
ctrl-t L Show line states (DTR, RTS, CTS, DSR, DCD, RI)
ctrl-t m Change mapping of characters on input or output
ctrl-t o Toggle output mode
ctrl-t p Pulse serial port line
ctrl-t q Quit
ctrl-t r Run script
ctrl-t R Execute shell command with I/O redirected to device
ctrl-t s Show TX/RX statistics
ctrl-t t Toggle line timestamp mode
ctrl-t v Show version
ctrl-t x Send file using the XMODEM-1K or XMODEM-CRC protocol (prompts for file name and protocol)
ctrl-t y Send file using the YMODEM protocol (prompts for file name)
ctrl-t ctrl-t Send ctrl-t character
SCRIPT API
Tio suppots Lua scripting to easily automate interaction with the tty device.
In addition to the standard Lua API tio makes the following functions available:
expect(string, timeout)
Expect string - waits for string to match or timeout before continuing. Supports regular expressions. Special characters must be escaped with '\\'. Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
Returns 1 on successful match, 0 on timeout, or -1 on error.
On successful match it also returns the match string as second return value.
read(size, timeout)
Read up to size bytes from serial device. If timeout is 0 or not provided it will wait forever until data is ready to read.
Returns number of bytes read on success, 0 on timeout, or -1 on error.
On success, returns read string as second return value. Also emits a single timestamp to stdout and log file per options.timestamp and options.log.
read_line(timeout)
Read line from serial device. If timeout is 0 or not provided it will wait forever until data is ready to read.
Returns number of bytes read on success, 0 on timeout, or -1 on error.
On success, returns the string that was read as second return value. Also emits a single timestamp to stdout and log file per options.timestamp and options.log.
write(string)
Write string to serial device.
Returns number of bytes written on success or -1 on error.
send(file, protocol)
Send file using x/y-modem protocol.
Protocol can be any of XMODEM_1K, XMODEM_CRC, YMODEM.
tty_search()
Search for serial devices.
Returns a table of number indexed tables, one for each serial device found. Each of these tables contains the serial device information accessible via the following string indexed elements "path", "tid", "uptime", "dri
ver", "description".
Returns nil if no serial devices are found.
set{line=state, ...}
Set state of one or multiple tty modem lines.
Line can be any of DTR, RTS, CTS, DSR, CD, RI
State is high, low, or toggle.
sleep(seconds)
Sleep for seconds.
msleep(ms)
Sleep for milliseconds.
exit(code)
Exit with exit code.
CONFIGURATION FILE
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:
$XDG_CONFIG_HOME/tio/config
$HOME/.config/tio/config
$HOME/.tioconfig
Labels can be used to group settings into named configuration profiles which can be activated from the command-line when starting tio.
tio will try to match the user input to a configuration profile by name or by pattern to get the TTY device 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.
device 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-reconnect Do not reconnect
log Enable log to file
log-file Set log filename
log-directory Set log directory path in which to save automatically named log files.
log-append Append to log file
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
timestamp-timeout Set timestamp timeout
map Map characters on input or output
color Colorize tio text using ANSI color code ranging from 0 to 255
input-mode Set input mode
output-mode Set output mode
socket Set socket to redirect I/O to
prefix-ctrl-key Set prefix ctrl key (a..z or 'none', default: t)
rs-485 Enable RS-485 mode
rs-485-config Set RS-485 configuration
alert Set alert action on connect/disconnect
mute Mute tio messages
script Run script from string
script-file Run script from file
script-run Run script on connect
exec Execute shell command with I/O redirected to device
It is possible to include the content of other configuration files using the include directive like so: "[include <file>]".
CONFIGURATION FILE EXAMPLES
To change the default configuration simply set options like so:
[default]
baudrate = 9600
databits = 8
parity = none
stopbits = 1
color = 10
line-pulse-duration = DTR=200,RTS=400
Named configuration profiles can be added via labels:
[rpi3]
device = /dev/serial/by-id/usb-FTDI_TTL232R-3V3_FTGQVXBL-if00-port0
baudrate = 115200
color = 11
Activate the configuration profile 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 configuration profile can also be activated by its pattern which supports regular expressions:
[usb-devices]
pattern = ^usb([0-9]*)
device = /dev/ttyUSB%m1
baudrate = 115200
Activate the configuration profile by pattern match:
$ tio usb12
Which becomes equivalent to:
$ tio -b 115200 /dev/ttyUSB12
It is also possible to combine use of configuration profile 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/tio-socket0 /dev/ttyUSB0
Then, to issue a command via the file socket simply do:
$ echo "ls -la" | nc -UN /tmp/tio-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> "
It is also possible to use tio's own simpler expect/send script functionality to e.g. automate logins:
$ tio --script 'expect("login: "); write("root\n"); expect("Password: "); write("root\n")' /dev/ttyUSB0
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
Pipe command to serial device and wait for line response within 1 second:
$ echo "*IDN?" | tio /dev/ttyACM0 --script "expect('\r\n', 1000)" --mute
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
Map NL to CR-NL on input from device and DEL to BS on output to device:
$ tio --map INLCRNL,ODELBS /dev/ttyUSB0
Enable RS-485 mode:
$ tio --rs-485 --rs-485-config=RTS_ON_SEND=1,RX_DURING_TX /dev/ttyUSB0
Manipulate DTR and RTS lines upon first connect to reset connected microcontroller:
$ tio --script "set{DTR=high,RTS=low}; msleep(100); set{RTS=toggle}" --script-run once /dev/ttyUSB0
WEBSITE
Visit https://tio.github.io
AUTHOR
Maintained by Martin Lund <martin.lund@keep-it-simple.com>.
tio 3.9 2025-04-13 tio(1)

87
meson.build Normal file
View file

@ -0,0 +1,87 @@
project('tio', 'c',
version : '3.9',
license : 'GPL-2.0-or-later',
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 = '2025-04-13'
# Test for dynamic baudrate configuration interface
compiler = meson.get_compiler('c')
enable_setspeed2 = false
enable_iossiospeed = false
if host_machine.system() != 'darwin'
if compiler.check_header('asm-generic/ioctls.h')
enable_setspeed2 = compiler.has_header_symbol('asm-generic/ioctls.h', 'TCGETS2')
endif
else
if compiler.check_header('IOKit/serial/ioss.h')
enable_iossiospeed = compiler.has_header_symbol('IOKit/serial/ioss.h', 'IOSSIOSPEED')
endif
endif
# Test for supported baudrates
test_baudrates = [
0,
50,
75,
110,
134,
150,
200,
300,
600,
1200,
1800,
2400,
4800,
7200,
9600,
14400,
19200,
28800,
38400,
57600,
76800,
115200,
230400,
460800,
500000,
576000,
921600,
1000000,
1152000,
1500000,
2000000,
2500000,
3000000,
3500000,
4000000 ]
baudrates = ''
baudrate_cases = ''
foreach rate : test_baudrates
baudrate = rate.to_string()
value = compiler.get_define('B' + baudrate, prefix: '#include <termios.h>')
if value != ''
baudrates = baudrates + baudrate + ' '
baudrate_cases = baudrate_cases + ' case ' + baudrate + ': baudrate = B' + baudrate + '; break;'
endif
endforeach
# Test for RS-485 support on Linux
enable_rs485 = false
if host_machine.system() == 'linux'
if compiler.check_header('linux/serial.h')
enable_rs485 = compiler.has_header_symbol('sys/ioctl.h', 'TIOCSRS485')
endif
endif
subdir('src')
install_man_pages = get_option('install_man_pages')
if install_man_pages
subdir('man')
endif

6
meson_options.txt Normal file
View file

@ -0,0 +1,6 @@
option('bashcompletiondir',
type : 'string',
description : 'Directory for bash completion scripts ["no" disables]')
option('install_man_pages',
type : 'boolean', value: true,
description : 'Install man pages')

View file

@ -1,19 +0,0 @@
AM_CFLAGS = -Wall
bin_PROGRAMS = tio
tio_SOURCES = tty.c \
options.c \
time.c \
main.c \
log.c \
error.c \
include/tio/tty.h \
include/tio/options.h \
include/tio/time.h \
include/tio/print.h \
include/tio/log.h \
include/tio/error.h
if ENABLE_BASH_COMPLETION
bashcompletiondir=@BASH_COMPLETION_DIR@
bashcompletion_DATA=bash-completion/tio
endif

83
src/alert.c Normal file
View file

@ -0,0 +1,83 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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 <stdio.h>
#include <unistd.h>
#include "options.h"
#include "alert.h"
void blink_background(void)
{
// Turn on reverse video
printf("\e[?5h");
fflush(stdout);
usleep(200*1000);
// Turn on normal video
printf("\e[?5l");
fflush(stdout);
}
void sound_bell(void)
{
// Audio bell
printf("\a");
fflush(stdout);
}
void alert_connect(void)
{
switch (option.alert)
{
case ALERT_NONE:
break;
case ALERT_BELL:
sound_bell();
break;
case ALERT_BLINK:
blink_background();
break;
default:
break;
}
}
void alert_disconnect(void)
{
switch (option.alert)
{
case ALERT_NONE:
break;
case ALERT_BELL:
sound_bell();
usleep(200*1000);
sound_bell();
break;
case ALERT_BLINK:
blink_background();
usleep(200*1000);
blink_background();
break;
default:
break;
}
}

33
src/alert.h Normal file
View file

@ -0,0 +1,33 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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
typedef enum
{
ALERT_NONE,
ALERT_BELL,
ALERT_BLINK,
ALERT_END,
} alert_t;
void alert_connect(void);
void alert_disconnect(void);

View file

@ -0,0 +1,18 @@
conf = configuration_data()
conf.set('baudrates', baudrates)
completion_file = configure_file( input: files('tio.in'),
output: 'tio',
configuration: conf )
bashcompletiondir = get_option('bashcompletiondir')
if bashcompletiondir == ''
bash_completion_dep = dependency('bash-completion', required: false)
if bash_completion_dep.found()
bashcompletiondir = join_paths(get_option('datadir'), 'bash-completion', 'completions')
endif
endif
if (bashcompletiondir != 'no') and (bashcompletiondir != '')
install_data(completion_file, install_dir: bashcompletiondir)
endif

View file

@ -4,7 +4,7 @@
_tio()
{
local cur prev opts base
local cur prev opts base ttys
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
@ -16,16 +16,44 @@ _tio()
-s --stopbits \
-p --parity \
-o --output-delay \
-n --no-autoconnect \
-o --output-line-delay \
--line-pulse-duration \
-a --auto-connect \
--exclude-devices \
--exclude-drivers \
--exclude-tids \
-n --no-reconnect \
-e --local-echo \
-l --log \
--log-file \
--log-directory \
--log-append \
--log-strip \
-m --map \
-t --timestamp \
--timestamp-format \
--timestamp-timeout \
-L --list \
-c --color \
-S --socket \
--input-mode \
--output-mode \
--rs-485 \
--rs-485-config \
--alert \
--mute \
--script \
--script-file \
--script-run \
--exec \
--complete-profiles \
-v --version \
-h --help"
# Complete the arguments to the options.
case "${prev}" in
-b | --baudrate)
local baudrates="@BAUDRATES@"
local baudrates="@baudrates@"
COMPREPLY=( $(compgen -W "$baudrates" -- ${cur}) )
return 0
;;
@ -46,35 +74,72 @@ _tio()
return 0
;;
-o | --output-delay)
COMPREPLY=( $(compgen -W "0 1 10 100" -- ${cur}) )
COMPREPLY=( $(compgen -W "1 10 100" -- ${cur}) )
return 0
;;
-n | --no-autoconnect)
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
-O | --output-line-delay)
COMPREPLY=( $(compgen -W "1 10 100" -- ${cur}) )
return 0
;;
-l | --log)
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
-a | --auto-connect)
COMPREPLY=( $(compgen -W "new latest none" -- ${cur}) )
return 0
;;
-m | --map)
COMPREPLY=( $(compgen -W "INLCR IGNCR ICRNL ONLCR OCRNL" -- ${cur}) )
COMPREPLY=( $(compgen -W "ICRNL IGNCR INLCR IFFESCC INLCRNL ICRCRNL IMSB2LSB OCRNL ODELBS ONLCRNL OLTU ONULBRK OIGNCR" -- ${cur}) )
return 0
;;
-v | --version)
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
--timestamp-format)
COMPREPLY=( $(compgen -W "24hour 24hour-start 24hour-delta iso8601 epoch epoch-usec" -- ${cur}) )
return 0
;;
-h | --help)
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
-c | --color)
COMPREPLY=( $(compgen -W "$(seq 0 255) none list" -- ${cur}) )
return 0
;;
-S | --socket)
COMPREPLY=( $(compgen -W "unix: inet: inet6:" -- ${cur}) )
return 0
;;
--input-mode)
COMPREPLY=( $(compgen -W "normal hex line" -- ${cur}) )
return 0
;;
--output-mode)
COMPREPLY=( $(compgen -W "normal hex" -- ${cur}) )
return 0
;;
--rs-485-config)
COMPREPLY=( $(compgen -W "RTS_ON_SEND RTS_AFTER_SEND RTS_DELAY_BEFORE_SEND RTS_DELAY_AFTER_SEND RX_DURING_TX" -- ${cur}) )
return 0
;;
--alert)
COMPREPLY=( $(compgen -W "none bell blink" -- ${cur}) )
return 0
;;
--script-run)
COMPREPLY=( $(compgen -W "once always never" -- ${cur}) )
return 0
;;
*)
;;
esac
case "${cur}" in
-*)
COMPREPLY=($(compgen -W "${opts}" -- ${cur}))
return 0
;;
esac
profiles="`tio --complete-profiles`"
if [ -d /dev/serial/by-id ]; then
ttys=$(printf '%s\n' /dev/tty* /dev/serial/by-id/*)
else
ttys=$(printf '%s\n' /dev/tty*)
fi
COMPREPLY=( $(compgen -W "${ttys} ${profiles}" -- ${cur}) )
return 0
}
# Bind completion to tio command

788
src/configfile.c Normal file
View file

@ -0,0 +1,788 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2020-2022 Liam Beguin
* 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.
*/
#define _GNU_SOURCE
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <libgen.h>
#include <errno.h>
#include <regex.h>
#include <glib.h>
#include "configfile.h"
#include "timestamp.h"
#include "print.h"
#include "rs485.h"
#include "misc.h"
#define CONFIG_GROUP_NAME_DEFAULT "default"
#define CONFIG_GROUP_INCLUDE_PREFIX "include "
#define MAX_LINE_LENGTH 1024
struct config_t config = {};
static void config_file_load(const char *filename, GString *buffer, bool test);
static void config_file_process(const char *filename, GString *buffer, GList **included_files, bool test);
static void config_get_string(GKeyFile *key_file, gchar *group, gchar *key, char **dest, char *allowed_string, ...)
{
(void)dest;
GError *error = NULL;
bool mismatch = true;
gchar *string = g_key_file_get_string(key_file, group, key, &error);
if (error != NULL)
{
if (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)
{
// Key not found - ignore key
g_error_free(error);
return;
}
tio_error_print("%s: %s", config.path, error->message);
g_error_free(error);
exit(EXIT_FAILURE);
}
va_list args;
const char* current_arg = allowed_string;
va_start(args, allowed_string);
if (current_arg == NULL)
{
mismatch = false;
}
// Iterate through variable arguments
while (current_arg != NULL)
{
if (strcmp(string, current_arg) == 0)
{
mismatch = false;
break;
}
current_arg = va_arg(args, const char *);
}
if (mismatch)
{
tio_error_print("%s: Invalid %s value '%s' in %s profile", config.path, key, string, group);
exit(EXIT_FAILURE);
}
va_end(args);
*dest = string;
}
static void config_get_integer(GKeyFile *key_file, gchar *group, gchar *key, int *dest, int min, int max)
{
(void)dest;
GError *error = NULL;
int value = g_key_file_get_integer(key_file, group, key, &error);
if (error != NULL)
{
if (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)
{
// Key not found - ignore key
g_error_free(error);
return;
}
tio_error_print("%s: %s", config.path, error->message);
g_error_free(error);
exit(EXIT_FAILURE);
}
if ((value < min) || (value > max))
{
tio_error_print("%s: Invalid %s value '%d' in %s profile", config.path, key, value, group);
exit(EXIT_FAILURE);
}
*dest = value;
}
static void config_get_bool(GKeyFile *key_file, gchar *group, gchar *key, bool *dest)
{
(void)dest;
GError *error = NULL;
bool value = g_key_file_get_boolean(key_file, group, key, &error);
if (error != NULL)
{
if (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)
{
// Key not found - ignore key
g_error_free(error);
return;
}
tio_error_print("%s: %s", config.path, error->message);
g_error_free(error);
exit(EXIT_FAILURE);
}
*dest = value;
}
static void config_parse_keys(GKeyFile *key_file, char *group)
{
char *string = NULL;
config_get_string(key_file, group, "device", &config.device, NULL);
config_get_integer(key_file, group, "baudrate", &option.baudrate, 0, INT_MAX);
config_get_integer(key_file, group, "databits", &option.databits, 5, 8);
config_get_string(key_file, group, "flow", &string, "none", "hard", "soft", NULL);
if (string != NULL)
{
option_parse_flow(string, &option.flow);
g_free((void *)string);
string = NULL;
}
config_get_integer(key_file, group, "stopbits", &option.stopbits, 1, 2);
config_get_string(key_file, group, "parity", &string, "odd", "even", "none", "mark", "space", NULL);
if (string != NULL)
{
option_parse_parity(string, &option.parity);
g_free((void *)string);
string = NULL;
}
config_get_integer(key_file, group, "output-delay", &option.output_delay, 0, INT_MAX);
config_get_integer(key_file, group, "output-line-delay", &option.output_line_delay, 0, INT_MAX);
config_get_string(key_file, group, "line-pulse-duration", &string, NULL);
if (string != NULL)
{
option_parse_line_pulse_duration(string);
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "auto-connect", &string, "new", "latest", "direct", NULL);
if (string != NULL)
{
option_parse_auto_connect(string, &option.auto_connect);
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "exclude-devices", &option.exclude_devices, NULL);
config_get_string(key_file, group, "exclude-drivers", &option.exclude_devices, NULL);
config_get_string(key_file, group, "exclude-tids", &option.exclude_devices, NULL);
config_get_bool(key_file, group, "no-reconnect", &option.no_reconnect);
config_get_bool(key_file, group, "local-echo", &option.local_echo);
config_get_string(key_file, group, "input-mode", &string, "normal", "hex", "line", NULL);
if (string != NULL)
{
option_parse_input_mode(string, &option.input_mode);
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "output-mode", &string, NULL);
if (string != NULL)
{
option_parse_output_mode(string, &option.output_mode);
g_free((void *)string);
string = NULL;
}
config_get_bool(key_file, group, "timestamp", (bool*) &option.timestamp);
if (option.timestamp != TIMESTAMP_NONE)
{
config_get_string(key_file, group, "timestamp-format", &string, "24hour", "24hour-start", "24hour-delta", "iso8601", "epoch", "epoch-usec", NULL);
if (string != NULL)
{
option_parse_timestamp(string, &option.timestamp);
g_free((void *)string);
string = NULL;
}
}
config_get_integer(key_file, group, "timestamp-timeout", &option.timestamp_timeout, 0, INT_MAX);
config_get_bool(key_file, group, "log", &option.log);
config_get_string(key_file, group, "log-file", &option.log_filename, NULL);
config_get_string(key_file, group, "log-directory", &option.log_directory, NULL);
config_get_bool(key_file, group, "log-append", &option.log_append);
config_get_bool(key_file, group, "log-strip", &option.log_strip);
config_get_string(key_file, group, "map", &string, NULL);
if (string != NULL)
{
option_parse_mappings(string);
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "color", &string, NULL);
if (string != NULL)
{
if (strcmp(string, "list") == 0)
{
// Ignore
}
else if (strcmp(string, "none") == 0)
{
option.color = -1; // No color
}
else if (strcmp(string, "bold") == 0)
{
option.color = 256; // Bold
}
else
{
option.color = atoi(string);
if ((option.color < 0) || (option.color > 255))
{
tio_error_print("%s: Invalid color value in %s profile", config.path, group);
exit(EXIT_FAILURE);
}
}
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "socket", &option.socket, NULL);
config_get_bool(key_file, group, "rs-485", &option.rs485);
config_get_string(key_file, group, "rs-385-config", &string, NULL);
if (string != NULL)
{
rs485_parse_config(string);
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "alert", &string, "bell", "blink", "none", NULL);
if (string != NULL)
{
option_parse_alert(string, &option.alert);
g_free((void *)string);
string = NULL;
}
config_get_bool(key_file, group, "mute", &option.mute);
config_get_string(key_file, group, "script", &option.script, NULL);
config_get_string(key_file, group, "script-file", &option.script_filename, NULL);
config_get_string(key_file, group, "script-run", &string, NULL);
if (string != NULL)
{
option_parse_script_run(string, &option.script_run);
g_free((void *)string);
string = NULL;
}
config_get_string(key_file, group, "exec", &option.exec, NULL);
config_get_string(key_file, group, "prefix-ctrl-key", &string, NULL);
if (string != NULL)
{
if (strcmp(string, "none") == 0)
{
option.prefix_enabled = false;
}
else if (strlen(string) >= 2)
{
tio_error_print("%s: Invalid prefix-ctrl-key value in %s profile", config.path, group);
exit(EXIT_FAILURE);
}
else if (ctrl_key_code(string[0]) > 0)
{
option.prefix_enabled = true;
option.prefix_code = ctrl_key_code(string[0]);
option.prefix_key = string[0];
}
else
{
tio_error_print("%s: Invalid prefix-ctrl-key value in %s profile", config.path, group);
exit(EXIT_FAILURE);
}
g_free((void *)string);
string = NULL;
}
}
static int config_file_resolve(void)
{
char *xdg = getenv("XDG_CONFIG_HOME");
if (xdg)
{
if (asprintf(&config.path, "%s/tio/config", xdg) != -1)
{
if (access(config.path, F_OK) == 0)
{
return 0;
}
free(config.path);
}
}
char *home = getenv("HOME");
if (home)
{
if (asprintf(&config.path, "%s/.config/tio/config", home) != -1)
{
if (access(config.path, F_OK) == 0)
{
return 0;
}
free(config.path);
}
if (asprintf(&config.path, "%s/.tioconfig", home) != -1)
{
if (access(config.path, F_OK) == 0)
{
return 0;
}
free(config.path);
}
}
config.path = NULL;
return -EINVAL;
}
void config_file_show_profiles(void)
{
GString *config_buffer;
GError *error = NULL;
GKeyFile *keyfile;
// Reset configuration
memset(&config, 0, sizeof(struct config_t));
// Find config file
if (config_file_resolve() != 0)
{
// None found - stop parsing
return;
}
// Load content of configuration file into buffer
config_buffer = g_string_new(NULL);
config_file_load(config.path, config_buffer, false);
// Load configuration
keyfile = g_key_file_new();
if (g_key_file_load_from_data(keyfile, config_buffer->str, config_buffer->len, G_KEY_FILE_NONE, &error) == false)
{
g_error_free(error);
goto error_load;
}
// Get all group names
gsize num_groups;
gchar **group = g_key_file_get_groups(keyfile, &num_groups);
for (gsize i = 0; i < num_groups; i++)
{
// Skip default group
if (strcmp(group[i], CONFIG_GROUP_NAME_DEFAULT) == 0)
{
continue;
}
// Skip group with include directive
if (strncmp(group[i], CONFIG_GROUP_INCLUDE_PREFIX, strlen(CONFIG_GROUP_INCLUDE_PREFIX)) == 0)
{
continue;
}
printf("%s ", group[i]);
}
g_strfreev(group);
error_load:
g_key_file_free(keyfile);
g_string_free(config_buffer, TRUE);
}
static void replace_substring(char *str, const char *substr, const char *replacement)
{
char *pos = strstr(str, substr);
if (pos != NULL)
{
int substrLen = strlen(substr);
int replacementLen = strlen(replacement);
memmove(pos + replacementLen, pos + substrLen, strlen(pos + substrLen) + 1);
memcpy(pos, replacement, replacementLen);
}
}
static char *match_and_replace(const char *str, const char *pattern, char *device)
{
char replacement_str[PATH_MAX] = {};
char m_key[14] = {};
regex_t regex;
assert(str != NULL);
assert(pattern != NULL);
assert(device != NULL);
char *string = calloc(PATH_MAX, 1);
if (string == NULL)
{
tio_debug_printf("Failure allocating string memory\n");
return NULL;
}
strncpy(string, device, PATH_MAX - 1);
/* Find matches of pattern in str. For each match, replace any '%mN' in the
* copy of the device string with the corresponding match subexpression and
* return the new formed device string.
*
* Note: %m0 = Full match expression.
* %m1 = First subexpression
* %m2 = Second subexpression
* %m3 = etc..
*/
if (regcomp(&regex, pattern, REG_EXTENDED) != 0)
{
// Failure to compile regular expression
tio_error_print("Failure compiling regular expression '%s'\n", pattern);
exit(EXIT_FAILURE);
}
regmatch_t matches[regex.re_nsub + 1];
int status = regexec(&regex, str, regex.re_nsub + 1, matches, 0);
if (status == 0)
{
tio_debug_printf("Full match: ");
int j = 0;
for (int i = matches[0].rm_so; i < matches[0].rm_eo; i++)
{
tio_debug_printf_raw("%c", str[i]);
replacement_str[j++] = str[i];
}
replacement_str[j] = '\0';
replace_substring(string, "%m0", replacement_str);
tio_debug_printf_raw("\n");
for (int i = 1; i < ((int)regex.re_nsub + 1) && matches[i].rm_so != -1; i++)
{
tio_debug_printf("Subexpression %d match: ", i);
int k = 0;
for (int l = matches[i].rm_so; l < matches[i].rm_eo; l++)
{
tio_debug_printf_raw("%c", str[l]);
replacement_str[k++] = str[l];
}
replacement_str[k] = '\0';
sprintf(m_key, "%%m%d", i);
replace_substring(string, m_key, replacement_str);
tio_debug_printf_raw("\n");
}
}
else if (status == REG_NOMATCH)
{
tio_debug_printf("No regex match\n");
goto error;
}
else
{
char error_message[100];
regerror(status, &regex, error_message, sizeof(error_message));
tio_debug_printf("Regex match failed: %s", error_message);
goto error;
}
regfree(&regex);
return string;
error:
regfree(&regex);
return NULL;
}
static void config_file_process_line(const char *line, GString *buffer, GList **included_files, bool test)
{
if (strncmp(line, "[include ", 9) == 0 && line[strlen(line) - 2] == ']')
{
char include_filename[MAX_LINE_LENGTH];
// Construct the format string safely
char format_string[50];
snprintf(format_string, sizeof(format_string), "[include %%%ds]", MAX_LINE_LENGTH - 1);
int ret = sscanf(line, format_string, include_filename);
if (ret != 1)
{
return;
}
// Remove the trailing ']' character
include_filename[strlen(include_filename) - 1] = '\0';
if (g_list_find_custom(*included_files, include_filename, (GCompareFunc)strcmp) != NULL)
{
// Already included, avoid recursion
return;
}
// Add to included files list
*included_files = g_list_append(*included_files, g_strdup(include_filename));
// Process the included file
config_file_process(include_filename, buffer, included_files, test);
}
else
{
// Normal line, add to buffer
g_string_append(buffer, line);
}
}
static void config_file_process(const char *filename, GString *buffer, GList **included_files, bool test)
{
if (test)
{
// Test that configuration file can be parsed
GError *error = NULL;
GKeyFile *keyfile = g_key_file_new();
if (g_key_file_load_from_file(keyfile, filename, G_KEY_FILE_NONE, &error) == false)
{
tio_error_print("Failure loading file %s: %s", filename, error->message);
g_key_file_free(keyfile);
g_error_free(error);
exit(EXIT_FAILURE);
}
}
FILE *file = fopen(filename, "r");
if (file)
{
char line[MAX_LINE_LENGTH];
while (fgets(line, sizeof(line), file))
{
config_file_process_line(line, buffer, included_files, test);
}
fclose(file);
}
}
static void config_file_load(const char *filename, GString *buffer, bool test)
{
char current_dir[PATH_MAX] = ".";
char *config_file_dir = dirname(strdup(config.path));
GList *included_files = NULL;
getcwd(current_dir, PATH_MAX);
// Change to the directory of the configuration file
chdir(config_file_dir);
config_file_process(filename, buffer, &included_files, test);
// Restore current directory
chdir(current_dir);
// Free memory
g_list_free_full(included_files, g_free);
free(config_file_dir);
}
void config_file_parse(void)
{
// Find config file
if (config_file_resolve() != 0)
{
// None found - stop parsing
return;
}
if (option.target == NULL)
{
return;
}
GString *config_buffer = g_string_new(NULL);
GKeyFile *keyfile = g_key_file_new();
GList *included_files = NULL;
GError *error = NULL;
config_file_load(config.path, config_buffer, true);
if (g_key_file_load_from_data(keyfile, config_buffer->str, config_buffer->len, G_KEY_FILE_NONE, &error) == false)
{
tio_error_print("Failure loading file %s: %s", config.path, error->message);
g_string_free(config_buffer, TRUE);
g_key_file_free(keyfile);
g_error_free(error);
exit(EXIT_FAILURE);
}
// Parse default group/section
if (g_key_file_has_group(keyfile, CONFIG_GROUP_NAME_DEFAULT))
{
config_parse_keys(keyfile, CONFIG_GROUP_NAME_DEFAULT);
}
// Parse target
if (g_key_file_has_group(keyfile, option.target))
{
config.active_group = strdup(option.target);
config_parse_keys(keyfile, option.target);
}
else
{
// Find group by pattern
gsize num_groups;
gchar **group = g_key_file_get_groups(keyfile, &num_groups);
for (gsize i = 0; i < num_groups; i++)
{
// Skip default group
if (strcmp(group[i], CONFIG_GROUP_NAME_DEFAULT) == 0)
{
continue;
}
// Lookup 'pattern' key
gchar *pattern = g_key_file_get_string(keyfile, group[i], "pattern", &error);
if (error != NULL)
{
g_error_free(error);
error = NULL;
continue;
}
// Lookup 'device' key
gchar *device = g_key_file_get_string(keyfile, group[i], "device", &error);
if (error != NULL)
{
g_error_free(error);
error = NULL;
continue;
}
// Match pattern against target and replace any sub expression
// matches (%mN) in device string and return resulting string
// representing the new pattern based string.
config.device = match_and_replace(option.target, pattern, device);
if (config.device != NULL)
{
// Match found - save device
device = strdup(config.device);
// Parse found group (may replace config.device)
config_parse_keys(keyfile, group[i]);
// Update configuration
config.active_group = strdup(group[i]);
config.device = device; // Restore new device string
break;
}
}
g_strfreev(group);
}
// Cleanup
g_key_file_free(keyfile);
g_string_free(config_buffer, TRUE);
g_list_free_full(included_files, g_free);
atexit(&config_exit);
}
void config_exit(void)
{
free(config.active_group);
free(config.path);
free(config.device);
}
void config_file_print(void)
{
if (config.path != NULL)
{
tio_printf(" Active configuration file: %s", config.path);
if (config.active_group != NULL)
{
tio_printf(" Active configuration profile: %s", config.active_group);
}
}
}
void config_list_targets(void)
{
memset(&config, 0, sizeof(struct config_t));
// Find config file
if (config_file_resolve() != 0)
{
// None found
return;
}
GKeyFile *keyfile;
GError *error = NULL;
keyfile = g_key_file_new();
GString *config_buffer = g_string_new(NULL);
config_file_load(config.path, config_buffer, false);
if (g_key_file_load_from_data(keyfile, config_buffer->str, config_buffer->len, G_KEY_FILE_NONE, &error) == false)
{
g_error_free(error);
goto cleanup;
}
// Get all group names
gsize num_groups;
gchar **group = g_key_file_get_groups(keyfile, &num_groups);
if (num_groups == 0)
{
goto cleanup;
}
printf("\nConfiguration profiles (%s)\n", config.path);
printf("--------------------------------------------------------------------------------\n");
int j = 1;
for (gsize i = 0; i < num_groups; i++)
{
// Skip default group
if (strcmp(group[i], CONFIG_GROUP_NAME_DEFAULT) == 0)
{
continue;
}
// Skip group with include directive
if (strncmp(group[i], CONFIG_GROUP_INCLUDE_PREFIX, strlen(CONFIG_GROUP_INCLUDE_PREFIX)) == 0)
{
continue;
}
printf("%-19s ", group[i]);
if (j++ % 4 == 0)
{
putchar('\n');
}
}
if ((j-1) % 4 != 0)
{
putchar('\n');
}
g_strfreev(group);
cleanup:
g_key_file_free(keyfile);
g_string_free(config_buffer, TRUE);
}

38
src/configfile.h Normal file
View file

@ -0,0 +1,38 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2020 Liam Beguin
* 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
struct config_t
{
char *path;
char *active_group;
char *device;
};
extern struct config_t config;
void config_file_print(void);
void config_file_parse(void);
void config_exit(void);
void config_file_show_profiles(void);
void config_list_targets(void);

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* Copyright (c) 2014-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
@ -19,23 +19,79 @@
* 02110-1301, USA.
*/
#include "config.h"
#define _GNU_SOURCE // To access vasprintf
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "tio/options.h"
#include "tio/print.h"
#include "tio/error.h"
#include "print.h"
char error[2][1000];
static char error[2][1000];
static bool in_session = false;
bool error_normal = true;
void switch_error_output_mode(void)
{
error_normal = 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", timestamp_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)
{
/* Always print errors but only print silent errors when in no autoconnect
* mode */
if (error[0][0] != 0)
printf("\rError: %s\r\n", error[0]);
else if ((error[1][0] != 0) && (option.no_autoconnect))
printf("\rError: %s\r\n", error[1]);
{
/* Print error */
error_printf_("Error: %s", error[0]);
}
else if ((error[1][0] != 0) && (option.no_reconnect))
{
/* Print silent error */
error_printf_("Error: %s", error[1]);
}
}

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* Copyright (c) 2014-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
@ -19,20 +19,17 @@
* 02110-1301, USA.
*/
#ifndef ERROR_H
#define ERROR_H
#pragma once
#include <stdbool.h>
extern bool error_normal;
#define TIO_SUCCESS 0
#define TIO_ERROR 1
extern char error[2][1000];
#define error_printf(format, args...) \
snprintf (error[0], 1000, format, ## args);
#define error_printf_silent(format, args...) \
snprintf (error[1], 1000, format, ## args);
void tio_error_printf(const char *format, ...);
void tio_error_printf_silent(const char *format, ...);
void error_exit(void);
#endif
void error_enter_session_mode(void);
void switch_error_output_mode(void);

226
src/fs.c Normal file
View file

@ -0,0 +1,226 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2024 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 _GNU_SOURCE // For statx()
#include "config.h"
#include <dirent.h>
#include <fcntl.h>
#include <regex.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <poll.h>
#include <termios.h>
#include "error.h"
#include "print.h"
#include "options.h"
bool fs_dir_exists(const char *path)
{
struct stat st;
if (stat(path, &st) != 0)
{
return false;
}
else if (!S_ISDIR(st.st_mode))
{
return false;
}
return true;
}
// Function to read the content of a file but stripped of newline
ssize_t fs_read_file_stripped(char *buf, size_t bufsiz, const char *format, ...)
{
char filename[PATH_MAX];
int bytes_printed = 0;
va_list args;
va_start(args, format);
bytes_printed = vsnprintf(filename, sizeof(filename), format, args);
va_end(args);
if (bytes_printed < 0)
{
return -1;
}
FILE *file = fopen(filename, "r");
if (!file)
{
return -1;
}
ssize_t length = fread(buf, 1, bufsiz - 1, file);
if (length == -1)
{
fclose(file);
return -1;
}
// Strip any newline
buf[strcspn(buf, "\n")] = 0;
buf[length] = '\0'; // Make sure to null-terminate the string
fclose(file);
return length;
}
bool fs_file_exists(const char *format, ...)
{
char filename[PATH_MAX];
int bytes_printed = 0;
struct stat st;
va_list args;
va_start(args, format);
bytes_printed = vsnprintf(filename, sizeof(filename), format, args);
va_end(args);
if (bytes_printed < 0)
{
return false;
}
return stat(filename, &st) == 0;
}
char* fs_search_directory(const char *dir_path, const char *dirname)
{
struct dirent *entry;
char path[PATH_MAX];
struct stat st;
DIR *dir;
if ((dir = opendir(dir_path)) == NULL)
{
// Error opening directory
return NULL;
}
while ((entry = readdir(dir)) != NULL)
{
snprintf(path, PATH_MAX, "%s/%s", dir_path, entry->d_name);
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
continue;
}
if (lstat(path, &st) == -1)
{
// Error getting directory status
closedir(dir);
return NULL;
}
if (S_ISLNK(st.st_mode))
{
// Skip symbolic links
continue;
}
if (S_ISDIR(st.st_mode))
{
// If it's a directory, check if it's the one we're looking for
if (strcmp(entry->d_name, dirname) == 0)
{
char *result = strndup(path, PATH_MAX);
closedir(dir);
return result;
}
else
{
// Recursively search within directories
char* result = fs_search_directory(path, dirname);
if (result != NULL)
{
closedir(dir);
return result;
}
}
}
}
closedir(dir);
return NULL;
}
#if defined(__linux__) && defined(STATX_BTIME)
// Function to return creation time of file
double fs_get_creation_time(const char *path)
{
struct statx stx;
int fd = open(path, O_RDONLY);
if (fd == -1)
{
return -1;
}
if (statx(fd, "", AT_EMPTY_PATH, STATX_ALL, &stx) != 0)
{
close(fd);
return -1;
}
// Close the file
close(fd);
return stx.stx_btime.tv_sec + stx.stx_btime.tv_nsec / 1e9;
}
#elif defined(__APPLE__) || defined(__MACH__)
double fs_get_creation_time(const char *path)
{
struct stat st;
if (stat(path, &st) != 0)
{
return -1;
}
return st.st_mtimespec.tv_sec + st.st_mtimespec.tv_nsec / 1e9;
}
#else
double fs_get_creation_time(const char *path)
{
struct stat st;
if (stat(path, &st) != 0)
{
return -1;
}
return (double) st.st_ctime;
}
#endif

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* Copyright (c) 2014-2024 Martin Lund
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -19,32 +19,13 @@
* 02110-1301, USA.
*/
#ifndef OPTIONS_H
#define OPTIONS_H
#pragma once
#include <stdbool.h>
#include <limits.h>
#include <termios.h>
#include <sys/param.h>
#include <stdio.h>
/* Options */
struct option_t
{
const char *tty_device;
unsigned int baudrate;
int databits;
char *flow;
int stopbits;
char *parity;
int output_delay;
bool no_autoconnect;
bool log;
const char *log_filename;
const char *map;
};
extern struct option_t option;
void parse_options(int argc, char *argv[]);
#endif
bool fs_dir_exists(const char *path);
bool fs_file_exists(const char *format, ...);
char* fs_search_directory(const char *dir_path, const char *dirname);
ssize_t fs_read_file_stripped(char *buf, size_t bufsiz, const char *format, ...);
double fs_get_creation_time(const char *path);

View file

@ -1,53 +0,0 @@
/*
* tio - a simple TTY terminal I/O application
*
* Copyright (c) 2014-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.
*/
#ifndef PRINT_H
#define PRINT_H
#define ANSI_COLOR_GRAY "\x1b[1;30m"
#define ANSI_COLOR_RED "\x1b[1;31m"
#define ANSI_COLOR_GREEN "\x1b[1;32m"
#define ANSI_COLOR_YELLOW "\x1b[1;33m"
#define ANSI_COLOR_BLUE "\x1b[1;34m"
#define ANSI_COLOR_PINK "\x1b[1;35m"
#define ANSI_COLOR_CYAN "\x1b[1;36m"
#define ANSI_COLOR_WHITE "\x1b[1;37m"
#define ANSI_COLOR_RESET "\x1b[0m"
#define color_printf(format, args...) \
fprintf (stdout, "\r" ANSI_COLOR_YELLOW format ANSI_COLOR_RESET "\r\n", ## args); \
fflush(stdout);
#define warning_printf(format, args...) \
fprintf (stdout, "\rWarning: " format "\r\n", ## args); \
fflush(stdout);
#ifdef DEBUG
#define debug_printf(format, args...) \
fprintf (stdout, "[debug] " format, ## args)
#define debug_printf_raw(format, args...) \
fprintf (stdout, "" format, ## args)
#else
#define debug_printf(format, args...)
#define debug_printf_raw(format, args...)
#endif
#endif

226
src/log.c
View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* Copyright (c) 2014-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
@ -19,46 +19,224 @@
* 02110-1301, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define _GNU_SOURCE // To access vasprintf
#include <sys/time.h>
#include <libgen.h>
#include <errno.h>
#include "tio/options.h"
#include "tio/print.h"
#include "tio/error.h"
#include "print.h"
#include "fs.h"
static FILE *fp;
static bool log_error = false;
#define IS_ESC_CSI_INTERMEDIATE_CHAR(c) ((c >= 0x20) && (c <= 0x3F))
#define IS_ESC_END_CHAR(c) ((c >= 0x30) && (c <= 0x7E))
#define IS_CTRL_CHAR(c) ((c >= 0x00) && (c <= 0x1F))
void log_open(const char *filename)
static FILE *fp = NULL;
static char file_buffer[BUFSIZ];
static const char *log_filename = NULL;
static char *date_time(void)
{
fp = fopen(filename, "w+");
static char date_time_string[50];
struct tm *tm;
struct timeval tv;
if (fp == NULL)
{
log_error = true;
exit(EXIT_FAILURE);
}
gettimeofday(&tv, NULL);
tm = localtime(&tv.tv_sec);
strftime(date_time_string, sizeof(date_time_string), "%Y-%m-%dT%H:%M:%S", tm);
return date_time_string;
}
void log_write(char c)
int log_open(const char *filename)
{
if (fp != NULL)
char *automatic_filename;
char *dir_plus_automatic_filename;
if (filename == NULL)
{
// Generate filename if none provided
if (option.auto_connect == AUTO_CONNECT_DIRECT)
{
// File name format ("tio_TARGET_YYYY-MM-DDTHH:MM:SS.log")
asprintf(&automatic_filename, "tio_%s_%s.log", basename((char *)option.target), date_time());
}
else
{
// If using 'new' or 'latest' autoconnect strategy we simply use strategy
// name to name autogenerated log name as device names may vary
asprintf(&automatic_filename, "tio_%s_%s.log",
option_auto_connect_state_to_string(option.auto_connect),
date_time());
}
if (option.log_directory != NULL)
{
if (fs_dir_exists(option.log_directory) == false)
{
tio_error_printf("Log directory not found");
exit(EXIT_FAILURE);
}
asprintf(&dir_plus_automatic_filename, "%s/%s", option.log_directory, automatic_filename);
filename = dir_plus_automatic_filename;
}
else
{
filename = automatic_filename;
}
}
log_filename = filename;
// Open log file
if (option.log_append)
{
// Append to existing log file
fp = fopen(filename, "a+");
}
else
{
// Truncate existing log file
fp = fopen(filename, "w+");
}
if (fp == NULL)
{
tio_warning_printf("Could not open log file %s (%s)", filename, strerror(errno));
return -1;
}
// Enable line buffering
setvbuf(fp, file_buffer, _IOLBF, BUFSIZ);
return 0;
}
bool log_strip(char c)
{
static char previous_char = 0;
static bool esc_sequence = false;
bool strip = false;
/* Detect if character should be stripped or not */
switch (c)
{
case 0xa:
/* Line feed / new line */
/* Reset ESC sequence just in case something went wrong with the
* escape sequence parsing. */
esc_sequence = false;
break;
case 0x1b:
/* Escape */
strip = true;
break;
case 0x5b:
/* Left bracket */
if (previous_char == 0x1b)
{
// Start of ESC sequence
esc_sequence = true;
strip = true;
}
break;
default:
if (IS_CTRL_CHAR(c))
{
/* Strip ASCII control characters */
strip = true;
break;
}
else
if ((esc_sequence) && (IS_ESC_CSI_INTERMEDIATE_CHAR(c)))
{
strip = true;
break;
}
else
if ((esc_sequence) && (IS_ESC_END_CHAR(c)))
{
esc_sequence = false;
strip = true;
break;
}
break;
}
previous_char = c;
return strip;
}
void log_printf(const char *format, ...)
{
if (fp == NULL)
{
return;
}
char *line;
va_list(args);
va_start(args, format);
vasprintf(&line, format, args);
va_end(args);
fwrite(line, strlen(line), 1, fp);
free(line);
}
void log_putc(char c)
{
if (fp == NULL)
{
return;
}
if (option.output_mode == OUTPUT_MODE_HEX)
{
fprintf(fp, "%02x ", (unsigned char) c);
}
else
{
if (option.log_strip)
{
if (log_strip(c) == false)
{
fputc(c, fp);
}
}
else
{
fputc(c, fp);
}
}
}
void log_close(void)
{
if (fp != NULL)
{
fclose(fp);
tio_printf("Saved log to file %s", log_filename);
fp = NULL;
log_filename = NULL;
}
}
void log_exit(void)
{
if (option.log)
if ((option.log) && (log_filename != NULL))
{
log_close();
if (log_error)
error_printf("Could not open log file %s (%s)", option.log_filename, strerror(errno));
}
}
const char *log_get_filename(void)
{
return log_filename;
}

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* Copyright (c) 2014-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
@ -19,12 +19,11 @@
* 02110-1301, USA.
*/
#ifndef LOG_H
#define LOG_H
#pragma once
void log_open(const char *filename);
void log_write(char c);
int log_open(const char *filename);
void log_printf(const char *format, ...);
void log_putc(char c);
void log_close(void);
void log_exit(void);
#endif
const char * log_get_filename(void);

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* Copyright (c) 2014-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
@ -19,52 +19,128 @@
* 02110-1301, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "tio/options.h"
#include "tio/tty.h"
#include "tio/log.h"
#include "tio/error.h"
#include "tio/print.h"
#include "version.h"
#include "config.h"
#include "options.h"
#include "configfile.h"
#include "tty.h"
#include "log.h"
#include "error.h"
#include "print.h"
#include "signals.h"
#include "socket.h"
int main(int argc, char *argv[])
{
int status;
int status = 0;
/* Install error exit handler */
/* Handle received signals */
signal_handlers_install();
/* Add error exit handler */
atexit(&error_exit);
/* Parse options */
parse_options(argc, argv);
/* Parse command-line options (1st pass) */
options_parse(argc, argv);
if (option.complete_profiles)
{
config_file_show_profiles();
return status;
}
/* Parse configuration file */
config_file_parse();
/* Parse command-line options (2nd pass) */
options_parse_final(argc, argv);
/* Configure tty device */
tty_configure();
/* Disable line buffering in stdout. This is necessary if we
* want things like local echo to work correctly. */
setvbuf(stdout, NULL, _IONBF, 0);
/* Configure input terminal */
if (isatty(fileno(stdin)))
{
stdin_configure();
}
else
{
// Enter non interactive mode
interactive_mode = false;
}
/* Switch error output format */
switch_error_output_mode();
/* Configure output terminal */
if (isatty(fileno(stdout)))
{
stdout_configure();
}
else
{
// No color when piping
option.color = -1;
}
/* Install log exit handler */
/* Add log exit handler */
atexit(&log_exit);
/* Create log file */
if (option.log)
{
log_open(option.log_filename);
}
/* Initialize ANSI text formatting (colors etc.) */
print_init_ansi_formatting();
/* Change error printing mode */
error_enter_session_mode();
/* Print launch hints */
tio_printf("tio %s", VERSION);
if (interactive_mode)
{
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 */
if (option.socket)
{
socket_configure();
}
/* Spawn input handling into separate thread */
tty_input_thread_create();
/* Wait for input to be ready */
tty_input_thread_wait_ready();
/* Connect to tty device */
if (option.no_autoconnect)
if (option.no_reconnect)
{
tty_search();
status = tty_connect();
}
else
{
/* Enter connect loop */
while (true)
{
tty_wait_for_device();
status = tty_connect();
tty_connect();
}
}

76
src/meson.build Normal file
View file

@ -0,0 +1,76 @@
# Generate version header
version_h = vcs_tag(command : ['git', 'describe', '--tags', '--always', '--dirty'],
input : 'version.h.in',
output :'version.h',
replace_string:'@VERSION@')
config_h = configuration_data()
config_h.set('BAUDRATE_CASES', baudrate_cases)
configure_file(output: 'config.h', configuration: config_h)
tio_sources = [
'error.c',
'log.c',
'main.c',
'options.c',
'misc.c',
'tty.c',
'print.c',
'configfile.c',
'signals.c',
'socket.c',
'setspeed.c',
'rs485.c',
'timestamp.c',
'alert.c',
'xymodem.c',
'script.c',
'fs.c',
'readline.c',
version_h
]
foreach name: ['lua-5.4', 'lua-5.3', 'lua-5.2', 'lua-5.1', 'lua']
lua_dep = dependency(name, version: '>=5.1', required: false)
if lua_dep.found()
break
endif
endforeach
if not lua_dep.found()
error('Lua could not be found!')
endif
tio_dep = [
dependency('threads', required: true),
dependency('glib-2.0', required: true),
lua_dep
]
if host_machine.system() == 'darwin'
iokit_dep = dependency('appleframeworks', modules: ['IOKit'], required: true)
corefoundation_dep = dependency('appleframeworks', modules: ['CoreFoundation'], required: true)
tio_dep += [iokit_dep, corefoundation_dep]
endif
tio_c_args = ['-Wshadow','-Wno-unused-result']
if enable_setspeed2
tio_c_args += '-DHAVE_TERMIOS2'
endif
if enable_iossiospeed
tio_c_args += '-DHAVE_IOSSIOSPEED'
endif
if enable_rs485
tio_c_args += '-DHAVE_RS485'
endif
executable('tio',
tio_sources,
c_args: tio_c_args,
dependencies: tio_dep,
install: true )
subdir('bash-completion')

253
src/misc.c Normal file
View file

@ -0,0 +1,253 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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 _GNU_SOURCE // For FNM_EXTMATCH
#include <unistd.h>
#include <string.h>
#include <poll.h>
#include <sys/wait.h>
#include <fnmatch.h>
#include <regex.h>
#include <errno.h>
#include "print.h"
void delay(long ms)
{
struct timespec ts;
if (ms <= 0)
{
return;
}
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&ts, NULL);
}
int ctrl_key_code(unsigned char key)
{
if ((key >= 'a') && (key <= 'z'))
{
return key & ~0x60;
}
return -1;
}
bool regex_match(const char *string, const char *pattern)
{
regex_t regex;
int status;
if (regcomp(&regex, pattern, REG_EXTENDED | REG_NOSUB) != 0)
{
// No match
return false;
}
status = regexec(&regex, string, (size_t) 0, NULL, 0);
regfree(&regex);
if (status != 0)
{
// No match
return false;
}
// Match
return true;
}
int read_poll(int fd, void *data, size_t len, int timeout)
{
struct pollfd fds;
int ret = 0;
fds.events = POLLIN;
fds.fd = fd;
/* Wait data available */
ret = poll(&fds, 1, timeout);
if (ret < 0)
{
tio_error_print("%s", strerror(errno));
return ret;
}
else if (ret > 0)
{
if (fds.revents & POLLIN)
{
// Read ready data
return read(fd, data, len);
}
}
/* Timeout */
return ret;
}
// Function to calculate djb2 hash of string
unsigned long djb2_hash(const unsigned char *str)
{
unsigned long hash = 5381;
int c;
while ((c = *str++))
{
hash = ((hash << 5) + hash) + c; // hash * 33 + c
}
return hash;
}
// Function to encode a number to base62
void *base62_encode(unsigned long num, char *output)
{
const char base62_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
if (output == NULL)
{
tio_error_print("Memory allocation failed");
exit(EXIT_FAILURE);
}
for (int i = 0; i < 4; ++i)
{
output[i] = base62_chars[num % 62];
num /= 62;
}
output[4] = '\0';
return output;
}
// Function to return current time
double get_current_time(void)
{
struct timespec current_time_ts;
if (clock_gettime(CLOCK_REALTIME, &current_time_ts) == -1)
{
// Error
return -1;
}
return current_time_ts.tv_sec + current_time_ts.tv_nsec / 1e9;
}
bool match_patterns(const char *string, const char *patterns)
{
char *pattern;
char *patterns_copy;
if ((string == NULL) || (patterns == NULL))
{
return false;
}
patterns_copy = strdup(patterns);
// Tokenize the patterns string using strtok
pattern = strtok(patterns_copy, ",");
while (pattern != NULL)
{
// Check if the string matches the current pattern
#ifdef FNM_EXTMATCH
if (fnmatch(pattern, string, FNM_EXTMATCH) == 0)
#else
if (fnmatch(pattern, string, 0) == 0)
#endif
{
free(patterns_copy);
return true;
}
// Move to the next pattern
pattern = strtok(NULL, ",");
}
free(patterns_copy);
return false;
}
// Function that forks subprocess, redirects its stdin and stdout to the
// specified filedescriptor, and runs command.
int execute_shell_command(int fd, const char *command)
{
pid_t pid;
int status;
// Fork a child process
pid = fork();
if (pid == -1)
{
// Error occurred
tio_error_print("fork() failed (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
// Child process
tio_printf("Executing shell command '%s'", command);
// Redirect stdout and stderr to the file descriptor
if (dup2(fd, STDOUT_FILENO) == -1 || dup2(fd, STDERR_FILENO) == -1)
{
tio_error_print("dup2() failed (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
// Execute the shell command
execl("/bin/sh", "sh", "-c", command, (char *)NULL);
// If execlp() returns, it means an error occurred
perror("execlp");
tio_error_print("execlp() failed (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
else
{
// Parent process
// Wait for the child process to finish
waitpid(pid, &status, 0);
if (WIFEXITED(status))
{
tio_printf("Command exited with status %d", WEXITSTATUS(status));
return WEXITSTATUS(status);
}
else
{
tio_error_printf("Child process exited abnormally\n");
return -1;
}
}
return 0;
}
void clear_line()
{
print("\r\033[K");
}

38
src/misc.h Normal file
View file

@ -0,0 +1,38 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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
#include <stdbool.h>
#include <stdio.h>
#define UNUSED(expr) do { (void)(expr); } while (0)
void delay(long ms);
int ctrl_key_code(unsigned char key);
bool regex_match(const char *string, const char *pattern);
unsigned long djb2_hash(const unsigned char *str);
void *base62_encode(unsigned long num, char *output);
int read_poll(int fd, void *data, size_t len, int timeout);
double get_current_time(void);
bool match_patterns(const char *string, const char *patterns);
int execute_shell_command(int fd, const char *command);
void clear_line();

File diff suppressed because it is too large Load diff

135
src/options.h Normal file
View file

@ -0,0 +1,135 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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
#include <stdint.h>
#include <stdbool.h>
#include "script.h"
#include "timestamp.h"
#include "alert.h"
#include "tty.h"
typedef enum
{
INPUT_MODE_NORMAL,
INPUT_MODE_HEX,
INPUT_MODE_LINE,
INPUT_MODE_END,
} input_mode_t;
typedef enum
{
OUTPUT_MODE_NORMAL,
OUTPUT_MODE_HEX,
OUTPUT_MODE_END,
} output_mode_t;
/* Options */
struct option_t
{
char *target;
int baudrate;
int databits;
flow_t flow;
int stopbits;
parity_t parity;
int output_delay;
int output_line_delay;
int dtr_pulse_duration;
int rts_pulse_duration;
int cts_pulse_duration;
int dsr_pulse_duration;
int dcd_pulse_duration;
int ri_pulse_duration;
bool no_reconnect;
auto_connect_t auto_connect;
bool log;
bool log_append;
bool log_strip;
bool local_echo;
timestamp_t timestamp;
char *log_filename;
char *log_directory;
char *socket;
int color;
input_mode_t input_mode;
output_mode_t output_mode;
char prefix_code;
char prefix_key;
bool prefix_enabled;
bool mute;
bool rs485;
uint32_t rs485_config_flags;
int32_t rs485_delay_rts_before_send;
int32_t rs485_delay_rts_after_send;
alert_t alert;
bool complete_profiles;
char *script;
char *script_filename;
script_run_t script_run;
int timestamp_timeout;
char *exclude_devices;
char *exclude_drivers;
char *exclude_tids;
int hex_n_value;
bool vt100;
char *exec;
bool map_i_nl_cr;
bool map_i_cr_nl;
bool map_ign_cr;
bool map_i_ff_escc;
bool map_i_nl_crnl;
bool map_i_cr_crnl;
bool map_o_cr_nl;
bool map_o_nl_crnl;
bool map_o_del_bs;
bool map_o_ltu;
bool map_o_nulbrk;
bool map_i_msb2lsb;
bool map_o_ign_cr;
};
extern struct option_t option;
void options_print();
void options_parse(int argc, char *argv[]);
void options_parse_final(int argc, char *argv[]);
int option_string_to_integer(const char *string, int *value, const char *desc, int min, int max);
void option_parse_flow(const char *arg, flow_t *flow);
void option_parse_parity(const char *arg, parity_t *parity);
void option_parse_output_mode(const char *arg, output_mode_t *mode);
void option_parse_input_mode(const char *arg, input_mode_t *mode);
void option_parse_line_pulse_duration(const char *arg);
void option_parse_script_run(const char *arg, script_run_t *script_run);
void option_parse_alert(const char *arg, alert_t *alert);
void option_parse_auto_connect(const char *arg, auto_connect_t *auto_connect);
const char *option_auto_connect_state_to_string(auto_connect_t strategy);
void option_parse_timestamp(const char *arg, timestamp_t *timestamp);
const char* option_timestamp_format_to_string(timestamp_t timestamp);
void option_parse_mappings(const char *map);

112
src/print.c Normal file
View file

@ -0,0 +1,112 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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 "print.h"
bool print_tainted = false;
char ansi_format[30];
void print_hex(char c)
{
print_tainted = true;
printf("%02x ", (unsigned char) c);
}
void print_normal(char c)
{
print_tainted = true;
putchar(c);
}
void print_init_ansi_formatting()
{
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);
}
}
void tio_printf_array(const char *array)
{
int i = 0, j = 0;
tio_printf("");
while (array[i])
{
if (array[i] == '\n')
{
const char *line = &array[j];
char *line_copy = strndup(line, i-j);
tio_printf_raw("%s\r", line_copy);
free(line_copy);
j = i;
}
i++;
}
tio_printf("");
}
void print_tainted_set()
{
print_tainted = true;
}
void print(const char *format, ...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
fflush(stdout);
va_end(args);
print_tainted = true;
}
void print_padded(char *string, size_t length, char pad_char)
{
size_t padding = 0;
size_t string_length = 0;
size_t i;
string_length = strlen(string);
if (string_length < length)
{
padding += length - string_length;
printf("%s", string);
for (i=0; i<padding; i++)
{
putchar(pad_char);
}
}
else
{
printf("%s", string);
}
}

143
src/print.h Normal file
View file

@ -0,0 +1,143 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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
#include <stdio.h>
#include <stdbool.h>
#include "error.h"
#include "options.h"
#include "timestamp.h"
extern bool print_tainted;
extern char ansi_format[];
#define ANSI_RESET "\e[0m"
#define ansi_printf(format, args...) \
{ \
if (!option.mute) \
{ \
if (option.color < 0) \
fprintf (stdout, "\r" format "\r\n", ## args); \
else \
fprintf (stdout, "\r%s" format ANSI_RESET "\r\n", ansi_format, ## args); \
} \
}
#define ansi_error_printf(format, args...) \
{ \
if (!option.mute) \
{ \
if (option.color < 0) \
fprintf (stderr, "\r" format "\r\n", ## args); \
else \
fprintf (stderr, "\r%s" format ANSI_RESET "\r\n", ansi_format, ## args); \
fflush(stderr); \
} \
}
#define ansi_printf_raw(format, args...) \
{ \
if (!option.mute) \
{ \
if (option.color < 0) \
fprintf (stdout, format, ## args); \
else \
fprintf (stdout, "%s" format ANSI_RESET, ansi_format, ## args); \
} \
}
#define tio_warning_printf(format, args...) \
{ \
if (!option.mute) \
{ \
if (print_tainted) \
putchar('\n'); \
if (option.color < 0) \
fprintf (stdout, "\r[%s] Warning: " format "\r\n", timestamp_current_time(), ## args); \
else \
ansi_printf("[%s] Warning: " format, timestamp_current_time(), ## args); \
print_tainted = false; \
} \
}
#define tio_error_print(format, args...) \
{ \
if (!option.mute) \
{ \
if (print_tainted) \
putchar('\n'); \
if (option.color < 0) { \
if (error_normal) \
fprintf (stderr, "Error: " format "\n", ## args); \
else \
fprintf (stderr, "\r[%s] Error: " format "\r\n", timestamp_current_time(), ## args); \
} \
else { \
if (error_normal) \
{ ansi_error_printf("Error: " format, ## args); }\
else \
{ ansi_error_printf("[%s] Error: " format, timestamp_current_time(), ## args); }\
} \
print_tainted = false; \
} \
}
#define tio_printf(format, args...) \
{ \
if (!option.mute) \
{ \
if (print_tainted) \
putchar('\n'); \
ansi_printf("[%s] " format, timestamp_current_time(), ## args); \
print_tainted = false; \
} \
}
#define tio_printf_raw(format, args...) \
{ \
if (!option.mute) \
{ \
if (print_tainted) \
putchar('\n'); \
ansi_printf_raw("[%s] " format, timestamp_current_time(), ## args); \
print_tainted = false; \
} \
}
#ifdef DEBUG
#define tio_debug_printf(format, args...) \
fprintf(stdout, "[debug] " format, ## args)
#define tio_debug_printf_raw(format, args...) \
fprintf(stdout, "" format, ## args)
#else
#define tio_debug_printf(format, args...)
#define tio_debug_printf_raw(format, args...)
#endif
void print(const char *format, ...);
void print_hex(char c);
void print_normal(char c);
void print_init_ansi_formatting(void);
void tio_printf_array(const char *array);
void print_tainted_set(void);
void print_padded(char *string, size_t length, char pad_char);

276
src/readline.c Normal file
View file

@ -0,0 +1,276 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2024 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 "print.h"
#include "misc.h"
#define RL_LINE_LENGTH_MAX PATH_MAX
#define RL_HISTORY_MAX 1000
static char rl_line[RL_LINE_LENGTH_MAX] = {};
static char *rl_history[RL_HISTORY_MAX];
static int rl_history_count = 0;
static int rl_history_index = 0;
static int rl_line_length = 0;
static int rl_cursor_pos = 0;
static int rl_escape = 0;
static void print_line(const char *string, int cursor_pos)
{
clear_line();
print("%s", string);
print("\r"); // Move the cursor back to the beginning
for (int i = 0; i < cursor_pos; ++i)
{
print("\x1b[C"); // Move the cursor right
}
}
void readline_init(void)
{
rl_history_count = 0;
rl_history_index = 0;
for (int i = 0; i < RL_HISTORY_MAX; ++i)
{
rl_history[i] = NULL;
}
rl_line[0] = 0;
rl_line_length = 0;
rl_cursor_pos = 0;
rl_escape = 0;
}
char * readline_get(void)
{
return rl_line;
}
static void readline_input_char(char input_char)
{
if (rl_line_length < RL_LINE_LENGTH_MAX - 1)
{
memmove(&rl_line[rl_cursor_pos + 1], &rl_line[rl_cursor_pos], rl_line_length - rl_cursor_pos);
rl_line[rl_cursor_pos] = input_char;
rl_line_length++;
rl_cursor_pos++;
rl_line[rl_line_length] = '\0';
print_line(rl_line, rl_cursor_pos);
}
rl_escape = 0;
}
static void readline_input_cr(void)
{
if (rl_line_length > 0)
{
// Save to history
if (rl_history_count < RL_HISTORY_MAX)
{
rl_history[rl_history_count] = strndup(rl_line, rl_line_length);
rl_history_count++;
}
else
{
free(rl_history[0]);
memmove(&rl_history[0], &rl_history[1], (RL_HISTORY_MAX - 1) * sizeof(char*));
rl_history[RL_HISTORY_MAX - 1] = strndup(rl_line, rl_line_length);
}
}
rl_line[rl_line_length] = '\0';
if (option.local_echo == false)
{
clear_line();
}
else
{
print("\r\n");
}
rl_line_length = 0;
rl_cursor_pos = 0;
rl_history_index = rl_history_count;
rl_escape = 0;
}
static void readline_input_bs(void)
{
if (rl_cursor_pos > 0)
{
memmove(&rl_line[rl_cursor_pos - 1], &rl_line[rl_cursor_pos], rl_line_length - rl_cursor_pos);
rl_line_length--;
rl_cursor_pos--;
rl_line[rl_line_length] = '\0';
print_line(rl_line, rl_cursor_pos);
}
rl_escape = 0;
}
static void readline_input_escape(void)
{
rl_escape = 1;
}
static void readline_input_left_bracket(void)
{
if (rl_escape == 1)
{
rl_escape = 2;
}
else
{
rl_escape = 0;
}
}
static void readline_input_A(void)
{
if (rl_escape == 2)
{
// Up arrow
if (rl_history_index > 0)
{
rl_history_index--;
strncpy(rl_line, rl_history[rl_history_index], RL_LINE_LENGTH_MAX-1);
rl_line_length = strlen(rl_line);
rl_cursor_pos = rl_line_length;
print_line(rl_line, rl_cursor_pos);
}
}
else
{
readline_input_char('A');
}
rl_escape = 0;
}
static void readline_input_B(void)
{
if (rl_escape == 2)
{
// Down arrow
if (rl_history_index < rl_history_count - 1)
{
rl_history_index++;
strncpy(rl_line, rl_history[rl_history_index], RL_LINE_LENGTH_MAX-1);
rl_line_length = strlen(rl_line);
rl_cursor_pos = rl_line_length;
print_line(rl_line, rl_cursor_pos);
}
else if (rl_history_index == rl_history_count - 1)
{
rl_history_index++;
rl_line_length = 0;
rl_cursor_pos = 0;
rl_line[rl_line_length] = '\0';
print_line(rl_line, rl_cursor_pos);
}
}
else
{
readline_input_char('B');
}
rl_escape = 0;
}
static void readline_input_C(void)
{
if (rl_escape == 2)
{
// Right arrow
if (rl_cursor_pos < rl_line_length)
{
rl_cursor_pos++;
print("\x1b[C");
}
}
else
{
readline_input_char('C');
}
rl_escape = 0;
}
static void readline_input_D(void)
{
if (rl_escape == 2)
{
// Left arrow
if (rl_cursor_pos > 0)
{
rl_cursor_pos--;
print("\b");
}
}
else
{
readline_input_char('D');
}
rl_escape = 0;
}
void readline_input(char input_char)
{
switch (input_char)
{
case '\r': // Carriage return
readline_input_cr();
break;
case 127: // Backspace
readline_input_bs();
break;
case 27: // Escape
readline_input_escape();
break;
case '[':
readline_input_left_bracket();
break;
case 'A':
readline_input_A();
break;
case 'B':
readline_input_B();
break;
case 'C':
readline_input_C();
break;
case 'D':
readline_input_D();
break;
default:
readline_input_char(input_char);
break;
}
}

26
src/readline.h Normal file
View file

@ -0,0 +1,26 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2024 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
void readline_init(void);
void readline_input(char input_char);
char * readline_get(void);

210
src/rs485.c Normal file
View file

@ -0,0 +1,210 @@
/*
* tio - a serial device 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.
*/
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include "options.h"
#include "print.h"
#include "misc.h"
#ifdef HAVE_RS485
#include <linux/serial.h>
static struct serial_rs485 rs485_config_saved;
static struct serial_rs485 rs485_config;
static bool rs485_config_written = false;
void rs485_parse_config(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[31];
unsigned int value;
int match_count;
match_count = sscanf(token, "%30[^=]=%d", keyname, &value);
if (match_count == 2)
{
if (!strcmp(keyname, "RTS_ON_SEND"))
{
if (value)
{
/* Set logical level for RTS pin equal to 1 when sending */
option.rs485_config_flags |= SER_RS485_RTS_ON_SEND;
}
else
{
/* Set logical level for RTS pin equal to 0 when sending */
option.rs485_config_flags &= ~(SER_RS485_RTS_ON_SEND);
}
}
else if (!strcmp(keyname, "RTS_AFTER_SEND"))
{
if (value)
{
/* Set logical level for RTS pin equal to 1 after sending */
option.rs485_config_flags |= SER_RS485_RTS_AFTER_SEND;
}
else
{
/* Set logical level for RTS pin equal to 0 after sending */
option.rs485_config_flags &= ~(SER_RS485_RTS_AFTER_SEND);
}
}
else if (!strcmp(keyname, "RTS_DELAY_BEFORE_SEND"))
{
/* Set RTS delay before send */
option.rs485_delay_rts_before_send = value;
}
else if (!strcmp(keyname, "RTS_DELAY_AFTER_SEND"))
{
/* Set RTS delay after send */
option.rs485_delay_rts_after_send = value;
}
}
else if (match_count == 1)
{
if (!strcmp(keyname, "RX_DURING_TX"))
{
/* Receive data even while sending data */
option.rs485_config_flags |= SER_RS485_RX_DURING_TX;
}
}
else
{
token_found = false;
}
}
else
{
token_found = false;
}
}
free(buffer);
}
void rs485_print_config(void)
{
tio_printf(" RS-485 Configuration:");
tio_printf(" RTS_ON_SEND: %s", (rs485_config.flags & SER_RS485_RTS_ON_SEND) ? "high" : "low");
tio_printf(" RTS_AFTER_SEND: %s", (rs485_config.flags & SER_RS485_RTS_AFTER_SEND) ? "high" : "low");
tio_printf(" RTS_DELAY_BEFORE_SEND = %d", rs485_config.delay_rts_before_send);
tio_printf(" RTS_DELAY_AFTER_SEND = %d", rs485_config.delay_rts_after_send);
tio_printf(" RX_DURING_TX: %s", (rs485_config.flags & SER_RS485_RX_DURING_TX) ? "true" : "false");
}
int rs485_mode_enable(int fd)
{
/* Save existing RS-485 configuration */
ioctl (fd, TIOCGRS485, &rs485_config_saved);
/* Prepare new RS-485 configuration */
rs485_config.flags = SER_RS485_ENABLED;
rs485_config.flags |= option.rs485_config_flags;
if (option.rs485_delay_rts_before_send > 0)
{
rs485_config.delay_rts_before_send = option.rs485_delay_rts_before_send;
}
else
{
rs485_config.delay_rts_before_send = rs485_config_saved.delay_rts_before_send;
}
if (option.rs485_delay_rts_after_send > 0)
{
rs485_config.delay_rts_after_send = option.rs485_delay_rts_after_send;
}
else
{
rs485_config.delay_rts_after_send = rs485_config_saved.delay_rts_after_send;
}
/* Write new RS-485 configuration */
if (ioctl(fd, TIOCSRS485, &rs485_config) < 0)
{
tio_warning_printf("RS-485 mode is not supported by your device (%s)", strerror(errno));
return -1;
}
rs485_config_written = true;
return 0;
}
void rs485_mode_restore(int fd)
{
if (rs485_config_written)
{
/* Write saved RS-485 configuration */
if (ioctl(fd, TIOCSRS485, &rs485_config_saved) < 0)
{
tio_warning_printf("TIOCGRS485 ioctl failed (%s)", strerror(errno));
}
}
}
#else
void rs485_parse_config(const char *arg)
{
UNUSED(arg);
return;
}
void rs485_print_config(void)
{
return;
}
int rs485_mode_enable(int fd)
{
UNUSED(fd);
tio_error_printf("RS485 mode is not supported on your system");
exit(EXIT_FAILURE);
}
void rs485_mode_restore(int fd)
{
UNUSED(fd);
return;
}
#endif

27
src/rs485.h Normal file
View file

@ -0,0 +1,27 @@
/*
* tio - a serial device 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
void rs485_parse_config(const char *arg);
int rs485_mode_enable(int fd);
void rs485_mode_restore(int fd);
void rs485_print_config(void);

547
src/script.c Normal file
View file

@ -0,0 +1,547 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2024 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>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <lauxlib.h>
#include <lualib.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include "misc.h"
#include "print.h"
#include "options.h"
#include "tty.h"
#include "xymodem.h"
#include "log.h"
#include "script.h"
#include "fs.h"
#include "timestamp.h"
#include "termios.h"
#define MAX_BUFFER_SIZE 2000 // Maximum size of circular buffer
#define READ_LINE_SIZE 4096 // read_line buffer length
static int device_fd;
static char script_init[] =
"tio.set = function(arg)\n"
" local dtr = arg.DTR or -1\n"
" local rts = arg.RTS or -1\n"
" local cts = arg.CTS or -1\n"
" local dsr = arg.DSR or -1\n"
" local cd = arg.CD or -1\n"
" local ri = arg.RI or -1\n"
" tio.line_set(dtr, rts, cts, dsr, cd, ri)\n"
"end\n"
"tio.expect = function(pattern, timeout)\n"
" local str = ''\n"
" while true do\n"
" local c = tio.read(1, timeout)\n"
" if c then\n"
" str = str .. c\n"
" if string.match(str, pattern) then\n"
" return string.match(str, pattern)\n"
" end\n"
" else\n"
" return nil, str\n"
" end\n"
" end\n"
"end\n"
"tio.alwaysecho = true\n"
"setmetatable(tio, tio)\n";
static bool alwaysecho(lua_State *L)
{
bool b;
lua_getglobal(L, "tio");
lua_getfield(L, -1, "alwaysecho");
b = lua_toboolean(L, -1);
lua_pop(L, 2);
return b;
}
static int api_echo(lua_State *L)
{
size_t len = 0;
const char *str = luaL_checklstring(L, 1, &len);
if (option.timestamp)
{
char *pTimeStampNow = timestamp_current_time();
if (pTimeStampNow)
{
tio_printf("%s", str);
if (option.log)
{
log_printf("\n[%s] %s", pTimeStampNow, str);
}
}
} else {
for (size_t i=0; i<len; i++)
{
putchar(str[i]);
if (option.log)
log_putc(str[i]);
}
}
return 0;
}
static void maybe_echo(lua_State *L)
{
if (alwaysecho(L))
{
lua_pushcfunction(L, api_echo);
lua_pushvalue(L, -2);
lua_call(L, 1, 0);
}
}
// lua: tio.sleep(seconds)
static int api_sleep(lua_State *L)
{
long seconds = lua_tointeger(L, 1);
if (seconds < 0)
{
return 0;
}
tio_printf("Sleeping %ld seconds", seconds);
sleep(seconds);
return 0;
}
// lua: tio.msleep(miliseconds)
static int api_msleep(lua_State *L)
{
long mseconds = lua_tointeger(L, 1);
long useconds = mseconds * 1000;
if (useconds < 0)
{
return 0;
}
tio_printf("Sleeping %ld ms", mseconds);
usleep(useconds);
return 0;
}
// lua: tio.line_set(dtr,rts,cts,dsr,cd,ri)
static int line_set(lua_State *L)
{
tty_line_config_t line_config[6] = { };
int dtr = lua_tointeger(L, 1);
int rts = lua_tointeger(L, 2);
int cts = lua_tointeger(L, 3);
int dsr = lua_tointeger(L, 4);
int cd = lua_tointeger(L, 5);
int ri = lua_tointeger(L, 6);
if (dtr != -1)
{
line_config[0].mask = TIOCM_DTR;
line_config[0].value = dtr;
line_config[0].reserved = true;
}
if (rts != -1)
{
line_config[1].mask = TIOCM_RTS;
line_config[1].value = rts;
line_config[1].reserved = true;
}
if (cts != -1)
{
line_config[2].mask = TIOCM_CTS;
line_config[2].value = cts;
line_config[2].reserved = true;
}
if (dsr != -1)
{
line_config[3].mask = TIOCM_DSR;
line_config[3].value = dsr;
line_config[3].reserved = true;
}
if (cd != -1)
{
line_config[4].mask = TIOCM_CD;
line_config[4].value = cd;
line_config[4].reserved = true;
}
if (ri != -1)
{
line_config[5].mask = TIOCM_RI;
line_config[5].value = ri;
line_config[5].reserved = true;
}
tty_line_set(device_fd, line_config);
return 0;
}
// lua: tio.send(file, protocol)
static int api_send(lua_State *L)
{
const char *file = luaL_checkstring(L, 1);
int protocol = luaL_checkinteger(L, 2);
int ret;
if (file == NULL)
{
return 0;
}
switch (protocol)
{
case XMODEM_1K:
tio_printf("Sending file '%s' using XMODEM-1K", file);
ret = xymodem_send(device_fd, file, XMODEM_1K);
tio_printf("%s", ret < 0 ? "Aborted" : "Done");
break;
case XMODEM_CRC:
tio_printf("Sending file '%s' using XMODEM-CRC", file);
ret = xymodem_send(device_fd, file, XMODEM_CRC);
tio_printf("%s", ret < 0 ? "Aborted" : "Done");
break;
case YMODEM:
tio_printf("Sending file '%s' using YMODEM", file);
ret = xymodem_send(device_fd, file, YMODEM);
tio_printf("%s", ret < 0 ? "Aborted" : "Done");
break;
}
return 0;
}
// lua: tio.write(string)
static int api_write(lua_State *L)
{
size_t len = 0;
const char *string = luaL_checklstring(L, 1, &len);
ssize_t ret;
int attempts = 100;
do {
ret = write(device_fd, string, len);
if (ret < 0)
return luaL_error(L, "%s", strerror(errno));
len -= ret;
string += ret;
} while (len > 0 && --attempts);
if (len > 0)
return luaL_error(L, "partial write");
fsync(device_fd); // flush these characters now
tcdrain(device_fd); //ensure we flushed characters to our device
lua_getglobal(L, "tio");
return 1;
}
// lua: tio.read(size, timeout)
static int api_read(lua_State *L)
{
int size = luaL_checkinteger(L, 1);
int timeout = lua_tointeger(L, 2);
if (timeout == 0)
{
timeout = -1; // Wait forever
}
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
#if LUA_VERSION_NUM >= 502
char *p = luaL_prepbuffsize(&buffer, size);
#else
if (size > LUAL_BUFFERSIZE)
return luaL_error(L, "buffer overflow, max size is: %d", LUAL_BUFFERSIZE);
char *p = luaL_prepbuffer(&buffer);
#endif
ssize_t ret = read_poll(device_fd, p, size, timeout);
if (ret < 0)
return luaL_error(L, "%s", strerror(errno));
luaL_addsize(&buffer, ret);
luaL_pushresult(&buffer);
if (ret == 0)
{
// On timeout return nil instead of an empty string
lua_pop(L, 1);
lua_pushnil(L);
}
else
{
maybe_echo(L);
}
return 1;
}
// lua: string = tio.readline(timeout)
static int api_readline(lua_State *L) {
int timeout = lua_tointeger(L, 1); //ms
luaL_Buffer b;
char ch;
if (timeout == 0)
{
timeout = -1; // Wait forever
}
luaL_buffinit(L, &b);
luaL_prepbuffer(&b);
while (true) {
int ret = read_poll(device_fd, &ch, 1, timeout);
if (ret < 0)
return luaL_error(L, "%s", strerror(errno));
if (ret == 0)
{
luaL_pushresult(&b);
maybe_echo(L);
lua_pushnil(L);
lua_insert(L, -2);
return 2;
}
if (ch == '\n')
{
luaL_pushresult(&b);
maybe_echo(L);
return 1;
}
luaL_addchar(&b, ch);
}
}
// lua: table = tio.ttysearch()
static int api_ttysearch(lua_State *L)
{
UNUSED(L);
GList *iter;
int i = 1;
GList *device_list = tty_search_for_serial_devices();
if (device_list == NULL)
{
return 0;
}
// Create a new table
lua_newtable(L);
// Iterate through found devices
for (iter = device_list; iter != NULL; iter = g_list_next(iter))
{
device_t *device = (device_t *) iter->data;
// Create a new sub-table for each serial device
lua_newtable(L);
// Add elements to the table
lua_pushstring(L, "path");
lua_pushstring(L, device->path);
lua_settable(L, -3);
lua_pushstring(L, "tid");
lua_pushstring(L, device->tid);
lua_settable(L, -3);
lua_pushstring(L, "uptime");
lua_pushnumber(L, device->uptime);
lua_settable(L, -3);
lua_pushstring(L, "driver");
lua_pushstring(L, device->driver);
lua_settable(L, -3);
lua_pushstring(L, "description");
lua_pushstring(L, device->description);
lua_settable(L, -3);
// Set the sub-table as a row in the main table
lua_rawseti(L, -2, i++);
}
// Return table
return 1;
}
static void script_buffer_run(lua_State *L, const char *script_buffer)
{
int error;
error = luaL_loadbuffer(L, script_buffer, strlen(script_buffer), "tio") ||
lua_pcall(L, 0, 0, 0);
if (error)
{
tio_warning_printf("lua: %s\n", lua_tostring(L, -1));
lua_pop(L, 1); /* Pop error message from the stack */
}
}
static void script_file_run(lua_State *L, const char *filename)
{
if (strlen(filename) == 0)
{
tio_warning_printf("Missing script filename\n");
return;
}
if (luaL_dofile(L, filename))
{
tio_warning_printf("lua: %s", lua_tostring(L, -1));
lua_pop(L, 1); /* pop error message from the stack */
return;
}
}
static const struct luaL_Reg tio_lib[] =
{
{ "echo", api_echo},
{ "sleep", api_sleep},
{ "msleep", api_msleep},
{ "line_set", line_set},
{ "send", api_send},
{ "write", api_write},
{ "read", api_read},
{ "readline", api_readline},
{ "ttysearch", api_ttysearch},
{NULL, NULL}
};
static void script_load(lua_State *L)
{
int error;
error = luaL_loadbuffer(L, script_init, strlen(script_init), "tio") || lua_pcall(L, 0, 0, 0);
if (error)
{
tio_error_print("%s\n", lua_tostring(L, -1));
lua_pop(L, 1); // Pop error message from the stack
}
}
static void script_set_global(lua_State *L, const char *name, long value)
{
lua_pushnumber(L, value);
lua_setglobal(L, name);
}
static void script_set_globals(lua_State *L)
{
script_set_global(L, "toggle", 2);
script_set_global(L, "high", 1);
script_set_global(L, "low", 0);
script_set_global(L, "XMODEM_CRC", XMODEM_CRC);
script_set_global(L, "XMODEM_1K", XMODEM_1K);
script_set_global(L, "YMODEM", YMODEM);
}
#if LUA_VERSION_NUM >= 502
static int luaopen_tio(lua_State *L)
{
luaL_newlib(L, tio_lib);
return 1;
}
#endif
void script_run(int fd, const char *script_filename)
{
lua_State *L;
device_fd = fd;
L = luaL_newstate();
luaL_openlibs(L);
#if LUA_VERSION_NUM >= 502
luaL_requiref(L, "tio", luaopen_tio, 1);
#else
luaL_register(L, "tio", tio_lib);
#endif
lua_pop(L, 1);
// Load lua init script
script_load(L);
// Initialize globals
script_set_globals(L);
if (script_filename != NULL)
{
tio_printf("Running script %s", script_filename);
script_file_run(L, script_filename);
}
else if (option.script_filename != NULL)
{
tio_printf("Running script %s", option.script_filename);
script_file_run(L, option.script_filename);
}
else if (option.script != NULL)
{
tio_printf("Running script");
script_buffer_run(L, option.script);
}
lua_close(L);
}
const char *script_run_state_to_string(script_run_t state)
{
switch (state)
{
case SCRIPT_RUN_ONCE:
return "once";
case SCRIPT_RUN_ALWAYS:
return "always";
case SCRIPT_RUN_NEVER:
return "never";
default:
return "Unknown";
}
}

33
src/script.h Normal file
View file

@ -0,0 +1,33 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2024 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
typedef enum
{
SCRIPT_RUN_ONCE,
SCRIPT_RUN_ALWAYS,
SCRIPT_RUN_NEVER,
SCRIPT_RUN_END,
} script_run_t;
void script_run(int fd, const char *script_filename);
const char *script_run_state_to_string(script_run_t state);

72
src/setspeed.c Normal file
View file

@ -0,0 +1,72 @@
/*
* tio - a serial device 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
#include "misc.h"
#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)
{
UNUSED(fd);
UNUSED(baudrate);
errno = EINVAL;
return -1;
}
#endif

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* 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
@ -19,10 +19,6 @@
* 02110-1301, USA.
*/
#ifndef TIME_H
#define TIME_H
#pragma once
char * current_time(void);
void delay(long ms);
#endif
int setspeed(int fd, int baudrate);

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* 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
@ -22,35 +22,30 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "tio/error.h"
#include "tio/print.h"
#include <signal.h>
#include <errno.h>
#include "error.h"
#include "print.h"
#include "misc.h"
#include "tty.h"
char * current_time(void)
static void signal_handler(int signum)
{
static char time_string[20];
time_t t;
struct tm *tmp;
t = time(NULL);
tmp = localtime(&t);
if (tmp == NULL)
switch (signum)
{
error_printf("Retrieving local time failed");
exit(EXIT_FAILURE);
case SIGHUP:
tio_printf("Received SIGHUP signal!");
break;
case SIGINT:
tio_printf("Received SIGINT signal!");
break;
}
strftime(time_string, sizeof(time_string), "%H:%M:%S", tmp);
return time_string;
exit(EXIT_FAILURE);
}
void delay(long ms)
void signal_handlers_install(void)
{
struct timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000000;
nanosleep(&ts, NULL);
signal(SIGHUP, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGPIPE, SIG_IGN);
}

24
src/signals.h Normal file
View file

@ -0,0 +1,24 @@
/*
* tio - a serial device 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
void signal_handlers_install();

384
src/socket.c Normal file
View file

@ -0,0 +1,384 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2022 Martin Lund
* Copyright (c) 2022 Google LLC
*
* 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>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <unistd.h>
#include <string.h>
#include "socket.h"
#include "options.h"
#include "print.h"
#include "tty.h"
#define MAX_SOCKET_CLIENTS 16
#define SOCKET_PORT_DEFAULT 3333
static int sockfd;
static int clientfds[MAX_SOCKET_CLIENTS];
static int socket_family = AF_UNSPEC;
static int port_number = SOCKET_PORT_DEFAULT;
static const char *socket_filename(void)
{
/* skip 'unix:' */
return option.socket + 5;
}
static int socket_inet_port(void)
{
/* skip 'inet:' */
int port = atoi(option.socket + 5);
if (port == 0)
{
port = SOCKET_PORT_DEFAULT;
}
return port;
}
static int socket_inet6_port(void)
{
/* skip 'inet6:' */
int port = atoi(option.socket + 6);
if (port == 0)
{
port = SOCKET_PORT_DEFAULT;
}
return port;
}
static void socket_exit(void)
{
if (socket_family == AF_UNIX)
{
unlink(socket_filename());
}
}
static bool socket_stale(const char *path)
{
struct sockaddr_un addr;
bool stale = false;
int sfd;
/* Test if socket file exists */
if (access(path, F_OK) == 0)
{
/* Create test socket */
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd < 0)
{
tio_warning_printf("Failure opening socket (%s)", strerror(errno));
return false;
}
/* Prepare address */
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
/* Perform connect to test if socket is active */
if (connect(sockfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
{
if (errno == ECONNREFUSED)
{
// No one is listening on socket file
stale = true;
}
}
/* Cleanup */
close(sockfd);
}
return stale;
}
void socket_configure(void)
{
struct sockaddr_un sockaddr_unix = {};
struct sockaddr_in sockaddr_inet = {};
struct sockaddr_in6 sockaddr_inet6 = {};
struct sockaddr *sockaddr_p;
socklen_t socklen;
int optval;
/* Parse socket string */
if (strncmp(option.socket, "unix:", 5) == 0)
{
socket_family = AF_UNIX;
if (strlen(socket_filename()) == 0)
{
tio_error_printf("Missing socket filename");
exit(EXIT_FAILURE);
}
if (strlen(socket_filename()) > sizeof(sockaddr_unix.sun_path) - 1)
{
tio_error_printf("Socket file path %s too long", option.socket);
exit(EXIT_FAILURE);
}
}
if (strncmp(option.socket, "inet:", 5) == 0)
{
socket_family = AF_INET;
port_number = socket_inet_port();
if (port_number < 0)
{
tio_error_printf("Invalid port number: %d", port_number);
exit(EXIT_FAILURE);
}
}
if (strncmp(option.socket, "inet6:", 6) == 0)
{
socket_family = AF_INET6;
port_number = socket_inet6_port();
if (port_number < 0)
{
tio_error_printf("Invalid port number: %d", port_number);
exit(EXIT_FAILURE);
}
}
if (socket_family == AF_UNSPEC)
{
tio_error_printf("%s: Invalid socket scheme, must be prefixed with 'unix:', 'inet:', or 'inet6:'", option.socket);
exit(EXIT_FAILURE);
}
/* Configure socket */
switch (socket_family)
{
case AF_UNIX:
sockaddr_unix.sun_family = AF_UNIX;
strncpy(sockaddr_unix.sun_path, socket_filename(), sizeof(sockaddr_unix.sun_path) - 1);
sockaddr_p = (struct sockaddr *) &sockaddr_unix;
socklen = sizeof(sockaddr_unix);
/* Test for stale unix socket file */
if (socket_stale(socket_filename()))
{
tio_printf("Cleaning up old socket file");
unlink(socket_filename());
}
break;
case AF_INET:
sockaddr_inet.sin_family = AF_INET;
sockaddr_inet.sin_addr.s_addr = INADDR_ANY;
sockaddr_inet.sin_port = htons(port_number);
sockaddr_p = (struct sockaddr *) &sockaddr_inet;
socklen = sizeof(sockaddr_inet);
break;
case AF_INET6:
sockaddr_inet6.sin6_family = AF_INET6;
sockaddr_inet6.sin6_addr = in6addr_any;
sockaddr_inet6.sin6_port = htons(port_number);
sockaddr_p = (struct sockaddr *) &sockaddr_inet6;
socklen = sizeof(sockaddr_inet6);
break;
default:
tio_error_printf("Invalid socket family (%d)", socket_family);
exit(EXIT_FAILURE);
break;
}
/* Create socket */
sockfd = socket(socket_family, SOCK_STREAM, 0);
if (sockfd < 0)
{
tio_error_printf("Failed to create socket (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_NOSIGPIPE, &optval, sizeof(optval)))
#else
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)))
#endif
{
tio_error_printf("Failed to set socket options (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
/* Bind */
if (bind(sockfd, sockaddr_p, socklen) < 0)
{
tio_error_printf("Failed to bind to socket (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
/* Listen */
if (listen(sockfd, MAX_SOCKET_CLIENTS) < 0)
{
tio_error_printf("Failed to listen on socket (%s)", strerror(errno));
exit(EXIT_FAILURE);
}
memset(clientfds, -1, sizeof(clientfds));
atexit(socket_exit);
if (socket_family == AF_UNIX)
{
tio_printf("Listening on socket %s", socket_filename());
}
else
{
tio_printf("Listening on socket port %d", port_number);
}
}
void socket_write(char input_char)
{
if (!option.socket)
{
return;
}
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
{
if (clientfds[i] != -1)
{
#if defined(SO_NOSIGPIPE) && !defined(MSG_NOSIGNAL)
if (send(clientfds[i], &input_char, 1, 0) <= 0)
#else
if (send(clientfds[i], &input_char, 1, MSG_NOSIGNAL) <= 0)
#endif
{
tio_error_printf_silent("Failed to write to socket (%s)", strerror(errno));
close(clientfds[i]);
clientfds[i] = -1;
}
}
}
}
int socket_add_fds(fd_set *rdfs, bool connected)
{
if (!option.socket)
{
return 0;
}
int numclients = 0, maxfd = 0;
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
{
if (clientfds[i] != -1)
{
/* let clients block if they try to send while we're disconnected */
if (connected)
{
FD_SET(clientfds[i], rdfs);
maxfd = MAX(maxfd, clientfds[i]);
}
numclients++;
}
}
/* don't bother to accept clients if we're already full */
if (numclients != MAX_SOCKET_CLIENTS)
{
FD_SET(sockfd, rdfs);
maxfd = MAX(maxfd, sockfd);
}
return maxfd;
}
bool socket_handle_input(fd_set *rdfs, char *output_char)
{
if (!option.socket)
{
return false;
}
if (FD_ISSET(sockfd, rdfs))
{
int clientfd = accept(sockfd, NULL, NULL);
/* this loop should always succeed because we don't select on sockfd when full */
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
{
if (clientfds[i] == -1)
{
clientfds[i] = clientfd;
break;
}
}
}
for (int i = 0; i != MAX_SOCKET_CLIENTS; ++i)
{
if (clientfds[i] != -1 && FD_ISSET(clientfds[i], rdfs))
{
int status = read(clientfds[i], output_char, 1);
if (status == 0)
{
close(clientfds[i]);
clientfds[i] = -1;
continue;
}
if (status < 0)
{
tio_error_printf_silent("Failed to read from socket (%s)", strerror(errno));
close(clientfds[i]);
clientfds[i] = -1;
continue;
}
/* If INLCR is set, a received NL character shall be translated into a CR character */
if (*output_char == '\n' && option.map_i_nl_cr)
{
*output_char = '\r';
}
else if (*output_char == '\r')
{
/* If IGNCR is set, a received CR character shall be ignored (not read). */
if (option.map_ign_cr)
{
return false;
}
/* If IGNCR is not set and ICRNL is set, a received CR character shall be translated into an NL character. */
if (option.map_i_cr_nl)
{
*output_char = '\n';
}
}
return true;
}
}
return false;
}

31
src/socket.h Normal file
View file

@ -0,0 +1,31 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2022 Martin Lund
* Copyright (c) 2022 Google LLC
*
* 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
#include <stdbool.h>
#include <sys/select.h>
void socket_configure(void);
void socket_write(char input_char);
int socket_add_fds(fd_set *fds, bool connected);
bool socket_handle_input(fd_set *fds, char *output_char);

104
src/timestamp.c Normal file
View file

@ -0,0 +1,104 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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 "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include "error.h"
#include "print.h"
#include "options.h"
#include "timestamp.h"
char *timestamp_current_time(void)
{
static char time_string[TIME_STRING_SIZE_MAX];
static struct timeval tv, tv_now, tv_start, tv_previous;
static bool first = true;
struct tm *tm;
size_t len;
// Get current time value
gettimeofday(&tv_now, NULL);
if (first)
{
tv_start = tv_now;
first = false;
}
// Add formatted timestamp
switch (option.timestamp)
{
case TIMESTAMP_NONE:
case TIMESTAMP_24HOUR:
// "hh:mm:ss.sss" (24 hour format)
tv = tv_now;
tm = localtime(&tv.tv_sec);
len = strftime(time_string, sizeof(time_string), "%H:%M:%S", tm);
break;
case TIMESTAMP_24HOUR_START:
// "hh:mm:ss.sss" (24 hour format relative to start time)
timersub(&tv_now, &tv_start, &tv);
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);
tm = gmtime(&tv.tv_sec);
len = strftime(time_string, sizeof(time_string), "%H:%M:%S", tm);
break;
case TIMESTAMP_ISO8601:
// "YYYY-MM-DDThh:mm:ss.sss" (ISO-8601)
tv = tv_now;
tm = localtime(&tv.tv_sec);
len = strftime(time_string, sizeof(time_string), "%Y-%m-%dT%H:%M:%S", tm);
break;
case TIMESTAMP_EPOCH:
case TIMESTAMP_EPOCH_USEC:
// "N.sss" (seconds since Unix epoch, 1970-01-01 00:00:00Z)
tv = tv_now;
tm = localtime(&tv.tv_sec);
len = strftime(time_string, sizeof(time_string), "%s", tm);
break;
default:
return NULL;
}
// Append millis-/microseconds to all timestamps
if (len)
{
if ( option.timestamp == TIMESTAMP_EPOCH_USEC )
{
len = snprintf(time_string + len, TIME_STRING_SIZE_MAX - len, ".%06ld", (long)tv.tv_usec);
}
else
{
len = snprintf(time_string + len, TIME_STRING_SIZE_MAX - len, ".%03ld", (long)tv.tv_usec / 1000);
}
}
// Save previous time value for next run
tv_previous = tv_now;
return (len < TIME_STRING_SIZE_MAX) ? time_string : NULL;
}

View file

@ -1,7 +1,7 @@
/*
* tio - a simple TTY terminal I/O application
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2017 Martin Lund
* Copyright (c) 2014-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
@ -19,28 +19,21 @@
* 02110-1301, USA.
*/
#ifndef TTY_H
#define TTY_H
#pragma once
#define KEY_QUESTION 0x3f
#define KEY_B 0x62
#define KEY_C 0x63
#define KEY_H 0x68
#define KEY_L 0x6C
#define KEY_Q 0x71
#define KEY_S 0x73
#define KEY_T 0x74
#define KEY_CTRL_T 0x14
typedef enum
{
TIMESTAMP_NONE,
TIMESTAMP_24HOUR,
TIMESTAMP_24HOUR_START,
TIMESTAMP_24HOUR_DELTA,
TIMESTAMP_ISO8601,
TIMESTAMP_EPOCH,
TIMESTAMP_EPOCH_USEC,
TIMESTAMP_END,
} timestamp_t;
#define NORMAL 0
#define HEX 1
#define TIME_STRING_SIZE_MAX 24
void stdout_configure(void);
void stdout_restore(void);
void stdin_configure(void);
void stdin_restore(void);
void tty_configure(void);
int tty_connect(void);
void tty_wait_for_device(void);
char *timestamp_current_time(void);
#endif

2803
src/tty.c

File diff suppressed because it is too large Load diff

86
src/tty.h Normal file
View file

@ -0,0 +1,86 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-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
#include <stdbool.h>
#include <glib.h>
#define LINE_HIGH true
#define LINE_LOW false
#define TOPOLOGY_ID_SIZE 4
typedef enum
{
FLOW_NONE,
FLOW_HARD,
FLOW_SOFT,
} flow_t;
typedef enum
{
PARITY_NONE,
PARITY_ODD,
PARITY_EVEN,
PARITY_MARK,
PARITY_SPACE,
} parity_t;
typedef enum
{
AUTO_CONNECT_DIRECT,
AUTO_CONNECT_NEW,
AUTO_CONNECT_LATEST,
AUTO_CONNECT_END,
} auto_connect_t;
typedef struct
{
char *tid;
double uptime;
char *path;
char *driver;
char *description;
} device_t;
typedef struct
{
int mask;
int value;
bool reserved;
} tty_line_config_t;
extern const char *device_name;
extern bool interactive_mode;
void stdout_configure(void);
void stdin_configure(void);
void tty_configure(void);
void tty_reconfigure(void);
int tty_connect(void);
void tty_wait_for_device(void);
void list_serial_devices(void);
void tty_input_thread_create(void);
void tty_input_thread_wait_ready(void);
void tty_line_set(int fd, tty_line_config_t line_config[]);
void tty_search(void);
GList *tty_search_for_serial_devices(void);

3
src/version.h.in Normal file
View file

@ -0,0 +1,3 @@
#pragma once
#define VERSION "@VERSION@"

739
src/xymodem.c Normal file
View file

@ -0,0 +1,739 @@
/*
* Minimalistic implementation of the xmodem-1k and ymodem sender protocol.
* https://en.wikipedia.org/wiki/XMODEM
* https://en.wikipedia.org/wiki/YMODEM
*
* SPDX-License-Identifier: GPL-2.0-or-later OR MIT-0
*
*/
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <termios.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <poll.h>
#include "xymodem.h"
#include "print.h"
#include "misc.h"
#define SOH 0x01
#define STX 0x02
#define ACK 0x06
#define NAK 0x15
#define CAN 0x18
#define EOT 0x04
#define SOH_STR "\001"
#define ACK_STR "\006"
#define NAK_STR "\025"
#define CAN_STR "\030"
#define EOT_STR "\004"
#define OK 0
#define ERR (-1)
#define ERR_FATAL (-2)
#define USER_CAN (-5)
#define RX_IGNORE 5
#define min(a, b) ((a) < (b) ? (a) : (b))
struct xpacket_1k {
uint8_t type;
uint8_t seq;
uint8_t nseq;
uint8_t data[1024];
uint8_t crc_hi;
uint8_t crc_lo;
} __attribute__((packed));
struct xpacket {
uint8_t type;
uint8_t seq;
uint8_t nseq;
uint8_t data[128];
uint8_t crc_hi;
uint8_t crc_lo;
} __attribute__((packed));
/* See https://en.wikipedia.org/wiki/Computation_of_cyclic_redundancy_checks */
static uint16_t crc16(const uint8_t *data, uint16_t size)
{
uint16_t crc, s;
for (crc = 0; size > 0; size--) {
s = *data++ ^ (crc >> 8);
s ^= (s >> 4);
crc = (crc << 8) ^ s ^ (s << 5) ^ (s << 12);
}
return crc;
}
static int xmodem_1k(int sio, const void *data, size_t len, int seq)
{
struct xpacket_1k packet;
const uint8_t *buf = data;
char resp = 0;
int rc, crc;
/* Drain pending characters from serial line. Insist on the
* last drained character being 'C'.
*/
while(1) {
if (key_hit)
return -1;
rc = read_poll(sio, &resp, 1, 50);
if (rc == 0) {
if (resp == 'C') break;
if (resp == CAN) return ERR;
continue;
}
else if (rc < 0) {
tio_error_print("Read sync from serial failed");
return ERR;
}
}
/* Always work with 1K packets */
packet.seq = seq;
packet.type = STX;
while (len) {
size_t sz, z = 0;
char *from, status;
/* Build next packet, pad with 0 to full seq */
z = min(len, sizeof(packet.data));
memcpy(packet.data, buf, z);
memset(packet.data + z, 0, sizeof(packet.data) - z);
crc = crc16(packet.data, sizeof(packet.data));
packet.crc_hi = crc >> 8;
packet.crc_lo = crc;
packet.nseq = 0xff - packet.seq;
/* Send packet */
from = (char *) &packet;
sz = sizeof(packet);
while (sz) {
if (key_hit)
return ERR;
if ((rc = write(sio, from, sz)) < 0 ) {
if (errno == EWOULDBLOCK) {
usleep(1000);
continue;
}
tio_error_print("Write packet to serial failed");
return ERR;
}
from += rc;
sz -= rc;
}
/* Clear response */
resp = 0;
/* 'lrzsz' does not ACK ymodem's fin packet */
if (seq == 0 && packet.data[0] == 0) resp = ACK;
/* Read receiver response, timeout 1 s */
for(int n=0; n < 20; n++) {
if (key_hit)
return ERR;
rc = read_poll(sio, &resp, 1, 50);
if (rc < 0) {
tio_error_print("Read ack/nak from serial failed");
return ERR;
} else if(rc > 0) {
break;
}
}
/* Update "progress bar" */
switch (resp) {
case NAK: status = 'N'; break;
case ACK: status = '.'; break;
case 'C': status = 'C'; break;
case CAN: status = '!'; return ERR;
default: status = '?';
}
write(STDOUT_FILENO, &status, 1);
/* Move to next block after ACK */
if (resp == ACK) {
packet.seq++;
len -= z;
buf += z;
}
}
/* Send EOT at 1 Hz until ACK or CAN received */
while (seq) {
if (key_hit)
return ERR;
if (write(sio, EOT_STR, 1) < 0) {
tio_error_print("Write EOT to serial failed");
return ERR;
}
write(STDOUT_FILENO, "|", 1);
/* 1s timeout */
rc = read_poll(sio, &resp, 1, 1000);
if (rc < 0) {
tio_error_print("Read from serial failed");
return ERR;
} else if(rc == 0) {
continue;
}
if (resp == ACK || resp == CAN) {
write(STDOUT_FILENO, "\r\n", 2);
return (resp == ACK) ? OK : ERR;
}
}
return 0; /* not reached */
}
static int xmodem(int sio, const void *data, size_t len)
{
struct xpacket packet;
const uint8_t *buf = data;
char resp = 0;
int rc, crc;
/* Drain pending characters from serial line. Insist on the
* last drained character being 'C'.
*/
while(1) {
if (key_hit)
return -1;
rc = read_poll(sio, &resp, 1, 50);
if (rc == 0) {
if (resp == 'C') break;
if (resp == CAN) return ERR;
continue;
}
else if (rc < 0) {
tio_error_print("Read sync from serial failed");
return ERR;
}
}
/* Always work with 128b packets */
packet.seq = 1;
packet.type = SOH;
while (len) {
size_t sz, z = 0;
char *from, status;
/* Build next packet, pad with 0 to full seq */
z = min(len, sizeof(packet.data));
memcpy(packet.data, buf, z);
memset(packet.data + z, 0, sizeof(packet.data) - z);
crc = crc16(packet.data, sizeof(packet.data));
packet.crc_hi = crc >> 8;
packet.crc_lo = crc;
packet.nseq = 0xff - packet.seq;
/* Send packet */
from = (char *) &packet;
sz = sizeof(packet);
while (sz) {
if (key_hit)
return ERR;
if ((rc = write(sio, from, sz)) < 0 ) {
if (errno == EWOULDBLOCK) {
usleep(1000);
continue;
}
tio_error_print("Write packet to serial failed");
return ERR;
}
from += rc;
sz -= rc;
}
/* Clear response */
resp = 0;
/* Read receiver response, timeout 1 s */
for(int n=0; n < 20; n++) {
if (key_hit)
return ERR;
rc = read_poll(sio, &resp, 1, 50);
if (rc < 0) {
tio_error_print("Read ack/nak from serial failed");
return ERR;
} else if(rc > 0) {
break;
}
}
/* Update "progress bar" */
switch (resp) {
case NAK: status = 'N'; break;
case ACK: status = '.'; break;
case 'C': status = 'C'; break;
case CAN: status = '!'; return ERR;
default: status = '?';
}
write(STDOUT_FILENO, &status, 1);
/* Move to next block after ACK */
if (resp == ACK) {
packet.seq++;
len -= z;
buf += z;
}
}
/* Send EOT at 1 Hz until ACK or CAN received */
while (1) {
if (key_hit)
return ERR;
if (write(sio, EOT_STR, 1) < 0) {
tio_error_print("Write EOT to serial failed");
return ERR;
}
write(STDOUT_FILENO, "|", 1);
/* 1s timeout */
rc = read_poll(sio, &resp, 1, 1000);
if (rc < 0) {
tio_error_print("Read from serial failed");
return ERR;
} else if(rc == 0) {
continue;
}
if (resp == ACK || resp == CAN) {
write(STDOUT_FILENO, "\r\n", 2);
return (resp == ACK) ? OK : ERR;
}
}
return 0; /* not reached */
}
int start_receive(int sio)
{
int rc;
struct pollfd fds;
fds.events = POLLIN;
fds.fd = sio;
for (int n = 0; n < 20; n++)
{
/* Send the 'C' byte until the sender of the file responds with
something. The start character will be sent once a second for a number of
seconds. If nothing is received in that time then return false to indicate
that the transfer did not start. */
rc = write(sio, "C", 1);
if (rc < 0) {
if (errno == EWOULDBLOCK) {
usleep(1000);
continue;
}
tio_error_print("Write packet to serial failed");
return ERR;
}
/* Wait until data is available */
rc = poll(&fds, 1, 3000);
if (rc < 0)
{
tio_error_print("%s", strerror(errno));
return rc;
}
else if (rc > 0)
{
if (fds.revents & POLLIN)
{
return rc;
}
}
if (key_hit)
return USER_CAN;
}
return rc;
}
uint16_t update_CRC(uint16_t crc, char data_char)
{
uint8_t data = data_char;
crc = crc ^ ((uint16_t)data << 8);
for (int ix = 0; (ix < 8); ix++)
{
if (crc & 0x8000)
{
crc = (crc << 1) ^ 0x1021;
}
else
{
crc <<= 1;
}
}
return crc;
}
int receive_packet(int sio, struct xpacket packet, int fd)
{
char rxSeq1, rxSeq2 = 0;
char resp = 0;
uint16_t calcCrc = 0;
uint16_t rxCrc = 0;
int rc;
struct pollfd fds;
fds.events = POLLIN;
fds.fd = sio;
/* Read seq bytes*/
rc = read_poll(sio, &rxSeq1, 1, 3000);
if (rc == 0) {
tio_error_print("Timeout waiting for first seq byte");
return ERR;
} else if (rc < 0) {
tio_error_print("Error reading first seq byte")
return ERR_FATAL;
}
rc = read_poll(sio, &rxSeq2, 1, 3000);
if (rc == 0) {
tio_error_print("Timeout waiting for second seq byte");
return ERR;
} else if (rc < 0) {
tio_error_print("Error reading second seq byte")
return ERR_FATAL;
}
if (key_hit)
return USER_CAN;
/* Read packet Data */
for (unsigned ix = 0; (ix < sizeof(packet.data)); ix++)
{
rc = read_poll(sio, &resp, 1, 3000);
/* If the read times out or fails then fail this packet. */
if (rc == 0)
{
tio_error_print("Timeout waiting for next packet char");
rc = write(sio, CAN_STR, 1);
if (rc < 0) {
tio_error_print("Write cancel packet to serial failed");
return ERR_FATAL;
}
return ERR;
} else if (rc < 0) {
tio_error_print("Error reading next packet char")
rc = write(sio, CAN_STR, 1);
if (rc < 0) {
tio_error_print("Write cancel packet to serial failed");
}
return ERR_FATAL;
}
packet.data[ix] = (uint8_t) resp;
calcCrc = update_CRC(calcCrc, resp);
if (key_hit)
return USER_CAN;
}
/* Read CRC */
rc = read_poll(sio, &resp, 1, 3000);
if (rc == 0) {
tio_error_print("Timeout waiting for first CRC byte");
return ERR;
} else if (rc < 0) {
tio_error_print("Error reading first CRC byte")
return ERR_FATAL;
}
uint8_t uresp = resp;
uint16_t uresp16 = uresp;
rxCrc = uresp16 << 8;
rc = read_poll(sio, &resp, 1, 3000);
if (rc == 0) {
tio_error_print("Timeout waiting for second CRC byte");
return ERR;
} else if (rc < 0) {
tio_error_print("Error reading second CRC byte")
return ERR_FATAL;
}
uresp = resp;
uresp16 = uresp;
rxCrc |= uresp16;
if (key_hit)
return USER_CAN;
/* At this point in the code, there should not be anything in the receive buffer
because the sender has just sent a complete packet and is waiting on a response. */
rc = poll(&fds, 1, 10);
if (rc < 0)
{
tio_error_print("%s", strerror(errno));
tio_error_print("Poll check error after packet finish");
rc = write(sio, CAN_STR, 1);
if (rc < 0) {
tio_error_print("Write cancel packet to serial failed");
}
return ERR_FATAL;
}
else if (rc > 0)
{
if (fds.revents & POLLIN)
{
tio_error_print("RX sync error");
char dummy = 0;
/* Drain buffer */
while (read_poll(sio, &dummy, 1, 100) > 0) {}
return ERR;
}
}
uint8_t tester = 0xff;
uint8_t seq1 = rxSeq1;
uint8_t seq2 = rxSeq2;
if ((calcCrc == rxCrc) && (seq1 == packet.seq - 1) && ((seq1 ^ seq2) == tester))
{
/* Resend of previously processed packet. */
rc = write(sio, ACK_STR, 1);
if (rc < 0) {
tio_error_print("Write acknowlegdement packet to serial failed");
return ERR_FATAL;
}
return RX_IGNORE;
}
else if ((calcCrc != rxCrc) || (seq1 != packet.seq) || ((seq1 ^ seq2) != tester))
{
/* Fail if the CRC or sequence number is not correct or if the two received
sequence numbers are not the complement of one another. */
tio_error_print("Bad CRC or sequence number");
tio_debug_printf("CRC read: %u", rxCrc);
tio_debug_printf("CRC calculated: %u", calcCrc);
tio_debug_printf("Seq read: %hhu", rxSeq1);
tio_debug_printf("Seq should be: %hhu", packet.seq);
tio_debug_printf("inv seq: %hhu", rxSeq2);
return ERR;
}
else
{
/* The data is good. Process the packet then ACK it to the sender. */
rc = write(fd, packet.data, sizeof(packet.data));
if (rc < 0)
{
tio_error_print("Problem writing to file");
rc = write(sio, CAN_STR, 1);
if (rc < 0) {
tio_error_print("Write cancel packet to serial failed");
}
return ERR_FATAL;
}
rc = write(sio, ACK_STR, 1);
if (rc < 0)
{
tio_error_print("Write acknowlegdement packet to serial failed");
return ERR_FATAL;
}
}
return OK;
}
int xmodem_receive(int sio, int fd)
{
struct xpacket packet;
char resp = 0;
int rc;
bool complete = false;
char status;
/* Drain pending characters from serial line.*/
while(1) {
if (key_hit)
return -1;
rc = read_poll(sio, &resp, 1, 50);
if (rc == 0) {
if (resp == CAN) return ERR;
break;
}
else if (rc < 0) {
if (rc != USER_CAN) {
tio_error_print("Read sync from serial failed");
}
return ERR;
}
}
/* Always work with 128b packets */
packet.seq = 1;
packet.type = SOH;
/* Start Receive*/
rc = start_receive(sio);
if (rc == 0)
{
tio_error_print("Timeout waiting for transfer to start");
return ERR;
} else if (rc < 0) {
tio_error_print("Error starting XMODEM receive");
return ERR;
}
while (!complete) {
/* Poll for 1 new byte for 3 seconds */
rc = read_poll(sio, &resp, 1, 3000);
if (rc == 0) {
tio_error_print("Timeout waiting for start of next packet");
return ERR;
} else if (rc < 0) {
tio_error_print("Error reading start of next packet")
return ERR;
}
if (key_hit)
return USER_CAN;
switch(resp)
{
case SOH:
/* Start of a packet */
rc = receive_packet(sio, packet, fd);
if (rc == OK) {
packet.seq++;
status = '.';
} else if (rc == ERR) {
rc = write(sio, NAK_STR, 1);
if (rc < 0) {
tio_error_print("Writing not acknowledge packet to serial failed");
return ERR;
}
status = 'N';
} else if (rc == ERR_FATAL) {
tio_error_print("Receive cancelled due to fatal error");
return ERR;
} else if (rc == USER_CAN) {
rc = write(sio, CAN_STR, 1);
if (rc < 0) {
tio_error_print("Writing cancel to serial failed");
return ERR;
}
return USER_CAN;
} else if (rc == RX_IGNORE) {
status = ':';
}
break;
case EOT:
/* End of Transfer */
rc = write(sio, ACK_STR, 1);
if (rc < 0)
{
tio_error_print("Write acknowlegdement packet to serial failed");
return ERR;
}
complete = true;
status = '\0';
write(STDOUT_FILENO, "|\r\n", 3);
break;
case CAN:
/* Cancel from sender */
tio_error_print("Transmission cancelled from sender");
return ERR;
break;
default:
tio_error_print("Unexpected character received waiting for next packet");
return ERR;
break;
}
/* Update "progress bar" */
write(STDOUT_FILENO, &status, 1);
}
return OK;
}
int xymodem_send(int sio, const char *filename, modem_mode_t mode)
{
size_t len;
int rc, fd;
struct stat stat;
const uint8_t *buf;
/* Open file, map into memory */
fd = open(filename, O_RDONLY);
if (fd < 0) {
tio_error_print("Could not open file");
return ERR;
}
fstat(fd, &stat);
len = stat.st_size;
buf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
if (!buf) {
close(fd);
tio_error_print("Could not mmap file");
return ERR;
}
/* Do transfer */
key_hit = 0;
if (mode == XMODEM_1K) {
rc = xmodem_1k(sio, buf, len, 1);
}
else if (mode == XMODEM_CRC) {
rc = xmodem(sio, buf, len);
}
else {
/* Ymodem: hdr + file + fin */
while(1) {
char hdr[1024], *p;
rc = -1;
if (strlen(filename) > 977) break; /* hdr block overrun */
p = stpncpy(hdr, filename, 1024) + 1;
p += sprintf(p, "%ld %lo %o", len, stat.st_mtime, stat.st_mode);
if (xmodem_1k(sio, hdr, p - hdr, 0) < 0) break; /* hdr with metadata */
if (xmodem_1k(sio, buf, len, 1) < 0) break; /* xmodem file */
if (xmodem_1k(sio, "", 1, 0) < 0) break; /* empty hdr = fin */
rc = 0; break;
}
}
key_hit = 0xff;
/* Flush serial and release resources */
tcflush(sio, TCIOFLUSH);
munmap((void *)buf, len);
close(fd);
return rc;
}
int xymodem_receive(int sio, const char *filename, modem_mode_t mode)
{
int rc, fd;
/* Create new file */
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (fd < 0) {
tio_error_print("Could not open file");
return ERR;
}
/* Do transfer */
key_hit = 0;
if (mode == XMODEM_1K) {
tio_error_print("Not supported");
rc = -1;
}
else if (mode == XMODEM_CRC) {
rc = xmodem_receive(sio, fd);
}
else {
tio_error_print("Not supported");
rc = -1;
}
key_hit = 0xff;
/* Flush serial and release resources */
tcflush(sio, TCIOFLUSH);
close(fd);
return rc;
}

34
src/xymodem.h Normal file
View file

@ -0,0 +1,34 @@
/*
* tio - a serial device I/O tool
*
* Copyright (c) 2014-2024 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
typedef enum {
XMODEM_1K,
XMODEM_CRC,
YMODEM,
} modem_mode_t;
extern char key_hit;
int xymodem_send(int sio, const char *filename, modem_mode_t mode);
int xymodem_receive(int sio, const char *filename, modem_mode_t mode);