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: In addition to the Lua API tio makes the following functions available:
``` ```
expect(string) expect(string, timeout)
Expect string - waits for string to match before continueing. Expect string - waits for string to match or timeout before continueing.
Supports regular expressions. Special characters must be escaped with '\\'. 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)
Send string. Send string.

View file

@ -379,8 +379,10 @@ In addition to the Lua API tio makes the following functions available:
.TP 6n .TP 6n
.IP "\fBexpect(string)" .IP "\fBexpect(string, timeout)"
Expect string - waits for string to match before continueing. Supports regular expressions. Special characters must be escaped with '\\\\'. 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)" .IP "\fBsend(string)"
Send string. Send string.
.IP "\fBmodem_send(file, protocol)" .IP "\fBmodem_send(file, protocol)"

View file

@ -28,6 +28,7 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <sys/poll.h>
#include "error.h" #include "error.h"
#include "print.h" #include "print.h"
#include "options.h" #include "options.h"
@ -112,3 +113,31 @@ bool regex_match(const char *string, const char *pattern)
// Match // Match
return true; 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 #pragma once
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#define UNUSED(expr) do { (void)(expr); } while (0) #define UNUSED(expr) do { (void)(expr); } while (0)
@ -33,3 +34,4 @@ void alert_connect(void);
void alert_disconnect(void); void alert_disconnect(void);
bool fs_dir_exists(const char *path); bool fs_dir_exists(const char *path);
bool regex_match(const char *string, const char *pattern); 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; return false;
} }
// lua: expect(string) // lua: expect(string, timeout)
static int expect(lua_State *L) static int expect(lua_State *L)
{ {
const char *string = lua_tostring(L, 1); const char *string = lua_tostring(L, 1);
long timeout = lua_tointeger(L, 2);
regex_t regex; regex_t regex;
int ret = 0; int ret = 0;
char c; char c;
if (string == NULL) if ((string == NULL) || (timeout < 0))
{ {
ret = -1; ret = -1;
goto error; goto error;
} }
if (timeout == 0)
{
// Let poll() wait forever
timeout = -1;
}
// Compile the regular expression // Compile the regular expression
ret = regcomp(&regex, string, REG_EXTENDED); ret = regcomp(&regex, string, REG_EXTENDED);
if (ret) if (ret)
@ -282,7 +289,7 @@ static int expect(lua_State *L)
// Main loop to read and match // Main loop to read and match
while (true) 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) if (bytes_read > 0)
{ {
putchar(c); putchar(c);
@ -293,6 +300,11 @@ static int expect(lua_State *L)
break; break;
} }
} }
else
{
// Timeout or error
break;
}
} }
// Cleanup // Cleanup

View file

@ -65,27 +65,6 @@ static uint16_t crc16(const uint8_t *data, uint16_t size)
return crc; 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) static int xmodem_1k(int sio, const void *data, size_t len, int seq)
{ {
struct xpacket_1k packet; struct xpacket_1k packet;
@ -99,7 +78,7 @@ static int xmodem_1k(int sio, const void *data, size_t len, int seq)
while(1) { while(1) {
if (key_hit) if (key_hit)
return -1; return -1;
rc = serial_poll(sio, &resp, 1, 50); rc = read_poll(sio, &resp, 1, 50);
if (rc == 0) { if (rc == 0) {
if (resp == 'C') break; if (resp == 'C') break;
if (resp == CAN) return ERR; 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++) { for(int n=0; n < 20; n++) {
if (key_hit) if (key_hit)
return ERR; return ERR;
rc = serial_poll(sio, &resp, 1, 50); rc = read_poll(sio, &resp, 1, 50);
if (rc < 0) { if (rc < 0) {
tio_error_print("Read ack/nak from serial failed"); tio_error_print("Read ack/nak from serial failed");
return ERR; return ERR;
@ -193,7 +172,7 @@ static int xmodem_1k(int sio, const void *data, size_t len, int seq)
} }
write(STDOUT_FILENO, "|", 1); write(STDOUT_FILENO, "|", 1);
/* 1s timeout */ /* 1s timeout */
rc = serial_poll(sio, &resp, 1, 1000); rc = read_poll(sio, &resp, 1, 1000);
if (rc < 0) { if (rc < 0) {
tio_error_print("Read from serial failed"); tio_error_print("Read from serial failed");
return ERR; return ERR;
@ -221,7 +200,7 @@ static int xmodem(int sio, const void *data, size_t len)
while(1) { while(1) {
if (key_hit) if (key_hit)
return -1; return -1;
rc = serial_poll(sio, &resp, 1, 50); rc = read_poll(sio, &resp, 1, 50);
if (rc == 0) { if (rc == 0) {
if (resp == 'C') break; if (resp == 'C') break;
if (resp == CAN) return ERR; 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++) { for(int n=0; n < 20; n++) {
if (key_hit) if (key_hit)
return ERR; return ERR;
rc = serial_poll(sio, &resp, 1, 50); rc = read_poll(sio, &resp, 1, 50);
if (rc < 0) { if (rc < 0) {
tio_error_print("Read ack/nak from serial failed"); tio_error_print("Read ack/nak from serial failed");
return ERR; return ERR;
@ -312,7 +291,7 @@ static int xmodem(int sio, const void *data, size_t len)
} }
write(STDOUT_FILENO, "|", 1); write(STDOUT_FILENO, "|", 1);
/* 1s timeout */ /* 1s timeout */
rc = serial_poll(sio, &resp, 1, 1000); rc = read_poll(sio, &resp, 1, 1000);
if (rc < 0) { if (rc < 0) {
tio_error_print("Read from serial failed"); tio_error_print("Read from serial failed");
return ERR; return ERR;