Add timeout feature to expect()

This commit is contained in:
Martin Lund 2024-04-13 15:30:14 +02:00
parent 3ad090caf7
commit 51300cc4f0
6 changed files with 60 additions and 34 deletions

View file

@ -222,11 +222,13 @@ Tio suppots Lua scripting to easily automate interaction with the tty device.
In addition to the Lua API tio makes the following functions available:
```
expect(string)
Expect string - waits for string to match before continueing.
expect(string, timeout)
Expect string - waits for string to match or timeout before continueing.
Supports regular expressions. Special characters must be escaped with '\\'.
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
send(string)
Send string.

View file

@ -379,8 +379,10 @@ 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 "\fBexpect(string, timeout)"
Expect string - waits for string to match or timeout before continueing.
Supports regular expressions. Special characters must be escaped with '\\\\'.
Timeout is in milliseconds, defaults to 0 meaning it will wait forever.
.IP "\fBsend(string)"
Send string.
.IP "\fBmodem_send(file, protocol)"

View file

@ -28,6 +28,7 @@
#include <sys/stat.h>
#include <time.h>
#include <errno.h>
#include <sys/poll.h>
#include "error.h"
#include "print.h"
#include "options.h"
@ -112,3 +113,31 @@ bool regex_match(const char *string, const char *pattern)
// 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;
}

View file

@ -22,6 +22,7 @@
#pragma once
#include <stdbool.h>
#include <stdio.h>
#define UNUSED(expr) do { (void)(expr); } while (0)
@ -33,3 +34,4 @@ void alert_connect(void);
void alert_disconnect(void);
bool fs_dir_exists(const char *path);
bool regex_match(const char *string, const char *pattern);
int read_poll(int fd, void *data, size_t len, int timeout);

View file

@ -256,20 +256,27 @@ bool match_regex(regex_t *regex)
return false;
}
// lua: expect(string)
// lua: expect(string, timeout)
static int expect(lua_State *L)
{
const char *string = lua_tostring(L, 1);
long timeout = lua_tointeger(L, 2);
regex_t regex;
int ret = 0;
char c;
if (string == NULL)
if ((string == NULL) || (timeout < 0))
{
ret = -1;
goto error;
}
if (timeout == 0)
{
// Let poll() wait forever
timeout = -1;
}
// Compile the regular expression
ret = regcomp(&regex, string, REG_EXTENDED);
if (ret)
@ -282,7 +289,7 @@ static int expect(lua_State *L)
// Main loop to read and match
while (true)
{
ssize_t bytes_read = read(serial_fd, &c, 1);
ssize_t bytes_read = read_poll(serial_fd, &c, 1, timeout);
if (bytes_read > 0)
{
putchar(c);
@ -293,6 +300,11 @@ static int expect(lua_State *L)
break;
}
}
else
{
// Timeout or error
break;
}
}
// Cleanup

View file

@ -65,27 +65,6 @@ static uint16_t crc16(const uint8_t *data, uint16_t size)
return crc;
}
static int serial_poll(int sio, void *data, size_t len, int timeout)
{
struct pollfd fds[1];
fds[0].fd = sio;
fds[0].events = POLLIN ;
int ret = 0;
/* Wait data available */
ret = poll(fds, 1, timeout);
if (ret < 0) {
return ret;
}
else if (ret > 0) {
if(fds[0].revents & POLLIN) {
return read(sio, data, len);
}
}
/* Timeout */
return ret;
}
static int xmodem_1k(int sio, const void *data, size_t len, int seq)
{
struct xpacket_1k packet;
@ -99,7 +78,7 @@ static int xmodem_1k(int sio, const void *data, size_t len, int seq)
while(1) {
if (key_hit)
return -1;
rc = serial_poll(sio, &resp, 1, 50);
rc = read_poll(sio, &resp, 1, 50);
if (rc == 0) {
if (resp == 'C') break;
if (resp == CAN) return ERR;
@ -156,7 +135,7 @@ static int xmodem_1k(int sio, const void *data, size_t len, int seq)
for(int n=0; n < 20; n++) {
if (key_hit)
return ERR;
rc = serial_poll(sio, &resp, 1, 50);
rc = read_poll(sio, &resp, 1, 50);
if (rc < 0) {
tio_error_print("Read ack/nak from serial failed");
return ERR;
@ -193,7 +172,7 @@ static int xmodem_1k(int sio, const void *data, size_t len, int seq)
}
write(STDOUT_FILENO, "|", 1);
/* 1s timeout */
rc = serial_poll(sio, &resp, 1, 1000);
rc = read_poll(sio, &resp, 1, 1000);
if (rc < 0) {
tio_error_print("Read from serial failed");
return ERR;
@ -221,7 +200,7 @@ static int xmodem(int sio, const void *data, size_t len)
while(1) {
if (key_hit)
return -1;
rc = serial_poll(sio, &resp, 1, 50);
rc = read_poll(sio, &resp, 1, 50);
if (rc == 0) {
if (resp == 'C') break;
if (resp == CAN) return ERR;
@ -275,7 +254,7 @@ static int xmodem(int sio, const void *data, size_t len)
for(int n=0; n < 20; n++) {
if (key_hit)
return ERR;
rc = serial_poll(sio, &resp, 1, 50);
rc = read_poll(sio, &resp, 1, 50);
if (rc < 0) {
tio_error_print("Read ack/nak from serial failed");
return ERR;
@ -312,7 +291,7 @@ static int xmodem(int sio, const void *data, size_t len)
}
write(STDOUT_FILENO, "|", 1);
/* 1s timeout */
rc = serial_poll(sio, &resp, 1, 1000);
rc = read_poll(sio, &resp, 1, 1000);
if (rc < 0) {
tio_error_print("Read from serial failed");
return ERR;