#ifndef LEANSDR_FRAMEWORK_H #define LEANSDR_FRAMEWORK_H #include #include #include #include namespace leansdr { inline void fatal(const char *s) { perror(s); exit(1); } inline 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() { } virtual void shutdown() { } #ifdef DEBUG ~runnable_common() { fprintf(stderr, "Deallocating %s !\n", name); } #endif }; 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; } } void shutdown() { for ( int i=0; ishutdown(); } 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 ) { fprintf(stderr, "Bug: overflow to %s\n", buf.name); exit(1); } buf.wr += n; buf.total_written += n; } void write(const T &e) { *wr() = e; written(1); } }; // Convenience functions for working with optional pipes template pipewriter *opt_writer(pipebuf *buf) { return buf ? new pipewriter(*buf) : NULL; } template bool opt_writable(pipewriter *p, int n=1) { return (p==NULL) || p->writable()>=n; } template void opt_write(pipewriter *p, T val) { if ( p ) p->write(val); } 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 ) { fprintf(stderr, "Bug: underflow from %s\n", buf.name); exit(1); } 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); } template T min(const T &x, const T &y) { return (x T max(const T &x, const T &y) { return (x