mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
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')
This commit is contained in:
parent
0afae5d3ee
commit
fc54df1f22
4 changed files with 133 additions and 7 deletions
15
man/tio.1.in
15
man/tio.1.in
|
|
@ -375,17 +375,18 @@ Send ctrl-t character
|
|||
.PP
|
||||
Tio suppots Lua scripting to easily automate interaction with the tty device.
|
||||
|
||||
This means that in addition to the Lua API tio makes the following functions
|
||||
available:
|
||||
In addition to the Lua API tio makes the following functions available:
|
||||
|
||||
.TP 6n
|
||||
|
||||
.IP "\fBexpect(string)"
|
||||
Expect string - waits for string to match before continueing. Supports regular expressions. Special characters must be escaped with '\\\\'.
|
||||
.IP "\fBsend(string)"
|
||||
Send string.
|
||||
.IP "\fBmodem_send(file, protocol)"
|
||||
Send file using x/y-modem protocol.
|
||||
|
||||
Protocol can be any of XMODEM_1K, XMODEM_CRC, YMODEM.
|
||||
.IP "\fBsend(string)"
|
||||
Send string.
|
||||
.IP "\fBhigh(line)"
|
||||
Set tty line high.
|
||||
.IP "\fBlow(line)"
|
||||
|
|
@ -660,10 +661,14 @@ Enable RS-485 mode:
|
|||
$ tio --rs-485 --rs-485-config=RTS_ON_SEND=1,RX_DURING_TX /dev/ttyUSB0
|
||||
|
||||
.TP
|
||||
Script manipulation of DTR and RTS lines upon first connect:
|
||||
Manipulate DTR and RTS lines upon first connect to reset connected microcontroller:
|
||||
|
||||
$ tio --script "high(DTR); low(RTS); msleep(100); toggle(DTR)" --script-run once /dev/ttyUSB0
|
||||
|
||||
.TP
|
||||
Automatically log in to connected OS:
|
||||
|
||||
$ tio --script "expect('password:'); send('my_password\\n')" /dev/ttyUSB0
|
||||
|
||||
.SH "WEBSITE"
|
||||
.PP
|
||||
|
|
|
|||
25
src/misc.c
25
src/misc.c
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -87,3 +88,27 @@ bool fs_dir_exists(const char *path)
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool regex_match(const char *string, const char *pattern)
|
||||
{
|
||||
regex_t regex;
|
||||
int status;
|
||||
|
||||
if (regcomp(®ex, pattern, REG_EXTENDED | REG_NOSUB) != 0)
|
||||
{
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
|
||||
status = regexec(®ex, string, (size_t) 0, NULL, 0);
|
||||
regfree(®ex);
|
||||
|
||||
if (status != 0)
|
||||
{
|
||||
// No match
|
||||
return false;
|
||||
}
|
||||
|
||||
// Match
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,3 +32,4 @@ int ctrl_key_code(unsigned char key);
|
|||
void alert_connect(void);
|
||||
void alert_disconnect(void);
|
||||
bool fs_dir_exists(const char *path);
|
||||
bool regex_match(const char *string, const char *pattern);
|
||||
|
|
|
|||
99
src/script.c
99
src/script.c
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -34,7 +35,11 @@
|
|||
#include "tty.h"
|
||||
#include "xymodem.h"
|
||||
|
||||
#define MAX_BUFFER_SIZE 2000 // Maximum size of circular buffer
|
||||
|
||||
static int serial_fd;
|
||||
static char circular_buffer[MAX_BUFFER_SIZE];
|
||||
static int buffer_size = 0;
|
||||
|
||||
// lua: sleep(seconds)
|
||||
static int sleep_(lua_State *L)
|
||||
|
|
@ -209,6 +214,95 @@ static int send(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
// Function to add a character to the circular buffer
|
||||
void add_to_buffer(char c)
|
||||
{
|
||||
if (buffer_size < MAX_BUFFER_SIZE)
|
||||
{
|
||||
circular_buffer[buffer_size++] = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Shift the buffer to accommodate the new character
|
||||
memmove(circular_buffer, circular_buffer + 1, MAX_BUFFER_SIZE - 1);
|
||||
circular_buffer[MAX_BUFFER_SIZE - 1] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to match against the circular buffer using regex
|
||||
bool match_regex(regex_t *regex)
|
||||
{
|
||||
char buffer[MAX_BUFFER_SIZE + 1]; // Temporary buffer for regex matching
|
||||
memcpy(buffer, circular_buffer, buffer_size);
|
||||
buffer[buffer_size] = '\0'; // Null-terminate the buffer
|
||||
|
||||
// Match against the regex
|
||||
int ret = regexec(regex, buffer, 0, NULL, 0);
|
||||
if (!ret)
|
||||
{
|
||||
// Match found
|
||||
return true;
|
||||
}
|
||||
else if (ret == REG_NOMATCH)
|
||||
{
|
||||
// No match found, do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error occurred during matching
|
||||
tio_error_print("Regex match failed");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// lua: expect(string)
|
||||
static int expect(lua_State *L)
|
||||
{
|
||||
const char *string = lua_tostring(L, 1);
|
||||
regex_t regex;
|
||||
int ret = 0;
|
||||
char c;
|
||||
|
||||
if (string == NULL)
|
||||
{
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Compile the regular expression
|
||||
ret = regcomp(®ex, string, REG_EXTENDED);
|
||||
if (ret)
|
||||
{
|
||||
tio_error_print("Could not compile regex");
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Main loop to read and match
|
||||
while (true)
|
||||
{
|
||||
ssize_t bytes_read = read(serial_fd, &c, 1);
|
||||
if (bytes_read > 0)
|
||||
{
|
||||
putchar(c);
|
||||
add_to_buffer(c);
|
||||
// Match against the entire buffer
|
||||
if (match_regex(®ex))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
regfree(®ex);
|
||||
|
||||
error:
|
||||
lua_pushnumber(L, ret);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void script_buffer_run(lua_State *L, const char *script_buffer)
|
||||
{
|
||||
int error;
|
||||
|
|
@ -217,7 +311,7 @@ static void script_buffer_run(lua_State *L, const char *script_buffer)
|
|||
lua_pcall(L, 0, 0, 0);
|
||||
if (error)
|
||||
{
|
||||
tio_warning_printf("%s\n", lua_tostring(L, -1));
|
||||
tio_warning_printf("lua: %s\n", lua_tostring(L, -1));
|
||||
lua_pop(L, 1); /* pop error message from the stack */
|
||||
}
|
||||
}
|
||||
|
|
@ -234,6 +328,7 @@ static const struct luaL_Reg tio_lib[] =
|
|||
{ "config_apply", config_apply},
|
||||
{ "modem_send", modem_send},
|
||||
{ "send", send},
|
||||
{ "expect", expect},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
@ -276,7 +371,7 @@ void script_file_run(lua_State *L, const char *filename)
|
|||
|
||||
if (luaL_dofile(L, filename))
|
||||
{
|
||||
tio_warning_printf("%s\n", lua_tostring(L, -1));
|
||||
tio_warning_printf("lua: %s\n", lua_tostring(L, -1));
|
||||
lua_pop(L, 1); /* pop error message from the stack */
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue