From 51300cc4f0380cb551ef31e945d329e4cca03a1a Mon Sep 17 00:00:00 2001 From: Martin Lund Date: Sat, 13 Apr 2024 15:30:14 +0200 Subject: [PATCH] Add timeout feature to expect() --- README.md | 6 ++++-- man/tio.1.in | 6 ++++-- src/misc.c | 29 +++++++++++++++++++++++++++++ src/misc.h | 2 ++ src/script.c | 18 +++++++++++++++--- src/xymodem.c | 33 ++++++--------------------------- 6 files changed, 60 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 32a826d..dadeb46 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/man/tio.1.in b/man/tio.1.in index eb61cb3..1bc32c8 100644 --- a/man/tio.1.in +++ b/man/tio.1.in @@ -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)" diff --git a/src/misc.c b/src/misc.c index 06d7512..cf57724 100644 --- a/src/misc.c +++ b/src/misc.c @@ -28,6 +28,7 @@ #include #include #include +#include #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; +} diff --git a/src/misc.h b/src/misc.h index ec80d3d..c669cbd 100644 --- a/src/misc.h +++ b/src/misc.h @@ -22,6 +22,7 @@ #pragma once #include +#include #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); diff --git a/src/script.c b/src/script.c index bd1d6fe..7874574 100644 --- a/src/script.c +++ b/src/script.c @@ -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(®ex, 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 diff --git a/src/xymodem.c b/src/xymodem.c index df83a25..83ac6dc 100644 --- a/src/xymodem.c +++ b/src/xymodem.c @@ -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;