1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-23 16:38:37 -05:00
sdrangel/plugins/channelrx/demoddatv/leansdr/framework.h

463 lines
9.6 KiB
C
Raw Normal View History

// This file is part of LeanSDR Copyright (C) 2016-2018 <pabr@pabr.org>.
// See the toplevel README for more information.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
2018-02-22 16:52:49 -05:00
#ifndef LEANSDR_FRAMEWORK_H
#define LEANSDR_FRAMEWORK_H
#include <cstddef>
#include <algorithm>
#include <math.h>
#include <stdint.h>
2018-02-22 16:52:49 -05:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef VERSION
#define VERSION "undefined"
#endif
2018-02-22 16:52:49 -05:00
2018-02-24 18:07:08 -05:00
namespace leansdr
{
void fatal(const char *s);
void fail(const char *s);
2018-02-24 18:07:08 -05:00
//////////////////////////////////////////////////////////////////////
// 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(std::size_t *total_bufs)
2018-02-24 18:07:08 -05:00
{
(void)total_bufs;
2018-02-24 18:07:08 -05:00
}
const char *name;
pipebuf_common(const char *_name) : name(_name)
2018-02-24 18:07:08 -05:00
{
}
virtual ~pipebuf_common()
{
}
};
struct runnable_common
{
const char *name;
runnable_common(const char *_name) : name(_name)
2018-02-24 18:07:08 -05:00
{
}
virtual ~runnable_common()
{
}
virtual void run()
{
}
virtual void shutdown()
{
}
2018-02-22 16:52:49 -05:00
#ifdef DEBUG
2018-02-24 18:07:08 -05:00
~runnable_common()
{
fprintf(stderr, "Deallocating %s !\n", name);
}
2018-02-22 16:52:49 -05:00
#endif
2018-02-24 18:07:08 -05:00
};
struct window_placement
{
2018-02-22 16:52:49 -05:00
const char *name; // NULL to terminate
int x, y, w, h;
2018-02-24 18:07:08 -05:00
};
2018-02-22 16:52:49 -05:00
2018-02-24 18:07:08 -05:00
struct scheduler
{
2018-02-22 16:52:49 -05:00
pipebuf_common *pipes[MAX_PIPES];
int npipes;
runnable_common *runnables[MAX_RUNNABLES];
int nrunnables;
window_placement *windows;
bool verbose, debug, debug2;
2018-02-22 16:52:49 -05:00
scheduler() : npipes(0),
nrunnables(0),
windows(NULL),
verbose(false),
debug(false),
debug2(false)
2018-02-24 18:07:08 -05:00
{
}
void add_pipe(pipebuf_common *p)
{
if (npipes == MAX_PIPES)
fail("MAX_PIPES");
2018-02-24 18:07:08 -05:00
pipes[npipes++] = p;
}
void add_runnable(runnable_common *r)
{
if (nrunnables == MAX_RUNNABLES)
fail("MAX_RUNNABLES");
2018-02-24 18:07:08 -05:00
runnables[nrunnables++] = r;
}
void step()
{
for (int i = 0; i < nrunnables; ++i)
2018-02-24 18:07:08 -05:00
runnables[i]->run();
}
void run()
{
unsigned long long prev_hash = 0;
while (1)
{
step();
unsigned long long h = hash();
if (h == prev_hash)
2018-02-24 18:07:08 -05:00
break;
prev_hash = h;
}
}
void shutdown()
{
for (int i = 0; i < nrunnables; ++i)
2018-02-24 18:07:08 -05:00
runnables[i]->shutdown();
}
unsigned long long hash()
{
unsigned long long h = 0;
for (int i = 0; i < npipes; ++i)
2018-02-24 18:07:08 -05:00
h += (1 + i) * pipes[i]->hash();
return h;
}
void dump()
{
fprintf(stderr, "\n");
std::size_t total_bufs = 0;
for (int i = 0; i < npipes; ++i)
2018-02-24 18:07:08 -05:00
pipes[i]->dump(&total_bufs);
fprintf(stderr, "Total buffer memory: %ld KiB\n",
(unsigned long)total_bufs / 1024);
2018-02-24 18:07:08 -05:00
}
};
struct runnable : runnable_common
2018-02-24 18:07:08 -05:00
{
runnable(scheduler *_sch, const char *name) : runnable_common(name), sch(_sch)
2018-02-24 18:07:08 -05:00
{
sch->add_runnable(this);
}
protected:
2018-02-22 16:52:49 -05:00
scheduler *sch;
2018-02-24 18:07:08 -05:00
};
template <typename T>
struct pipebuf : pipebuf_common
2018-02-24 18:07:08 -05:00
{
2018-02-22 16:52:49 -05:00
T *buf;
T *rds[MAX_READERS];
int nrd;
T *wr;
T *end;
2018-02-24 18:07:08 -05:00
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)
2018-02-24 18:07:08 -05:00
{
sch->add_pipe(this);
}
int add_reader()
{
if (nrd == MAX_READERS)
fail("too many readers");
2018-02-24 18:07:08 -05:00
rds[nrd] = wr;
return nrd++;
}
void pack()
{
T *rd = wr;
for (int i = 0; i < nrd; ++i)
if (rds[i] < rd)
2018-02-24 18:07:08 -05:00
rd = rds[i];
memmove(buf, rd, (wr - rd) * sizeof(T));
wr -= rd - buf;
for (int i = 0; i < nrd; ++i)
2018-02-24 18:07:08 -05:00
rds[i] -= rd - buf;
}
long long hash()
{
return total_written + total_read;
}
void dump(std::size_t *total_bufs)
{
if (total_written < 10000)
fprintf(stderr, ".%-16s : %4ld/%4ld", name, total_read,
total_written);
else if (total_written < 1000000)
fprintf(stderr, ".%-16s : %3ldk/%3ldk", name, total_read / 1000,
total_written / 1000);
else
fprintf(stderr, ".%-16s : %3ldM/%3ldM", name, total_read / 1000000,
total_written / 1000000);
2018-02-24 18:07:08 -05:00
*total_bufs += (end - buf) * sizeof(T);
unsigned long nw = end - wr;
fprintf(stderr, " %6ld writable %c,", nw, (nw < min_write) ? '!' : ' ');
2018-02-24 18:07:08 -05:00
T *rd = wr;
for (int j = 0; j < nrd; ++j)
if (rds[j] < rd)
2018-02-24 18:07:08 -05:00
rd = rds[j];
fprintf(stderr, " %6d unread (", (int)(wr - rd));
for (int j = 0; j < nrd; ++j)
fprintf(stderr, " %d", (int)(wr - rds[j]));
fprintf(stderr, " )\n");
2018-02-22 16:52:49 -05:00
}
unsigned long min_write;
unsigned long total_written, total_read;
#ifdef DEBUG
2018-02-24 18:07:08 -05:00
~pipebuf()
{
fprintf(stderr, "Deallocating %s !\n", name);
}
2018-02-22 16:52:49 -05:00
#endif
2018-02-24 18:07:08 -05:00
};
template <typename T>
2018-02-24 18:07:08 -05:00
struct pipewriter
{
2018-02-22 16:52:49 -05:00
pipebuf<T> &buf;
2018-02-24 18:07:08 -05:00
pipewriter(pipebuf<T> &_buf, unsigned long min_write = 1) : buf(_buf)
2018-02-24 18:07:08 -05:00
{
if (min_write > buf.min_write)
2018-02-24 18:07:08 -05:00
buf.min_write = min_write;
}
// Return number of items writable at this->wr, 0 if full.
long writable()
2018-02-24 18:07:08 -05:00
{
if (buf.end < buf.min_write + buf.wr)
2018-02-24 18:07:08 -05:00
buf.pack();
return buf.end - buf.wr;
2018-02-24 18:07:08 -05:00
}
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);
2018-02-24 18:07:08 -05:00
}
2018-02-24 18:07:08 -05:00
buf.wr += n;
buf.total_written += n;
}
void write(const T &e)
{
*wr() = e;
written(1);
}
};
// Convenience functions for working with optional pipes
template <typename T>
pipewriter<T> *opt_writer(pipebuf<T> *buf, unsigned long min_write = 1)
2018-02-24 18:07:08 -05:00
{
return buf ? new pipewriter<T>(*buf, min_write) : NULL;
2018-02-24 18:07:08 -05:00
}
2018-02-22 16:52:49 -05:00
template <typename T>
bool opt_writable(pipewriter<T> *p, int n = 1)
2018-02-24 18:07:08 -05:00
{
return (p == NULL) || p->writable() >= n;
}
2018-02-22 16:52:49 -05:00
template <typename T>
2018-02-24 18:07:08 -05:00
void opt_write(pipewriter<T> *p, T val)
{
if (p)
2018-02-24 18:07:08 -05:00
p->write(val);
}
2018-02-22 16:52:49 -05:00
template <typename T>
2018-02-24 18:07:08 -05:00
struct pipereader
{
2018-02-22 16:52:49 -05:00
pipebuf<T> &buf;
int id;
2018-02-24 18:07:08 -05:00
pipereader(pipebuf<T> &_buf) : buf(_buf), id(_buf.add_reader())
2018-02-24 18:07:08 -05:00
{
}
long readable()
2018-02-24 18:07:08 -05:00
{
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);
2018-02-24 18:07:08 -05:00
}
2018-02-24 18:07:08 -05:00
buf.rds[id] += n;
buf.total_read += n;
}
};
// Math functions for templates
template <typename T>
T gen_sqrt(T x);
2018-02-24 18:07:08 -05:00
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 <typename T>
T gen_abs(T x);
2018-02-24 18:07:08 -05:00
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 <typename T>
T gen_hypot(T x, T y);
2018-02-24 18:07:08 -05:00
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 <typename T>
T gen_atan2(T y, T x);
2018-02-24 18:07:08 -05:00
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 <typename T>
2018-02-24 18:07:08 -05:00
T min(const T &x, const T &y)
{
return (x < y) ? x : y;
}
template <typename T>
2018-02-24 18:07:08 -05:00
T max(const T &x, const T &y)
{
return (x < y) ? y : x;
}
// Abreviations for integer types
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
typedef signed char s8;
typedef signed short s16;
typedef signed long s32;
2018-02-22 16:52:49 -05:00
} // namespace leansdr
2018-02-22 16:52:49 -05:00
#endif // LEANSDR_FRAMEWORK_H