From 0cf4738d702e7002895e8fc4edb96e5fe7fd8eae Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Fri, 13 May 2016 19:00:21 +0200
Subject: [PATCH] time view, not tested at all

---
 common/utils/T/tracer/view/Makefile |   2 +-
 common/utils/T/tracer/view/time.c   | 297 ++++++++++++++++++++++++++++
 common/utils/T/tracer/view/view.h   |   3 +
 3 files changed, 301 insertions(+), 1 deletion(-)
 create mode 100644 common/utils/T/tracer/view/time.c

diff --git a/common/utils/T/tracer/view/Makefile b/common/utils/T/tracer/view/Makefile
index a922ec025d..51b5114a0e 100644
--- a/common/utils/T/tracer/view/Makefile
+++ b/common/utils/T/tracer/view/Makefile
@@ -1,7 +1,7 @@
 CC=gcc
 CFLAGS=-Wall -g -pthread -I..
 
-OBJS=stdout.o textlist.o xy.o tti.o
+OBJS=stdout.o textlist.o xy.o tti.o time.o
 
 view.a: $(OBJS)
 	ar cr view.a $(OBJS)
diff --git a/common/utils/T/tracer/view/time.c b/common/utils/T/tracer/view/time.c
new file mode 100644
index 0000000000..417760f9d5
--- /dev/null
+++ b/common/utils/T/tracer/view/time.c
@@ -0,0 +1,297 @@
+#include "view.h"
+#include "../utils.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+/****************************************************************************/
+/*                              timeview                                    */
+/****************************************************************************/
+
+struct plot {
+  long *nano;
+  int nanosize;
+  int nanomaxsize;
+  int line;
+  int color;
+};
+
+struct tick {
+  struct plot *p;              /* one plot per subview,
+                                * so size is 'subcount'
+                                * (see in struct time below)
+                                */
+};
+
+struct time {
+  view common;
+  gui *g;
+  widget *w;
+  float refresh_rate;
+  pthread_mutex_t lock;
+  struct tick *t;              /* t is a circular list
+                                * a tick lasts one second
+                                */
+  int tsize;                   /* size of t */
+  int tstart;                  /* starting index in t */
+  time_t tstart_time;          /* timestamp (in seconds) of starting in t */
+  int subcount;                /* number of subviews */
+  struct timespec latest_time; /* time of latest received tick */
+  int64_t pixel_length;        /* unit: nanosecond (maximum 1 hour/pixel) */
+};
+
+/* TODO: put that function somewhere else (utils.c) */
+static struct timespec time_add(struct timespec a, struct timespec b)
+{
+  struct timespec ret;
+  ret.tv_sec = a.tv_sec + b.tv_sec;
+  ret.tv_nsec = a.tv_nsec + b.tv_nsec;
+  if (ret.tv_nsec > 1000000000) {
+    ret.tv_sec++;
+    ret.tv_nsec -= 1000000000;
+  }
+  return ret;
+}
+
+/* TODO: put that function somewhere else (utils.c) */
+static struct timespec time_sub(struct timespec a, struct timespec b)
+{
+  struct timespec ret;
+  if (a.tv_nsec < b.tv_nsec) {
+    ret.tv_nsec = (int64_t)a.tv_nsec - (int64_t)b.tv_nsec + 1000000000;
+    ret.tv_sec = a.tv_sec - b.tv_sec - 1;
+  } else {
+    ret.tv_nsec = a.tv_nsec - b.tv_nsec;
+    ret.tv_sec = a.tv_sec - b.tv_sec;
+  }
+  return ret;
+}
+
+/* TODO: put that function somewhere else (utils.c) */
+static struct timespec nano_to_time(int64_t n)
+{
+  struct timespec ret;
+  ret.tv_sec = n / 1000000000;
+  ret.tv_nsec = n % 1000000000;
+  return ret;
+}
+
+/* TODO: put that function somewhere else (utils.c) */
+static int time_cmp(struct timespec a, struct timespec b)
+{
+  if (a.tv_sec < b.tv_sec) return -1;
+  if (a.tv_sec > b.tv_sec) return 1;
+  if (a.tv_nsec < b.tv_nsec) return -1;
+  if (a.tv_nsec > b.tv_nsec) return 1;
+  return 0;
+}
+
+static void *time_thread(void *_this)
+{
+  struct time *this = _this;
+  int width;
+  int l;
+  int i;
+  int t;
+  struct timespec tstart;
+  struct timespec tnext;
+  struct plot *p;
+
+  while (1) {
+    if (pthread_mutex_lock(&this->lock)) abort();
+
+    timeline_get_width(this->g, this->w, &width);
+
+    /* TODO: optimize/cleanup */
+
+    tnext = time_add(this->latest_time,(struct timespec){tv_sec:0,tv_nsec:1});
+    tstart = time_sub(tnext, nano_to_time(this->pixel_length * width));
+
+    for (l = 0; l < this->subcount; l++) {
+      for (i = 0; i < width; i++) {
+        struct timespec tick_start, tick_end;
+        tick_start = time_add(tstart, nano_to_time(this->pixel_length * i));
+        tick_end = time_add(tick_start, nano_to_time(this->pixel_length-1));
+        /* if tick is before start, do nothing */
+        if (time_cmp(tick_end,
+                (struct timespec){tv_sec:this->tstart_time,tv_nsec:0}) < 0)
+          continue;
+        /* if tick after end, do nothing */
+        if (time_cmp(tick_start,
+              time_add((struct timespec){tv_sec:this->tstart_time,tv_nsec:0},
+                       nano_to_time(this->pixel_length * width))) >= 0)
+          continue;
+        /* look for a nano between tick_start and tick_end */
+        /* TODO: optimize */
+        for (t = 0; t < this->tsize; t++) {
+          int n;
+          time_t current_second = this->tstart_time + t;
+          time_t next_second = current_second + 1;
+          struct timespec current_time =
+              (struct timespec){tv_sec:current_second,tv_nsec:0};
+          struct timespec next_time =
+              (struct timespec){tv_sec:next_second,tv_nsec:0};
+          if (time_cmp(tick_end, current_time) < 0) continue;
+          if (time_cmp(tick_start, next_time) >= 0) continue;
+          p = &this->t[(this->tstart + t) % this->tsize].p[l];
+          for (n = 0; n < p->nanosize; n++) {
+            struct timespec nano =
+                (struct timespec){tv_sec:current_second,tv_nsec:p->nano[n]};
+            if (time_cmp(tick_start, nano) <= 0 &&
+                time_cmp(nano, tick_end) < 0)
+              goto gotit;
+          }
+        }
+        continue;
+gotit:
+        /* TODO: only one call */
+        timeline_add_points(this->g, this->w, p->line, p->color, &i, 1);
+      }
+    }
+
+    if (pthread_mutex_unlock(&this->lock)) abort();
+    sleepms(1000 / this->refresh_rate);
+  }
+
+  return 0;
+}
+
+view *new_view_time(int number_of_seconds, float refresh_rate,
+    gui *g, widget *w)
+{
+  struct time *ret = calloc(1, sizeof(struct time));
+  if (ret == NULL) abort();
+
+  ret->refresh_rate = refresh_rate;
+  ret->g = g;
+  ret->w = w;
+
+  ret->t = calloc(number_of_seconds, sizeof(struct tick));
+  if (ret->t == NULL) abort();
+  ret->tsize = number_of_seconds;
+  ret->tstart = 0;
+  ret->tstart_time = 0;
+  ret->subcount = 0;
+  ret->pixel_length = 10 * 1000000;   /* 10ms */
+
+  if (pthread_mutex_init(&ret->lock, NULL)) abort();
+
+  new_thread(time_thread, ret);
+
+  return (view *)ret;
+}
+
+/****************************************************************************/
+/*                            subtimeview                                   */
+/****************************************************************************/
+
+struct subtime {
+  view common;
+  struct time *parent;
+  int line;
+  int color;
+  int subview;
+};
+
+static void append(view *_this, struct timespec t)
+{
+  struct subtime *this = (struct subtime *)_this;
+  struct time    *time = this->parent;
+  time_t         start_time, end_time;
+  int            i, l;
+  int            tpos;
+  struct plot    *p;
+
+  if (pthread_mutex_lock(&time->lock)) abort();
+
+  start_time = time->tstart_time;
+  end_time   = time->tstart_time + time->tsize - 1;
+
+  /* useless test? */
+  if (t.tv_sec < start_time) abort();
+
+  /* tick out of current window? if yes, move window */
+  /* if too far, free all */
+  if (end_time - t.tv_sec > time->tsize) {
+    for (l = 0; l < time->tsize; l++)
+      for (i = 0; i < time->subcount; i++) {
+        free(time->t[l].p[i].nano);
+        time->t[l].p[i].nano = NULL;
+        time->t[l].p[i].nanosize = 0;
+        time->t[l].p[i].nanomaxsize = 0;
+      }
+    time->tstart = 0;
+    time->tstart_time = t.tv_sec - (time->tsize-1);
+    start_time = time->tstart_time;
+    end_time   = time->tstart_time + time->tsize - 1;
+  }
+  while (t.tv_sec > end_time) {
+    for (i = 0; i < time->subcount; i++) {
+      free(time->t[time->tstart].p[i].nano);
+      time->t[time->tstart].p[i].nano = NULL;
+      time->t[time->tstart].p[i].nanosize = 0;
+      time->t[time->tstart].p[i].nanomaxsize = 0;
+    }
+    time->tstart = (time->tstart+1) % time->tsize;
+    time->tstart_time++;
+    start_time++;
+    end_time++;
+  }
+
+  tpos = (time->tstart + (t.tv_sec - time->tstart_time)) % time->tsize;
+  p = &time->t[tpos].p[this->subview];
+
+  /* can we get a new event with <= time than last in list? */
+  if (p->nanosize != 0 && t.tv_nsec <= p->nano[p->nanosize-1])
+    { printf("%s:%d: possible?\n", __FILE__, __LINE__);  abort(); }
+
+  if (p->nanosize == p->nanomaxsize) {
+    p->nanomaxsize += 4096;
+    p->nano = realloc(p->nano, p->nanomaxsize * sizeof(long));
+    if (p->nano == NULL) abort();
+  }
+
+  p->nano[p->nanosize] = t.tv_nsec;
+  p->nanosize++;
+
+  if (time->latest_time.tv_sec < t.tv_sec ||
+      (time->latest_time.tv_sec == t.tv_sec &&
+       time->latest_time.tv_nsec < t.tv_nsec))
+    time->latest_time = t;
+
+  if (pthread_mutex_unlock(&time->lock)) abort();
+}
+
+view *new_subview_time(view *_time, int line, int color)
+{
+  int i;
+  struct time *time = (struct time *)_time;
+  struct subtime *ret = calloc(1, sizeof(struct subtime));
+  if (ret == NULL) abort();
+
+  ret->common.append = (void (*)(view *, ...))append;
+
+  if (pthread_mutex_lock(&time->lock)) abort();
+
+  ret->parent = time;
+  ret->line = line;
+  ret->color = color;
+  ret->subview = time->subcount;
+
+  for (i = 0; i < time->tsize; i++) {
+    time->t[i].p = realloc(time->t[i].p,
+        (time->subcount + 1) * sizeof(struct plot));
+    if (time->t[i].p == NULL) abort();
+    time->t[i].p[time->subcount].nano = NULL;
+    time->t[i].p[time->subcount].nanosize = 0;
+    time->t[i].p[time->subcount].nanomaxsize = 0;
+    time->t[i].p[time->subcount].line = line;
+    time->t[i].p[time->subcount].color = color;
+  }
+
+  time->subcount++;
+
+  if (pthread_mutex_unlock(&time->lock)) abort();
+
+  return (view *)ret;
+}
diff --git a/common/utils/T/tracer/view/view.h b/common/utils/T/tracer/view/view.h
index 529e598d09..8d8036721c 100644
--- a/common/utils/T/tracer/view/view.h
+++ b/common/utils/T/tracer/view/view.h
@@ -17,5 +17,8 @@ view *new_view_xy(int length, float refresh_rate, gui *g, widget *w,
     int color);
 view *new_view_tti(float refresh_rate, gui *g, widget *w,
     int color);
+view *new_view_time(int number_of_seconds, float refresh_rate,
+    gui *g, widget *w);
+view *new_subview_time(view *time, int line, int color);
 
 #endif /* _VIEW_H_ */
-- 
GitLab