#ifndef LEANSDR_FRAMEWORK_H #define LEANSDR_FRAMEWORK_H #include #include #include #include namespace leansdr { void fatal(const char *s) { perror(s); exit(1); } void fail(const char *s) { fprintf(stderr, "** %s\n", s); exit(1); } ////////////////////////////////////////////////////////////////////// // DSP framework ////////////////////////////////////////////////////////////////////// // [pipebuf] is a FIFO buffer with multiple readers. // [pipewriter] is a client-side hook for writing into a [pipebuf]. // [pipereader] is a client-side hook reading from a [pipebuf]. // [runnable] is anything that moves data between [pipebufs]. // [scheduler] is a global context which invokes [runnables] until fixpoint. static const int MAX_PIPES = 64; static const int MAX_RUNNABLES = 64; static const int MAX_READERS = 8; struct pipebuf_common { virtual int sizeofT() { return 0; } virtual long long hash() { return 0; } virtual void dump(size_t *total_bufs) { } const char *name; pipebuf_common(const char *_name) : name(_name) { } }; struct runnable_common { const char *name; runnable_common(const char *_name) : name(_name) { } virtual void run() { } }; struct window_placement { const char *name; // NULL to terminate int x, y, w, h; }; struct scheduler { pipebuf_common *pipes[MAX_PIPES]; int npipes; runnable_common *runnables[MAX_RUNNABLES]; int nrunnables; window_placement *windows; bool verbose, debug; scheduler() : npipes(0), nrunnables(0), windows(NULL), verbose(false), debug(false) { } void add_pipe(pipebuf_common *p) { if ( npipes == MAX_PIPES ) fail("MAX_PIPES"); pipes[npipes++] = p; } void add_runnable(runnable_common *r) { if ( nrunnables == MAX_RUNNABLES ) fail("MAX_RUNNABLES"); runnables[nrunnables++] = r; } void step() { for ( int i=0; irun(); } void run() { unsigned long long prev_hash = 0; while ( 1 ) { step(); unsigned long long h = hash(); if ( h == prev_hash ) break; prev_hash = h; } } unsigned long long hash() { unsigned long long h = 0; for ( int i=0; ihash(); return h; } void dump() { fprintf(stderr, "\n"); size_t total_bufs = 0; for ( int i=0; idump(&total_bufs); fprintf(stderr, "Total buffer memory: %ld KiB\n", (unsigned long)total_bufs/1024); } }; struct runnable : runnable_common { runnable(scheduler *_sch, const char *name) : runnable_common(name), sch(_sch) { sch->add_runnable(this); } protected: scheduler *sch; }; template struct pipebuf : pipebuf_common { T *buf; T *rds[MAX_READERS]; int nrd; T *wr; T *end; int sizeofT() { return sizeof(T); } pipebuf(scheduler *sch, const char *name, unsigned long size) : pipebuf_common(name), buf(new T[size]), nrd(0), wr(buf), end(buf+size), min_write(1), total_written(0), total_read(0) { sch->add_pipe(this); } int add_reader() { if ( nrd == MAX_READERS ) fail("too many readers"); rds[nrd] = wr; return nrd++; } void pack() { T *rd = wr; for ( int i=0; i struct pipewriter { pipebuf &buf; pipewriter(pipebuf &_buf, unsigned long min_write=1) : buf(_buf) { if ( min_write > buf.min_write ) buf.min_write = min_write; } // Return number of items writable at this->wr, 0 if full. unsigned long writable() { if ( buf.end-buf.wr < buf.min_write ) buf.pack(); return buf.end - buf.wr; } T *wr() { return buf.wr; } void written(unsigned long n) { if ( buf.wr+n > buf.end ) fail("Bug: overflow"); buf.wr += n; buf.total_written += n; } }; template struct pipereader { pipebuf &buf; int id; pipereader(pipebuf &_buf) : buf(_buf), id(_buf.add_reader()) { } unsigned long readable() { return buf.wr - buf.rds[id]; } T *rd() { return buf.rds[id]; } void read(unsigned long n) { if ( buf.rds[id]+n > buf.wr ) fail("Bug: underflow"); buf.rds[id] += n; buf.total_read += n; } }; // Math functions for templates template T gen_sqrt(T x); inline float gen_sqrt(float x) { return sqrtf(x); } inline unsigned int gen_sqrt(unsigned int x) { return sqrtl(x); } inline long double gen_sqrt(long double x) { return sqrtl(x); } template T gen_abs(T x); inline float gen_abs(float x) { return fabsf(x); } inline int gen_abs(int x) { return abs(x); } inline long int gen_abs(long int x) { return labs(x); } template T gen_hypot(T x, T y); inline float gen_hypot(float x, float y) { return hypotf(x,y); } inline long double gen_hypot(long double x, long double y) { return hypotl(x,y); } template T gen_atan2(T y, T x); inline float gen_atan2(float y, float x) { return atan2f(y,x); } inline long double gen_atan2(long double y, long double x) { return atan2l(y,x); } } // namespace #endif // LEANSDR_FRAMEWORK_H