tio.line_get()
Get state of multiple tty modem lines.
It is equivalent to the key command ctrl-t L.
Return 6 values DTR, RTS, CTS, DSR, CD, RI.
Each return value is high (==tio.C.LN_HIGH) or low (==tio.C.LN_LOW).
tio.get_state()
Return the main state of tio as a integer.
Return value is one of tio.C.SA_INTERACTIVE, tio.C.SA_STARTING,
tio.C.SA_PIPED_INPUT, tio.C.SA_PIPED_INPUT,
tio.C.SA_EXEC_SHELL_COMMAND, tio.C.SA_XYMODEM.
refactoring
rename line_set() to api_line_set().
User key-script mapping function:
You can specify the mappings as @<key-1>=<script-description-1>
@<key-2>=<script-description-2>... @<key-N>=<script-description-N>.
Script-description is script-filename or '!'script-commands.
After that,
When you press ctrl-t and <key-n>, tio executes <script-description-n>.
This user keymap takes precedence over the default settings (except for
ctrl-t q).
Example of startup option:
tio /dev/ttyUSB1 --keymap '@1=!print(tio.banner())
@2=!tio.write("test\r") @ctrl-a=!tio.write("ctrl-a\r")
@ctrl-j=test-script.tio'
Example of .tioconfig: (note: backslash escape needed.)
keymap = @1=!print(tio.banner()) @2=!tio.write("test\\r")
@ctrl-a=!tio.write("ctrl-a\\r") @ctrl-j=test-script.tio
The script-init-file is the file to be loaded and executed when the
interpreter starts.
If this option is defined, it will be executed after the tio module is
loaded as a built-in module.
Example of .tioconfig:
script-init-file = /home/user/.tio-script-init.lua
Example of option specification:
tio --script-init-file /home/user/.tio-script-init.lua
Fix the v3.9-incompatible changes in 8e02cde ("Lua API Timeout
Specification Changes to Enable Non-Blocking Reads", November 15, 2025)
to make them compatible.
The timeout arguments for tio.expect/s(), tio.read(), and tio.readline()
have been changed as follows:
- The timeout is in milliseconds, and the default is 0, which means to
wait forever (as in v3.9).
- A negative value means to nowait.
A constant table (tio.C) has also been added,
defining tio.C.FOREVER to 0 and tio.C.NOWAIT to -1.
The "shell command execution feature" previously only supported the
ability to transfer a command's stdout and stderr to a device.
To support bidirectional commands, a feature will be added to connect
input from a device to the command's stdin.
Since some communication commands (sz, rz) require stderr to be kept
local, a feature will also be added to not transfer stderr to a device
if the command string begins with a '?'.
On Linux, you can terminate a running command by pressing Ctrl-t R again
while the command is running (this uses the command /usr/bin/pkill
internally).
Non-interactive operations (input from a pipe, running a shell command,
XYMODEM transfers) often fail when mapping, soft flow control, or output
delay are enabled.
To reduce the hassle of switching settings, add the function shown in
the title.
The raw option can be set to one of the following:
- off ... no effects
- on ... soft-flow off, character mapping off, output delay enabled
- on-nodelay ... soft-flow off, character mapping off, output delay
disable
raw option is for Piped-input / Shell command execution / XYMODEM
transfering. default is on.
raw-interactive option is for socket-mode and normal terminal use.
default is off.
You can type Ctrl-t j if you need to change raw setting for
non-interactive case. it toggles the raw setting.
You can type Ctrl-t J if you need to change raw setting of interactive
case. it toggles the raw setting.
It is useful when transferring files in socket mode.
Add tty_raw_write function and reorganize roles of them.
tty_raw_write:
Performs any processing that must be done character-by-character on the
fly. That is, output delays and ONULBRK processing.
tty_write :
Converts input data using output mapping and passes it to tty_raw_write.
forward_to_tty :
Converts input data according to the input/output mode and passes it to
tty_write. (output-mapping function move to tty_write. tx_total
statistics counting move to tty_raw_write and tty_sync.)
On exit, do not reset the tty device settings to the state they were in
before the program started.
This is effective when sending characters at a low baud rate and then
immediately exiting, to ensure that the last character is output
correctly.
Typing "@repl" after Ctrl-t r, enter Lua REPL mode.
Typing "@exit" in REPL mode will return you to normal mode.
Note:
- the determination of continuation lines is not done automatically, and
if the end of a line is \, it is determined to be a continuation
instruction.
- In REPL mode, tio's main loop is blocked. (Ctrl-t q works.)
Example:
>> t = {1,2,3,4,5}
>> for _,v in ipairs(t) do\
>> print(v,"\r")\
>> end
Implementation improvements:
- Add tty_init() and script_interp_init() in order to only once
initialization.
- Fix script function to work without device_fd.
bidir_cmd_herlper.sh: Bidirectional command helper by socat.
bidir_cmd_helper.py: Bidirectional command helper by python and netcat.
pexpect-ping.py, pexpect-pong.py: Scripts for throwing Ping-Pong between
cross-connected tios.
When calling the Lua interpreter with Ctrl-t r, change to start with the
previous call state.
This allows you to use it like REPL:
(example)
Ctrl-t r : my_library.lua
Ctrl-t r : !result1 = my_func("test1"); result2 = my_func("test2")
Ctrl-t r : !if (result1 == result2) then print("OK") else print("NG")
Ctrl-t r : @new
When you enter strings using Ctrl-t r, the string is interpreted as
follows:
- If the string does not begin with either "!" or "@", the string is
assumed to be the file name of a script and is executed.
- If the string begins with "!", the string excluding the "!" is
interpreted as Lua commands.
- If the string begins with "@", Strings beginning with "@" are
considered instructions to the interpreter. Currently valid instructions
are:
@new: Clear the Lua state. (== reset the Lua interpreter.)
@doopt: Execute the Lua script action specified by the option that start
with clearing the Lua state.
@nuldo=opt: do @doopt action when an empty string is entered (default).
@nuldo=none: Do nothing when an empty string is entered.
And now, lua interpreter start with GC.
If you need to stop GC, do lua function collectgarbage("stop").
Ctrl-t r/R/x/y commands require string input. To reduce the hassle of
repeatedly entering this information, I apply readline functions
(line-editing and history) to the string input.
Now tio have two histories: one for the line input-mode and one for the
ctrl-t command's string input.
And the following changes are made to the line input:
- Add prompts.
"> ": line input-mode, ">> " Ctrl-t string input.
- Omits duplicate lines from the history.
To implement the above functionality, we will modify the readline
functions to use the multi-instance style.
tio.expect[s]() performs pattern matching for each character received,
but there are cases where the character reception speed exceeds the
pattern matching speed, resulting in characters being missed.
Add non-blocking reads to read all characters that have been received at
that time.
Change timeout argument of tio.read / readline / expect[s] to be similar
to the timeout specification for poll(2) and LuaSocket.
If timeout is negative value or not provided or nil, it will wait
indefinitely until data is ready to read.
If timeout is 0, it will read data that has arrived with non-blocking.
Prior to this fix, non-blocking reads could not be specified.
Add tio.expects() which has a table of patterns in the arguments to
support "OR" pattern waiting.
The return values of tio.expects() are:
1st: index of the matched pattern in the table. nil if unmatched.
2nd: a table of captures if one of the patterns are matched.
nil if any of the patterns are unmatched and timeout.
3rd: all received strings in tio.expects() to treat the strings after
match.
Add all received string to tio.expect()'s return values too.
For example,
idx, captures, all_received = tio.expects( {"\nOK", "\nERROR"}, 1000 )
captures, all_received = tio.expect( "\nPROMPT>", 1000 )
Lua regular expressions do not have an OR specification, so the current
tio.expect() cannot wait until any of multiple patterns match.
This will cause OR waiting behavior when a table of multiple regular
expressions is passed as a pattern.
If you pass a string as a pattern, it will treats a table has single
regular expression.
and this will change return values.
1st: table of captures if one of the patterns matched
nil if any pattern unmatched and timeout.
2nd: whole input strings
3rd: index of the matched pattern. 0 if unmatched.
For example,
captures, whole, idx = tio.expect( {"\nOK", "\nERROR"} )
captures, whole, idx = tio.expect( "\nOK" )
The twrite Lua API is a variation of the write API, with the output
character mapping and output-delay / output-line-delay features enabled.
Since it processes each character internally, writing speed is slower
than the write API.
~~~~~~~~~~~~~~~~~~~~~~~
twrite(string)
Translate string with output character mapping and write the
translated string to serial device with output-delay /
output-line-delay.
If output-line-delay is non-zero and output-delay is any, line delay
time set output-line-delay.
If output-line-delay is zero and output-delay is non-zero, line delay
time set output-delay.
It was previously (output-line-delay + output-delay) in any case.
Also, since the buffer was flushed after the line delay, there was a
possibility that the delay would be reduced or not applied at all.