From ca945b53de338818d60742f17f542e63db2d009c Mon Sep 17 00:00:00 2001
From: Cedric Roux <cedric.roux@eurecom.fr>
Date: Thu, 28 Apr 2016 15:02:01 +0200
Subject: [PATCH] first version of textlog with GUI introducing generic "view"
with two instantiations: stdout and textlist
---
common/utils/T/tracer/Makefile.remote | 13 ++--
common/utils/T/tracer/remote.c | 30 ++++++++++
common/utils/T/tracer/textlog.c | 61 ++++++++++++++++---
common/utils/T/tracer/textlog.h | 4 ++
common/utils/T/tracer/utils.c | 61 +++++++++++++++++++
common/utils/T/tracer/utils.h | 19 ++++++
common/utils/T/tracer/view/Makefile | 13 ++++
common/utils/T/tracer/view/stdout.c | 35 +++++++++++
common/utils/T/tracer/view/textlist.c | 85 +++++++++++++++++++++++++++
common/utils/T/tracer/view/view.h | 16 +++++
10 files changed, 326 insertions(+), 11 deletions(-)
create mode 100644 common/utils/T/tracer/utils.c
create mode 100644 common/utils/T/tracer/utils.h
create mode 100644 common/utils/T/tracer/view/Makefile
create mode 100644 common/utils/T/tracer/view/stdout.c
create mode 100644 common/utils/T/tracer/view/textlist.c
create mode 100644 common/utils/T/tracer/view/view.h
diff --git a/common/utils/T/tracer/Makefile.remote b/common/utils/T/tracer/Makefile.remote
index 79b1d6ea1e..9dc082e01e 100644
--- a/common/utils/T/tracer/Makefile.remote
+++ b/common/utils/T/tracer/Makefile.remote
@@ -1,5 +1,5 @@
CC=gcc
-CFLAGS=-Wall -g -pthread -DT_TRACER
+CFLAGS=-Wall -g -pthread -DT_TRACER -I.
#CFLAGS += -O3 -ffast-math -fomit-frame-pointer
@@ -11,10 +11,14 @@ OBJS=remote_old.o plot.o database.o gui.o
$(PROG): gui/gui.a $(OBJS)
$(CC) $(CFLAGS) -o $(PROG) $(OBJS) gui/gui.a $(LIBS)
-textlog: remote.o database.o event.o handler.o textlog.o
- $(CC) $(CFLAGS) -o textlog $^
+textlog: utils.o remote.o database.o event.o handler.o textlog.o \
+ view/view.a gui/gui.a
+ $(CC) $(CFLAGS) -o textlog $^ $(LIBS)
-.PHONY: gui/gui.a
+.PHONY: gui/gui.a view/view.a
+
+view/view.a:
+ cd view && make
gui/gui.a:
cd gui && make
@@ -25,3 +29,4 @@ gui/gui.a:
clean:
rm -f *.o $(PROG) core textlog
cd gui && make clean
+ cd view && make clean
diff --git a/common/utils/T/tracer/remote.c b/common/utils/T/tracer/remote.c
index c22cc1bf55..020aba3cdb 100644
--- a/common/utils/T/tracer/remote.c
+++ b/common/utils/T/tracer/remote.c
@@ -8,6 +8,9 @@
#include "event.h"
#include "handler.h"
#include "textlog.h"
+#include "view/view.h"
+#include "gui/gui.h"
+#include "utils.h"
#include "../T_defs.h"
#define DEFAULT_REMOTE_PORT 2021
@@ -55,6 +58,7 @@ void usage(void)
" they will be processed in order\n"
" by default, all is off\n"
" -p <port> use given port (default %d)\n"
+" -x GUI output\n",
DEFAULT_REMOTE_PORT
);
exit(1);
@@ -88,6 +92,13 @@ event get_event(int s, char *v, void *d)
return new_event(type, length, v, d);
}
+static void *gui_thread(void *_g)
+{
+ gui *g = _g;
+ gui_loop(g);
+ return NULL;
+}
+
int main(int n, char **v)
{
char *database_filename = NULL;
@@ -104,6 +115,7 @@ int main(int n, char **v)
int l;
event_handler *h;
textlog *textlog;
+ int gui_mode = 0;
on_off_name = malloc(n * sizeof(char *)); if (on_off_name == NULL) abort();
on_off_action = malloc(n * sizeof(int)); if (on_off_action == NULL) abort();
@@ -122,6 +134,7 @@ int main(int n, char **v)
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=1; continue; }
if (!strcmp(v[i], "-OFF"))
{ on_off_name[on_off_n]=NULL; on_off_action[on_off_n++]=0; continue; }
+ if (!strcmp(v[i], "-x")) { gui_mode = 1; continue; }
usage();
}
@@ -142,6 +155,23 @@ int main(int n, char **v)
"ENB_UL_CHANNEL_ESTIMATE",
"ev: {} eNB_id [eNB_ID] frame [frame] subframe [subframe]");
+ if (gui_mode) {
+ view *tout;
+ gui *g;
+ widget *w, *win;
+ g = gui_init();
+ w = new_text_list(g, 600, 20, 0);
+ win = new_toplevel_window(g, 600, 20*12, "textlog");
+ widget_add_child(g, win, w, -1);
+ //tout = new_textlist(1000, 10, g, w);
+ tout = new_textlist(7, 4, g, w);
+ new_thread(gui_thread, g);
+ textlog_add_view(textlog, tout);
+ } else {
+ view *sout = new_stdout();
+ textlog_add_view(textlog, sout);
+ }
+
for (i = 0; i < on_off_n; i++)
on_off(database, on_off_name[i], is_on, on_off_action[i]);
diff --git a/common/utils/T/tracer/textlog.c b/common/utils/T/tracer/textlog.c
index e6728f9674..4bc66953d5 100644
--- a/common/utils/T/tracer/textlog.c
+++ b/common/utils/T/tracer/textlog.c
@@ -1,8 +1,10 @@
#include "textlog.h"
#include "handler.h"
#include "database.h"
+#include "view/view.h"
#include <stdlib.h>
#include <string.h>
+#include <stdio.h>
enum format_item_type {
INSTRING,
@@ -23,25 +25,62 @@ struct textlog {
char *format;
void *database;
unsigned long handler_id;
+ /* parsed format string */
struct format_item *f;
int fsize;
+ /* list of views */
+ view **v;
+ int vsize;
+ /* local output buffer */
+ int osize;
+ int omaxsize;
+ char *obuf;
};
-#include <stdio.h>
+static void PUTC(struct textlog *l, char c)
+{
+ if (l->osize == l->omaxsize) {
+ l->omaxsize += 512;
+ l->obuf = realloc(l->obuf, l->omaxsize);
+ if (l->obuf == NULL) abort();
+ }
+ l->obuf[l->osize] = c;
+ l->osize++;
+}
+
+static void PUTS(struct textlog *l, char *s)
+{
+ while (*s) PUTC(l, *s++);
+}
+
+static void PUTI(struct textlog *l, int i)
+{
+ char s[64];
+ sprintf(s, "%d", i);
+ PUTS(l, s);
+}
+
static void _event(void *p, event e)
{
struct textlog *l = p;
int i;
-//printf("%s %s\n", l->event_name, l->format);
+
+ l->osize = 0;
for (i = 0; i < l->fsize; i++)
switch(l->f[i].type) {
- case INSTRING: printf("%s", l->f[i].s); break;
- case INT: printf("%d", e.e[l->f[i].event_arg].i); break;
- case STRING: printf("%s", e.e[l->f[i].event_arg].s); break;
- case BUFFER: printf("{buffer size:%d}",e.e[l->f[i].event_arg].bsize);break;
+ case INSTRING: PUTS(l, l->f[i].s); break;
+ case INT: PUTI(l, e.e[l->f[i].event_arg].i); break;
+ case STRING: PUTS(l, e.e[l->f[i].event_arg].s); break;
+ case BUFFER:
+ PUTS(l, "{buffer size:");
+ PUTI(l, e.e[l->f[i].event_arg].bsize);
+ PUTS(l, "}");
+ break;
}
- printf("\n");
+ PUTC(l, 0);
+
+ for (i = 0; i < l->vsize; i++) l->v[i]->append(l->v[i], l->obuf);
}
enum chunk_type { C_ERROR, C_STRING, C_ARG_NAME, C_EVENT_NAME };
@@ -166,3 +205,11 @@ error:
printf("%s:%d: bad format '%s'\n", __FILE__, __LINE__, format);
abort();
}
+
+void textlog_add_view(textlog *_l, view *v)
+{
+ struct textlog *l = _l;
+ l->vsize++;
+ l->v = realloc(l->v, l->vsize * sizeof(view *)); if (l->v == NULL) abort();
+ l->v[l->vsize-1] = v;
+}
diff --git a/common/utils/T/tracer/textlog.h b/common/utils/T/tracer/textlog.h
index 5c23f3a2db..b9e9a3e8e3 100644
--- a/common/utils/T/tracer/textlog.h
+++ b/common/utils/T/tracer/textlog.h
@@ -6,4 +6,8 @@ typedef void textlog;
textlog *new_textlog(void *event_handler, void *database,
char *event_name, char *format);
+#include "view/view.h"
+
+void textlog_add_view(textlog *l, view *v);
+
#endif /* _TEXTLOG_H_ */
diff --git a/common/utils/T/tracer/utils.c b/common/utils/T/tracer/utils.c
new file mode 100644
index 0000000000..2e18ccb60e
--- /dev/null
+++ b/common/utils/T/tracer/utils.c
@@ -0,0 +1,61 @@
+#include "utils.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <time.h>
+
+void new_thread(void *(*f)(void *), void *data)
+{
+ pthread_t t;
+ pthread_attr_t att;
+
+ if (pthread_attr_init(&att))
+ { fprintf(stderr, "pthread_attr_init err\n"); exit(1); }
+ if (pthread_attr_setdetachstate(&att, PTHREAD_CREATE_DETACHED))
+ { fprintf(stderr, "pthread_attr_setdetachstate err\n"); exit(1); }
+ if (pthread_attr_setstacksize(&att, 10000000))
+ { fprintf(stderr, "pthread_attr_setstacksize err\n"); exit(1); }
+ if (pthread_create(&t, &att, f, data))
+ { fprintf(stderr, "pthread_create err\n"); exit(1); }
+ if (pthread_attr_destroy(&att))
+ { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); }
+}
+
+void sleepms(int ms)
+{
+ struct timespec t;
+
+ t.tv_sec = ms / 1000;
+ t.tv_nsec = (ms % 1000) * 1000000L;
+
+ /* TODO: deal with EINTR */
+ if (nanosleep(&t, NULL)) abort();
+}
+
+/****************************************************************************/
+/* list */
+/****************************************************************************/
+
+list *list_remove_head(list *l)
+{
+ list *ret;
+ if (l == NULL) return NULL;
+ ret = l->next;
+ if (ret != NULL) ret->last = l->last;
+ free(l);
+ return ret;
+}
+
+list *list_append(list *l, void *data)
+{
+ list *new = calloc(1, sizeof(list));
+ if (new == NULL) abort();
+ new->data = data;
+ if (l == NULL) {
+ new->last = new;
+ return new;
+ }
+ l->last->next = new;
+ l->last = new;
+ return l;
+}
diff --git a/common/utils/T/tracer/utils.h b/common/utils/T/tracer/utils.h
new file mode 100644
index 0000000000..5a37aa34c3
--- /dev/null
+++ b/common/utils/T/tracer/utils.h
@@ -0,0 +1,19 @@
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+void new_thread(void *(*f)(void *), void *data);
+void sleepms(int ms);
+
+/****************************************************************************/
+/* list */
+/****************************************************************************/
+
+typedef struct list {
+ struct list *last, *next;
+ void *data;
+} list;
+
+list *list_remove_head(list *l);
+list *list_append(list *l, void *data);
+
+#endif /* _UTILS_H_ */
diff --git a/common/utils/T/tracer/view/Makefile b/common/utils/T/tracer/view/Makefile
new file mode 100644
index 0000000000..bcf49d15cb
--- /dev/null
+++ b/common/utils/T/tracer/view/Makefile
@@ -0,0 +1,13 @@
+CC=gcc
+CFLAGS=-Wall -g -pthread -I..
+
+OBJS=stdout.o textlist.o
+
+view.a: $(OBJS)
+ ar cr view.a $(OBJS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -o $@ -c $<
+
+clean:
+ rm -f *.a *.o
diff --git a/common/utils/T/tracer/view/stdout.c b/common/utils/T/tracer/view/stdout.c
new file mode 100644
index 0000000000..695704e422
--- /dev/null
+++ b/common/utils/T/tracer/view/stdout.c
@@ -0,0 +1,35 @@
+#include "view.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <pthread.h>
+
+struct stdout {
+ view common;
+ pthread_mutex_t lock;
+};
+
+static void clear(view *this)
+{
+ /* do nothing */
+}
+
+static void append(view *_this, char *s)
+{
+ struct stdout *this = (struct stdout *)_this;
+ if (pthread_mutex_lock(&this->lock)) abort();
+ printf("%s\n", s);
+ if (pthread_mutex_unlock(&this->lock)) abort();
+}
+
+view *new_stdout(void)
+{
+ struct stdout *ret = calloc(1, sizeof(struct stdout));
+ if (ret == NULL) abort();
+
+ ret->common.clear = clear;
+ ret->common.append = (void (*)(view *, ...))append;
+
+ if (pthread_mutex_init(&ret->lock, NULL)) abort();
+
+ return (view *)ret;
+}
diff --git a/common/utils/T/tracer/view/textlist.c b/common/utils/T/tracer/view/textlist.c
new file mode 100644
index 0000000000..7d1948e044
--- /dev/null
+++ b/common/utils/T/tracer/view/textlist.c
@@ -0,0 +1,85 @@
+#include "view.h"
+#include "../utils.h"
+#include "gui/gui.h"
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+
+struct textlist {
+ view common;
+ gui *g;
+ widget *w;
+ int maxsize;
+ int cursize;
+ float refresh_rate;
+ int autoscroll;
+ pthread_mutex_t lock;
+ list * volatile to_append;
+};
+
+static void _append(struct textlist *this, char *s)
+{
+ if (this->cursize == this->maxsize) {
+ text_list_del(this->g, this->w, 0);
+ this->cursize--;
+ }
+ text_list_add(this->g, this->w, s, -1);
+ this->cursize++;
+}
+
+static void *textlist_thread(void *_this)
+{
+ struct textlist *this = _this;
+
+ while (1) {
+ if (pthread_mutex_lock(&this->lock)) abort();
+ while (this->to_append != NULL) {
+ char *s = this->to_append->data;
+ this->to_append = list_remove_head(this->to_append);
+ _append(this, s);
+ free(s);
+ }
+ if (pthread_mutex_unlock(&this->lock)) abort();
+ sleepms(1000/this->refresh_rate);
+ }
+
+ return 0;
+}
+
+static void clear(view *this)
+{
+ /* TODO */
+}
+
+static void append(view *_this, char *s)
+{
+ struct textlist *this = (struct textlist *)_this;
+ char *dup;
+
+ if (pthread_mutex_lock(&this->lock)) abort();
+ dup = strdup(s); if (dup == NULL) abort();
+ this->to_append = list_append(this->to_append, dup);
+ if (pthread_mutex_unlock(&this->lock)) abort();
+}
+
+view *new_textlist(int maxsize, float refresh_rate, gui *g, widget *w)
+{
+ struct textlist *ret = calloc(1, sizeof(struct textlist));
+ if (ret == NULL) abort();
+
+ ret->common.clear = clear;
+ ret->common.append = (void (*)(view *, ...))append;
+
+ ret->cursize = 0;
+ ret->maxsize = maxsize;
+ ret->refresh_rate = refresh_rate;
+ ret->g = g;
+ ret->w = w;
+ ret->autoscroll = 1;
+
+ if (pthread_mutex_init(&ret->lock, NULL)) abort();
+
+ new_thread(textlist_thread, ret);
+
+ return (view *)ret;
+}
diff --git a/common/utils/T/tracer/view/view.h b/common/utils/T/tracer/view/view.h
new file mode 100644
index 0000000000..9929e6e5d4
--- /dev/null
+++ b/common/utils/T/tracer/view/view.h
@@ -0,0 +1,16 @@
+#ifndef _VIEW_H_
+#define _VIEW_H_
+
+#include "gui/gui.h"
+
+/* defines the public API of views */
+
+typedef struct view {
+ void (*clear)(struct view *this);
+ void (*append)(struct view *this, ...);
+} view;
+
+view *new_stdout(void);
+view *new_textlist(int maxsize, float refresh_rate, gui *g, widget *w);
+
+#endif /* _VIEW_H_ */
--
GitLab