SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
framework.h
Go to the documentation of this file.
1 // This file is part of LeanSDR Copyright (C) 2016-2018 <pabr@pabr.org>.
2 // See the toplevel README for more information.
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 #ifndef LEANSDR_FRAMEWORK_H
18 #define LEANSDR_FRAMEWORK_H
19 
20 #include <cstddef>
21 #include <algorithm>
22 
23 #include <math.h>
24 #include <stdint.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #ifndef VERSION
30 #define VERSION "undefined"
31 #endif
32 
33 namespace leansdr
34 {
35 
36 void fatal(const char *s);
37 void fail(const char *s);
38 
40 // DSP framework
42 
43 // [pipebuf] is a FIFO buffer with multiple readers.
44 // [pipewriter] is a client-side hook for writing into a [pipebuf].
45 // [pipereader] is a client-side hook reading from a [pipebuf].
46 // [runnable] is anything that moves data between [pipebufs].
47 // [scheduler] is a global context which invokes [runnables] until fixpoint.
48 
49 static const int MAX_PIPES = 64;
50 static const int MAX_RUNNABLES = 64;
51 static const int MAX_READERS = 8;
52 
54 {
55  virtual int sizeofT()
56  {
57  return 0;
58  }
59 
60  virtual long long hash()
61  {
62  return 0;
63  }
64 
65  virtual void dump(std::size_t *total_bufs)
66  {
67  (void)total_bufs;
68  }
69 
70  const char *name;
71 
72  pipebuf_common(const char *_name) : name(_name)
73  {
74  }
75 
76  virtual ~pipebuf_common()
77  {
78  }
79 };
80 
82 {
83  const char *name;
84 
85  runnable_common(const char *_name) : name(_name)
86  {
87  }
88 
89  virtual ~runnable_common()
90  {
91  }
92 
93  virtual void run()
94  {
95  }
96 
97  virtual void shutdown()
98  {
99  }
100 #ifdef DEBUG
101  ~runnable_common()
102  {
103  fprintf(stderr, "Deallocating %s !\n", name);
104  }
105 #endif
106 };
107 
109 {
110  const char *name; // NULL to terminate
111  int x, y, w, h;
112 };
113 
114 struct scheduler
115 {
116  pipebuf_common *pipes[MAX_PIPES];
117  int npipes;
118  runnable_common *runnables[MAX_RUNNABLES];
121  bool verbose, debug, debug2;
122 
123  scheduler() : npipes(0),
124  nrunnables(0),
125  windows(NULL),
126  verbose(false),
127  debug(false),
128  debug2(false)
129  {
130  }
131 
133  {
134  if (npipes == MAX_PIPES)
135  fail("MAX_PIPES");
136  pipes[npipes++] = p;
137  }
138 
140  {
141  if (nrunnables == MAX_RUNNABLES)
142  fail("MAX_RUNNABLES");
143  runnables[nrunnables++] = r;
144  }
145 
146  void step()
147  {
148  for (int i = 0; i < nrunnables; ++i)
149  runnables[i]->run();
150  }
151 
152  void run()
153  {
154  unsigned long long prev_hash = 0;
155 
156  while (1)
157  {
158  step();
159  unsigned long long h = hash();
160  if (h == prev_hash)
161  break;
162  prev_hash = h;
163  }
164  }
165 
166  void shutdown()
167  {
168  for (int i = 0; i < nrunnables; ++i)
169  runnables[i]->shutdown();
170  }
171 
172  unsigned long long hash()
173  {
174  unsigned long long h = 0;
175  for (int i = 0; i < npipes; ++i)
176  h += (1 + i) * pipes[i]->hash();
177  return h;
178  }
179 
180  void dump()
181  {
182  fprintf(stderr, "\n");
183  std::size_t total_bufs = 0;
184  for (int i = 0; i < npipes; ++i)
185  pipes[i]->dump(&total_bufs);
186  fprintf(stderr, "Total buffer memory: %ld KiB\n",
187  (unsigned long)total_bufs / 1024);
188  }
189 };
190 
192 {
193  runnable(scheduler *_sch, const char *name) : runnable_common(name), sch(_sch)
194  {
195  sch->add_runnable(this);
196  }
197 
198  protected:
200 };
201 
202 template <typename T>
204 {
205  T *buf;
206  T *rds[MAX_READERS];
207  int nrd;
208  T *wr;
209  T *end;
210 
211  int sizeofT()
212  {
213  return sizeof(T);
214  }
215 
216  pipebuf(scheduler *sch, const char *name, unsigned long size) : pipebuf_common(name),
217  buf(new T[size]),
218  nrd(0), wr(buf),
219  end(buf + size),
220  min_write(1),
221  total_written(0),
222  total_read(0)
223  {
224  sch->add_pipe(this);
225  }
226 
228  {
229  if (nrd == MAX_READERS)
230  fail("too many readers");
231  rds[nrd] = wr;
232  return nrd++;
233  }
234 
235  void pack()
236  {
237  T *rd = wr;
238  for (int i = 0; i < nrd; ++i)
239  if (rds[i] < rd)
240  rd = rds[i];
241  memmove(buf, rd, (wr - rd) * sizeof(T));
242  wr -= rd - buf;
243  for (int i = 0; i < nrd; ++i)
244  rds[i] -= rd - buf;
245  }
246 
247  long long hash()
248  {
249  return total_written + total_read;
250  }
251 
252  void dump(std::size_t *total_bufs)
253  {
254  if (total_written < 10000)
255  fprintf(stderr, ".%-16s : %4ld/%4ld", name, total_read,
256  total_written);
257  else if (total_written < 1000000)
258  fprintf(stderr, ".%-16s : %3ldk/%3ldk", name, total_read / 1000,
259  total_written / 1000);
260  else
261  fprintf(stderr, ".%-16s : %3ldM/%3ldM", name, total_read / 1000000,
262  total_written / 1000000);
263  *total_bufs += (end - buf) * sizeof(T);
264  unsigned long nw = end - wr;
265  fprintf(stderr, " %6ld writable %c,", nw, (nw < min_write) ? '!' : ' ');
266  T *rd = wr;
267  for (int j = 0; j < nrd; ++j)
268  if (rds[j] < rd)
269  rd = rds[j];
270  fprintf(stderr, " %6d unread (", (int)(wr - rd));
271  for (int j = 0; j < nrd; ++j)
272  fprintf(stderr, " %d", (int)(wr - rds[j]));
273  fprintf(stderr, " )\n");
274  }
275  unsigned long min_write;
276  unsigned long total_written, total_read;
277 #ifdef DEBUG
278  ~pipebuf()
279  {
280  fprintf(stderr, "Deallocating %s !\n", name);
281  }
282 #endif
283 };
284 
285 template <typename T>
287 {
289 
290  pipewriter(pipebuf<T> &_buf, unsigned long min_write = 1) : buf(_buf)
291  {
292  if (min_write > buf.min_write)
293  buf.min_write = min_write;
294  }
295  // Return number of items writable at this->wr, 0 if full.
296  long writable()
297  {
298  if (buf.end < buf.min_write + buf.wr)
299  buf.pack();
300  return buf.end - buf.wr;
301  }
302 
303  T *wr()
304  {
305  return buf.wr;
306  }
307 
308  void written(unsigned long n)
309  {
310  if (buf.wr + n > buf.end)
311  {
312  fprintf(stderr, "Bug: overflow to %s\n", buf.name);
313  }
314 
315  buf.wr += n;
316  buf.total_written += n;
317  }
318 
319  void write(const T &e)
320  {
321  *wr() = e;
322  written(1);
323  }
324 };
325 
326 // Convenience functions for working with optional pipes
327 
328 template <typename T>
329 pipewriter<T> *opt_writer(pipebuf<T> *buf, unsigned long min_write = 1)
330 {
331  return buf ? new pipewriter<T>(*buf, min_write) : NULL;
332 }
333 
334 template <typename T>
335 bool opt_writable(pipewriter<T> *p, int n = 1)
336 {
337  return (p == NULL) || p->writable() >= n;
338 }
339 
340 template <typename T>
341 void opt_write(pipewriter<T> *p, T val)
342 {
343  if (p)
344  p->write(val);
345 }
346 
347 template <typename T>
349 {
351  int id;
352 
353  pipereader(pipebuf<T> &_buf) : buf(_buf), id(_buf.add_reader())
354  {
355  }
356 
357  long readable()
358  {
359  return buf.wr - buf.rds[id];
360  }
361 
362  T *rd()
363  {
364  return buf.rds[id];
365  }
366 
367  void read(unsigned long n)
368  {
369  if (buf.rds[id] + n > buf.wr)
370  {
371  fprintf(stderr, "Bug: underflow from %s\n", buf.name);
372  }
373 
374  buf.rds[id] += n;
375  buf.total_read += n;
376  }
377 };
378 
379 // Math functions for templates
380 
381 template <typename T>
382 T gen_sqrt(T x);
383 inline float gen_sqrt(float x)
384 {
385  return sqrtf(x);
386 }
387 
388 inline unsigned int gen_sqrt(unsigned int x)
389 {
390  return sqrtl(x);
391 }
392 
393 inline long double gen_sqrt(long double x)
394 {
395  return sqrtl(x);
396 }
397 
398 template <typename T>
399 T gen_abs(T x);
400 inline float gen_abs(float x)
401 {
402  return fabsf(x);
403 }
404 
405 inline int gen_abs(int x)
406 {
407  return abs(x);
408 }
409 
410 inline long int gen_abs(long int x)
411 {
412  return labs(x);
413 }
414 
415 template <typename T>
416 T gen_hypot(T x, T y);
417 inline float gen_hypot(float x, float y)
418 {
419  return hypotf(x, y);
420 }
421 
422 inline long double gen_hypot(long double x, long double y)
423 {
424  return hypotl(x, y);
425 }
426 
427 template <typename T>
428 T gen_atan2(T y, T x);
429 inline float gen_atan2(float y, float x)
430 {
431  return atan2f(y, x);
432 }
433 
434 inline long double gen_atan2(long double y, long double x)
435 {
436  return atan2l(y, x);
437 }
438 
439 template <typename T>
440 T min(const T &x, const T &y)
441 {
442  return (x < y) ? x : y;
443 }
444 
445 template <typename T>
446 T max(const T &x, const T &y)
447 {
448  return (x < y) ? y : x;
449 }
450 
451 // Abreviations for integer types
452 
453 typedef unsigned char u8;
454 typedef unsigned short u16;
455 typedef unsigned long u32;
456 typedef signed char s8;
457 typedef signed short s16;
458 typedef signed long s32;
459 
460 } // namespace leansdr
461 
462 #endif // LEANSDR_FRAMEWORK_H
virtual void run()
Definition: framework.h:93
T * rds[MAX_READERS]
Definition: framework.h:206
pipereader(pipebuf< T > &_buf)
Definition: framework.h:353
virtual ~runnable_common()
Definition: framework.h:89
unsigned long total_read
Definition: framework.h:276
void add_pipe(pipebuf_common *p)
Definition: framework.h:132
const char * name
Definition: framework.h:70
unsigned char u8
Definition: framework.h:453
Fixed< IntType, IntBits > abs(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2313
runnable(scheduler *_sch, const char *name)
Definition: framework.h:193
virtual ~pipebuf_common()
Definition: framework.h:76
virtual void shutdown()
Definition: framework.h:97
signed short s16
Definition: framework.h:457
runnable_common(const char *_name)
Definition: framework.h:85
pipewriter(pipebuf< T > &_buf, unsigned long min_write=1)
Definition: framework.h:290
virtual void dump(std::size_t *total_bufs)
Definition: framework.h:65
pipebuf(scheduler *sch, const char *name, unsigned long size)
Definition: framework.h:216
T gen_abs(T x)
void opt_write(pipewriter< T > *p, T val)
Definition: framework.h:341
void fail(const char *s)
Definition: framework.cpp:11
int32_t i
Definition: decimators.h:244
bool opt_writable(pipewriter< T > *p, int n=1)
Definition: framework.h:335
unsigned long long hash()
Definition: framework.h:172
void written(unsigned long n)
Definition: framework.h:308
pipewriter< T > * opt_writer(pipebuf< T > *buf, unsigned long min_write=1)
Definition: framework.h:329
signed char s8
Definition: framework.h:456
void fatal(const char *s)
Definition: framework.cpp:6
virtual int sizeofT()
Definition: framework.h:55
T gen_sqrt(T x)
unsigned long min_write
Definition: framework.h:275
pipebuf_common(const char *_name)
Definition: framework.h:72
scheduler * sch
Definition: framework.h:199
signed long s32
Definition: framework.h:458
void write(const T &e)
Definition: framework.h:319
unsigned long total_written
Definition: framework.h:276
pipebuf< T > & buf
Definition: framework.h:350
long long hash()
Definition: framework.h:247
T gen_atan2(T y, T x)
void add_runnable(runnable_common *r)
Definition: framework.h:139
unsigned short u16
Definition: framework.h:454
void dump(std::size_t *total_bufs)
Definition: framework.h:252
void read(unsigned long n)
Definition: framework.h:367
unsigned long u32
Definition: framework.h:455
T max(const T &x, const T &y)
Definition: framework.h:446
T gen_hypot(T x, T y)
pipebuf< T > & buf
Definition: framework.h:288
virtual long long hash()
Definition: framework.h:60
window_placement * windows
Definition: framework.h:120
T min(const T &x, const T &y)
Definition: framework.h:440