diff --git a/README.md b/README.md index 91a3543..94eaf59 100644 --- a/README.md +++ b/README.md @@ -417,7 +417,6 @@ Tio suppots Lua scripting to easily automate interaction with the tty device. In addition to the standard Lua API tio makes the functions and variables available The following are representative. See the man page for the complete list.: - #### `tio.expect(pattern, timeout)` Waits for the Lua pattern to match or timeout before continuing. @@ -468,6 +467,13 @@ Send file using x/y-modem protocol. Protocol can be any of `XMODEM_1K`, `XMODEM_CRC`, `XMODEM_SUM`, `YMODEM`. Alternatively, it can be one of tio.C.XM_1K, tio.C.XM_CRC, tio.C.XM_SUM, or tio.C.YM_NORMAL. +#### `tio.receive(file, protocol)` + +eceive a file using the XMODEM protocol. + +protocol can be one of XMODEM_CRC or XMODEM_SUM. +Alternatively, use tio.C.XM_CRC or tio.C.XM_SUM. + #### `tio.ttysearch()` Search for serial devices. @@ -495,6 +501,45 @@ Sleep for seconds. Sleep for milliseconds. +#### `tio.inkey(timeout)` + +Read a key press as a string. + +timeout is specified in milliseconds. +Defaults to tio.C.NOWAIT (==-1), meaning the call returns immediately. +If set to tio.C.WAIT_FOREVER (==0), the function blocks until a key is pressed. + +Returns nil on timeout. + +#### `tio.input(prompt)` + +Display a prompt and read user input until Enter is pressed. +Basic editing is supported (Backspace key). + +If prompt is omitted, no prompt is displayed. +Returns the entered string. + +#### `tio.inputline(prompt)` + +Display a prompt and read a line of input until Enter is pressed. +Supports line editing (cursor keys, Backspace) and command history. + +Returns the entered string. + +#### `tio.set_keymap(keymaps)` + +Add, update, or remove key mappings. + +#### `tio.subcmd_println(fmt, ...)` + +Print a formatted line using sub-command style output +(e.g. [] ). + +#### `tio.subcmd_puts(string)` + +Print string using sub-command style output. +(e.g. [] ). + #### `tio.alwaysecho` A boolean value, defaults to `true`. diff --git a/man/tio.1.in b/man/tio.1.in index e264a64..3f969e9 100644 --- a/man/tio.1.in +++ b/man/tio.1.in @@ -547,6 +547,14 @@ Send file using x/y-modem protocol. Protocol can be any of XMODEM_1K, XMODEM_CRC, XMODEM_SUM, YMODEM. It can alternatively be one of tio.C.XM_1K, tio.C.XM_CRC, tio.C.XM_SUM, tio.C.YM_NORMAL. +.IP "\fBtio.receive(file, protocol)" +Receive a file using the XMODEM protocol. + +Protocol can be any of XMODEM_CRC or XMODEM_SUM. +It can alternatively be one of tio.C.XM_CRC or tio.C.XM_SUM. + +Returns the tio table on success or nil on error. + .IP "\fBtio.ttysearch()" Search for serial devices. @@ -643,6 +651,82 @@ Return value is one of tio.C.SA_INTERACTIVE, tio.C.SA_STARTING, tio.C.SA_PIPED_I Return the version of tio as a string. It is equivalent to the key command ctrl-t v. +.IP "\fBtio.inkey(timeout)" +Read a key press and return it as a string. + +Timeout is in milliseconds. If timeout is tio.C.WAIT_FOREVER(==0), +the function blocks until a key is pressed. If timeout is +tio.C.NOWAIT (==-1) or not provided, the function returns +immediately. + +Returns the key as a string on success, or nil on timeout. + +.IP "\fBtio.input(prompt)" +Display a prompt and read user input until Enter is pressed. + +Basic line editing is supported (Backspace key). + +If prompt is not provided, no prompt is displayed. + +Returns the entered string. + +.IP "\fBtio.inputline(prompt)" +Display a prompt and read a line of input until Enter is pressed. + +Supports line editing (cursor keys, Backspace) and command history. + +Returns the entered string. + +.IP "\fBtio.set_keymap(keymaps)" +Add, update, or remove key mappings. + +The keymaps argument uses the same syntax as the --keymap option: + + @= + @= + ... + @= + +Each must be either a script filename or an +inline script prefixed with '!'. + +When a mapping is defined, pressing Ctrl-t followed by +executes the corresponding script. + +If a key already has a mapping, it is updated. If + is empty, the mapping is removed. + +User-defined key mappings take precedence over default key bindings, +except for "Ctrl-t q", which is always reserved. + +This function allows key mappings to be modified at runtime after tio +has started. + +.IP "\fBtio.subcmd_println(fmt, ...)" +Print a formatted line using sub-command style output. + +The output format is: + [] + +.IP "\fBtio.subcmd_warning_println(fmt, ...)" +Print a formatted warning line using sub-command style output. + +.IP "\fBtio.subcmd_error_println(fmt, ...)" +Print a formatted error line using sub-command style output. +.IP "\fBtio.subcmd_error_println(fmt, ...)" + +.IP "\fBtio.subcmd_puts(string)" +Print a string using sub-command style output. + +The output format is: + [] + +.IP "\fBtio.subcmd_warning_puts(string)" +Print a warning string using sub-command style output. + +.IP "\fBtio.subcmd_error_puts(string)" +Print an error string using sub-command style output. + .IP "\fBtio.alwaysecho" A boolean value, defaults to true. @@ -958,7 +1042,6 @@ Receive file from device by gkermit command: $ tio --exec '?gkermit -XSr' /dev/ttyUSB0 - .SH "WEBSITE" .PP Visit https://tio.github.io diff --git a/man/tio.1.txt b/man/tio.1.txt index 76df0ab..4456ab2 100644 --- a/man/tio.1.txt +++ b/man/tio.1.txt @@ -454,6 +454,14 @@ SCRIPT API Protocol can be any of XMODEM_1K, XMODEM_CRC, XMODEM_SUM, YMODEM. It can alternatively be one of tio.C.XM_1K, tio.C.XM_CRC, tio.C.XM_SUM, tio.C.YM_NORMAL. + tio.receive(file, protocol) + Receive a file using the XMODEM protocol. + + Protocol can be any of XMODEM_CRC or XMODEM_SUM. + It can alternatively be one of tio.C.XM_CRC or tio.C.XM_SUM. + + Returns the tio table on success or nil on error. + tio.ttysearch() Search for serial devices. @@ -548,6 +556,77 @@ SCRIPT API Return the version of tio as a string. It is equivalent to the key command ctrl-t v. + tio.inkey(timeout) + Read a key press and return it as a string. + + Timeout is in milliseconds. If timeout is tio.C.WAIT_FOREVER(==0), + the function blocks until a key is pressed. If timeout is + tio.C.NOWAIT (==-1) or not provided, the function returns + immediately. + + Returns the key as a string on success, or nil on timeout. + + tio.input(prompt) + Display a prompt and read user input until Enter is pressed. + + Basic line editing is supported (Backspace key). + + If prompt is not provided, no prompt is displayed. + + Returns the entered string. + + tio.inputline(prompt) + Display a prompt and read a line of input until Enter is pressed. + + Supports line editing (cursor keys, Backspace) and command + history. + + Returns the entered string. + + tio.set_keymap(keymaps) + Add, update, or remove key mappings. + + The argument uses the same syntax as the --keymap option: + + @= + @= + ... + @= + + Each must be either a script filename or an inline script prefixed with '!'. + + When a mapping is defined, pressing Ctrl-T followed by executes the corresponding script. + + If a key already has a mapping, it will be updated. If is empty, the mapping is removed. + + User-defined key mappings take precedence over default key bindings, except for "Ctrl-T q", which is always reserved. + + This function can be used to dynamically modify key mappings at runtime after tio has started. + + tio.subcmd_println(fmt, ...) + Print a formatted line using sub-command style output. + + The output format is: + [] + + tio.subcmd_warning_println(fmt, ...) + Print a formatted warning line using sub-command style output. + + tio.subcmd_error_println(fmt, ...) + Print a formatted error line using sub-command style output. + + tio.subcmd_puts(string) + Print a string using sub-command style output. + + The output format is: + [] + + tio.subcmd_warning_puts(string) + Print a warning string using sub-command style output. + + tio.subcmd_error_puts(string) + Print an error string using sub-command style output. + tio.alwaysecho A boolean value, defaults to true. diff --git a/src/script.c b/src/script.c index 3062cf7..d29ef2e 100644 --- a/src/script.c +++ b/src/script.c @@ -108,6 +108,15 @@ static char script_init[] = " end\n" " end\n" "end\n" +"tio.subcmd_println = function(fmt, ...)\n" +" tio.subcmd_puts(string.format(fmt, select(1, ...)))\n" +"end\n" +"tio.subcmd_warning_println = function(fmt, ...)\n" +" tio.subcmd_warning_puts(fmt, string.format(fmt, select(1, ...)))\n" +"end\n" +"tio.subcmd_error_println = function(fmt, ...)\n" +" tio.subcmd_error_puts(fmt, string.format(fmt, select(1, ...)))\n" +"end\n" "tio.alwaysecho = true\n" "setmetatable(tio, tio)\n"; // clang-format on @@ -339,6 +348,54 @@ static int api_send(lua_State *L) return 0; } +// lua: tio.receive(file, protocol) +static int api_receive(lua_State *L) +{ + const char *file = luaL_checkstring(L, 1); + int protocol = luaL_checkinteger(L, 2); + int ret; + + if (device_fd == 0) + { + return luaL_error(L, "tty device not ready"); + } + + if (file == NULL) + { + return 0; + } + + state_t state_orig = state; + state = STATE_XYMODEM; + tty_tcsetattr(device_fd); + + switch (protocol) + { + case XMODEM_CRC: + tio_printf("Receiving file '%s' using XMODEM-CRC", file); + ret = xymodem_receive(device_fd, file, XMODEM_CRC); + tio_printf("%s", ret < 0 ? "Aborted" : "Done"); + break; + + case XMODEM_SUM: + tio_printf("Receiving file '%s' using XMODEM-SUM", file); + ret = xymodem_receive(device_fd, file, XMODEM_SUM); + tio_printf("%s", ret < 0 ? "Aborted" : "Done"); + break; + + case XMODEM_1K: + case YMODEM: + default: + tio_error_printf("Not supported"); + break; + } + + state = state_orig; + tty_tcsetattr(device_fd); + + return 0; +} + // lua: tio.write(string) static int api_write(lua_State *L) { @@ -497,6 +554,145 @@ static int api_readline(lua_State *L) } } +// lua: str = tio.inkey(mseconds) +static int api_inkey(lua_State *L) +{ + extern char inkey_chars[]; + int ret; + int mseconds; + int arg_num = lua_gettop(L); + int arg; + if (arg_num == 0) + { + arg = -1; + } + else + { + arg = lua_tointeger(L, 1); + } + if (arg == 0) + { + mseconds = POLL_FOREVER; + } + else if (arg < 0) + { + mseconds = POLL_NOWAIT; + } + else + { + mseconds = arg; + } + ret = tty_inkey(mseconds); + if (ret == 0) + { + /* Timeout */ + lua_pushnil(L); + return 1; + } + else if (ret < 0) { + return luaL_error(L, "inkey failed"); + } + lua_pushlstring(L, inkey_chars, ret); + return 1; +} + +// lua: str = tio.input(prompt) +static int api_input(lua_State *L) +{ + extern char line[]; + int arg_num = lua_gettop(L); + const char *prompt = ""; + if (arg_num > 0) + { + prompt = luaL_checkstring(L, 1); + } + tty_simple_readln(prompt); + lua_pushstring(L, line); + return 1; +} + +// lua: str = tio.inputline(title_prompt) +static int api_input_line(lua_State *L) +{ + extern char line[]; + int arg_num = lua_gettop(L); + const char *prompt = ""; + if (arg_num > 0) + { + prompt = luaL_checkstring(L, 1); + } + tty_subcmd_readln(prompt); + lua_pushstring(L, line); + return 1; +} + +// lua: api_subcmd_puts(str) +static int api_subcmd_puts(lua_State *L) +{ + int arg_num = lua_gettop(L); + const char *str; + if (arg_num != 1) + { + return luaL_error(L, "arguments error"); + } + str = luaL_checkstring(L, 1); + tio_printf("%s", str); + return 0; +} + +// lua: api_subcmd_warning_puts(str) +static int api_subcmd_warning_puts(lua_State *L) +{ + int arg_num = lua_gettop(L); + const char *str; + if (arg_num != 1) + { + return luaL_error(L, "arguments error"); + } + str = luaL_checkstring(L, 1); + tio_warning_printf("%s", str); + return 0; +} + +// lua: api_subcmd_error_puts(str) +static int api_subcmd_error_puts(lua_State *L) +{ + int arg_num = lua_gettop(L); + const char *str; + if (arg_num != 1) + { + return luaL_error(L, "arguments error"); + } + str = luaL_checkstring(L, 1); + tio_error_printf("%s", str); + return 0; +} + +// lua: true/false, error = tio.set_keymap(keymap_str) +static int api_set_keymap(lua_State *L) +{ + int arg_num = lua_gettop(L); + const char *keymap_str; + if (arg_num != 1) + { + return luaL_error(L, "arguments error"); + } + keymap_str = luaL_checkstring(L, 1); +#if 1 + option_parse_key_mappings(keymap_str); + return 0; +#else + ret = option_parse_key_mappings(keymap_str); + if (ret < 0) + { + return luaL_error(L, "keymap setting failed"); + } + lua_pushboolean(L, true); + return 1; +#endif +} + + // lua: table = tio.ttysearch() static int api_ttysearch(lua_State *L) { @@ -797,6 +993,7 @@ static const struct luaL_Reg tio_lib[] = { "line_set", api_line_set}, { "line_get", api_line_get}, { "send", api_send}, + { "receive", api_receive}, { "write", api_write}, { "twrite", api_twrite}, { "read", api_read}, @@ -816,6 +1013,15 @@ static const struct luaL_Reg tio_lib[] = { "get_state", api_get_state}, { "get_version", api_get_version}, + { "inkey", api_inkey}, + { "input", api_input}, + { "inputline", api_input_line}, + { "set_keymap", api_set_keymap}, + + { "subcmd_puts", api_subcmd_puts}, + { "subcmd_warning_puts", api_subcmd_warning_puts}, + { "subcmd_error_puts", api_subcmd_error_puts}, + {NULL, NULL} }; // clang-format on