From: Timo Kokkonen Date: Sun, 6 Oct 2013 19:25:04 +0000 (+0300) Subject: read_data: Handle the input data more gracefully X-Git-Url: http://git.itanic.dy.fi/?p=log-plotter;a=commitdiff_plain;h=3d8040b9815e450cec28cc26aa1d158fb02500ae;hp=564f4d9d9c2cc16e53265c40ad63712cf14f534d read_data: Handle the input data more gracefully The serial port is giving the data to us very slowly, perhaps only a few bytes a time. Therefore we need to take special care in order to not handle incomplete log lines. Add a new function to read one complete line of data from the device. Once the complete line is read, write it to the logfile (if one is open) and then also to the console. Signed-off-by: Timo Kokkonen --- diff --git a/main.c b/main.c index 6189b7b..e116477 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -9,12 +10,67 @@ #include "baud.h" #include "debug.h" -int read_data(int infd, int outfd) +/** + * Read data from a slow device + * + * return 1 when a complete NULL terminated line has been read + * + * return 0 when a partial line has been read and appended to the + * buffer at @offset + * + * return negative on error + */ +static int read_log_line(int infd, char *buf, size_t bufsize, int *offset) +{ + int ret; + int i; + + ret = read(infd, buf + *offset, bufsize - *offset - 1); + if (read < 0) { + pr_err("read: %m\n"); + return -1; + } + + if (ret == 0) { + pr_err("Read EOF, stopping\n"); + return -1; + } + buf[*offset + ret] = 0; + + for (i = 0; i < ret; i++) { + if (buf[i + *offset] == '\n' || + buf[i + *offset] == '\r') { + /* + * Got a complete line when there is a newline + * at the end. Remove the newline and possible + * other junk, such as '\r' + */ + buf[i + *offset] = 0; + *offset = 0; + + return 1; + } + + /* + * Fixme! Nothing guarantees that there isn't actually + * more data (a part of a new log entry perhaps) after + * the newline. So in rare cases (we are prevented + * from reading the serial line in very long time) we + * might lose data from the stream.. + */ + } + + *offset += ret; + return 0; +} + +static int read_data(int infd, int outfd) { struct epoll_event ev; int epoll_fd; int ret; char buf[256]; + int offset; epoll_fd = epoll_create(1); if (epoll_fd < 0) { @@ -39,22 +95,28 @@ int read_data(int infd, int outfd) return -1; } - ret = read(infd, buf, sizeof(buf)); - if (read < 0) { - pr_err("read: %m\n"); - break; - } + ret = read_log_line(infd, buf, sizeof(buf), &offset); + if (ret < 0) + return ret; - if (ret == 0) { - pr_err("Read EOF, stopping\n"); - break; - } + if (ret == 0) + continue; - ret = write(outfd, buf, ret); - if (read < 0) { - pr_err("write: %m\n"); - break; + if (outfd) { + char newline = '\n'; + ret = write(outfd, buf, strlen(buf)); + if (read < 0) { + pr_err("write: %m\n"); + break; + } + ret = write(outfd, &newline, 1); + if (read < 0) { + pr_err("write: %m\n"); + break; + } } + + pr_info("%s\n", buf); } return 0; @@ -63,7 +125,7 @@ int read_data(int infd, int outfd) int main(int argc, char *argv[]) { struct plotter_options options; - int fd, baud, ret = 0, out_fd = STDOUT_FILENO; + int fd, baud, ret = 0, out_fd = 0; if (read_args(argc, argv, &options)) return 1;