diff --git a/common/utils/T/tracer/Makefile.remote b/common/utils/T/tracer/Makefile.remote index 79b1d6ea1eaa40d9cd51fb800159cd216c1685c3..9dc082e01e1d1f3b02ab0e81d5030f6124cb7785 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 c22cc1bf55231bb5b45d8577d0c8a33e11273d5b..020aba3cdb80bf0ca81bb7baf99c2956f4c2ae36 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 e6728f9674badcc66270064db3878b2dbd039f80..4bc66953d52647ec73ee6dd88e2037bd6d69efda 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 5c23f3a2db8af2a6854d4ac02d9dfbc7178a09c2..b9e9a3e8e3d9bd13fb3879c35f3537790b53f2b4 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 0000000000000000000000000000000000000000..2e18ccb60e3f35cf0f5dd38544aaccebe53dfd02 --- /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 0000000000000000000000000000000000000000..5a37aa34c3485b40f260e39685091ca4fe094a38 --- /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 0000000000000000000000000000000000000000..bcf49d15cb55b6c511914298ed38351fed0bc18b --- /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 0000000000000000000000000000000000000000..695704e4221d4a4667f9dae9e036c49c01824d01 --- /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 0000000000000000000000000000000000000000..7d1948e044b082b45777e9c911b266e39b735e09 --- /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 0000000000000000000000000000000000000000..9929e6e5d4324d562553bb791ebf209d7e94e7db --- /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_ */