first version of textlog with GUI
introducing generic "view" with two instantiations: stdout and textlist
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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_ */
|
||||
Reference in New Issue
Block a user