time view, not tested at all
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
|
||||
Reference in New Issue
Block a user