diff --git a/tracer/defs.h b/tracer/defs.h index 873292a70ca7cd39c9b84188838328aa3c472c37..483e42ae906389dc260ba752c1d3a5a81d90217e 100644 --- a/tracer/defs.h +++ b/tracer/defs.h @@ -5,11 +5,12 @@ #define PLOT_VS_TIME 0 #define PLOT_IQ_POINTS 1 -void *make_plot(int width, int height, int bufsize, char *title, int type); -void plot_set(void *plot, float *data, int len, int pos); -void iq_plot_set(void *plot, short *data, int len, int pos); -void iq_plot_set_sized(void *_plot, short *data, int len); -void iq_plot_add_point_loop(void *_plot, short i, short q); +/* ... is { int count; int type; char *color; } for 'nplots' plots */ +void *make_plot(int width, int height, char *title, int nplots, ...); +void plot_set(void *plot, float *data, int len, int pos, int pp); +void iq_plot_set(void *plot, short *data, int len, int pos, int pp); +void iq_plot_set_sized(void *_plot, short *data, int len, int pp); +void iq_plot_add_point_loop(void *_plot, short i, short q, int pp); /* returns an opaque pointer - truly a 'database *', see t_data.c */ void *parse_database(char *filename); diff --git a/tracer/main.c b/tracer/main.c index 853ed46fedf24a87500515f46ed7d326c93c74c0..0b529b132b21b96453d56e593a1623bfb27262c7 100644 --- a/tracer/main.c +++ b/tracer/main.c @@ -218,7 +218,7 @@ void get_message(int s) #endif if (size != 4 * 7680) {printf("bad T_ENB_INPUT_SIGNAL, only 7680 samples allowed\n");abort();} - if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680); + if (ul_plot) iq_plot_set(ul_plot, (short*)buf, 7680, subframe*7680, 0); break; } case T_ENB_UL_CHANNEL_ESTIMATE: { @@ -235,7 +235,7 @@ void get_message(int s) if (size != 512*4) {printf("bad T_ENB_UL_CHANNEL_ESTIMATE, only 512 samples allowed\n"); abort();} - if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0); + if (chest_plot) iq_plot_set(chest_plot, (short*)buf, 512, 0, 0); break; } case T_PUSCH_IQ: { @@ -260,7 +260,7 @@ void get_message(int s) src = (uint32_t*)buf + l * 12 * 25; for (i = 0; i < nb_rb*12; i++) *dst++ = *src++; } - iq_plot_set_sized(pusch_iq_plot, (short*)buf, nb_rb*12*14); + iq_plot_set_sized(pusch_iq_plot, (short*)buf, nb_rb*12*14, 0); } break; } @@ -273,7 +273,7 @@ void get_message(int s) GET(s, &I, sizeof(int)); GET(s, &Q, sizeof(int)); printf("receiving %d %d\n", I, Q); - if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10); + if (pucch_iq_plot) iq_plot_add_point_loop(pucch_iq_plot, I*10, Q*10, 0); break; } case T_buf_test: { @@ -385,11 +385,14 @@ int main(int n, char **v) if (do_dump_database) { dump_database(database); return 0; } if (do_xforms) { - ul_plot = make_plot(512, 100, 7680*10, "UL Input Signal", PLOT_VS_TIME); - chest_plot = make_plot(512, 100, 512, "UL Channel Estimate UE 0", - PLOT_VS_TIME); - pusch_iq_plot = make_plot(100, 100, 12*25*14, "PUSCH IQ",PLOT_IQ_POINTS); - pucch_iq_plot = make_plot(100, 100, 1000, "PUCCH IQ", PLOT_IQ_POINTS); + ul_plot = make_plot(512, 100, "UL Input Signal", 1, + 7680*10, PLOT_VS_TIME, "blue"); + chest_plot = make_plot(512, 100, "UL Channel Estimate UE 0", 1, + 512, PLOT_VS_TIME, "blue"); + pusch_iq_plot = make_plot(100, 100, "PUSCH IQ", 1, + 12*25*14, PLOT_IQ_POINTS, "blue"); + pucch_iq_plot = make_plot(100, 100, "PUCCH IQ", 1, + 1000, PLOT_IQ_POINTS, "blue"); } for (i = 0; i < on_off_n; i++) diff --git a/tracer/plot.c b/tracer/plot.c index e13398ab5e5d7fee653a7ae0b89c6a63f0c1119a..bdb864f2954431b9a5d857b27fca325cf9f2be23 100644 --- a/tracer/plot.c +++ b/tracer/plot.c @@ -8,22 +8,30 @@ #include <unistd.h> #include <pthread.h> #include <sys/select.h> +#include <stdarg.h> typedef struct { - Display *d; - Window w; - Pixmap p; - int width; - int height; float *buf; short *iqbuf; int count; int type; volatile int iq_count; /* for ULSCH IQ data */ int iq_insert_pos; + GC g; +} data; + +typedef struct { + Display *d; + Window w; + Pixmap px; + GC bg; + int width; + int height; pthread_mutex_t lock; float zoom; int timer_pipe[2]; + data *p; /* list of plots */ + int nplots; } plot; static void *timer_thread(void *_p) @@ -52,6 +60,7 @@ static void *plot_thread(void *_p) fd_set rset; int xfd = ConnectionNumber(p->d); int maxfd = xfd > p->timer_pipe[0] ? xfd : p->timer_pipe[0]; + int pp; while (1) { while (XPending(p->d)) { @@ -73,41 +82,31 @@ static void *plot_thread(void *_p) replot = 0; redraw = 1; - /* TODO: get white & black GCs at startup */ - { - GC gc; - XGCValues v; - gc = DefaultGC(p->d, DefaultScreen(p->d)); - v.foreground = WhitePixel(p->d, DefaultScreen(p->d)); - XChangeGC(p->d, gc, GCForeground, &v); - XFillRectangle(p->d, p->p, gc, 0, 0, p->width, p->height); - v.foreground = BlackPixel(p->d, DefaultScreen(p->d)); - XChangeGC(p->d, gc, GCForeground, &v); - } - if (pthread_mutex_lock(&p->lock)) abort(); - if (p->type == PLOT_VS_TIME) { - for (i = 0; i < p->count; i++) - p->buf[i] = 10*log10(1.0+(float)(p->iqbuf[2*i]*p->iqbuf[2*i]+ - p->iqbuf[2*i+1]*p->iqbuf[2*i+1])); - s = p->buf; - for (i = 0; i < 512; i++) { - v = 0; - for (j = 0; j < p->count/512; j++, s++) v += *s; - v /= p->count/512; - XDrawLine(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), - i, 100, i, 100-v); + for (pp = 0; pp < p->nplots; pp++) { + XFillRectangle(p->d, p->px, p->bg, 0, 0, p->width, p->height); + if (p->p[pp].type == PLOT_VS_TIME) { + for (i = 0; i < p->p[pp].count; i++) + p->p[pp].buf[i] = + 10*log10(1.0+(float)(p->p[pp].iqbuf[2*i]*p->p[pp].iqbuf[2*i]+ + p->p[pp].iqbuf[2*i+1]*p->p[pp].iqbuf[2*i+1])); + s = p->p[pp].buf; + for (i = 0; i < 512; i++) { + v = 0; + for (j = 0; j < p->p[pp].count/512; j++, s++) v += *s; + v /= p->p[pp].count/512; + XDrawLine(p->d, p->px, p->p[pp].g, i, 100, i, 100-v); + } + } else if (p->p[pp].type == PLOT_IQ_POINTS) { + XPoint pts[p->p[pp].iq_count]; + int count = p->p[pp].iq_count; + for (i = 0; i < count; i++) { + pts[i].x = p->p[pp].iqbuf[2*i]*p->zoom/20+50; + pts[i].y = -p->p[pp].iqbuf[2*i+1]*p->zoom/20+50; + } + XDrawPoints(p->d, p->px, p->p[pp].g, pts, count, CoordModeOrigin); } - } else if (p->type == PLOT_IQ_POINTS) { - XPoint pts[p->iq_count]; - int count = p->iq_count; - for (i = 0; i < count; i++) { - pts[i].x = p->iqbuf[2*i]*p->zoom/20+50; - pts[i].y = -p->iqbuf[2*i+1]*p->zoom/20+50; - } - XDrawPoints(p->d, p->p, DefaultGC(p->d, DefaultScreen(p->d)), - pts, count, CoordModeOrigin); } if (pthread_mutex_unlock(&p->lock)) abort(); @@ -115,7 +114,7 @@ static void *plot_thread(void *_p) if (redraw) { redraw = 0; - XCopyArea(p->d, p->p, p->w, DefaultGC(p->d, DefaultScreen(p->d)), + XCopyArea(p->d, p->px, p->w, DefaultGC(p->d, DefaultScreen(p->d)), 0, 0, p->width, p->height, 0, 0); } @@ -125,7 +124,7 @@ static void *plot_thread(void *_p) if (select(maxfd+1, &rset, NULL, NULL, NULL) == -1) abort(); if (FD_ISSET(p->timer_pipe[0], &rset)) { char b[512]; - read(p->timer_pipe[0], b, 512); + if (read(p->timer_pipe[0], b, 512) <= 0) abort(); replot = 1; } } @@ -150,12 +149,17 @@ static void new_thread(void *(*f)(void *), void *data) { fprintf(stderr, "pthread_attr_destroy err\n"); exit(1); } } -void *make_plot(int width, int height, int count, char *title, int type) +void *make_plot(int width, int height, char *title, int nplots, ...) { plot *p; Display *d; Window w; Pixmap pm; + int i; + va_list ap; + XGCValues gcv; + + p = malloc(sizeof(*p)); if (p == NULL) abort(); d = XOpenDisplay(0); if (d == NULL) abort(); w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, width, height, @@ -163,31 +167,70 @@ void *make_plot(int width, int height, int count, char *title, int type) XSelectInput(d, w, ExposureMask | ButtonPressMask); XMapWindow(d, w); + { + XSetWindowAttributes att; + att.backing_store = Always; + XChangeWindowAttributes(d, w, CWBackingStore, &att); + } + XStoreName(d, w, title); + p->bg = XCreateGC(d, w, 0, NULL); + XCopyGC(d, DefaultGC(d, DefaultScreen(d)), -1L, p->bg); + gcv.foreground = WhitePixel(d, DefaultScreen(d)); + XChangeGC(d, p->bg, GCForeground, &gcv); + pm = XCreatePixmap(d, w, width, height, DefaultDepth(d, DefaultScreen(d))); - p = malloc(sizeof(*p)); if (p == NULL) abort(); p->width = width; p->height = height; - if (type == PLOT_VS_TIME) { - p->buf = malloc(sizeof(float) * count); if (p->buf == NULL) abort(); - p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort(); - } else { - p->buf = NULL; - p->iqbuf = malloc(sizeof(short) * count * 2); if(p->iqbuf==NULL)abort(); + p->p = malloc(nplots * sizeof(data)); if (p->p == NULL) abort(); + + va_start(ap, nplots); + for (i = 0; i < nplots; i++) { + int count; + int type; + char *color; + XColor rcol, scol; + + count = va_arg(ap, int); + type = va_arg(ap, int); + color = va_arg(ap, char *); + + p->p[i].g = XCreateGC(d, w, 0, NULL); + XCopyGC(d, DefaultGC(d, DefaultScreen(d)), -1L, p->p[i].g); + if (XAllocNamedColor(d, DefaultColormap(d, DefaultScreen(d)), + color, &scol, &rcol)) { + gcv.foreground = scol.pixel; + XChangeGC(d, p->p[i].g, GCForeground, &gcv); + } else { + printf("could not allocate color '%s'\n", color); + abort(); + } + + if (type == PLOT_VS_TIME) { + p->p[i].buf = malloc(sizeof(float) * count); + if (p->p[i].buf == NULL) abort(); + p->p[i].iqbuf = malloc(sizeof(short) * count * 2); + if(p->p[i].iqbuf==NULL)abort(); + } else { + p->p[i].buf = NULL; + p->p[i].iqbuf = malloc(sizeof(short) * count * 2); + if(p->p[i].iqbuf==NULL)abort(); + } + p->p[i].count = count; + p->p[i].type = type; + p->p[i].iq_count = 0; + p->p[i].iq_insert_pos = 0; } - p->count = count; + va_end(ap); p->d = d; p->w = w; - p->p = pm; - p->type = type; - - p->iq_count = 0; - p->iq_insert_pos = 0; + p->px = pm; p->zoom = 1; + p->nplots = nplots; pthread_mutex_init(&p->lock, NULL); @@ -199,39 +242,39 @@ void *make_plot(int width, int height, int count, char *title, int type) return p; } -void plot_set(void *_plot, float *data, int len, int pos) +void plot_set(void *_plot, float *data, int len, int pos, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - memcpy(p->buf + pos, data, len * sizeof(float)); + memcpy(p->p[pp].buf + pos, data, len * sizeof(float)); if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_set(void *_plot, short *data, int count, int pos) +void iq_plot_set(void *_plot, short *data, int count, int pos, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - memcpy(p->iqbuf + pos * 2, data, count * 2 * sizeof(short)); + memcpy(p->p[pp].iqbuf + pos * 2, data, count * 2 * sizeof(short)); if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_set_sized(void *_plot, short *data, int count) +void iq_plot_set_sized(void *_plot, short *data, int count, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - memcpy(p->iqbuf, data, count * 2 * sizeof(short)); - p->iq_count = count; + memcpy(p->p[pp].iqbuf, data, count * 2 * sizeof(short)); + p->p[pp].iq_count = count; if (pthread_mutex_unlock(&p->lock)) abort(); } -void iq_plot_add_point_loop(void *_plot, short i, short q) +void iq_plot_add_point_loop(void *_plot, short i, short q, int pp) { plot *p = _plot; if (pthread_mutex_lock(&p->lock)) abort(); - p->iqbuf[p->iq_insert_pos*2] = i; - p->iqbuf[p->iq_insert_pos*2+1] = q; - if (p->iq_count != p->count) p->iq_count++; - p->iq_insert_pos++; - if (p->iq_insert_pos == p->count) p->iq_insert_pos = 0; + p->p[pp].iqbuf[p->p[pp].iq_insert_pos*2] = i; + p->p[pp].iqbuf[p->p[pp].iq_insert_pos*2+1] = q; + if (p->p[pp].iq_count != p->p[pp].count) p->p[pp].iq_count++; + p->p[pp].iq_insert_pos++; + if (p->p[pp].iq_insert_pos == p->p[pp].count) p->p[pp].iq_insert_pos = 0; if (pthread_mutex_unlock(&p->lock)) abort(); }