+ Add system timestamps to lua read() and new lua read_line() per global options

+ Add missing timestamp-format epoch
+ Update send_ to use fsync and tcdrain like normal tty_sync does
+ Rework read_line to save partial line at timeout
+ Simplified read_line to reduce cyclomatic complexity

+ renamed example files read.lua and read_line.lua
+ moved #define READ_LINE_SIZE to top of file
+ renamed g_linebuf to linebuf, and moved it into read_line as a static variable
This commit is contained in:
Keith Hill 2024-10-25 11:22:56 -05:00 committed by Martin Lund
parent db3f109c7d
commit afd82f7ac4
12 changed files with 171 additions and 24 deletions

14
examples/lua/read.lua Normal file
View file

@ -0,0 +1,14 @@
read(1000, 6000) -- initial config
send("\n")
msleep(100)
read(650, 60) -- main menu
send("S") -- S menu
msleep(30)
read(650, 60)
send("t") -- Parallel Value Table
read(650, 60)
while true do
msleep(1000)
send("t")
read(650, 50) -- repeat PVT forever
end

View file

@ -0,0 +1,17 @@
read(1000, 8000) -- read initial config
send("\n")
read(650, 100) -- main menu
send("S") -- S menu
n = 1
while n > 0 do -- while not empty, read more
n, str = read_line(25)
end
while true do
send("t") -- query PV table
msleep(880)
n = 1
while n > 0 do -- while not empty, read more
n, str = read_line(60)
msleep(60)
end
end

View file

@ -467,7 +467,18 @@ until data is ready to read.
Returns number of bytes read on success, 0 on timeout, or -1 on error.
On success, returns read string as second return value.
On success, returns read string as second return value. Also emits a single
timestamp to stdout and log file per options.timestamp and options.log.
.IP "\fBread_line(timeout)"
Read line from serial device. If timeout is 0 or not provided it will wait
forever until data is ready to read.
Returns number of bytes read on success, 0 on timeout, or -1 on error.
On success, returns the string that was read as second return value. Also
emits a single timestamp to stdout and log file per options.timestamp
and options.log.
.IP "\fBset{line=state, ...}"
Set state of one or multiple tty modem lines.

View file

@ -373,7 +373,14 @@ SCRIPT API
Returns number of bytes read on success, 0 on timeout, or -1 on error.
On success, returns read string as second return value.
On success, returns read string as second return value. Also emits a single timestamp to stdout and log file per options.timestamp and options.log.
read_line(timeout)
Read line from serial device. If timeout is 0 or not provided it will wait forever until data is ready to read.
Returns number of bytes read on success, 0 on timeout, or -1 on error.
On success, returns the string that was read as second return value. Also emits a single timestamp to stdout and log file per options.timestamp and options.log.
set{line=state, ...}
Set state of one or multiple tty modem lines.

View file

@ -209,7 +209,7 @@ static void config_parse_keys(GKeyFile *key_file, char *group)
{
option.timestamp = TIMESTAMP_24HOUR;
}
config_get_string(key_file, group, "timestamp-format", &string, "24hour", "24hour-start", "24hour-delta", "iso8601", NULL);
config_get_string(key_file, group, "timestamp-format", &string, "24hour", "24hour-start", "24hour-delta", "iso8601", "epoch", NULL);
if (string != NULL)
{
option_parse_timestamp(string, &option.timestamp);

View file

@ -19,8 +19,7 @@
* 02110-1301, USA.
*/
#define __STDC_WANT_LIB_EXT2__ 1 // To access vasprintf
#define _GNU_SOURCE // To access vasprintf
#include <stdio.h>
#include "print.h"

View file

@ -19,8 +19,7 @@
* 02110-1301, USA.
*/
#define __STDC_WANT_LIB_EXT2__ 1 // To access vasprintf
#define _GNU_SOURCE // To access vasprintf
#include <sys/time.h>
#include <libgen.h>
#include <errno.h>

View file

@ -19,6 +19,8 @@
* 02110-1301, USA.
*/
#define _GNU_SOURCE // To access vasprintf
#include <assert.h>
#include <regex.h>
#include <getopt.h>

View file

@ -29,6 +29,7 @@
#include <lauxlib.h>
#include <lualib.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include "misc.h"
#include "print.h"
#include "options.h"
@ -37,8 +38,11 @@
#include "log.h"
#include "script.h"
#include "fs.h"
#include "timestamp.h"
#include "termios.h"
#define MAX_BUFFER_SIZE 2000 // Maximum size of circular buffer
#define READ_LINE_SIZE 4096 // read_line buffer length
static int device_fd;
static char circular_buffer[MAX_BUFFER_SIZE];
@ -192,6 +196,8 @@ static int send_(lua_State *L)
}
ret = write(device_fd, string, strlen(string));
fsync(device_fd); // flush these characters now
tcdrain(device_fd); //ensure we flushed characters to our device
lua_pushnumber(L, ret);
@ -248,10 +254,39 @@ static bool match_regex(regex_t *regex)
return false;
}
// lua: ret,string = read_string(size, timeout)
// Function to echo a buffer to stdout and to the log
// per the option.timestamp and option.log settings
static void echo_buffer(char buffer[], ssize_t len)
{
if (option.timestamp)
{
char *pTimeStampNow;
pTimeStampNow = timestamp_current_time();
if (pTimeStampNow)
{
tio_printf("%s", buffer); //does timestamps for us
if (option.log)
{
log_printf("\n[%s] %s", pTimeStampNow, buffer);
}
}
} else {
for (ssize_t i=0; i<len; i++)
{
putchar(buffer[i]);
if (option.log)
{
log_putc(buffer[i]);
}
}
}
}
// lua: ret,string = read(size, timeout)
static int read_string(lua_State *L)
{
int size = lua_tointeger(L, 1);
int size = lua_tointeger(L, 1) + 1; //plus one for null-terminated string
int timeout = lua_tointeger(L, 2);
int ret = 0;
@ -259,7 +294,7 @@ static int read_string(lua_State *L)
if (buffer == NULL)
{
ret = -1; // Error
goto error;
goto error_rs;
}
if (timeout == 0)
@ -271,33 +306,94 @@ static int read_string(lua_State *L)
if (bytes_read < 0)
{
ret = -1; // Error
goto error;
goto error_rs;
}
else if (bytes_read == 0)
{
ret = 0; // Timeout
goto error;
goto error_rs;
}
for (ssize_t i=0; i<bytes_read; i++)
else
{
putchar(buffer[i]);
if (option.log)
{
log_putc(buffer[i]);
}
buffer[bytes_read] = (char)0;
}
echo_buffer(&buffer[0], bytes_read);
ret = bytes_read;
error:
error_rs:
lua_pushnumber(L, ret);
if (buffer != NULL)
{
lua_pushstring(L, buffer);
lua_pushstring(L, ret > 0 ? buffer : "");
free(buffer);
}
else
{
lua_pushstring(L, ""); // give empty string to caller
}
return 2;
}
// lua: ret,string = read_line(timeout)
static int read_line(lua_State *L)
{
static char linebuf[READ_LINE_SIZE];
int timeout = lua_tointeger(L, 1); //ms
int ret = 0;
int read_result = 1; //enable reading input from device
char ch;
int bytes_read = 0;
linebuf[0] = '\0';
if (timeout == 0)
{
timeout = -1; // Wait forever
}
// loop reading input until a newline seen or timeout
while (true)
{
read_result = read_poll(device_fd, &ch, 1, timeout);
if (read_result < 0)
{
ret = -1; // Error
linebuf[bytes_read] = '\0';
goto error_rl;
}
else if (!read_result)
{
// Timeout returns a non-empty linebuf as a 'line'
ret = bytes_read;
linebuf[bytes_read] = '\0';
break;
}
else // we got a character, so handle it
{
if (ch == '\n')
{
linebuf[bytes_read] = '\0';
break;
}
else if (bytes_read <= (READ_LINE_SIZE-2))
{
if (isprint(ch)) // store all printable chars
{
linebuf[bytes_read++] = ch;
}
}
}
}
if (bytes_read)
{
echo_buffer(linebuf, bytes_read);
}
ret = bytes_read;
error_rl:
lua_pushnumber(L, ret);
lua_pushstring(L, linebuf);
return 2;
}
@ -457,6 +553,7 @@ static const struct luaL_Reg tio_lib[] =
{ "modem_send", modem_send},
{ "send", send_},
{ "read", read_string},
{ "read_line", read_line},
{ "expect", expect},
{ "exit", exit_},
{ "tty_search", tty_search_},

View file

@ -29,8 +29,6 @@
#include "options.h"
#include "timestamp.h"
#define TIME_STRING_SIZE_MAX 24
char *timestamp_current_time(void)
{
static char time_string[TIME_STRING_SIZE_MAX];

View file

@ -32,5 +32,7 @@ typedef enum
TIMESTAMP_END,
} timestamp_t;
#define TIME_STRING_SIZE_MAX 24
char *timestamp_current_time(void);

View file

@ -1615,6 +1615,7 @@ const char* get_serial_port_type(const char* port_name)
const char* get_serial_port_type(const char* port_name)
{
(void)port_name;
return "";
}