plot.c 7.56 KB
Newer Older
1 2 3 4 5 6 7 8
#include "defs.h"
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <math.h>
#include <unistd.h>
Cedric Roux's avatar
Cedric Roux committed
9
#include <sys/select.h>
10
#include <stdarg.h>
11 12 13 14

typedef struct {
  float *buf;
  short *iqbuf;
Cedric Roux's avatar
Cedric Roux committed
15 16 17 18
  int count;
  int type;
  volatile int iq_count;  /* for ULSCH IQ data */
  int iq_insert_pos;
19 20 21 22 23 24 25 26 27 28
  GC g;
} data;

typedef struct {
  Display *d;
  Window w;
  Pixmap px;
  GC bg;
  int width;
  int height;
Cedric Roux's avatar
Cedric Roux committed
29 30 31
  pthread_mutex_t lock;
  float zoom;
  int timer_pipe[2];
32 33
  data *p;             /* list of plots */
  int nplots;
34 35
} plot;

Cedric Roux's avatar
Cedric Roux committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
static void *timer_thread(void *_p)
{
  plot *p = _p;
  char c;

  while (1) {
    /* more or less 10Hz */
    usleep(100*1000);
    c = 1;
    if (write(p->timer_pipe[1], &c, 1) != 1) abort();
  }

  return NULL;
}

51 52 53 54 55 56
static void *plot_thread(void *_p)
{
  float v;
  float *s;
  int i, j;
  plot *p = _p;
Cedric Roux's avatar
Cedric Roux committed
57 58 59 60 61
  int redraw = 0;
  int replot = 0;
  fd_set rset;
  int xfd = ConnectionNumber(p->d);
  int maxfd = xfd > p->timer_pipe[0] ? xfd : p->timer_pipe[0];
62
  int pp;
Cedric Roux's avatar
Cedric Roux committed
63

64 65 66 67
  while (1) {
    while (XPending(p->d)) {
      XEvent e;
      XNextEvent(p->d, &e);
Cedric Roux's avatar
Cedric Roux committed
68 69 70 71 72 73 74 75 76 77
      switch (e.type) {
      case ButtonPress:
        /* button 4: zoom out */
        if (e.xbutton.button == 4) { p->zoom = p->zoom * 1.25; replot = 1; }
        /* button 5: zoom in */
        if (e.xbutton.button == 5) { p->zoom = p->zoom * 0.8; replot = 1; }
        printf("zoom: %f\n", p->zoom);
        break;
      case Expose: redraw = 1; break;
      }
78 79
    }

Cedric Roux's avatar
Cedric Roux committed
80 81 82 83 84 85
    if (replot == 1) {
      replot = 0;
      redraw = 1;

      if (pthread_mutex_lock(&p->lock)) abort();

Cedric Roux's avatar
Cedric Roux committed
86 87
      XFillRectangle(p->d, p->px, p->bg, 0, 0, p->width, p->height);

88
      for (pp = 0; pp < p->nplots; pp++) {
Cedric Roux's avatar
Cedric Roux committed
89 90 91 92 93 94 95 96 97 98 99 100
        if (p->p[pp].type == PLOT_MINMAX) {
          s = p->p[pp].buf;
          for (i = 0; i < 512; i++) {
            int min = *s;
            int max = *s;
            for (j = 0; j < p->p[pp].count/512; j++, s++) {
              if (*s < min) min = *s;
              if (*s > max) max = *s;
            }
            XDrawLine(p->d, p->px, p->p[pp].g, i, 100-min, i, 100-max);
          }
        } else if (p->p[pp].type == PLOT_VS_TIME) {
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
          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);
Cedric Roux's avatar
Cedric Roux committed
120 121 122 123
        }
      }

      if (pthread_mutex_unlock(&p->lock)) abort();
124 125
    }

Cedric Roux's avatar
Cedric Roux committed
126 127
    if (redraw) {
      redraw = 0;
128
      XCopyArea(p->d, p->px, p->w, DefaultGC(p->d, DefaultScreen(p->d)),
Cedric Roux's avatar
Cedric Roux committed
129
                0, 0, p->width, p->height, 0, 0);
130 131
    }

Cedric Roux's avatar
Cedric Roux committed
132 133
    XFlush(p->d);

Cedric Roux's avatar
Cedric Roux committed
134 135 136 137 138 139
    FD_ZERO(&rset);
    FD_SET(p->timer_pipe[0], &rset);
    FD_SET(xfd, &rset);
    if (select(maxfd+1, &rset, NULL, NULL, NULL) == -1) abort();
    if (FD_ISSET(p->timer_pipe[0], &rset)) {
      char b[512];
140
      if (read(p->timer_pipe[0], b, 512) <= 0) abort();
Cedric Roux's avatar
Cedric Roux committed
141 142
      replot = 1;
    }
143 144 145 146 147
  }

  return NULL;
}

148
void *make_plot(int width, int height, char *title, int nplots, ...)
149 150 151 152 153
{
  plot *p;
  Display *d;
  Window w;
  Pixmap pm;
154 155 156 157 158
  int i;
  va_list ap;
  XGCValues gcv;

  p = malloc(sizeof(*p)); if (p == NULL) abort();
159 160 161 162

  d = XOpenDisplay(0); if (d == NULL) abort();
  w = XCreateSimpleWindow(d, DefaultRootWindow(d), 0, 0, width, height,
        0, WhitePixel(d, DefaultScreen(d)), WhitePixel(d, DefaultScreen(d)));
Cedric Roux's avatar
Cedric Roux committed
163
  XSelectInput(d, w, ExposureMask | ButtonPressMask);
164 165
  XMapWindow(d, w);

166 167 168 169 170 171
  {
    XSetWindowAttributes att;
    att.backing_store = Always;
    XChangeWindowAttributes(d, w, CWBackingStore, &att);
  }

172 173
  XStoreName(d, w, title);

174 175 176 177 178
  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);

179 180 181 182
  pm = XCreatePixmap(d, w, width, height, DefaultDepth(d, DefaultScreen(d)));

  p->width = width;
  p->height = height;
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
  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();
Cedric Roux's avatar
Cedric Roux committed
212 213 214 215
    } else if (type == PLOT_MINMAX) {
      p->p[i].buf = malloc(sizeof(float) * count);
      if (p->p[i].buf == NULL) abort();
      p->p[i].iqbuf = NULL;
216 217 218 219 220 221 222 223 224
    } 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;
Cedric Roux's avatar
Cedric Roux committed
225
  }
226
  va_end(ap);
227 228 229

  p->d = d;
  p->w = w;
230
  p->px = pm;
Cedric Roux's avatar
Cedric Roux committed
231 232

  p->zoom = 1;
233
  p->nplots = nplots;
Cedric Roux's avatar
Cedric Roux committed
234 235 236 237

  pthread_mutex_init(&p->lock, NULL);

  if (pipe(p->timer_pipe)) abort();
238 239

  new_thread(plot_thread, p);
Cedric Roux's avatar
Cedric Roux committed
240
  new_thread(timer_thread, p);
241 242 243 244

  return p;
}

245
void plot_set(void *_plot, float *data, int len, int pos, int pp)
246 247
{
  plot *p = _plot;
Cedric Roux's avatar
Cedric Roux committed
248
  if (pthread_mutex_lock(&p->lock)) abort();
249
  memcpy(p->p[pp].buf + pos, data, len * sizeof(float));
Cedric Roux's avatar
Cedric Roux committed
250 251 252
  if (pthread_mutex_unlock(&p->lock)) abort();
}

253
void iq_plot_set(void *_plot, short *data, int count, int pos, int pp)
Cedric Roux's avatar
Cedric Roux committed
254 255 256
{
  plot *p = _plot;
  if (pthread_mutex_lock(&p->lock)) abort();
257
  memcpy(p->p[pp].iqbuf + pos * 2, data, count * 2 * sizeof(short));
Cedric Roux's avatar
Cedric Roux committed
258 259 260
  if (pthread_mutex_unlock(&p->lock)) abort();
}

261
void iq_plot_set_sized(void *_plot, short *data, int count, int pp)
Cedric Roux's avatar
Cedric Roux committed
262 263 264
{
  plot *p = _plot;
  if (pthread_mutex_lock(&p->lock)) abort();
265 266
  memcpy(p->p[pp].iqbuf, data, count * 2 * sizeof(short));
  p->p[pp].iq_count = count;
Cedric Roux's avatar
Cedric Roux committed
267
  if (pthread_mutex_unlock(&p->lock)) abort();
268 269
}

Cedric Roux's avatar
Cedric Roux committed
270
void iq_plot_add_iq_point_loop(void *_plot, short i, short q, int pp)
271 272
{
  plot *p = _plot;
Cedric Roux's avatar
Cedric Roux committed
273
  if (pthread_mutex_lock(&p->lock)) abort();
274 275 276 277 278
  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;
Cedric Roux's avatar
Cedric Roux committed
279
  if (pthread_mutex_unlock(&p->lock)) abort();
280
}
Cedric Roux's avatar
Cedric Roux committed
281 282 283 284 285 286 287 288 289 290 291

void iq_plot_add_energy_point_loop(void *_plot, int e, int pp)
{
  plot *p = _plot;
  if (pthread_mutex_lock(&p->lock)) abort();
  p->p[pp].buf[p->p[pp].iq_insert_pos] = e;
  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();
}