]> git.itanic.dy.fi Git - log-plotter/commitdiff
read_data: Handle the input data more gracefully
authorTimo Kokkonen <timo.t.kokkonen@iki.fi>
Sun, 6 Oct 2013 19:25:04 +0000 (22:25 +0300)
committerTimo Kokkonen <timo.t.kokkonen@iki.fi>
Sun, 6 Oct 2013 19:46:14 +0000 (22:46 +0300)
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 <timo.t.kokkonen@iki.fi>
main.c

diff --git a/main.c b/main.c
index 6189b7be34b7048123c441f8ea1c33e96c258741..e116477dd5d77ba2d731dde0e404ea1f888ff435 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <string.h>
 #include <sys/epoll.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #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;