--- /dev/null
+setMode CWL
+setFilter -1000 -500
--- /dev/null
+CFLAGS = -g -O3 -I. -I/usr/local/include
+#CFLAGS = -g -I. -I/usr/local/include
+LIBS = -L/usr/local/lib -ljack -lpthread -lfftw -lm
+#LIBS = -lefence -L/usr/local/lib -ljack -lpthread -lfftw -lm
+
+staticlibname=libDttSP.a
+
+OBJ = am_demod.o\
+ banal.o\
+ bufvec.o\
+ chan.o\
+ chap.o\
+ correctIQ.o\
+ crc16.o\
+ cxops.o\
+ digitalagc.o\
+ fastrig.o\
+ filter.o\
+ fm_demod.o\
+ lmadf.o\
+ noiseblanker.o\
+ oscillator.o\
+ ovsv.o\
+ ringb.o\
+ sdr.o\
+ sdrexport.o\
+ speechproc.o\
+ splitfields.o\
+ spottone.o\
+ thunk.o\
+ window.o\
+ update.o
+
+jsdr: main.o $(OBJ)
+ $(CC) -o jsdr main.o $(OBJ) $(LIBS)
+
+$(OBJ): sdrexport.h
+
+metermon: metermon.o chan.o ringb.o bufvec.o cxops.o banal.o
+ $(CC) -o metermon metermon.o chan.o ringb.o bufvec.o cxops.o banal.o $(LIBS)
+
+mkchan: mkchan.o bufvec.o banal.o cxops.o
+ $(CC) -o mkchan mkchan.o bufvec.o banal.o cxops.o $(LIBS)
+
+ipc:
+ ./setup-ipc
+
+obj: $(OBJ)
+
+clean:
+ /bin/rm *.o jsdr mkchan metermon $(staticlibname)
+
+staticlib: $(OBJ)
+ ar rcs $(staticlibname) $(OBJ)
+ ranlib $(staticlibname)
+
+#CFLAGS = -fPIC -g -O3 -I. -I/usr/local/include
+# sharedlibname=libDttSP.so
+# sharedlibvers=0.0.1
+# sharedlib=$(sharedlibname).$(sharedlibvers)
+# sharedlib: $(OBJ)
+# gcc -shared -Wl,-soname,$(sharedlib) -o $(sharedlib) $(OBJ) -lc
--- /dev/null
+/* am_demod.c */
+
+#include <am_demod.h>
+#include <cxops.h>
+
+/*------------------------------------------------------------------------------*/
+/* private to AM */
+/*------------------------------------------------------------------------------*/
+
+static void
+init_pll(AMD am,
+ REAL samprate,
+ REAL freq,
+ REAL lofreq,
+ REAL hifreq,
+ REAL bandwidth) {
+ REAL fac = TWOPI / samprate;
+ am->pll.freq.f = freq * fac;
+ am->pll.freq.l = lofreq * fac;
+ am->pll.freq.h = hifreq * fac;
+ am->pll.phs = 0.0;
+ am->pll.delay = cxJ;
+
+ am->pll.iir.alpha = bandwidth * fac; /* arm filter */
+ am->pll.alpha = am->pll.iir.alpha * 0.3; /* pll bandwidth */
+ am->pll.beta = am->pll.alpha * am->pll.alpha * 0.25; /* second order term */
+ am->pll.fast_alpha = am->pll.alpha;
+}
+
+static void
+pll(AMD am, COMPLEX sig) {
+ COMPLEX z = Cmplx(cos(am->pll.phs), sin(am->pll.phs));
+ REAL diff;
+
+ am->pll.delay.re = z.re * sig.re + z.im * sig.im;
+ am->pll.delay.im = -z.im * sig.re + z.re * sig.im;
+ diff = Cmag(sig) * ATAN2(am->pll.delay.im, am->pll.delay.re);
+
+ am->pll.freq.f += am->pll.beta * diff;
+
+ if (am->pll.freq.f < am->pll.freq.l)
+ am->pll.freq.f = am->pll.freq.l;
+ if (am->pll.freq.f > am->pll.freq.h)
+ am->pll.freq.f = am->pll.freq.h;
+
+ am->pll.phs += am->pll.freq.f + am->pll.alpha * diff;
+
+ while (am->pll.phs >= TWOPI) am->pll.phs -= TWOPI;
+ while (am->pll.phs < 0) am->pll.phs += TWOPI;
+}
+
+static double
+dem(AMD am) {
+ am->lock.curr = 0.999 * am->lock.curr + 0.001 * fabs(am->pll.delay.im);
+
+ /* env collapse? */
+ /* if ((am->lock.curr < 0.05) && (am->lock.prev >= 0.05)) {
+ am->pll.alpha = 0.1 * am->pll.fast_alpha;
+ am->pll.beta = am->pll.alpha * am->pll.alpha * 0.25;
+ } else if ((am->pll.alpha > 0.05) && (am->lock.prev <= 0.05)) {
+ am->pll.alpha = am->pll.fast_alpha;
+ }*/
+ am->lock.prev = am->lock.curr;
+ am->dc = 0.99*am->dc + 0.01*am->pll.delay.re;
+ return am->pll.delay.re-am->dc;
+}
+
+/*------------------------------------------------------------------------------*/
+/* public */
+/*------------------------------------------------------------------------------*/
+
+void
+AMDemod(AMD am) {
+ int i;
+ double demout;
+ switch (am->mode) {
+ case SAMdet:
+ for (i = 0; i < am->size; i++) {
+ pll(am, CXBdata(am->ibuf, i));
+ demout = dem(am);
+ CXBdata(am->obuf, i) = Cmplx(demout, demout);
+ }
+ break;
+ case AMdet:
+ for (i = 0; i < am->size; i++) {
+ am->lock.curr = Cmag(CXBdata(am->ibuf, i));
+ am->dc = 0.9999 * am->dc + 0.0001 * am->lock.curr;
+ am->smooth = 0.5 * am->smooth + 0.5 * (am->lock.curr - am->dc);
+ /* demout = am->smooth; */
+ CXBdata(am->obuf, i) = Cmplx(am->smooth, am->smooth);
+ }
+ break;
+ }
+}
+
+AMD
+newAMD(REAL samprate,
+ REAL f_initial,
+ REAL f_lobound,
+ REAL f_hibound,
+ REAL f_bandwid,
+ int size,
+ COMPLEX *ivec,
+ COMPLEX *ovec,
+ AMMode mode,
+ char *tag) {
+ AMD am = (AMD) safealloc(1, sizeof(AMDDesc), tag);
+
+ am->size = size;
+ am->ibuf = newCXB(size, ivec, tag);
+ am->obuf = newCXB(size, ovec, tag);
+ am->mode = mode;
+ init_pll(am,
+ samprate,
+ f_initial,
+ f_lobound,
+ f_hibound,
+ f_bandwid);
+
+ am->lock.curr = 0.5;
+ am->lock.prev = 1.0;
+ am->dc = 0.0;
+
+ return am;
+}
+
+void
+delAMD(AMD am) {
+ if (am) {
+ delCXB(am->ibuf);
+ delCXB(am->obuf);
+ safefree((char *) am);
+ }
+}
--- /dev/null
+/* am_demod.h */
+
+#ifndef _am_demod_h
+#define _am_demod_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <fastrig.h>
+#include <update.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <ovsv.h>
+#include <filter.h>
+#include <oscillator.h>
+#include <chap.h>
+typedef enum _ammode {AMdet, SAMdet} AMMode;
+typedef
+struct _am_demod {
+ int size;
+ CXB ibuf, obuf;
+
+ struct {
+ REAL alpha, beta,fast_alpha;
+ struct { REAL f, l, h; } freq;
+ REAL phs;
+ struct { REAL alpha; } iir;
+ COMPLEX delay;
+ } pll;
+
+ struct { REAL curr, prev; } lock;
+
+ REAL dc;
+ REAL smooth;
+ AMMode mode;
+} AMDDesc, *AMD;
+
+extern void AMDemod(AMD am);
+extern AMD newAMD(REAL samprate,
+ REAL f_initial,
+ REAL f_lobound,
+ REAL f_hibound,
+ REAL f_bandwid,
+ int size,
+ COMPLEX *ivec,
+ COMPLEX *ovec,
+ AMMode mode,
+ char *tag);
+extern void delAMD(AMD am);
+
+#ifndef TWOPI
+#define TWOPI (2.0*M_PI)
+#endif
+
+#endif
--- /dev/null
+/* banal.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <fromsys.h>
+#include <banal.h>
+
+void
+nilfunc(void) {}
+
+double
+sqr(double x) { return x * x; }
+
+int
+popcnt(int k) {
+ int c, i;
+ c = k & 01;
+ for (i = 1; i < 32; i++) c += (k >> i) & 01;
+ return c;
+}
+
+int
+npoof2(int n) {
+ int i = 0;
+ --n;
+ while (n > 0) n >>= 1, i++;
+ return i;
+}
+
+int
+nblock2(int n) { return 1 << npoof2(n); }
+
+int
+in_blocks(int count, int block_size) {
+ if (block_size < 1) {
+ fprintf(stderr, "block_size zero in in_blocks\n");
+ exit(1);
+ }
+ return (1 + ((count - 1) / block_size));
+}
+
+FILE *
+efopen(char *path, char *mode) {
+ FILE *iop = fopen(path, mode);
+ if (!iop) {
+ fprintf(stderr, "can't open \"%s\" in mode \"%s\"\n", path, mode);
+ exit(1);
+ }
+ return iop;
+}
+
+FILE *
+efreopen(char *path, char *mode, FILE *strm) {
+ FILE *iop = freopen(path, mode, strm);
+ if (!iop) {
+ fprintf(stderr, "can't reopen \"%s\" in mode \"%s\"\n", path, mode);
+ exit(1);
+ }
+ return iop;
+}
+
+size_t
+filesize(char *path) {
+ struct stat sbuf;
+ if (stat(path, &sbuf) == -1) return -1;
+ return sbuf.st_size;
+}
+
+size_t
+fdsize(int fd) {
+ struct stat sbuf;
+ if (fstat(fd, &sbuf) == -1) return -1;
+ return sbuf.st_size;
+}
+
+#define MILLION (1000000)
+
+// return current tv
+struct timeval
+now_tv(void) {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return tv;
+}
+
+// return ta - tb
+struct timeval
+diff_tv(struct timeval *ta, struct timeval *tb) {
+ struct timeval tv;
+ if (tb->tv_usec > ta->tv_usec) {
+ ta->tv_sec--;
+ ta->tv_usec += MILLION;
+ }
+ tv.tv_sec = ta->tv_sec - tb->tv_sec;
+ if ((tv.tv_usec = ta->tv_usec - tb->tv_usec) >= MILLION) {
+ tv.tv_usec -= MILLION;
+ tv.tv_sec++;
+ }
+ return tv;
+}
+
+// return ta + tb
+struct timeval
+sum_tv(struct timeval *ta, struct timeval *tb) {
+ struct timeval tv;
+ tv.tv_sec = ta->tv_sec + tb->tv_sec;
+ if ((tv.tv_usec = ta->tv_usec + tb->tv_usec) >= MILLION) {
+ tv.tv_usec -= MILLION;
+ tv.tv_sec++;
+ }
+ return tv;
+}
+
+char *
+fmt_tv(struct timeval *tv) {
+ static char buff[256];
+ snprintf(buff, sizeof(buff), "%ds%du", tv->tv_sec, tv->tv_usec);
+ return buff;
+}
+
+char *
+since(struct timeval *tv) {
+ struct timeval nt = now_tv(),
+ dt = diff_tv(&nt, tv);
+ return fmt_tv(&dt);
+}
+
+// linear integer interpolation:
+// real vector v, n long, -> real vector u, m long
+// *** n must divide m
+// returns actual number of valid points in u
+// (== n - m/n since v[n] is undefined)
+
+int
+hinterp_vec(REAL *u, int m, REAL *v, int n) {
+ if (!u || !v || (n < 2) || (m < n) || (m % n)) return 0;
+ else {
+ int div = m / n, i, j = 0;
+ for (i = 1; i < n; i++) {
+ int k;
+ REAL vl = v[i - 1], del = (v[i] - vl) / div;
+ u[j++] = vl;
+ for (k = 1; k < div; k++) u[j++] = vl + k * del;
+ }
+ u[j++] = v[n - 1];
+ return j;
+ }
+}
+
+void
+status_message(char *msg) { write(2, msg, strlen(msg)); }
+
+FILE *
+find_rcfile(char *base) {
+ char path[MAXPATHLEN];
+ FILE *fp;
+ sprintf(path, "./%s", base);
+ if ((fp = fopen(path, "r"))) return fp;
+ else {
+ char *home = getenv("HOME");
+ if (!home)
+ fprintf(stderr, "can't get HOME!\n"), exit(1);
+ sprintf(path, "%s/%s", home, base);
+ if ((fp = fopen(path, "r"))) return fp;
+ }
+ return 0;
+}
+
--- /dev/null
+/* banal.h
+ stuff we're too embarrassed to declare otherwise
+
+ This file is part of a program that implements a Software-Defined Radio.
+
+ Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ The authors can be reached by email at
+
+ ab2kt@arrl.net
+ or
+ rwmcgwier@comcast.net
+
+ or by paper mail at
+
+ The DTTS Microwave Society
+ 6 Kathleen Place
+ Bridgewater, NJ 08807
+*/
+
+#ifndef _banal_h
+
+#define _banal_h
+
+#include <fromsys.h>
+#include <datatypes.h>
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef max
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#endif
+#define abs(a) ((a) >= 0 ? (a) : -(a))
+
+#define MONDO 1e15
+#define BITSY 1e-15
+
+#define TRUE 1
+#define FALSE 0
+
+extern void nilfunc(void);
+extern double sqr(double);
+extern int popcnt(int);
+extern int npoof2(int);
+extern int nblock2(int);
+
+extern int in_blocks(int count, int block_size);
+
+extern FILE *efopen(char *path, char *mode);
+extern FILE *efreopen(char *path, char *mode, FILE *strm);
+extern size_t filesize(char *path);
+extern size_t fdsize(int fd);
+
+extern struct timeval now_tv(void);
+extern struct timeval diff_tv(struct timeval *, struct timeval *);
+extern struct timeval sum_tv(struct timeval *, struct timeval *);
+extern char *fmt_tv(struct timeval *);
+extern char *since(struct timeval *);
+extern struct timeval now_tv(void);
+
+extern int hinterp_vec(REAL *, int, REAL *, int);
+
+extern void status_message(char *msg);
+
+extern FILE *find_rcfile(char *base);
+
+#endif
--- /dev/null
+/* bufvec.c
+ creation, deletion, management for vectors and buffers
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <bufvec.h>
+
+/*------------------------------------------------------------------------*/
+/* wrapper around calloc */
+
+char *
+safealloc(int count, int nbytes, char *tag) {
+ char *p = calloc(count, nbytes);
+ if (!p) {
+ if (tag && *tag) fprintf(stderr, "safealloc: %s\n", tag);
+ else perror("safealloc");
+ exit(1);
+ }
+ return p;
+}
+
+void
+safefree(char *p) { if (p) free(p); }
+
+/*------------------------------------------------------------------------*/
+/* allocate/free just vectors */
+
+REAL *
+newvec_REAL(int size, char *tag) {
+ return (REAL *) safealloc(size, sizeof(REAL), tag);
+}
+
+void
+delvec_REAL(REAL *vec) { if (vec) free((char *) vec); }
+
+IMAG *
+newvec_IMAG(int size, char *tag) {
+ return (IMAG *) safealloc(size, sizeof(IMAG), tag);
+}
+
+void
+delvec_IMAG(IMAG *vec) { if (vec) free((char *) vec); }
+
+COMPLEX *
+newvec_COMPLEX(int size, char *tag) {
+ return (COMPLEX *) safealloc(size, sizeof(COMPLEX), tag);
+}
+
+void
+delvec_COMPLEX(COMPLEX *vec) { if (vec) free((char *) vec); }
+
+/*------------------------------------------------------------------------*/
+/* buffers (mainly i/o) */
+/*------------------------------------------------------------------------*/
+/* complex */
+
+CXB
+newCXB(int size, COMPLEX *base, char *tag) {
+ CXB p = (CXB) safealloc(1, sizeof(CXBuffer), tag);
+ if (base) {
+ CXBbase(p) = base;
+ CXBmine(p) = FALSE;
+ } else {
+ CXBbase(p) = newvec_COMPLEX(size, "newCXB");
+ CXBmine(p) = TRUE;
+ }
+ CXBsize(p) = CXBwant(p) = size;
+ CXBovlp(p) = CXBhave(p) = CXBdone(p) = 0;
+ return p;
+}
+
+void
+delCXB(CXB p) {
+ if (p) {
+ if (CXBmine(p)) delvec_COMPLEX(CXBbase(p));
+ free((char *) p);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+/* real */
+
+RLB
+newRLB(int size, REAL *base, char *tag) {
+ RLB p = (RLB) safealloc(1, sizeof(RLBuffer), tag);
+ if (base) {
+ RLBbase(p) = base;
+ RLBmine(p) = FALSE;
+ } else {
+ RLBbase(p) = newvec_REAL(size, "newRLB");
+ RLBmine(p) = TRUE;
+ }
+ RLBsize(p) = RLBwant(p) = size;
+ RLBovlp(p) = RLBhave(p) = RLBdone(p) = 0;
+ return p;
+}
+
+void
+delRLB(RLB p) {
+ if (p) {
+ delvec_REAL(RLBbase(p));
+ free((char *) p);
+ }
+}
+
+//========================================================================
+// return normalization constant
+
+REAL
+normalize_vec_REAL(REAL *v, int n) {
+ if (v && (n > 0)) {
+ int i;
+ REAL big = -MONDO;
+ for (i = 0; i < n; i++) {
+ REAL a = abs(v[i]);
+ big = max(big, a);
+ }
+ if (big > 0.0) {
+ REAL scl = 1.0 / big;
+ for (i = 0; i < n; i++) v[i] *= scl;
+ return scl;
+ } else return 0.0;
+ } else return 0.0;
+}
+
+REAL
+normalize_vec_COMPLEX(COMPLEX *z, int n) {
+ if (z && (n > 0)) {
+ int i;
+ REAL big = -MONDO;
+ for (i = 0; i < n; i++) {
+ REAL a = Cabs(z[i]);
+ big = max(big, a);
+ }
+ if (big > 0.0) {
+ REAL scl = 1.0 / big;
+ for (i = 0; i < n; i++) z[i] = Cscl(z[i], scl);
+ return scl;
+ } else return 0.0;
+ } else return 0.0;
+}
+
+/*------------------------------------------------------------------------*/
+/*------------------------------------------------------------------------*/
+/* mostly for debugging when necessary */
+
+void
+dump_REAL(FILE *fp, char *head, REAL *ptr, int beg, int fin) {
+ int i;
+ FILE *iop = fp? fp : stderr;
+ if (head && *head) fprintf(iop, "dump_REAL: %s\n", head);
+ for (i = beg; i < fin; i++)
+ fprintf(iop, "%5d %g\n", i, ptr[i]);
+}
+
+void
+dump_IMAG(FILE *fp, char *head, IMAG *ptr, int beg, int fin) {
+ int i;
+ FILE *iop = fp? fp : stderr;
+ if (head && *head) fprintf(iop, "dump_REAL: %s\n", head);
+ for (i = beg; i < fin; i++)
+ fprintf(iop, "%5d %g\n", i, ptr[i]);
+}
+
+void
+dump_CX(FILE *fp, char *head, COMPLEX *ptr, int beg, int fin) {
+ int i;
+ FILE *iop = fp? fp : stderr;
+ if (head && *head) fprintf(iop, "dump_CX: %s\n", head);
+ for (i = beg; i < fin; i++)
+ fprintf(iop, "%5d %g %g\n", i, ptr[i].re, ptr[i].im);
+}
+
+
--- /dev/null
+/* bufvec.h
+
+defs for vector and buffer data structures and utilities
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _bufvec_h
+
+#define _bufvec_h
+
+#include <fromsys.h>
+#include <datatypes.h>
+#include <complex.h>
+#include <cxops.h>
+
+typedef struct _complex_buffer_desc {
+ COMPLEX *data;
+ int size, ovlp, want, have, done, mine;
+} CXBuffer, *CXB;
+
+/* all these should be OK rhs or lhs */
+
+#define CXBbase(p) ((p)->data)
+#define CXBdata(p, i) (CXBbase(p)[(i)])
+#define CXBreal(p, i) (CXBbase(p)[(i)].re)
+#define CXBimag(p, i) (CXBbase(p)[(i)].im)
+#define CXBsize(p) ((p)->size)
+#define CXBovlp(p) ((p)->ovlp)
+#define CXBwant(p) ((p)->want)
+#define CXBhave(p) ((p)->have)
+#define CXBdone(p) ((p)->done)
+#define CXBmine(p) ((p)->mine)
+
+typedef struct _real_buffer_desc {
+ REAL *data;
+ int size, ovlp, want, have, done, mine;
+} RLBuffer, *RLB;
+
+#define RLBbase(p) ((p)->data)
+#define RLBdata(p, i) (RLBbase(p)[(i)])
+#define RLBsize(p) ((p)->size)
+#define RLBovlp(p) ((p)->ovlp)
+#define RLBwant(p) ((p)->want)
+#define RLBhave(p) ((p)->have)
+#define RLBdone(p) ((p)->done)
+#define RLBmine(p) ((p)->mine)
+
+extern char *safealloc(int count, int nbytes, char *tag);
+extern void safefree(char *p);
+extern REAL *newvec_REAL(int size, char *tag);
+extern void delvec_REAL(REAL *vec);
+extern IMAG *newvec_IMAG(int size, char *tag);
+extern void delvec_IMAG(IMAG *vec);
+extern COMPLEX *newvec_COMPLEX(int size, char *tag);
+extern void delvec_COMPLEX(COMPLEX *buf);
+extern void dump_REAL(FILE *fp, char *head, REAL *ptr, int beg, int fin);
+extern void dump_IMAG(FILE *fp, char *head, IMAG *ptr, int beg, int fin);
+extern void dump_CX(FILE *fp, char *head, COMPLEX *ptr, int beg, int fin);
+
+extern CXB newCXB(int size, COMPLEX *base, char *tag);
+extern void delCXB(CXB p);
+
+extern RLB newRLB(int size, REAL *base, char *tag);
+extern void delRLB(RLB p);
+
+extern REAL normalize_vec_REAL(REAL *, int);
+extern REAL normalize_vec_COMPLEX(COMPLEX *, int);
+
+#endif
+
--- /dev/null
+/* chan.c
+
+fast inter-user-process single-reader/single-writer channels
+using a modified version of jack ringbuffers and memory-mapped files.
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <chan.h>
+
+size_t
+putChan(Chan c, char *data, size_t size) {
+ return ringb_write(c->rb, data, size);
+}
+
+size_t
+getChan(Chan c, char *data, size_t size) {
+ return ringb_read(c->rb, data, size);
+}
+
+BOOLEAN
+putChan_nowait(Chan c, char *data, size_t size) {
+ if (ringb_write_space(c->rb) >= size) {
+ ringb_write(c->rb, data, size);
+ return TRUE;
+ } else return FALSE;
+}
+
+BOOLEAN
+getChan_nowait(Chan c, char *data, size_t size) {
+ if (ringb_read_space(c->rb) >= size) {
+ ringb_read(c->rb, data, size);
+ return TRUE;
+ } else return FALSE;
+}
+
+Chan
+openChan(char *path, size_t want) {
+ Chan c = (Chan) safealloc(sizeof(ChanDesc), 1, "Chan header");
+ c->size.rib = sizeof(ringb_t);
+ c->size.buf = nblock2(want);
+ c->file.path = path;
+ if ((c->file.desc = open(c->file.path, O_RDWR)) == -1) {
+ fprintf(stderr, "can't open Chan file %s\n", c->file.path);
+ exit(1);
+ }
+ c->size.tot = c->size.rib + c->size.buf;
+ if ((c->size.tru = fdsize(c->file.desc)) < c->size.tot) {
+ fprintf(stderr,
+ "Chan file %s is too small (%d) for required size (%s)\n",
+ c->file.path, c->size.tru, c->size.tot);
+ exit(1);
+ }
+ if (!(c->map.base = (char *) mmap(0,
+ c->size.tot,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ c->file.desc,
+ 0))) {
+ fprintf(stderr, "can't memory map %s for Chan\n",
+ c->file.path);
+ exit(1);
+ }
+ if (!(c->rb = ringb_create(c->map.base, c->size.buf))) {
+ fprintf(stderr, "can't map RB for Chan\n");
+ exit(1);
+ }
+ return c;
+}
+
+void
+closeChan(Chan c) {
+ if (c) {
+ close(c->file.desc);
+ munmap(c->map.base, c->size.tot);
+ safefree((char *) c);
+ }
+}
--- /dev/null
+/* chan.h
+
+fast inter-user-process single-reader/single-writer channels
+using a modified version of jack ringbuffers and memory-mapped files.
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _chan_h
+#define _chan_h
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <values.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <libgen.h>
+#include <datatypes.h>
+#include <banal.h>
+#include <bufvec.h>
+#include <ringb.h>
+
+typedef
+struct _chan {
+ struct {
+ size_t buf, rib, tot, tru;
+ } size;
+ struct {
+ char *path;
+ int desc;
+ } file;
+ struct {
+ char *base;
+ } map;
+ ringb_t *rb;
+} ChanDesc, *Chan;
+
+extern size_t putChan(Chan c, char *data, size_t size);
+extern size_t getChan(Chan c, char *data, size_t size);
+extern BOOLEAN putChan_nowait(Chan c, char *data, size_t size);
+extern BOOLEAN getChan_nowait(Chan c, char *data, size_t size);
+// NB want will be rounded up to a power of 2
+extern Chan openChan(char *path, size_t want);
+extern void closeChan(Chan c);
+
+#endif
--- /dev/null
+/* chap.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <chap.h>
+
+REAL
+ChAp_eval(ChAp ca, REAL x, BOOLEAN *err) {
+ int i;
+ REAL d, e, u, v;
+
+ if (x < ChApLob(ca)) {
+ x = ChApLob(ca);
+ if (err) *err = TRUE;
+ } else if (x > ChApHib(ca)) {
+ x = ChApHib(ca);
+ if (err) *err = TRUE;
+ } else if (err) *err = FALSE;
+
+ d = e = 0.0;
+ u = (2.0 * x - ChApDif(ca)) / ChApDif(ca);
+ v = 2.0 * u;
+ for (i = ChApLen(ca) - 1; i > 0; --i) {
+ REAL sv = d;
+ d = v * d - e + ChApCoef(ca, i);
+ e = sv;
+ }
+
+ return u * d - e + 0.5 * ChApCoef(ca, 0);
+}
+
+ChAp
+ChAp_fit(ChAp ca) {
+ int i, j, n = ChApLen(ca);
+ REAL (*func)(REAL) = ChApFunc(ca),
+ bma = 0.5 * (ChApHib(ca) - ChApLob(ca)),
+ bpa = 0.5 * (ChApHib(ca) + ChApLob(ca)),
+ fac = 2.0 / n,
+ *tbl = newvec_REAL(n, ChApTag(ca));
+ for (j = 0; j < n; j++) {
+ REAL y = cos(M_PI * (j + 0.5) / n);
+ tbl[j] = (*func)(y * bma + bpa);
+ }
+ for (i = 0; i < n; i++) {
+ REAL sum = 0.0;
+ for (j = 0; j < n; j++)
+ sum += tbl[j] * cos((M_PI * i) * ((j + 0.5) / n));
+ ChApCoef(ca, i) = fac * sum;
+ }
+ delvec_REAL(tbl);
+ return ca;
+}
+
+ChAp
+newChAp(REAL (*func)(REAL arg),
+ REAL lo,
+ REAL hi,
+ int len,
+ char *tag) {
+ ChAp ca = (ChAp) safealloc(1, sizeof(ChApDesc), tag);
+ ChApFunc(ca) = func;
+ ChApLen(ca) = len;
+ ChApLob(ca) = lo;
+ ChApHib(ca) = hi;
+ ChApDif(ca) = hi - lo;
+ ChApCoefBase(ca) = newvec_REAL(len, tag);
+ ChApTag(ca) = strdup(tag);
+ return ChAp_fit(ca);
+}
+
+void
+delChAp(ChAp ca) {
+ if (ca) {
+ safefree((char *) ChApCoefBase(ca));
+ safefree(ChApTag(ca));
+ safefree((char *) ca);
+ }
+}
+
+
--- /dev/null
+/* chap.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _chap_h
+#define _chap_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <fastrig.h>
+#include <update.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <ovsv.h>
+#include <filter.h>
+#include <oscillator.h>
+
+typedef struct
+_cheby_approx {
+ REAL (*func)(REAL);
+ int len;
+ REAL *coef;
+ struct { REAL lo, hi, df; } lim;
+ char *tag;
+} ChApDesc, *ChAp;
+
+#define ChApFunc(p) ((p)->func)
+#define ChApLen(p) ((p)->len)
+#define ChApLob(p) ((p)->lim.lo)
+#define ChApHib(p) ((p)->lim.hi)
+#define ChApDif(p) ((p)->lim.df)
+#define ChApCoefBase(p) ((p)->coef)
+#define ChApCoef(p, i) (((p)->coef)[i])
+#define ChApTag(p) ((p)->tag)
+
+extern REAL ChAp_eval(ChAp ca, REAL x, BOOLEAN *err);
+extern ChAp ChAp_fit(ChAp ca);
+extern ChAp newChAp(REAL (*func)(REAL arg),
+ REAL lo,
+ REAL hi,
+ int len,
+ char *tag);
+
+extern void delChAp(ChAp ca);
+
+#endif
--- /dev/null
+#!/bin/sh
+
+CMDPIPE=./IPC/SDR-1000-0-commands.fifo
+
+while true
+do
+ read -p "command: " -e cmdline
+ if [ $? -ne 0 ]
+ then
+ break
+ fi
+ sendline="$cmdline"
+ echo $sendline
+done | m4 -e enums.m4 - >$CMDPIPE
--- /dev/null
+[TRX] indicates optional arg (RX or TX), RX default
+T|F indicates TRUE or FALSE
+(see enums.m4)
+
+setANF T|F // on/off, RX only
+setANFvals taps delay gain leak // int, int, float, float, RX only
+setATTOffset val // float, RX only, appears only in squelch calc
+setBIN T|F // binaural mode, on/off, RX only
+setFilter low-freq high-freq TRX
+setFinished // shutdown gracefully
+setGainOffset // float, RX only, appears only in squelch calc
+setMeterOffset lev // float, RX only, appears only in squelch calc
+setMode mode [TRX] // mode = USB, LSB, CWL, CWU, etc.
+setNB T|F // on/off, RX only
+setNBvals thresh // float, RX only
+setNR T|F // on/off, RX only
+setNRvals taps delay gain leak // int, int, float, float; RX only
+setOsc freq [TRX] // freq in Hz (float)
+setRXAGC T|F // on/off
+setRXAGC mode // mode = agcOFF, agcSLOW, etc.
+setRXAGCCompression lev // float
+setRXAGCHang dur // float
+setRXAGCLimit lim // float
+setRXEQ <bandspec> // f0 dB0 f1 dB1 f2 dB2 ... fN (see setTXEQ)
+setRXPostScl T|F // on/off
+setRXPostSclVal valQ // dB
+setRXPreScl T|F // on/off
+setRXPreSclVal valQ // dB
+setRunState state // RUN_MUTE, RUN_PASS, RUN_PLAY
+setSWCH trx [zap] // trx = RX|TX, int (always zaps at least 1)
+setSampleRate rate // Hz (float)
+setSpotTone T|F // turn on, off
+setSpotToneVals gain freq rise fall // dB, Hz, msec, msec [-12, 700, 5, 5]
+setSquelch lev // float, gain, RX only; default -30dB
+setSquelchSt T|F // on/off, RX only
+setTRX trx // trx = RX|TX
+setTXAGC T|F // on/off
+setTXAGCCompression lev // float
+setTXAGCHang dur // float
+setTXAGCLimit lim // float
+setTXEQ <bandspec> // f0 dB0 f1 dB1 f2 dB2 ... fN
+ // typical:
+ // 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600
+ // approximates W2IHY bandcenters
+setTXPostScl T|F // on/off
+setTXPostSclVal valQ // dB
+setTXPreScl T|F // on/off
+setTXPreSclVal valQ // dB
+setTXSpeechCompression T|F // on/off
+setTXSpeechCompressionGain gain // float
+setcorrectIQ phase gain // int, int
+setcorrectIQgain gain // int
+setcorrectIQphase phase // int
+setfixedAGC gain [TRX] // float
--- /dev/null
+/* common.h
+a simple way to get all the necessary includes
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _common_h
+
+#define _common_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <ringb.h>
+#include <chan.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <ovsv.h>
+#include <filter.h>
+#include <oscillator.h>
+#include <digitalagc.h>
+#include <am_demod.h>
+#include <fm_demod.h>
+#include <noiseblanker.h>
+#include <correctIQ.h>
+#include <crc16.h>
+#include <speechproc.h>
+#include <spottone.h>
+#include <update.h>
+#include <meter.h>
+#include <sdrexport.h>
+#include <local.h>
+
+#endif
+
--- /dev/null
+/* complex.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _complex_h
+#define _complex_h
+
+typedef
+struct _COMPLEX {
+ double re, im;
+} COMPLEX;
+
+#define c_re(x) ((x).re)
+#define c_im(x) ((x).im)
+
+#endif
+
--- /dev/null
+/* correctIQ.c
+
+This routine restores quadrature between arms of an analytic signal
+possibly distorted by ADC hardware.
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+IQ
+newCorrectIQ(REAL phaseadjustment, REAL gainadjustment) {
+ IQ iq = (IQ) safealloc(1, sizeof(iqstate), "IQ state");
+ iq->phase = phaseadjustment;
+ iq->gain = gainadjustment;
+ return iq;
+}
+
+void
+delCorrectIQ(IQ iq) { safefree((char *) iq); }
+
+void
+correctIQ(CXB sigbuf, IQ iq) {
+ int i;
+ for (i = 0; i < CXBhave(sigbuf); i++) {
+ CXBimag(sigbuf, i) += iq->phase * CXBreal(sigbuf, i);
+ CXBreal(sigbuf, i) *= iq->gain;
+ }
+}
--- /dev/null
+#ifndef _correctIQ_h
+#define _correctIQ_h
+
+#include <bufvec.h>
+
+typedef struct _iqstate {
+ REAL phase, gain;
+} *IQ, iqstate;
+
+extern IQ newCorrectIQ(REAL phaseadjusment, REAL gainadjustment);
+extern void delCorrectIQ(IQ iq);
+extern void correctIQ(CXB sigbuf, IQ iq);
+
+#endif
--- /dev/null
+/* crc16.c */
+
+/* CCITT 16-bit CRC table and calculation function */
+
+/* $Id$ */
+
+/****************************************************************************
+ * @format.tab-size 4 (Plain Text/Source Code File Header)
+ * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html)
+ *
+ * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html
+ *
+ * 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 2
+ * of the License, or (at your option) any later version.
+ * See the GNU General Public License for more details: gpl.txt or
+ * http://www.fsf.org/copyleft/gpl.html
+ *
+ * Anonymous FTP access to the most recent released source is available at
+ * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net
+ *
+ * Anonymous CVS access to the development source and modification history
+ * is available at cvs.synchro.net:/cvsroot/sbbs, example:
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login
+ * (just hit return, no password is necessary)
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src
+ *
+ * For Synchronet coding style and modification guidelines, see
+ * http://www.synchro.net/source.html
+ *
+ * You are encouraged to submit any modifications (preferably in Unix diff
+ * format) via e-mail to mods@synchro.net
+ *
+ * Note: If this box doesn't appear square, then you need to fix your tabs.
+ ****************************************************************************/
+
+/* modifications for DttSP
+ Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+ who can be reached by email at
+ ab2kt@arrl.net
+ or
+ rwmcgwier@comcast.net
+
+ or by paper mail at
+
+ The DTTS Microwave Society
+ 6 Kathleen Place
+ Bridgewater, NJ 08807 */
+
+#include <crc16.h>
+
+static unsigned short crc16tbl[] = {
+0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
+};
+
+#define ucrc16(ch,crc) (crc16tbl[(((crc)>>8)&0xff)^(unsigned char)(ch)]^((crc)<<8))
+
+unsigned short
+crc16(char *data, unsigned long len) {
+ unsigned short crc = 0;
+ if (data)
+ while (len-- > 0) {
+ char d = *data++;
+ crc = ucrc16(d, crc);
+ }
+ return crc;
+}
+
+#ifdef notdef
+unsigned short
+crc16(char *data, unsigned long len) {
+ unsigned short crc = 0;
+ unsigned long l;
+ if (len == 0 && data != NULL) len = strlen(data);
+ for (l = 0; l < len; l++) crc = ucrc16(data[l], crc);
+ return crc;
+}
+#endif
--- /dev/null
+/* crc16.h */
+
+/* CCITT 16-bit CRC table and calculation function header */
+
+/* $Id$ */
+
+/****************************************************************************
+ * @format.tab-size 4 (Plain Text/Source Code File Header)
+ * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html)
+ *
+ * Copyright 2003 Rob Swindell - http://www.synchro.net/copyright.html
+ *
+ * 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 2
+ * of the License, or (at your option) any later version.
+ * See the GNU General Public License for more details: gpl.txt or
+ * http://www.fsf.org/copyleft/gpl.html
+ *
+ * Anonymous FTP access to the most recent released source is available at
+ * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net
+ *
+ * Anonymous CVS access to the development source and modification history
+ * is available at cvs.synchro.net:/cvsroot/sbbs, example:
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login
+ * (just hit return, no password is necessary)
+ * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src
+ *
+ * For Synchronet coding style and modification guidelines, see
+ * http://www.synchro.net/source.html
+ *
+ * You are encouraged to submit any modifications (preferably in Unix diff
+ * format) via e-mail to mods@synchro.net
+ *
+ * Note: If this box doesn't appear square, then you need to fix your tabs.
+ ****************************************************************************/
+/* modifications for DttSP
+ Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+ who can be reached by email at
+ ab2kt@arrl.net
+ or
+ rwmcgwier@comcast.net
+
+ or by paper mail at
+
+ The DTTS Microwave Society
+ 6 Kathleen Place
+ Bridgewater, NJ 08807 */
+
+#ifndef _crc16_h
+#define _crc16_h
+
+#include <fromsys.h>
+
+extern unsigned short crc16(char *data, unsigned long len);
+
+#endif
--- /dev/null
+/* cxops.c
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <cxops.h>
+
+// useful constants
+
+COMPLEX cxzero = {0.0, 0.0};
+COMPLEX cxone = {1.0, 0.0};
+COMPLEX cxJ = {0.0, 1.0};
+COMPLEX cxminusone = {-1.0, 0.0};
+COMPLEX cxminusJ = {0.0, -1.0};
+
+// scalar
+
+COMPLEX
+Cscl(COMPLEX x, REAL a) {
+ COMPLEX z;
+ c_re(z) = c_re(x) * a;
+ c_im(z) = c_im(x) * a;
+ return z;
+}
+
+COMPLEX
+Cadd(COMPLEX x, COMPLEX y) {
+ COMPLEX z;
+ c_re(z) = c_re(x) + c_re(y);
+ c_im(z) = c_im(x) + c_im(y);
+ return z;
+}
+
+COMPLEX
+Csub(COMPLEX x, COMPLEX y) {
+ COMPLEX z;
+ c_re(z) = c_re(x) - c_re(y);
+ c_im(z) = c_im(x) - c_im(y);
+ return z;
+}
+
+COMPLEX
+Cmul(COMPLEX x, COMPLEX y) {
+ COMPLEX z;
+ c_re(z) = c_re(x) * c_re(y) - c_im(x) * c_im(y);
+ c_im(z) = c_im(x) * c_re(y) + c_re(x) * c_im(y);
+ return z;
+}
+
+COMPLEX
+Cdiv(COMPLEX x, COMPLEX y) {
+ REAL d = sqr(c_re(y)) + sqr(c_im(y));
+ COMPLEX z;
+ c_re(z) = (c_re(x) * c_re(y) + c_im(x) * c_im(y)) / d;
+ c_im(z) = (c_re(y) * c_im(x) - c_im(y) * c_re(x)) / d;
+ return z;
+}
+
+REAL
+Cmag(COMPLEX z) { return sqrt(sqr(z.re) + sqr(z.im)); }
+
+REAL
+Cabs(COMPLEX z) { return sqrt(sqr(z.re) + sqr(z.im)); }
+
+REAL
+Csqrmag(COMPLEX z) { return sqr(z.re) + sqr(z.im); }
+
+COMPLEX
+Cmplx(REAL x, IMAG y) {
+ COMPLEX z;
+ z.re = x, z.im = y;
+ return z;
+}
+
+COMPLEX
+Conjg(COMPLEX z) { return Cmplx(z.re, -z.im); }
+
+COMPLEX
+Cexp(COMPLEX z) {
+ REAL r = exp(z.re);
+ return Cmplx(r * cos(z.im), r * sin(z.im));
+}
--- /dev/null
+/* cxops.h
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _cxops_h
+
+#define _cxops_h
+
+#include <datatypes.h>
+
+extern COMPLEX cxzero;
+extern COMPLEX cxone;
+extern COMPLEX cxJ;
+extern COMPLEX cxminusone;
+extern COMPLEX cxminusJ;
+
+extern INLINE COMPLEX Cscl(COMPLEX, REAL);
+extern INLINE COMPLEX Cadd(COMPLEX, COMPLEX);
+extern INLINE COMPLEX Csub(COMPLEX, COMPLEX);
+extern INLINE COMPLEX Cmul(COMPLEX, COMPLEX);
+extern INLINE COMPLEX Cdiv(COMPLEX, COMPLEX);
+extern INLINE REAL Cmag(COMPLEX);
+extern INLINE REAL Cabs(COMPLEX);
+extern INLINE REAL Csqrmag(COMPLEX);
+extern INLINE COMPLEX Cmplx(REAL, IMAG);
+extern INLINE COMPLEX Conjg(COMPLEX);
+extern INLINE COMPLEX Cexp(COMPLEX);
+
+#endif
+
--- /dev/null
+/* datatypes.h
+ local definitions and aliases for our data
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _datatypes_h
+
+#define _datatypes_h
+
+#include <fromsys.h>
+
+typedef int BOOLEAN;
+typedef double REAL;
+typedef double IMAG;
+typedef short SAMPLE_16t;
+
+#include <complex.h>
+
+#ifndef PRIVATE
+#define PRIVATE static
+#endif
+
+#ifndef INLINE
+#define INLINE inline
+#endif
+
+#include <banal.h>
+
+#endif
+
--- /dev/null
+/* digitalagc.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+We appreciate the contributions to this subroutine by Gerald Youngblood,
+AC5OG and Phil Harman, VK6APH.
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+/*
+ * Mode is gross agc mode: off, slow, med, fast; just info
+ * Hang is basic hang time
+ * Size is max hang time
+ * Over is recover period after TRX switch
+ * Rcov is hang value used during recovery period
+ * BufSize is length of sample buffer
+ */
+
+DIGITALAGC
+newDigitalAgc(int Mode,
+ int Hang,
+ int Size,
+ int Over,
+ int Rcov,
+ int Ramp,
+ int BufSize,
+ REAL MaxGain,
+ REAL Limit,
+ REAL CurGain,
+ COMPLEX *Vec) {
+ DIGITALAGC a = (DIGITALAGC) safealloc(1,
+ sizeof(digital_agc_state),
+ "new digital agc state");
+ assert((Ramp >= 2) && (Ramp < BufSize));
+ a->mode = Mode;
+ a->hang = Hang;
+ a->size = Size;
+ a->over = Over;
+ a->rcov = Rcov;
+ a->ramp = Ramp;
+ a->gain.top = MaxGain;
+ a->gain.lim = Limit;
+ a->gain.old = a->gain.now = CurGain;
+ a->buff = newCXB(BufSize, Vec, "agc buffer");
+ memset((void *) a->hist, 0, sizeof(a->hist));
+ a->indx = 0;
+ a->gain.fix = 1000.0;
+ return a;
+}
+
+void
+delDigitalAgc(DIGITALAGC a) {
+ if (a) {
+ delCXB(a->buff);
+ safefree((void *) a);
+ }
+}
+
+void
+DigitalAgc(DIGITALAGC a, int tick) {
+
+ if (a->mode == agcOFF) {
+ int i;
+ for (i = 0; i < CXBsize(a->buff); i++)
+ CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.fix);
+
+ } else {
+ int i,
+ k = a->indx,
+ hang = tick < a->over ? a->rcov : a->hang;
+ REAL peak = 0.0;
+
+ for (i = 0; i < CXBsize(a->buff); i++)
+ peak = max(peak, Cmag(CXBdata(a->buff, i)));
+
+ if (peak != 0) {
+ a->size = hang;
+ a->hist[k] = a->gain.lim / peak;
+ for (i = 1, a->gain.now = a->hist[0]; i < hang; i++)
+ a->gain.now = min(a->hist[i], a->gain.now);
+ }
+ a->gain.now = min(a->gain.now, a->gain.top);
+
+ if (a->gain.now != a->gain.old) {
+ REAL step = (a->gain.now - a->gain.old) / (a->ramp - 1);
+ for (i = 0; i < a->ramp; i++)
+ CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.old + i * step);
+ for (; i < CXBsize(a->buff); i++)
+ CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.now);
+ a->gain.old = a->gain.now;
+
+ } else
+ for (i = 0; i < CXBsize(a->buff); i++)
+ CXBdata(a->buff, i) = Cscl(CXBdata(a->buff, i), a->gain.now);
+
+ a->indx = ++k % a->size;
+ }
+}
--- /dev/null
+/* digitalagc.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _digitalagc_h
+#define _digitalagc_h
+
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <banal.h>
+
+typedef enum _agcmode { agcOFF, agcLONG, agcSLOW, agcMED, agcFAST } AGCMODE;
+
+#define AGCHIST (24)
+
+typedef
+struct _digitalagc {
+ AGCMODE mode;
+ int hang, indx, over, ramp, rcov, size;
+ struct {
+ REAL fix, lim, now, old, top;
+ } gain;
+ REAL hist[AGCHIST];
+ CXB buff;
+} digital_agc_state, *DIGITALAGC;
+
+extern void delDigitalAgc(DIGITALAGC agc);
+
+extern DIGITALAGC
+newDigitalAgc(int Mode,
+ int Hang,
+ int Size,
+ int Ramp,
+ int Over,
+ int Rcov,
+ int BufSize,
+ REAL MaxGain,
+ REAL Limit,
+ REAL CurGain,
+ COMPLEX *Vec);
+
+extern void DigitalAgc(DIGITALAGC agc, int tick);
+
+#endif
--- /dev/null
+define(OFF,0)dnl\r
+define(ON,1)dnl\r
+define(FALSE,0)dnl\r
+define(TRUE,1)dnl\r
+define(F,0)dnl\r
+define(T,1)dnl\r
+define(FIR_Undef,0)dnl\r
+define(FIR_Lowpass,1)dnl\r
+define(FIR_Bandpass,2)dnl\r
+define(FIR_Highpass,3)dnl\r
+define(FIR_Hilbert,4)dnl\r
+define(FIR_Bandstop,5)dnl\r
+dnl\r
+define(FIR_Even,0)dnl\r
+define(FIR_Odd,1)dnl\r
+dnl\r
+define(MAG,0)dnl\r
+define(DB,1)dnl\r
+dnl\r
+define(SIGNAL_STRENGTH,0)dnl\r
+define(AVG_SIGNAL_STRENGTH,1)dnl\r
+define(ADC_REAL,2)dnl\r
+define(ADC_IMAG,3)dnl\r
+define(AGC_GAIN,4)dnl\r
+dnl\r
+define(agcOFF,0)dnl\r
+define(agcLONG,1)dnl\r
+define(agcSLOW,2)dnl\r
+define(agcMED,3)dnl\r
+define(agcFAST,4)dnl\r
+dnl\r
+define(LSB,0)dnl\r
+define(USB,1)dnl\r
+define(DSB,2)dnl\r
+define(CWL,3)dnl\r
+define(CWU,4)dnl\r
+define(FM,5)dnl\r
+define(FMN,5)dnl\r
+define(AM,6)dnl\r
+define(PSK,7)dnl\r
+define(SPEC,8)dnl\r
+define(RTTY,9)dnl\r
+define(SAM,10)dnl\r
+define(DRM,11)dnl\r
+dnl\r
+define(RX,0)dnl\r
+define(TX,1)dnl\r
+dnl\r
+define(RECTANGULAR_WINDOW,0)dnl\r
+define(HANNING_WINDOW,1)dnl\r
+define(WELCH_WINDOW,2)dnl\r
+define(PARZEN_WINDOW,3)dnl\r
+define(BARTLETT_WINDOW,4)dnl\r
+define(HAMMING_WINDOW,5)dnl\r
+define(BLACKMAN2_WINDOW,6)dnl\r
+define(BLACKMAN3_WINDOW,7)dnl\r
+define(BLACKMAN4_WINDOW,8)dnl\r
+define(EXPONENTIAL_WINDOW,9)dnl\r
+define(RIEMANN_WINDOW,10)dnl\r
+dnl\r
+define(RUN_MUTE,0)dnl\r
+define(RUN_PASS,1)dnl\r
+define(RUN_PLAY,2)dnl\r
+define(RUN_SWCH,3)dnl\r
--- /dev/null
+
+/****************************************************************
+ * Fast Trigonometric Routines Used for Imbedded Systems *
+ * Programmer: Bob McGwier, IDA CCR-P, June, 2000 *
+ ***************************************************************/
+/* This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The author can be reached by email at
+
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+Robert W McGwier, N4HY
+64 Brooktree Road
+East Windsor, NJ 08520
+*/
+
+#include <fastrig.h>
+
+REAL
+phasemod(REAL angle) {
+ while (angle >= TWOPI) angle -= TWOPI;
+ while (angle < 0.0) angle += TWOPI;
+ return angle;
+}
+
+//REAL phasemod(REAL angle)
+//{
+ // return (angle - floor(angle/TWOPI)*TWOPI);
+//}
+
+#if (TRIG_SPEED != 0)
+
+static REAL TABLE_FACTOR;
+static REAL *sinT, *cosT;
+
+/***************************************************************************/
+/* Constant definitions */
+/***************************************************************************/
+#define TAN_MAP_RES 0.003921569 /* (smallest non-zero value in table) */
+#define RAD_PER_DEG 0.017453293
+#define TAN_MAP_SIZE 256
+
+/* arctangents from 0 to pi/4 radians */
+static REAL fast_atan_table[257] = {
+ 0.000000e+00, 3.921549e-03, 7.842976e-03, 1.176416e-02,
+ 1.568499e-02, 1.960533e-02, 2.352507e-02, 2.744409e-02,
+ 3.136226e-02, 3.527947e-02, 3.919560e-02, 4.311053e-02,
+ 4.702413e-02, 5.093629e-02, 5.484690e-02, 5.875582e-02,
+ 6.266295e-02, 6.656816e-02, 7.047134e-02, 7.437238e-02,
+ 7.827114e-02, 8.216752e-02, 8.606141e-02, 8.995267e-02,
+ 9.384121e-02, 9.772691e-02, 1.016096e-01, 1.054893e-01,
+ 1.093658e-01, 1.132390e-01, 1.171087e-01, 1.209750e-01,
+ 1.248376e-01, 1.286965e-01, 1.325515e-01, 1.364026e-01,
+ 1.402496e-01, 1.440924e-01, 1.479310e-01, 1.517652e-01,
+ 1.555948e-01, 1.594199e-01, 1.632403e-01, 1.670559e-01,
+ 1.708665e-01, 1.746722e-01, 1.784728e-01, 1.822681e-01,
+ 1.860582e-01, 1.898428e-01, 1.936220e-01, 1.973956e-01,
+ 2.011634e-01, 2.049255e-01, 2.086818e-01, 2.124320e-01,
+ 2.161762e-01, 2.199143e-01, 2.236461e-01, 2.273716e-01,
+ 2.310907e-01, 2.348033e-01, 2.385093e-01, 2.422086e-01,
+ 2.459012e-01, 2.495869e-01, 2.532658e-01, 2.569376e-01,
+ 2.606024e-01, 2.642600e-01, 2.679104e-01, 2.715535e-01,
+ 2.751892e-01, 2.788175e-01, 2.824383e-01, 2.860514e-01,
+ 2.896569e-01, 2.932547e-01, 2.968447e-01, 3.004268e-01,
+ 3.040009e-01, 3.075671e-01, 3.111252e-01, 3.146752e-01,
+ 3.182170e-01, 3.217506e-01, 3.252758e-01, 3.287927e-01,
+ 3.323012e-01, 3.358012e-01, 3.392926e-01, 3.427755e-01,
+ 3.462497e-01, 3.497153e-01, 3.531721e-01, 3.566201e-01,
+ 3.600593e-01, 3.634896e-01, 3.669110e-01, 3.703234e-01,
+ 3.737268e-01, 3.771211e-01, 3.805064e-01, 3.838825e-01,
+ 3.872494e-01, 3.906070e-01, 3.939555e-01, 3.972946e-01,
+ 4.006244e-01, 4.039448e-01, 4.072558e-01, 4.105574e-01,
+ 4.138496e-01, 4.171322e-01, 4.204054e-01, 4.236689e-01,
+ 4.269229e-01, 4.301673e-01, 4.334021e-01, 4.366272e-01,
+ 4.398426e-01, 4.430483e-01, 4.462443e-01, 4.494306e-01,
+ 4.526070e-01, 4.557738e-01, 4.589307e-01, 4.620778e-01,
+ 4.652150e-01, 4.683424e-01, 4.714600e-01, 4.745676e-01,
+ 4.776654e-01, 4.807532e-01, 4.838312e-01, 4.868992e-01,
+ 4.899573e-01, 4.930055e-01, 4.960437e-01, 4.990719e-01,
+ 5.020902e-01, 5.050985e-01, 5.080968e-01, 5.110852e-01,
+ 5.140636e-01, 5.170320e-01, 5.199904e-01, 5.229388e-01,
+ 5.258772e-01, 5.288056e-01, 5.317241e-01, 5.346325e-01,
+ 5.375310e-01, 5.404195e-01, 5.432980e-01, 5.461666e-01,
+ 5.490251e-01, 5.518738e-01, 5.547124e-01, 5.575411e-01,
+ 5.603599e-01, 5.631687e-01, 5.659676e-01, 5.687566e-01,
+ 5.715357e-01, 5.743048e-01, 5.770641e-01, 5.798135e-01,
+ 5.825531e-01, 5.852828e-01, 5.880026e-01, 5.907126e-01,
+ 5.934128e-01, 5.961032e-01, 5.987839e-01, 6.014547e-01,
+ 6.041158e-01, 6.067672e-01, 6.094088e-01, 6.120407e-01,
+ 6.146630e-01, 6.172755e-01, 6.198784e-01, 6.224717e-01,
+ 6.250554e-01, 6.276294e-01, 6.301939e-01, 6.327488e-01,
+ 6.352942e-01, 6.378301e-01, 6.403565e-01, 6.428734e-01,
+ 6.453808e-01, 6.478788e-01, 6.503674e-01, 6.528466e-01,
+ 6.553165e-01, 6.577770e-01, 6.602282e-01, 6.626701e-01,
+ 6.651027e-01, 6.675261e-01, 6.699402e-01, 6.723452e-01,
+ 6.747409e-01, 6.771276e-01, 6.795051e-01, 6.818735e-01,
+ 6.842328e-01, 6.865831e-01, 6.889244e-01, 6.912567e-01,
+ 6.935800e-01, 6.958943e-01, 6.981998e-01, 7.004964e-01,
+ 7.027841e-01, 7.050630e-01, 7.073330e-01, 7.095943e-01,
+ 7.118469e-01, 7.140907e-01, 7.163258e-01, 7.185523e-01,
+ 7.207701e-01, 7.229794e-01, 7.251800e-01, 7.273721e-01,
+ 7.295557e-01, 7.317307e-01, 7.338974e-01, 7.360555e-01,
+ 7.382053e-01, 7.403467e-01, 7.424797e-01, 7.446045e-01,
+ 7.467209e-01, 7.488291e-01, 7.509291e-01, 7.530208e-01,
+ 7.551044e-01, 7.571798e-01, 7.592472e-01, 7.613064e-01,
+ 7.633576e-01, 7.654008e-01, 7.674360e-01, 7.694633e-01,
+ 7.714826e-01, 7.734940e-01, 7.754975e-01, 7.774932e-01,
+ 7.794811e-01, 7.814612e-01, 7.834335e-01, 7.853983e-01,
+ 7.853983e-01
+};
+
+void
+InitSPEEDTRIG(void) {
+ int i, SIZE;
+ TABLE_FACTOR = ONE_OVER_TWOPI * SIN_TABLE_SIZE;
+ SIZE = sizeof(REAL) * (SIN_TABLE_SIZE + 1);
+ sinT = (REAL *) malloc(SIZE + (SIZE >> 2) + 1);
+ /* cosT=(REAL *)malloc(SIZE); */
+ for (i = 0; i < SIN_TABLE_SIZE + (SIN_TABLE_SIZE >> 2) + 1; i++) {
+ sinT[i] = (REAL) sin((REAL) i * TWOPI / (REAL) SIN_TABLE_SIZE);
+ /* cosT[i] = (REAL)cos((REAL)i * TWOPI/(REAL)SIN_TABLE_SIZE); */
+ }
+ cosT = sinT + (SIN_TABLE_SIZE >> 2);
+}
+
+REAL
+fast_sin(REAL x) {
+#if (TRIG_SPEED==2)
+ x = (x * TABLE_FACTOR) + 0.5;
+ return sinT[((int) x) & (SIN_TABLE_SIZE_M1)];
+#else
+ int i, ip1;
+ REAL frac;
+ x = (x * TABLE_FACTOR);
+ i = (int)(frac = floor(x));
+ ip1 = i + 1;
+ frac = x - frac;
+ return (1.0 - frac) * sinT[i] + frac * sinT[ip1];
+#endif
+}
+
+REAL
+fast_cos(REAL x) {
+#if (TRIG_SPEED==2)
+ x = (x * TABLE_FACTOR) + 0.5;
+ return cosT[((int) x) & (SIN_TABLE_SIZE - 1)];
+#else
+ int i, ip1;
+ REAL frac;
+ x = (x * TABLE_FACTOR);
+ i = (int)(frac = floor(x));
+ ip1 = i + 1;
+ frac = x - frac;
+ return (1.0 - frac) * cosT[i] + frac * cosT[ip1];
+#endif
+}
+
+/*****************************************************************************
+ Function: Arc tangent
+
+ Syntax: angle = fast_atan2(y, x);
+ REAL y y component of input vector
+ REAL x x component of input vector
+ REAL angle angle of vector (x, y) in radians
+
+ Description: This function calculates the angle of the vector (x,y) based
+ on a table lookup and linear interpolation. The table uses
+ a 256 point table covering -45 to +45 degrees and uses
+ symetry to determine the final angle value in the range of
+ -180 to 180 degrees. Note that this function uses the small
+ angle approximation for values close to zero. This routine
+ calculates the arc tangent with an average error of
+ +/- 0.045 degrees.
+*****************************************************************************/
+
+REAL
+fast_atan2(REAL y, REAL x) {
+ REAL x_abs, y_abs, z;
+ REAL alpha, angle, base_angle;
+ int index;
+
+ /* don't divide by zero! */
+ if ((y == 0.0) && (x == 0.0)) angle = 0.0;
+ else {
+ /* normalize to +/- 45 degree range */
+ y_abs = fabs(y);
+ x_abs = fabs(x);
+ z = (y_abs < x_abs ? y_abs / x_abs : x_abs / y_abs);
+ /* when ratio approaches the table resolution, the angle is */
+ /* best approximated with the argument itself... */
+ if (z < TAN_MAP_RES) base_angle = z;
+ else {
+ /* find index and interpolation value */
+ alpha = z * (REAL) TAN_MAP_SIZE - .5;
+ index = (int) alpha;
+ alpha -= (REAL) index;
+ /* determine base angle based on quadrant and */
+ /* add or subtract table value from base angle based on quadrant */
+ base_angle = fast_atan_table[index];
+ base_angle +=
+ (fast_atan_table[index + 1] - fast_atan_table[index]) * alpha;
+ }
+
+ if (x_abs > y_abs) { /* -45 -> 45 or 135 -> 225 */
+ if (x >= 0.0) { /* -45 -> 45 */
+ if (y >= 0.0)
+ angle = base_angle; /* 0 -> 45, angle OK */
+ else
+ angle = -base_angle; /* -45 -> 0, angle = -angle */
+ } else { /* 135 -> 180 or 180 -> -135 */
+ angle = 3.14159265358979323846;
+ if (y >= 0.0)
+ angle -= base_angle; /* 135 -> 180, angle = 180 - angle */
+ else
+ angle = base_angle - angle; /* 180 -> -135, angle = angle - 180 */
+ }
+ } else { /* 45 -> 135 or -135 -> -45 */
+ if (y >= 0.0) { /* 45 -> 135 */
+ angle = 1.57079632679489661923;
+ if (x >= 0.0)
+ angle -= base_angle; /* 45 -> 90, angle = 90 - angle */
+ else
+ angle += base_angle; /* 90 -> 135, angle = 90 + angle */
+ } else { /* -135 -> -45 */
+ angle = -1.57079632679489661923;
+ if (x >= 0.0)
+ angle += base_angle; /* -90 -> -45, angle = -90 + angle */
+ else
+ angle -= base_angle; /* -135 -> -90, angle = -90 - angle */
+ }
+ }
+ }
+#ifdef ZERO_TO_TWOPI
+ if (angle < 0) return (angle + TWOPI);
+ else return (angle);
+#else
+ return (angle);
+#endif
+}
+
+#endif
--- /dev/null
+/* fastrig.h
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _fastrig_h
+#define _fastrig_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+
+#define SIN_TABLE_SIZE 4096
+#define SIN_TABLE_SIZE_M1 4095
+
+/* **********************************************
+ * TRIG_SPEED:
+ * 0 = normal (slow);
+ * 1 = table look up with interpolation (medium);
+ * 2 = table look up (fast)
+ * ***********************************************/
+
+/* Interpolation is ALWAYS done on atan2. The setting
+ only applies to sin and cos */
+
+#ifndef TRIG_SPEED
+#define TRIG_SPEED 0
+#endif
+
+#if (TRIG_SPEED == 2)
+#define SIN(x) fast_sin(x)
+#define COS(x) fast_cos(x)
+#define ATAN2(x,y) fast_atan2((x),(y))
+
+#elif (TRIG_SPEED == 1)
+
+#define SIN(x) fast_sin(x)
+#define COS(x) fast_cos(x)
+#define ATAN2(x,y) fast_atan2((x),(y))
+
+#elif (TRIG_SPEED == 0)
+
+#define SIN(x) (REAL)sin((REAL)x)
+#define COS(x) (REAL)cos((REAL)x)
+#define ATAN2(x,y) (REAL)atan2((REAL)(x),(REAL)(y))
+
+#endif
+
+#ifndef PI
+#define PI M_PI
+#endif /* PI */
+
+#ifndef TWOPI
+#define TWOPI (2.0 * PI)
+#endif
+
+#ifndef ONE_OVER_TWOPI
+#define ONE_OVER_TWOPI (0.159154943091895)
+#endif
+
+#if (TRIG_SPEED != 0)
+
+extern void InitSPEEDTRIG(void);
+extern REAL fast_sin(REAL);
+extern REAL fast_cos(REAL);
+extern REAL fast_atan2(REAL, REAL);
+
+#endif
+#endif
--- /dev/null
+/* -*- C -*- */
+/*
+ * Copyright (c) 1997-1999, 2003 Massachusetts Institute of Technology
+ *
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+/* fftw.h -- system-wide definitions */
+/* $Id$ */
+
+#ifndef FFTW_H
+#define FFTW_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Define for using single precision */
+/*
+ * If you can, use configure --enable-float instead of changing this
+ * flag directly
+ */
+/* #undef FFTW_ENABLE_FLOAT */
+
+/* our real numbers */
+#ifdef FFTW_ENABLE_FLOAT
+typedef float fftw_real;
+#else
+typedef double fftw_real;
+#endif
+
+/*********************************************
+ * Complex numbers and operations
+ *********************************************/
+typedef struct {
+ fftw_real re, im;
+} fftw_complex;
+
+#ifndef c_re
+#define c_re(c) ((c).re)
+#endif
+#ifndef c_im
+#define c_im(c) ((c).im)
+#endif
+
+typedef enum {
+ FFTW_FORWARD = -1, FFTW_BACKWARD = 1
+} fftw_direction;
+
+/* backward compatibility with FFTW-1.3 */
+typedef fftw_complex FFTW_COMPLEX;
+typedef fftw_real FFTW_REAL;
+
+#ifndef FFTW_1_0_COMPATIBILITY
+#define FFTW_1_0_COMPATIBILITY 0
+#endif
+
+#if FFTW_1_0_COMPATIBILITY
+/* backward compatibility with FFTW-1.0 */
+#define REAL fftw_real
+#define COMPLEX fftw_complex
+#endif
+
+/*********************************************
+ * Success or failure status
+ *********************************************/
+
+typedef enum {
+ FFTW_SUCCESS = 0, FFTW_FAILURE = -1
+} fftw_status;
+
+/*********************************************
+ * Codelets
+ *********************************************/
+typedef void (fftw_notw_codelet)
+ (const fftw_complex *, fftw_complex *, int, int);
+typedef void (fftw_twiddle_codelet)
+ (fftw_complex *, const fftw_complex *, int,
+ int, int);
+typedef void (fftw_generic_codelet)
+ (fftw_complex *, const fftw_complex *, int,
+ int, int, int);
+typedef void (fftw_real2hc_codelet)
+ (const fftw_real *, fftw_real *, fftw_real *,
+ int, int, int);
+typedef void (fftw_hc2real_codelet)
+ (const fftw_real *, const fftw_real *,
+ fftw_real *, int, int, int);
+typedef void (fftw_hc2hc_codelet)
+ (fftw_real *, const fftw_complex *,
+ int, int, int);
+typedef void (fftw_rgeneric_codelet)
+ (fftw_real *, const fftw_complex *, int,
+ int, int, int);
+
+/*********************************************
+ * Configurations
+ *********************************************/
+/*
+ * A configuration is a database of all known codelets
+ */
+
+enum fftw_node_type {
+ FFTW_NOTW, FFTW_TWIDDLE, FFTW_GENERIC, FFTW_RADER,
+ FFTW_REAL2HC, FFTW_HC2REAL, FFTW_HC2HC, FFTW_RGENERIC
+};
+
+/* description of a codelet */
+typedef struct {
+ const char *name; /* name of the codelet */
+ void (*codelet) (); /* pointer to the codelet itself */
+ int size; /* size of the codelet */
+ fftw_direction dir; /* direction */
+ enum fftw_node_type type; /* TWIDDLE or NO_TWIDDLE */
+ int signature; /* unique id */
+ int ntwiddle; /* number of twiddle factors */
+ const int *twiddle_order; /*
+ * array that determines the order
+ * in which the codelet expects
+ * the twiddle factors
+ */
+} fftw_codelet_desc;
+
+/* On Win32, you need to do funny things to access global variables
+ in shared libraries. Thanks to Andrew Sterian for this hack. */
+#ifdef HAVE_WIN32
+# if defined(BUILD_FFTW_DLL)
+# define DL_IMPORT(type) __declspec(dllexport) type
+# elif defined(USE_FFTW_DLL)
+# define DL_IMPORT(type) __declspec(dllimport) type
+# else
+# define DL_IMPORT(type) type
+# endif
+#else
+# define DL_IMPORT(type) type
+#endif
+
+extern DL_IMPORT(const char *) fftw_version;
+
+/*****************************
+ * Plans
+ *****************************/
+/*
+ * A plan is a sequence of reductions to compute a FFT of
+ * a given size. At each step, the FFT algorithm can:
+ *
+ * 1) apply a notw codelet, or
+ * 2) recurse and apply a twiddle codelet, or
+ * 3) apply the generic codelet.
+ */
+
+/* structure that contains twiddle factors */
+typedef struct fftw_twiddle_struct {
+ int n;
+ const fftw_codelet_desc *cdesc;
+ fftw_complex *twarray;
+ struct fftw_twiddle_struct *next;
+ int refcnt;
+} fftw_twiddle;
+
+typedef struct fftw_rader_data_struct {
+ struct fftw_plan_struct *plan;
+ fftw_complex *omega;
+ int g, ginv;
+ int p, flags, refcount;
+ struct fftw_rader_data_struct *next;
+ fftw_codelet_desc *cdesc;
+} fftw_rader_data;
+
+typedef void (fftw_rader_codelet)
+ (fftw_complex *, const fftw_complex *, int,
+ int, int, fftw_rader_data *);
+
+/* structure that holds all the data needed for a given step */
+typedef struct fftw_plan_node_struct {
+ enum fftw_node_type type;
+
+ union {
+ /* nodes of type FFTW_NOTW */
+ struct {
+ int size;
+ fftw_notw_codelet *codelet;
+ const fftw_codelet_desc *codelet_desc;
+ } notw;
+
+ /* nodes of type FFTW_TWIDDLE */
+ struct {
+ int size;
+ fftw_twiddle_codelet *codelet;
+ fftw_twiddle *tw;
+ struct fftw_plan_node_struct *recurse;
+ const fftw_codelet_desc *codelet_desc;
+ } twiddle;
+
+ /* nodes of type FFTW_GENERIC */
+ struct {
+ int size;
+ fftw_generic_codelet *codelet;
+ fftw_twiddle *tw;
+ struct fftw_plan_node_struct *recurse;
+ } generic;
+
+ /* nodes of type FFTW_RADER */
+ struct {
+ int size;
+ fftw_rader_codelet *codelet;
+ fftw_rader_data *rader_data;
+ fftw_twiddle *tw;
+ struct fftw_plan_node_struct *recurse;
+ } rader;
+
+ /* nodes of type FFTW_REAL2HC */
+ struct {
+ int size;
+ fftw_real2hc_codelet *codelet;
+ const fftw_codelet_desc *codelet_desc;
+ } real2hc;
+
+ /* nodes of type FFTW_HC2REAL */
+ struct {
+ int size;
+ fftw_hc2real_codelet *codelet;
+ const fftw_codelet_desc *codelet_desc;
+ } hc2real;
+
+ /* nodes of type FFTW_HC2HC */
+ struct {
+ int size;
+ fftw_direction dir;
+ fftw_hc2hc_codelet *codelet;
+ fftw_twiddle *tw;
+ struct fftw_plan_node_struct *recurse;
+ const fftw_codelet_desc *codelet_desc;
+ } hc2hc;
+
+ /* nodes of type FFTW_RGENERIC */
+ struct {
+ int size;
+ fftw_direction dir;
+ fftw_rgeneric_codelet *codelet;
+ fftw_twiddle *tw;
+ struct fftw_plan_node_struct *recurse;
+ } rgeneric;
+ } nodeu;
+
+ int refcnt;
+} fftw_plan_node;
+
+typedef enum {
+ FFTW_NORMAL_RECURSE = 0,
+ FFTW_VECTOR_RECURSE = 1
+} fftw_recurse_kind;
+
+struct fftw_plan_struct {
+ int n;
+ int refcnt;
+ fftw_direction dir;
+ int flags;
+ int wisdom_signature;
+ enum fftw_node_type wisdom_type;
+ struct fftw_plan_struct *next;
+ fftw_plan_node *root;
+ double cost;
+ fftw_recurse_kind recurse_kind;
+ int vector_size;
+};
+
+typedef struct fftw_plan_struct *fftw_plan;
+
+/* flags for the planner */
+#define FFTW_ESTIMATE (0)
+#define FFTW_MEASURE (1)
+
+#define FFTW_OUT_OF_PLACE (0)
+#define FFTW_IN_PLACE (8)
+#define FFTW_USE_WISDOM (16)
+
+#define FFTW_THREADSAFE (128) /* guarantee plan is read-only so that the
+ same plan can be used in parallel by
+ multiple threads */
+
+#define FFTWND_FORCE_BUFFERED (256) /* internal flag, forces buffering
+ in fftwnd transforms */
+
+#define FFTW_NO_VECTOR_RECURSE (512) /* internal flag, prevents use
+ of vector recursion */
+
+extern fftw_plan fftw_create_plan_specific(int n, fftw_direction dir,
+ int flags,
+ fftw_complex *in, int istride,
+ fftw_complex *out, int ostride);
+#define FFTW_HAS_PLAN_SPECIFIC
+extern fftw_plan fftw_create_plan(int n, fftw_direction dir, int flags);
+extern void fftw_print_plan(fftw_plan plan);
+extern void fftw_destroy_plan(fftw_plan plan);
+extern void fftw(fftw_plan plan, int howmany, fftw_complex *in, int istride,
+ int idist, fftw_complex *out, int ostride, int odist);
+extern void fftw_one(fftw_plan plan, fftw_complex *in, fftw_complex *out);
+extern void fftw_die(const char *s);
+extern void *fftw_malloc(size_t n);
+extern void fftw_free(void *p);
+extern void fftw_check_memory_leaks(void);
+extern void fftw_print_max_memory_usage(void);
+
+typedef void *(*fftw_malloc_type_function) (size_t n);
+typedef void (*fftw_free_type_function) (void *p);
+typedef void (*fftw_die_type_function) (const char *errString);
+extern DL_IMPORT(fftw_malloc_type_function) fftw_malloc_hook;
+extern DL_IMPORT(fftw_free_type_function) fftw_free_hook;
+extern DL_IMPORT(fftw_die_type_function) fftw_die_hook;
+
+extern size_t fftw_sizeof_fftw_real(void);
+
+/* Wisdom: */
+/*
+ * define this symbol so that users know we are using a version of FFTW
+ * with wisdom
+ */
+#define FFTW_HAS_WISDOM
+extern void fftw_forget_wisdom(void);
+extern void fftw_export_wisdom(void (*emitter) (char c, void *), void *data);
+extern fftw_status fftw_import_wisdom(int (*g) (void *), void *data);
+extern void fftw_export_wisdom_to_file(FILE *output_file);
+extern fftw_status fftw_import_wisdom_from_file(FILE *input_file);
+extern char *fftw_export_wisdom_to_string(void);
+extern fftw_status fftw_import_wisdom_from_string(const char *input_string);
+
+/*
+ * define symbol so we know this function is available (it is not in
+ * older FFTWs)
+ */
+#define FFTW_HAS_FPRINT_PLAN
+extern void fftw_fprint_plan(FILE *f, fftw_plan plan);
+
+/*****************************
+ * N-dimensional code
+ *****************************/
+typedef struct {
+ int is_in_place; /* 1 if for in-place FFTs, 0 otherwise */
+
+ int rank; /*
+ * the rank (number of dimensions) of the
+ * array to be FFTed
+ */
+ int *n; /*
+ * the dimensions of the array to the
+ * FFTed
+ */
+ fftw_direction dir;
+
+ int *n_before; /*
+ * n_before[i] = product of n[j] for j < i
+ */
+ int *n_after; /* n_after[i] = product of n[j] for j > i */
+
+ fftw_plan *plans; /* 1d fftw plans for each dimension */
+
+ int nbuffers, nwork;
+ fftw_complex *work; /*
+ * work array big enough to hold
+ * nbuffers+1 of the largest dimension
+ * (has nwork elements)
+ */
+} fftwnd_data;
+
+typedef fftwnd_data *fftwnd_plan;
+
+/* Initializing the FFTWND plan: */
+extern fftwnd_plan fftw2d_create_plan(int nx, int ny, fftw_direction dir,
+ int flags);
+extern fftwnd_plan fftw3d_create_plan(int nx, int ny, int nz,
+ fftw_direction dir, int flags);
+extern fftwnd_plan fftwnd_create_plan(int rank, const int *n,
+ fftw_direction dir,
+ int flags);
+
+extern fftwnd_plan fftw2d_create_plan_specific(int nx, int ny,
+ fftw_direction dir,
+ int flags,
+ fftw_complex *in, int istride,
+ fftw_complex *out, int ostride);
+extern fftwnd_plan fftw3d_create_plan_specific(int nx, int ny, int nz,
+ fftw_direction dir, int flags,
+ fftw_complex *in, int istride,
+ fftw_complex *out, int ostride);
+extern fftwnd_plan fftwnd_create_plan_specific(int rank, const int *n,
+ fftw_direction dir,
+ int flags,
+ fftw_complex *in, int istride,
+ fftw_complex *out, int ostride);
+
+/* Freeing the FFTWND plan: */
+extern void fftwnd_destroy_plan(fftwnd_plan plan);
+
+/* Printing the plan: */
+extern void fftwnd_fprint_plan(FILE *f, fftwnd_plan p);
+extern void fftwnd_print_plan(fftwnd_plan p);
+#define FFTWND_HAS_PRINT_PLAN
+
+/* Computing the N-Dimensional FFT */
+extern void fftwnd(fftwnd_plan plan, int howmany,
+ fftw_complex *in, int istride, int idist,
+ fftw_complex *out, int ostride, int odist);
+extern void fftwnd_one(fftwnd_plan p, fftw_complex *in, fftw_complex *out);
+
+#ifdef __cplusplus
+} /* extern "C" */
+
+#endif /* __cplusplus */
+#endif /* FFTW_H */
--- /dev/null
+/* filter.c
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <filter.h>
+
+static REAL onepi = 3.141592653589793;
+
+#define twopi TWOPI
+
+RealFIR
+newFIR_REAL(int size, char *tag) {
+ RealFIR p = (RealFIRDesc *) safealloc(1, sizeof(RealFIRDesc), tag);
+ FIRcoef(p) = (REAL *) safealloc(size, sizeof(REAL), tag);
+ FIRsize(p) = size;
+ FIRtype(p) = FIR_Undef;
+ FIRiscomplex(p) = FALSE;
+ FIRfqlo(p) = FIRfqhi(p) = -1.0;
+ return p;
+}
+
+ComplexFIR
+newFIR_COMPLEX(int size, char *tag) {
+ ComplexFIR p = (ComplexFIRDesc *) safealloc(1, sizeof(ComplexFIRDesc), tag);
+ FIRcoef(p) = (COMPLEX *) safealloc(size, sizeof(COMPLEX), tag);
+ FIRsize(p) = size;
+ FIRtype(p) = FIR_Undef;
+ FIRiscomplex(p) = TRUE;
+ FIRfqlo(p) = FIRfqhi(p) = -1.0;
+ return p;
+}
+
+void
+delFIR_REAL(RealFIR p) {
+ if (p) {
+ delvec_REAL(FIRcoef(p));
+ free((void *) p);
+ }
+}
+
+void
+delFIR_COMPLEX(ComplexFIR p) {
+ if (p) {
+ delvec_COMPLEX(FIRcoef(p));
+ free((void *) p);
+ }
+}
+
+RealFIR
+newFIR_Lowpass_REAL(REAL cutoff, REAL sr, int size) {
+ if ((cutoff < 0.0) || (cutoff > (sr / 2.0))) return 0;
+ else if (size < 1) return 0;
+ else {
+ RealFIR p;
+ REAL *h, *w, fc = cutoff / sr;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_REAL(size, "newFIR_Lowpass_REAL");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Lowpass_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint)
+ h[j] = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ h[midpoint - 1] = 2.0 * fc;
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Lowpass;
+ return p;
+ }
+}
+
+ComplexFIR
+newFIR_Lowpass_COMPLEX(REAL cutoff, REAL sr, int size) {
+ if ((cutoff < 0.0) || (cutoff > (sr / 2.0))) return 0;
+ else if (size < 1) return 0;
+ else {
+ ComplexFIR p;
+ COMPLEX *h;
+ REAL *w, fc = cutoff / sr;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_COMPLEX(size, "newFIR_Lowpass_COMPLEX");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Lowpass_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint)
+ h[j].re = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ h[midpoint - 1].re = 2.0 * fc;
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Lowpass;
+ return p;
+ }
+}
+
+RealFIR
+newFIR_Bandpass_REAL(REAL lo, REAL hi, REAL sr, int size) {
+ if ((lo < 0.0) || (hi > (sr / 2.0)) || (hi <= lo)) return 0;
+ else if (size < 1) return 0;
+ else {
+ RealFIR p;
+ REAL *h, *w, fc, ff;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_REAL(size, "newFIR_Bandpass_REAL");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Bandpass_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ lo /= sr, hi /= sr;
+ fc = (hi - lo) / 2.0;
+ ff = (lo + hi) * onepi;
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint)
+ h[j] = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ h[midpoint - 1] = 2.0 * fc;
+ h[j] *= 2.0 * cos(ff * (i - midpoint));
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Bandpass;
+ return p;
+ }
+}
+
+ComplexFIR
+newFIR_Bandpass_COMPLEX(REAL lo, REAL hi, REAL sr, int size) {
+ if ((lo < -(sr/2.0)) || (hi > (sr / 2.0)) || (hi <= lo)) return 0;
+ else if (size < 1) return 0;
+ else {
+ ComplexFIR p;
+ COMPLEX *h;
+ REAL *w, fc, ff;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_COMPLEX(size, "newFIR_Bandpass_COMPLEX");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Bandpass_COMPLEX window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ lo /= sr, hi /= sr;
+ fc = (hi - lo) / 2.0;
+ ff = (lo + hi) * onepi;
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1, k = i - midpoint;
+ REAL tmp, phs = ff * k;
+ if (i != midpoint)
+ tmp = (sin(twopi * k * fc) / (onepi * k)) * w[j];
+ else
+ tmp = 2.0 * fc;
+ tmp *= 2.0;
+ h[j].re = tmp * cos(phs);
+ h[j].im = tmp * sin(phs);
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Bandpass;
+ return p;
+ }
+}
+
+RealFIR
+newFIR_Highpass_REAL(REAL cutoff, REAL sr, int size) {
+ if ((cutoff < 0.0) || (cutoff > (sr / 2.0))) return 0;
+ else if (size < 1) return 0;
+ else {
+ RealFIR p;
+ REAL *h, *w, fc = cutoff / sr;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_REAL(size, "newFIR_Highpass_REAL");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Highpass_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint)
+ h[j] = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ h[midpoint - 1] = 2.0 * fc;
+ }
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint) h[j] = -h[j];
+ else h[midpoint - 1] = 1.0 - h[midpoint - 1];
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Highpass;
+ return p;
+ }
+}
+
+ComplexFIR
+newFIR_Highpass_COMPLEX(REAL cutoff, REAL sr, int size) {
+ if ((cutoff < 0.0) || (cutoff > (sr / 2.0))) return 0;
+ else if (size < 1) return 0;
+ else {
+ ComplexFIR p;
+ COMPLEX *h;
+ REAL *w, fc = cutoff / sr;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_COMPLEX(size, "newFIR_Highpass_REAL");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Highpass_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint)
+ h[j].re = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ h[midpoint - 1].re = 2.0 * fc;
+ }
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint) h[j].re = -h[j].re;
+ else h[midpoint - 1].re = 1.0 - h[midpoint - 1].re;
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Highpass;
+ return p;
+ }
+}
+
+RealFIR
+newFIR_Hilbert_REAL(REAL lo, REAL hi, REAL sr, int size) {
+ if ((lo < 0.0) || (hi > (sr / 2.0)) || (hi <= lo)) return 0;
+ else if (size < 1) return 0;
+ else {
+ RealFIR p;
+ REAL *h, *w, fc, ff;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_REAL(size, "newFIR_Hilbert_REAL");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Hilbert_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ lo /= sr, hi /= sr;
+ fc = (hi - lo) / 2.0;
+ ff = (lo + hi) * onepi;
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint)
+ h[j] = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ h[midpoint - 1] = 2.0 * fc;
+ h[j] *= 2.0 * sin(ff * (i - midpoint));
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Hilbert;
+ return p;
+ }
+}
+
+ComplexFIR
+newFIR_Hilbert_COMPLEX(REAL lo, REAL hi, REAL sr, int size) {
+ if ((lo < 0.0) || (hi > (sr / 2.0)) || (hi <= lo)) return 0;
+ else if (size < 1) return 0;
+ else {
+ ComplexFIR p;
+ COMPLEX *h;
+ REAL *w, fc, ff;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_COMPLEX(size, "newFIR_Hilbert_COMPLEX");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Hilbert_COMPLEX window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ lo /= sr, hi /= sr;
+ fc = (hi - lo) / 2.0;
+ ff = (lo + hi) * onepi;
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ REAL tmp, phs = ff * (i - midpoint);
+ if (i != midpoint)
+ tmp = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ tmp = 2.0 * fc;
+ tmp *= 2.0;
+ /* h[j].re *= tmp * cos(phs); */
+ h[j].im *= tmp * sin(phs);
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Hilbert;
+ return p;
+ }
+}
+
+RealFIR
+newFIR_Bandstop_REAL(REAL lo, REAL hi, REAL sr, int size) {
+ if ((lo < 0.0) || (hi > (sr / 2.0)) || (hi <= lo)) return 0;
+ else if (size < 1) return 0;
+ else {
+ RealFIR p;
+ REAL *h, *w, fc, ff;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_REAL(size, "newFIR_Bandstop_REAL");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Bandstop_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ lo /= sr, hi /= sr;
+ fc = (hi - lo) / 2.0;
+ ff = (lo + hi) * onepi;
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint)
+ h[j] = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ h[midpoint - 1] = 2.0 * fc;
+ h[j] *= 2.0 * cos(ff * (i - midpoint));
+ }
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint) h[j] = -h[j];
+ else h[midpoint - 1] = 1.0 - h[midpoint - 1];
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Bandstop;
+ return p;
+ }
+}
+
+ComplexFIR
+newFIR_Bandstop_COMPLEX(REAL lo, REAL hi, REAL sr, int size) {
+ if ((lo < 0.0) || (hi > (sr / 2.0)) || (hi <= lo)) return 0;
+ else if (size < 1) return 0;
+ else {
+ ComplexFIR p;
+ COMPLEX *h;
+ REAL *w, fc, ff;
+ int i, midpoint;
+
+ if (!(size & 01)) size++;
+ midpoint = (size >> 01) | 01;
+ p = newFIR_COMPLEX(size, "newFIR_Bandstop_REAL");
+ h = FIRcoef(p);
+ w = newvec_REAL(size, "newFIR_Bandstop_REAL window");
+ (void) makewindow(BLACKMANHARRIS_WINDOW, size, w);
+
+ lo /= sr, hi /= sr;
+ fc = (hi - lo) / 2.0;
+ ff = (lo + hi) * onepi;
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ REAL tmp, phs = ff * (i - midpoint);
+ if (i != midpoint)
+ tmp = (sin(twopi * (i - midpoint) * fc) / (onepi * (i - midpoint))) * w[j];
+ else
+ tmp = 2.0 * fc;
+ tmp *= 2.0;
+ h[j].re *= tmp * cos(phs);
+ h[j].im *= tmp * sin(phs);
+ }
+
+ for (i = 1; i <= size; i++) {
+ int j = i - 1;
+ if (i != midpoint) h[j] = Cmul(h[j], cxminusone);
+ else h[midpoint - 1] = Csub(cxone, h[midpoint - 1]);
+ }
+
+ delvec_REAL(w);
+ FIRtype(p) = FIR_Bandstop;
+ return p;
+ }
+}
+
+#ifdef notdef
+int
+main(int argc, char **argv) {
+ int i, size = 101;
+ RealFIR filt;
+#ifdef notdef
+ filt = newFIR_Lowpass_REAL(1000.0, 48000.0, size);
+ for (i = 0; i < FIRsize(filt); i++)
+ printf("%d %f\n", i, FIRtap(filt, i));
+ delFIR_REAL(filt);
+#endif
+
+#ifdef notdef
+ filt = newFIR_Bandstop_REAL(1000.0, 2000.0, 48000.0, size);
+ for (i = 0; i < FIRsize(filt); i++)
+ printf("%d %f\n", i, FIRtap(filt, i));
+ delFIR_REAL(filt);
+#endif
+
+ filt = newFIR_Bandpass_REAL(1000.0, 2000.0, 48000.0, size);
+ for (i = 0; i < FIRsize(filt); i++)
+ printf("%d %f\n", i, FIRtap(filt, i));
+ delFIR_REAL(filt);
+
+#ifdef notdef
+ filt = newFIR_Highpass_REAL(1000.0, 48000.0, size);
+ for (i = 0; i < FIRsize(filt); i++)
+ printf("%d %f\n", i, FIRtap(filt, i));
+ delFIR_REAL(filt);
+#endif
+
+#ifdef notdef
+ filt = newFIR_Hilbert_REAL(1000.0, 2000.0, 48000.0, size);
+ for (i = 0; i < FIRsize(filt); i++)
+ printf("%d %f\n", i, FIRtap(filt, i));
+ delFIR_REAL(filt);
+#endif
+
+#ifdef notdef
+ {
+ COMPLEX *z;
+ REAL *ttbl;
+ int fftlen;
+ fftlen = nblock2(size) * 2;
+ z = newvec_COMPLEX(fftlen, "z");
+ ttbl = newvec_REAL(fftlen, "ttbl");
+ cfftm(FFT_INIT, fftlen, (float *) z, (float *) z, ttbl);
+ for (i = 0; i < FIRsize(filt); i++)
+ z[i].re = FIRtap(filt, i);
+ cfftm(FFT_FORWARD, fftlen, (float *) z, (float *) z, ttbl);
+ for (i = 0; i < size; i++) {
+ printf("%d %f\n", i, Cabs(z[i]));
+ delvec_COMPLEX(z);
+ delvec_REAL(ttbl);
+ }
+ }
+#endif
+ exit(0);
+}
+#endif
--- /dev/null
+/* filter.h
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _filter_h
+
+#define _filter_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <fastrig.h>
+#include <update.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <window.h>
+
+typedef enum {
+ FIR_Undef, FIR_Lowpass, FIR_Bandpass, FIR_Highpass, FIR_Hilbert, FIR_Bandstop
+} FIR_response_type;
+
+typedef enum { FIR_Even, FIR_Odd } FIR_parity_type;
+
+typedef
+struct _real_FIR {
+ REAL *coef;
+ int size;
+ FIR_response_type type;
+ BOOLEAN cplx;
+ struct { REAL lo, hi; } freq;
+} RealFIRDesc, *RealFIR;
+
+typedef
+struct _complex_FIR {
+ COMPLEX *coef;
+ int size;
+ FIR_response_type type;
+ BOOLEAN cplx;
+ struct { REAL lo, hi; } freq;
+} ComplexFIRDesc, *ComplexFIR;
+
+#define FIRcoef(p) ((p)->coef)
+#define FIRtap(p, i) (FIRcoef(p)[(i)])
+#define FIRsize(p) ((p)->size)
+#define FIRtype(p) ((p)->type)
+#define FIRiscomplex(p) ((p)->cplx)
+#define FIRisreal(p) (!FIRiscomplex(p))
+#define FIRfqlo(p) ((p)->freq.lo)
+#define FIRfqhi(p) ((p)->freq.hi)
+
+#define delFIR_Lowpass_REAL(p) delFIR_REAL(p)
+#define delFIR_Lowpass_COMPLEX(p) delFIR_COMPLEX(p)
+#define delFIR_Bandpass_REAL(p) delFIR_REAL(p)
+#define delFIR_Bandpass_COMPLEX(p) delFIR_COMPLEX(p)
+#define delFIR_Highpass_REAL(p) delFIR_REAL(p)
+#define delFIR_Highpass_COMPLEX(p) delFIR_COMPLEX(p)
+#define delFIR_Hilbert_REAL(p) delFIR_REAL(p)
+#define delFIR_Hilbert_COMPLEX(p) delFIR_COMPLEX(p)
+#define delFIR_Bandstop_REAL(p) delFIR_REAL(p)
+#define delFIR_Bandstop_COMPLEX(p) delFIR_COMPLEX(p)
+
+extern RealFIR newFIR_REAL(int size, char *tag);
+extern ComplexFIR newFIR_COMPLEX(int size, char *tag);
+extern void delFIR_REAL(RealFIR p);
+extern void delFIR_COMPLEX(ComplexFIR p);
+extern RealFIR newFIR_Lowpass_REAL(REAL cutoff, REAL sr, int size);
+extern ComplexFIR newFIR_Lowpass_COMPLEX(REAL cutoff, REAL sr, int size);
+extern RealFIR newFIR_Bandpass_REAL(REAL lo, REAL hi, REAL sr, int size);
+extern ComplexFIR newFIR_Bandpass_COMPLEX(REAL lo, REAL hi, REAL sr, int size);
+extern RealFIR newFIR_Highpass_REAL(REAL cutoff, REAL sr, int size);
+extern ComplexFIR newFIR_Highpass_COMPLEX(REAL cutoff, REAL sr, int size);
+extern RealFIR newFIR_Hilbert_REAL(REAL lo, REAL hi, REAL sr, int size);
+extern ComplexFIR newFIR_Hilbert_COMPLEX(REAL lo, REAL hi, REAL sr, int size);
+extern RealFIR newFIR_Bandstop_REAL(REAL lo, REAL hi, REAL sr, int size);
+extern ComplexFIR newFIR_Bandstop_COMPLEX(REAL lo, REAL hi, REAL sr, int size);
+
+#endif
--- /dev/null
+/* fm_demod.c */
+
+#include <fm_demod.h>
+
+/*------------------------------------------------------------------------------*/
+/* private to FM */
+/*------------------------------------------------------------------------------*/
+
+PRIVATE void
+init_pll(FMD fm,
+ REAL samprate,
+ REAL freq,
+ REAL lofreq,
+ REAL hifreq,
+ REAL bandwidth) {
+ REAL fac = TWOPI / samprate;
+
+ fm->pll.freq.f = freq * fac;
+ fm->pll.freq.l = lofreq * fac;
+ fm->pll.freq.h = hifreq * fac;
+ fm->pll.phs = 0.0;
+ fm->pll.delay = cxJ;
+
+ fm->pll.iir.alpha = bandwidth * fac; /* arm filter */
+ fm->pll.alpha = fm->pll.iir.alpha * 0.3; /* pll bandwidth */
+ fm->pll.beta = fm->pll.alpha * fm->pll.alpha * 0.25; /* second order term */
+}
+
+PRIVATE void
+pll(FMD fm, COMPLEX sig) {
+ COMPLEX z = Cmplx(cos(fm->pll.phs), sin(fm->pll.phs));
+ REAL diff;
+
+ fm->pll.delay.re = z.re * sig.re + z.im * sig.im;
+ fm->pll.delay.im = -z.im * sig.re + z.re * sig.im;
+ diff = ATAN2(fm->pll.delay.im, fm->pll.delay.re);
+
+ fm->pll.freq.f += fm->pll.beta * diff;
+
+ if (fm->pll.freq.f < fm->pll.freq.l)
+ fm->pll.freq.f = fm->pll.freq.l;
+ if (fm->pll.freq.f > fm->pll.freq.h)
+ fm->pll.freq.f = fm->pll.freq.h;
+
+ fm->pll.phs += fm->pll.freq.f + fm->pll.alpha * diff;
+
+ while (fm->pll.phs >= TWOPI) fm->pll.phs -= TWOPI;
+ while (fm->pll.phs < 0) fm->pll.phs += TWOPI;
+}
+
+/*------------------------------------------------------------------------------*/
+/* public */
+/*------------------------------------------------------------------------------*/
+
+void
+FMDemod(FMD fm) {
+ int i;
+ for (i = 0; i < CXBsize(fm->ibuf); i++) {
+ pll(fm, CXBdata(fm->ibuf, i));
+ fm->afc = 0.9999 * fm->afc + 0.0001 * fm->pll.freq.f;
+ CXBreal(fm->obuf, i) =
+ CXBimag(fm->obuf, i) = (fm->pll.freq.f - fm->afc) * fm->cvt;
+ }
+}
+
+FMD
+newFMD(REAL samprate,
+ REAL f_initial,
+ REAL f_lobound,
+ REAL f_hibound,
+ REAL f_bandwid,
+ int size,
+ COMPLEX *ivec,
+ COMPLEX *ovec,
+ char *tag) {
+ FMD fm = (FMD) safealloc(1, sizeof(FMDDesc), tag);
+
+ fm->size = size;
+ fm->ibuf = newCXB(size, ivec, tag);
+ fm->obuf = newCXB(size, ovec, tag);
+
+ init_pll(fm,
+ samprate,
+ f_initial,
+ f_lobound,
+ f_hibound,
+ f_bandwid);
+
+ fm->lock = 0.5;
+ fm->afc = 0.0;
+ fm->cvt = 0.45*samprate/(M_PI*f_bandwid);
+
+ return fm;
+}
+
+void
+delFMD(FMD fm) {
+ if (fm) {
+ delCXB(fm->ibuf);
+ delCXB(fm->obuf);
+ safefree((char *) fm);
+ }
+}
--- /dev/null
+/* fm_demod.h */
+
+#ifndef _fm_demod_h
+#define _fm_demod_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <fastrig.h>
+#include <update.h>
+#include <lmadf.h>
+#include <fftw.h>
+#include <ovsv.h>
+#include <filter.h>
+#include <oscillator.h>
+#include <chap.h>
+
+typedef
+struct _fm_demod {
+ int size;
+ CXB ibuf, obuf;
+ struct {
+ REAL alpha, beta;
+ struct { REAL f, l, h; } freq;
+ REAL phs;
+ struct { REAL alpha; } iir;
+ COMPLEX delay;
+ } pll;
+
+ REAL lock, afc, cvt;
+} FMDDesc, *FMD;
+
+extern void FMDemod(FMD fm);
+extern FMD newFMD(REAL samprate,
+ REAL f_initial,
+ REAL f_lobound,
+ REAL f_hibound,
+ REAL f_bandwid,
+ int size,
+ COMPLEX *ivec,
+ COMPLEX *ovec,
+ char *tag);
+extern void delFMD(FMD fm);
+
+#ifndef TWOPI
+#define TWOPI (2.0*M_PI)
+#endif
+#ifndef CvtMod2Freq
+#define CvtMod2Freq 0.25
+#endif
+
+#endif
--- /dev/null
+/* fromsys.h
+ stuff we need to import everywhere
+ This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _fromsys_h
+#define _fromsys_h
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <setjmp.h>
+
+#include <stdlib.h>
+#include <values.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <libgen.h>
+
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+#endif
--- /dev/null
+/* lmadf.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <lmadf.h>
+
+#ifdef REALLMS
+
+LMSR
+new_lmsr(CXB signal,
+ int delay,
+ REAL adaptation_rate,
+ REAL leakage,
+ int adaptive_filter_size,
+ int filter_type) {
+ LMSR lms = (LMSR) safealloc(1, sizeof(_lmsstate), "new_lmsr state");
+
+ lms->signal = signal;
+ CXBsize(lms->signal);
+ lms->delay = delay;
+ lms->size = 512;
+ lms->mask = lms->size - 1;
+ lms->delay_line = newvec_REAL(lms->size, "lmsr delay");
+ lms->adaptation_rate = adaptation_rate;
+ lms->leakage = leakage;
+ lms->adaptive_filter_size = adaptive_filter_size;
+ lms->adaptive_filter = newvec_REAL(128, "lmsr filter");
+ lms->filter_type = filter_type;
+ lms->delay_line_ptr = 0;
+
+ return lms;
+}
+
+void
+del_lmsr(LMSR lms) {
+ if (lms) {
+ delvec_REAL(lms->delay_line);
+ delvec_REAL(lms->adaptive_filter);
+ safefree((char *) lms);
+ }
+}
+
+// just to make the algorithm itself a little clearer,
+// get the admin stuff out of the way
+
+#define ssiz (lms->signal_size)
+#define asiz (lms->adaptive_filter_size)
+#define dptr (lms->delay_line_ptr)
+#define rate (lms->adaptation_rate)
+#define leak (lms->leakage)
+
+#define ssig(n) (CXBreal(lms->signal,(n)))
+
+#define dlay(n) (lms->delay_line[(n)])
+
+#define afil(n) (lms->adaptive_filter[(n)])
+#define wrap(n) (((n) + (lms->delay) + (lms->delay_line_ptr)) & (lms->mask))
+#define bump(n) (((n) + (lms->mask)) & (lms->mask))
+
+static void
+lmsr_adapt_i(LMSR lms) {
+ int i, j, k;
+ REAL sum_sq, scl1, scl2;
+ REAL accum, error;
+
+ scl1 = 1.0 - rate * leak;
+
+ for (i = 0; i < ssiz; i++) {
+
+ dlay(dptr) = ssig(i);
+ accum = 0.0;
+ sum_sq = 0.0;
+
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ sum_sq += sqr(dlay(k));
+ accum += afil(j) * dlay(k);
+ }
+
+ error = ssig(i) - accum;
+ ssig(i) = error;
+
+ scl2 = rate / (sum_sq + 1e-10);
+ error *= scl2;
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ afil(j) = afil(j) * scl1 + error * dlay(k);
+ }
+
+ dptr = bump(dptr);
+ }
+}
+
+static void
+lmsr_adapt_n(LMSR lms) {
+ int i, j, k;
+ REAL sum_sq, scl1, scl2;
+ REAL accum, error;
+
+ scl1 = 1.0 - rate * leak;
+
+ for (i = 0; i < ssiz; i++) {
+
+ dlay(dptr) = ssig(i);
+ accum = 0.0;
+ sum_sq = 0.0;
+
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ sum_sq += sqr(dlay(k));
+ accum += afil(j) * dlay(k);
+ }
+
+ error = ssig(i) - accum;
+ ssig(i) = accum;
+
+ scl2 = rate / (sum_sq + 1e-10);
+ error *= scl2;
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ afil(j) = afil(j) * scl1 + error * dlay(k);
+ }
+
+ dptr = bump(dptr);
+ }
+}
+
+#else
+
+LMSR
+new_lmsr(CXB signal,
+ int delay,
+ REAL adaptation_rate,
+ REAL leakage,
+ int adaptive_filter_size,
+ int filter_type) {
+ LMSR lms = (LMSR) safealloc(1, sizeof(_lmsstate), "new_lmsr state");
+
+ lms->signal = signal;
+ CXBsize(lms->signal);
+ lms->delay = delay;
+ lms->size = 512;
+ lms->mask = lms->size - 1;
+ lms->delay_line = newvec_COMPLEX(lms->size, "lmsr delay");
+ lms->adaptation_rate = adaptation_rate;
+ lms->leakage = leakage;
+ lms->adaptive_filter_size = adaptive_filter_size;
+ lms->adaptive_filter = newvec_COMPLEX(128, "lmsr filter");
+ lms->filter_type = filter_type;
+ lms->delay_line_ptr = 0;
+
+ return lms;
+}
+
+void
+del_lmsr(LMSR lms) {
+ if (lms) {
+ delvec_COMPLEX(lms->delay_line);
+ delvec_COMPLEX(lms->adaptive_filter);
+ safefree((char *) lms);
+ }
+}
+
+// just to make the algorithm itself a little clearer,
+// get the admin stuff out of the way
+
+#define ssiz (lms->signal_size)
+#define asiz (lms->adaptive_filter_size)
+#define dptr (lms->delay_line_ptr)
+#define rate (lms->adaptation_rate)
+#define leak (lms->leakage)
+
+#define ssig(n) (CXBdata(lms->signal,(n)))
+
+#define dlay(n) (lms->delay_line[(n)])
+
+#define afil(n) (lms->adaptive_filter[(n)])
+#define wrap(n) (((n) + (lms->delay) + (lms->delay_line_ptr)) & (lms->mask))
+#define bump(n) (((n) + (lms->mask)) & (lms->mask))
+
+static void
+lmsr_adapt_i(LMSR lms) {
+ int i, j, k;
+ REAL sum_sq, scl1, scl2;
+ COMPLEX accum, error;
+ scl1 = 1.0 - rate * leak;
+ for (i = 0; i < ssiz; i++) {
+
+ dlay(dptr) = ssig(i);
+ accum = cxzero;
+ sum_sq = 0.0;
+
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ sum_sq += Csqrmag(dlay(k));
+ accum = Cadd(accum, Cmul(Conjg(afil(j)), dlay(k)));
+ }
+
+ error = Csub(ssig(i), accum);
+ ssig(i) = error;
+
+ scl2 = rate / (sum_sq + 1e-10);
+ error = Cscl(Conjg(error),scl2);
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ afil(j) = Cadd(Cscl(afil(j), scl1),Cmul(error, dlay(k)));
+ }
+
+ dptr = bump(dptr);
+ }
+}
+
+static void
+lmsr_adapt_n(LMSR lms) {
+ int i, j, k;
+ REAL sum_sq, scl1, scl2;
+ COMPLEX accum, error;
+ scl1 = 1.0 - rate * leak;
+ for (i = 0; i < ssiz; i++) {
+
+ dlay(dptr) = ssig(i);
+ accum = cxzero;
+ sum_sq = 0.0;
+
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ sum_sq += Csqrmag(dlay(k));
+ accum = Cadd(accum, Cmul(Conjg(afil(j)), dlay(k)));
+ }
+
+ error = Csub(ssig(i), accum);
+ ssig(i) = accum;
+
+ scl2 = rate / (sum_sq + 1e-10);
+ error = Cscl(Conjg(error),scl2);
+ for (j = 0; j < asiz; j++) {
+ k = wrap(j);
+ afil(j) = Cadd(Cscl(afil(j), scl1),Cmul(error, dlay(k)));
+ }
+
+ dptr = bump(dptr);
+ }
+}
+
+#endif
+
+extern void
+lmsr_adapt(LMSR lms) {
+ switch(lms->filter_type) {
+ case LMADF_NOISE:
+ lmsr_adapt_n(lms);
+ break;
+ case LMADF_INTERFERENCE:
+ lmsr_adapt_i(lms);
+ break;
+ }
+}
--- /dev/null
+/* lmadf.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _lmadf_h
+
+#define _lmadf_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+
+#define LMADF_INTERFERENCE 0
+#define LMADF_NOISE 1
+#define LMADF_NOSIG (-1)
+#define LMADF_NOLINE (-2)
+#define LMADF_NOFILT (-3)
+
+extern int lmadf_err;
+
+#define REALLMS
+
+#ifdef REALLMS
+
+typedef struct _LMSR {
+ CXB signal; /* Signal Buffer */
+ int signal_size; /* Number of samples in signal buffer */
+ REAL *delay_line; /* Delay Line circular buffer for holding samples */
+ REAL *adaptive_filter; /* Filter coefficients */
+ REAL adaptation_rate; /* Adaptation rate for the LMS stochastic gradient */
+ REAL leakage; /* Exponential decay constant for filter coefficients */
+ int adaptive_filter_size; /* number taps in adaptive filter */
+ int filter_type; /* Filter type */
+ int delay; /* Total delay between current sample and filter */
+ int delay_line_ptr; /* Pointer for next sample into the delay line */
+ int size; /* Delay line size */
+ int mask; /* Mask for circular buffer */
+} *LMSR, _lmsstate;
+
+#else
+
+typedef struct _LMSR {
+ CXB signal; /* Signal Buffer */
+ int signal_size; /* Number of samples in signal buffer */
+ COMPLEX *delay_line; /* Delay Line circular buffer for holding samples */
+ COMPLEX *adaptive_filter; /* Filter coefficients */
+ REAL adaptation_rate; /* Adaptation rate for the LMS stochastic gradient */
+ REAL leakage; /* Exponential decay constant for filter coefficients */
+ int adaptive_filter_size; /* number taps in adaptive filter */
+ int filter_type; /* Filter type */
+ int delay; /* Total delay between current sample and filter */
+ int delay_line_ptr; /* Pointer for next sample into the delay line */
+ int size; /* Delay line size */
+ int mask; /* Mask for circular buffer */
+} *LMSR, _lmsstate;
+
+#endif
+
+extern LMSR new_lmsr(CXB signal,
+ int delay,
+ REAL adaptation_rate,
+ REAL leakage,
+ int adaptive_filter_size,
+ int filter_type);
+
+extern void del_lmsr(LMSR lms);
+
+extern void lmsr_adapt(LMSR lms);
+
+#endif
--- /dev/null
+/* local.h
+
+Some manifest constants for the particular implementation
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+/* #include <fromsys.h> */
+/* #include <datatypes.h> */
+/* #include <banal.h> */
+/* #include <fftw.h> */
+/* #include <sdrexport.h> */
+
+#include <common.h>
+
+#ifndef _local_h
+#define _local_h
+
+#define RCBASE ".DttSPrc"
+#define PARMPATH "./IPC/SDR-1000-0-commands.fifo"
+#define METERPATH "./IPC/SDR-1000-0-meter.chan"
+#define WISDOMPATH "./wisdom"
+#define RINGMULT (4)
+#define METERMULT (2)
+#define DEFRATE (48000.0)
+#define DEFSIZE (2048)
+#define DEFMODE (SAM)
+
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 2048
+#endif
+
+extern struct _loc {
+ char name[MAXPATHLEN];
+ struct {
+ char rcfile[MAXPATHLEN],
+ parm[MAXPATHLEN],
+ meter[MAXPATHLEN],
+ wisdom[MAXPATHLEN];
+ } path;
+ struct {
+ REAL rate;
+ int size;
+ SDRMODE mode;
+ } def;
+ struct { int ring, meter; } mult;
+} loc;
+
+#endif
--- /dev/null
+/* main.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+/////////////////////////////////////////////////////////////////////////
+// elementary defaults
+
+struct _loc loc;
+
+/////////////////////////////////////////////////////////////////////////
+// most of what little we know here about the inner loop,
+// functionally speaking
+
+extern void process_samples(float *, float *, int);
+extern void setup_workspace(void);
+extern void destroy_workspace(void);
+
+//========================================================================
+
+PRIVATE void
+monitor_thread(void) {
+ while (top.running) {
+ sem_wait(&top.sync.mon.sem);
+ fprintf(stderr,
+ "@@@ mon [%d]: cb = %d rbi = %d rbo = %d xr = %d\n",
+ uni.tick,
+ top.jack.blow.cb,
+ top.jack.blow.rb.i,
+ top.jack.blow.rb.o,
+ top.jack.blow.xr);
+ memset((char *) &top.jack.blow, 0, sizeof(top.jack.blow));
+ }
+ pthread_exit(0);
+}
+
+//========================================================================
+
+PRIVATE void
+process_updates_thread(void) {
+ while (top.running) {
+ pthread_testcancel();
+ while (fgets(top.parm.buff, sizeof(top.parm.buff), top.parm.fp))
+ do_update(top.parm.buff, top.verbose ? stderr : 0);
+ }
+ pthread_exit(0);
+}
+
+PRIVATE void
+gethold(void) {
+ if (jack_ringbuffer_write_space(top.jack.ring.o.l)
+ < top.hold.size.bytes) {
+ // pathology
+ jack_ringbuffer_reset(top.jack.ring.o.l);
+ jack_ringbuffer_reset(top.jack.ring.o.r);
+ top.jack.blow.rb.o++;
+ }
+ jack_ringbuffer_write(top.jack.ring.o.l,
+ (char *) top.hold.buf.l,
+ top.hold.size.bytes);
+ jack_ringbuffer_write(top.jack.ring.o.r,
+ (char *) top.hold.buf.r,
+ top.hold.size.bytes);
+ if (jack_ringbuffer_read_space(top.jack.ring.i.l)
+ < top.hold.size.bytes) {
+ // pathology
+ jack_ringbuffer_reset(top.jack.ring.i.l);
+ jack_ringbuffer_reset(top.jack.ring.i.r);
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ top.jack.blow.rb.i++;
+ } else {
+ jack_ringbuffer_read(top.jack.ring.i.l,
+ (char *) top.hold.buf.l,
+ top.hold.size.bytes);
+ jack_ringbuffer_read(top.jack.ring.i.r,
+ (char *) top.hold.buf.r,
+ top.hold.size.bytes);
+ }
+}
+
+PRIVATE BOOLEAN
+canhold(void) {
+ return
+ jack_ringbuffer_read_space(top.jack.ring.i.l)
+ >= top.hold.size.bytes;
+}
+
+PRIVATE void
+run_mute(void) {
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ uni.tick++;
+}
+
+PRIVATE void
+run_pass(void) { uni.tick++; }
+
+PRIVATE void
+run_play(void) {
+ process_samples(top.hold.buf.l, top.hold.buf.r, top.hold.size.frames);
+}
+
+// NB do not set RUN_SWCH directly via setRunState;
+// use setSWCH instead
+
+PRIVATE void
+run_swch(void) {
+ if (top.swch.bfct.have == 0) {
+ // first time
+ // apply ramp down
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) 1.0 - (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ memset((char *) (top.hold.buf.l + m), 0, n);
+ memset((char *) (top.hold.buf.r + m), 0, n);
+ top.swch.bfct.have++;
+ } else if (top.swch.bfct.have < top.swch.bfct.want) {
+ // in medias res
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ top.swch.bfct.have++;
+ } else {
+ // last time
+ // apply ramp up
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ uni.mode.trx = top.swch.trx.next;
+ rx.tick = tx.tick = 0;
+ top.state = top.swch.run.last;
+ top.swch.bfct.want = top.swch.bfct.have = 0;
+ }
+
+ process_samples(top.hold.buf.l, top.hold.buf.r, top.hold.size.frames);
+}
+
+//========================================================================
+
+void
+clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes) {
+ int i;
+ char zero = 0;
+ for (i = 0; i < nbytes; i++)
+ jack_ringbuffer_write(rb, &zero, 1);
+}
+
+PRIVATE void
+audio_callback(jack_nframes_t nframes, void *arg) {
+ float *lp, *rp;
+ int nbytes = nframes * sizeof(float);
+
+ if (nframes == top.jack.size) {
+
+ // output: copy from ring to port
+ lp = (float *) jack_port_get_buffer(top.jack.port.o.l, nframes);
+ rp = (float *) jack_port_get_buffer(top.jack.port.o.r, nframes);
+
+ if (jack_ringbuffer_read_space(top.jack.ring.o.l) >= nbytes) {
+ jack_ringbuffer_read(top.jack.ring.o.l, (char *) lp, nbytes);
+ jack_ringbuffer_read(top.jack.ring.o.r, (char *) rp, nbytes);
+ } else { // rb pathology
+ memset((char *) lp, 0, nbytes);
+ memset((char *) rp, 0, nbytes);
+ jack_ringbuffer_reset(top.jack.ring.o.l);
+ jack_ringbuffer_reset(top.jack.ring.o.r);
+ clear_jack_ringbuffer(top.jack.ring.o.l, nbytes);
+ clear_jack_ringbuffer(top.jack.ring.o.r, nbytes);
+ top.jack.blow.rb.o++;
+ }
+
+ // input: copy from port to ring
+ if (jack_ringbuffer_write_space(top.jack.ring.i.l) >= nbytes) {
+ lp = (float *) jack_port_get_buffer(top.jack.port.i.l, nframes);
+ rp = (float *) jack_port_get_buffer(top.jack.port.i.r, nframes);
+ jack_ringbuffer_write(top.jack.ring.i.l, (char *) lp, nbytes);
+ jack_ringbuffer_write(top.jack.ring.i.r, (char *) rp, nbytes);
+ } else { // rb pathology
+ jack_ringbuffer_reset(top.jack.ring.i.l);
+ jack_ringbuffer_reset(top.jack.ring.i.r);
+ clear_jack_ringbuffer(top.jack.ring.i.l, nbytes);
+ clear_jack_ringbuffer(top.jack.ring.i.r, nbytes);
+ top.jack.blow.rb.i++;
+ }
+
+ } else { // callback pathology
+ jack_ringbuffer_reset(top.jack.ring.i.l);
+ jack_ringbuffer_reset(top.jack.ring.i.r);
+ jack_ringbuffer_reset(top.jack.ring.o.l);
+ jack_ringbuffer_reset(top.jack.ring.o.r);
+ clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
+ clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
+ top.jack.blow.cb++;
+ }
+
+ // if enough accumulated in ring, fire dsp
+ if (jack_ringbuffer_read_space(top.jack.ring.i.l) >= top.hold.size.bytes)
+ sem_post(&top.sync.buf.sem);
+
+ // check for blowups
+ if ((top.jack.blow.cb > 0) ||
+ (top.jack.blow.rb.i > 0) ||
+ (top.jack.blow.rb.o > 0))
+ sem_post(&top.sync.mon.sem);
+}
+
+PRIVATE void
+process_samples_thread(void) {
+ while (top.running) {
+ sem_wait(&top.sync.buf.sem);
+ do {
+ gethold();
+ sem_wait(&top.sync.upd.sem);
+ switch (top.state) {
+ case RUN_MUTE: run_mute(); break;
+ case RUN_PASS: run_pass(); break;
+ case RUN_PLAY: run_play(); break;
+ case RUN_SWCH: run_swch(); break;
+ }
+ sem_post(&top.sync.upd.sem);
+ } while (canhold());
+ }
+ pthread_exit(0);
+}
+
+//========================================================================
+
+PRIVATE void
+execute(void) {
+ // let updates run
+ sem_post(&top.sync.upd.sem);
+
+ // rcfile
+ {
+ FILE *frc = find_rcfile(loc.path.rcfile);
+ if (frc) {
+ while (fgets(top.parm.buff, sizeof(top.parm.buff), frc))
+ do_update(top.parm.buff, top.verbose ? stderr : 0);
+ fclose(frc);
+ }
+ }
+
+ // start audio processing
+ if (jack_activate(top.jack.client))
+ perror("cannot activate jack client"), exit(1);
+
+ // wait for threads to terminate
+ pthread_join(top.thrd.trx.id, 0);
+ pthread_join(top.thrd.upd.id, 0);
+ pthread_join(top.thrd.mon.id, 0);
+
+ // stop audio processing
+ jack_client_close(top.jack.client);
+}
+
+PRIVATE void
+closeup(void) {
+ jack_ringbuffer_free(top.jack.ring.o.r);
+ jack_ringbuffer_free(top.jack.ring.o.l);
+ jack_ringbuffer_free(top.jack.ring.i.r);
+ jack_ringbuffer_free(top.jack.ring.i.l);
+
+ safefree((char *) top.hold.buf.r);
+ safefree((char *) top.hold.buf.l);
+
+ destroy_workspace();
+
+ exit(0);
+}
+
+PRIVATE void
+usage(void) {
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "jsdr [-flag [arg]] [file]\n");
+ fprintf(stderr, "flags:\n");
+ fprintf(stderr, " -v verbose commentary\n");
+ fprintf(stderr, " -m do metering\n");
+ fprintf(stderr, " -l file execute update commands in file at startup\n");
+ fprintf(stderr, " -P cmdpath path to command/update pipe\n");
+ fprintf(stderr, " -S s-mtrpath path to S-meter output channel\n");
+ fprintf(stderr, " -W wispath path to FFTW wisdom file\n");
+ fprintf(stderr, " -R rate sampling rate\n");
+ fprintf(stderr, " -B bufsize internal DSP buffer size\n");
+ fprintf(stderr, " -M mode start up in mode (SAM, USB, LCW, etc.)\n");
+ fprintf(stderr, " -G num use num as ringbuffer mult\n");
+ fprintf(stderr, " -E num use num as meter chan mult\n");
+ fprintf(stderr, "'file' arg unused, but available\n");
+ exit(1);
+}
+
+PRIVATE void
+nonblock(int fd) {
+ long arg;
+ arg = fcntl(fd, F_GETFL);
+ arg |= O_NONBLOCK;
+/* if (fcntl(fd, F_GETFL, &arg) >= 0)
+ fcntl(fd, F_SETFL, arg | O_NONBLOCK); */
+ fcntl(fd, F_SETFL, arg);
+}
+
+//........................................................................
+
+PRIVATE void
+setup_switching(void) {
+ top.swch.fade = (int) (0.1 * uni.buflen + 0.5);
+ top.swch.tail = (top.hold.size.frames - top.swch.fade) * sizeof(float);
+}
+
+PRIVATE void
+setup_local_audio(void) {
+ top.hold.size.frames = uni.buflen;
+ top.hold.size.bytes = top.hold.size.frames * sizeof(float);
+ top.hold.buf.l = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer left");
+ top.hold.buf.r = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer right");
+}
+
+PRIVATE void
+setup_updates(void) {
+ top.parm.path = loc.path.parm;
+ if ((top.parm.fd = open(top.parm.path, O_RDWR)) == -1)
+ perror(top.parm.path), exit(1);
+ if (!(top.parm.fp = fdopen(top.parm.fd, "r+"))) {
+ fprintf(stderr, "can't fdopen parm pipe %s\n", loc.path.parm);
+ exit(1);
+ }
+}
+
+PRIVATE void
+jack_xrun(void *arg) {
+ top.jack.blow.xr++;
+ sem_post(&top.sync.mon.sem);
+}
+
+PRIVATE void
+jack_shutdown(void *arg) {}
+
+PRIVATE void
+setup_system_audio(void) {
+ if (loc.name[0]) strcpy(top.jack.name, loc.name);
+ else sprintf(top.jack.name, "sdr-%d", top.pid);
+ if (!(top.jack.client = jack_client_new(top.jack.name)))
+ perror("can't make client -- jack not running?"), exit(1);
+
+ jack_set_process_callback(top.jack.client, (void *) audio_callback, 0);
+ jack_on_shutdown(top.jack.client, (void *) jack_shutdown, 0);
+ jack_set_xrun_callback(top.jack.client, (void *) jack_xrun, 0);
+ top.jack.size = jack_get_buffer_size(top.jack.client);
+ memset((char *) &top.jack.blow, 0, sizeof(top.jack.blow));
+
+ top.jack.port.i.l = jack_port_register(top.jack.client,
+ "il",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput,
+ 0);
+ top.jack.port.i.r = jack_port_register(top.jack.client,
+ "ir",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput,
+ 0);
+ top.jack.port.o.l = jack_port_register(top.jack.client,
+ "ol",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ top.jack.port.o.r = jack_port_register(top.jack.client,
+ "or",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ top.jack.ring.i.l = jack_ringbuffer_create(top.hold.size.bytes * loc.mult.ring);
+ top.jack.ring.i.r = jack_ringbuffer_create(top.hold.size.bytes * loc.mult.ring);
+ top.jack.ring.o.l = jack_ringbuffer_create(top.hold.size.bytes * loc.mult.ring);
+ top.jack.ring.o.r = jack_ringbuffer_create(top.hold.size.bytes * loc.mult.ring);
+ clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
+ clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
+}
+
+PRIVATE void
+setup_threading(void) {
+ sem_init(&top.sync.upd.sem, 0, 0);
+ pthread_create(&top.thrd.upd.id, NULL, (void *) process_updates_thread, NULL);
+ sem_init(&top.sync.buf.sem, 0, 0);
+ pthread_create(&top.thrd.trx.id, NULL, (void *) process_samples_thread, NULL);
+ sem_init(&top.sync.mon.sem, 0, 0);
+ pthread_create(&top.thrd.mon.id, NULL, (void *) monitor_thread, NULL);
+}
+
+//========================================================================
+// hard defaults, then environment
+
+PRIVATE void
+setup_defaults(void) {
+ loc.name[0] = 0; // no default name for jack client
+ strcpy(loc.path.rcfile, RCBASE);
+ strcpy(loc.path.parm, PARMPATH);
+ strcpy(loc.path.meter, METERPATH);
+ strcpy(loc.path.wisdom, WISDOMPATH);
+ loc.def.rate = DEFRATE;
+ loc.def.size = DEFSIZE;
+ loc.def.mode = DEFMODE;
+ loc.mult.ring = RINGMULT;
+ loc.mult.meter = METERMULT;
+
+ {
+ char *ep;
+ if ((ep = getenv("SDR_NAME"))) strcpy(loc.name, ep);
+ if ((ep = getenv("SDR_RCBASE"))) strcpy(loc.path.rcfile, ep);
+ if ((ep = getenv("SDR_PARMPATH"))) strcpy(loc.path.parm, ep);
+ if ((ep = getenv("SDR_METERPATH"))) strcpy(loc.path.meter, ep);
+ if ((ep = getenv("SDR_WISDOMPATH"))) strcpy(loc.path.wisdom, ep);
+ if ((ep = getenv("SDR_RINGMULT"))) loc.mult.ring = atoi(ep);
+ if ((ep = getenv("SDR_METERMULT"))) loc.mult.meter = atoi(ep);
+ if ((ep = getenv("SDR_DEFRATE"))) loc.def.rate = atof(ep);
+ if ((ep = getenv("SDR_DEFSIZE"))) loc.def.size = atoi(ep);
+ if ((ep = getenv("SDR_DEFMODE"))) loc.def.mode = atoi(ep);
+ }
+}
+
+//========================================================================
+PRIVATE void
+setup(int argc, char **argv) {
+ int i;
+
+ top.uid = getuid();
+ top.pid = getpid();
+ top.start_tv = now_tv();
+ top.running = TRUE;
+ top.verbose = FALSE;
+ top.state = RUN_PLAY;
+
+ setup_defaults();
+
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1]) {
+ case 'v':
+ top.verbose = TRUE;
+ break;
+ case 'l':
+ strcpy(loc.path.rcfile, argv[++i]);
+ break;
+ case 'm':
+ uni.meter.flag = TRUE;
+ break;
+ case 'P':
+ strcpy(loc.path.parm, argv[++i]);
+ break;
+ case 'S':
+ strcpy(loc.path.meter, argv[++i]);
+ break;
+ case 'W':
+ strcpy(loc.path.wisdom, argv[++i]);
+ break;
+ case 'R':
+ loc.def.rate = atof(argv[++i]);
+ break;
+ case 'B':
+ loc.def.size = atoi(argv[++i]);
+ break;
+ case 'M':
+ loc.def.mode = atoi(argv[++i]);
+ break;
+ case 'G':
+ loc.mult.ring = atoi(argv[++i]);
+ break;
+ case 'E':
+ loc.mult.meter = atoi(argv[++i]);
+ break;
+ default:
+ usage();
+ }
+ else break;
+ if (i < argc) {
+ if (!freopen(argv[i], "r", stdin))
+ perror(argv[i]), exit(1);
+ i++;
+ }
+
+ setup_workspace();
+ setup_updates();
+
+ setup_local_audio();
+ setup_system_audio();
+
+ setup_threading();
+ setup_switching();
+}
+
+//========================================================================
+
+int
+main(int argc, char **argv) { setup(argc, argv), execute(), closeup(); }
--- /dev/null
+#ifndef _meter_h
+#define _meter_h
+
+typedef enum {
+ SIGNAL_STRENGTH,
+ AVG_SIGNAL_STRENGTH,
+ ADC_REAL,
+ ADC_IMAG,
+ AGC_GAIN
+} METERTYPE;
+
+#endif
--- /dev/null
+/* metermon.c */
+
+#include <chan.h>
+
+#define METERPATH "./IPC/SDR-1000-0-meter.chan"
+#define METERMULT (24)
+#define SLEEP (500000)
+
+jmp_buf here;
+
+void
+onsig(int sig) {
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ longjmp(here, TRUE);
+}
+
+int
+main(int argc, char **argv) {
+ Chan ch = 0;
+ int i = 0;
+ REAL val = 0.0;
+
+ signal(SIGHUP, onsig);
+ signal(SIGINT, onsig);
+ signal(SIGQUIT, onsig);
+
+ if (!(ch = openChan(METERPATH, METERMULT * sizeof(REAL))))
+ perror("openChan"), exit(1);
+
+ while (!setjmp(here)) {
+ if (getChan_nowait(ch, (char *) &val, sizeof(REAL))) {
+ printf("(%d)", i++);
+ do
+ printf(" %f", val);
+ while (getChan_nowait(ch, (char *) &val, sizeof(REAL)));
+ putchar('\n');
+ }
+ usleep(SLEEP);
+ }
+
+ closeChan(ch);
+}
--- /dev/null
+/* mkchan.c */
+/* create a file big enough to accommodate
+ a header + a ringbuffer of a given size */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <stdlib.h>
+#include <values.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <libgen.h>
+
+#include <datatypes.h>
+#include <banal.h>
+#include <ringb.h>
+
+char *rng_name = 0,
+ *buf_asks = 0;
+FILE *rng_file = 0;
+size_t rng_size = 0,
+ buf_size = 0,
+ blk_size = 0,
+ tot_size = 0;
+
+BOOLEAN verbose = FALSE;
+
+void
+execute(void) {
+ int i;
+ rng_size = sizeof(ringb_t);
+ if ((buf_size = atoi(buf_asks)) <= 0) {
+ fprintf(stderr, "buffer size %s?\n", buf_asks);
+ exit(1);
+ }
+ if (!(rng_file = fopen(rng_name, "w"))) {
+ perror(rng_name);
+ exit(1);
+ }
+ blk_size = nblock2(buf_size);
+ tot_size = rng_size + blk_size;
+ for (i = 0; i < tot_size; i++) putc(0, rng_file);
+ fclose(rng_file);
+ if (verbose)
+ fprintf(stderr,
+ "created chan file %s (%d + [%d -> %d] = %d)\n",
+ rng_name, rng_size, buf_size, blk_size, tot_size);
+}
+
+void
+closeup(void) { exit(0); }
+
+static void
+usage(void) {
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "mkchan [-v] name size\n");
+ exit(1);
+}
+
+static void
+setup(int argc, char **argv) {
+ int i;
+
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1]) {
+ case 'v': verbose = TRUE; break;
+ default: usage();
+ }
+ else break;
+ if (i < (argc - 2)) usage();
+ rng_name = argv[i++];
+ buf_asks = argv[i++];
+}
+
+int
+main(int argc, char **argv) { setup(argc, argv), execute(), closeup(); }
--- /dev/null
+/* noiseblanker.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+NB
+new_noiseblanker(CXB sigbuf, REAL threshold) {
+ NB nb = (NB) safealloc(1, sizeof(nbstate), "new nbstate");
+ nb->sigbuf = sigbuf;
+ nb->threshold = threshold;
+ nb->average_mag = 1.0;
+ return nb;
+}
+
+void
+del_nb(NB nb) {
+ if (nb) { safefree((char *) nb); }
+}
+
+void
+noiseblanker(NB nb) {
+ int i;
+ for (i = 0; i < CXBsize(nb->sigbuf); i++) {
+ REAL cmag = Cmag(CXBdata(nb->sigbuf, i));
+ nb->average_mag = 0.999 * (nb->average_mag) + 0.001 * cmag;
+ if (cmag > (nb->threshold * nb->average_mag))
+ CXBdata(nb->sigbuf, i) = Cmplx(0.0, 0.0);
+ }
+}
+
+void
+SDROMnoiseblanker(NB nb) {
+ int i;
+ for (i = 0; i < CXBsize(nb->sigbuf); i++) {
+ REAL cmag = Cmag(CXBdata(nb->sigbuf, i));
+ nb->average_sig = Cadd(Cscl(nb->average_sig, 0.75),
+ Cscl(CXBdata(nb->sigbuf, i), 0.25));
+ nb->average_mag = 0.999 * (nb->average_mag) + 0.001 * cmag;
+ if (cmag > (nb->threshold * nb->average_mag))
+ CXBdata(nb->sigbuf, i) = nb->average_sig;
+ }
+}
--- /dev/null
+/* update.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _noiseblanker_h
+#define _noiseblanker_h
+
+#include <cxops.h>
+#include <bufvec.h>
+
+typedef struct _nbstate {
+ CXB sigbuf; /* Signal Buffer */
+ REAL threshold; /* Noise Blanker Threshold */
+ COMPLEX average_sig;
+ REAL average_mag;
+} *NB, nbstate;
+
+extern NB new_noiseblanker(CXB sigbuf, REAL threshold);
+extern void del_nb(NB nb);
+extern void noiseblanker(NB nb);
+extern void SDROMnoiseblanker(NB nb);
+#endif
--- /dev/null
+/* oscillator.c
+
+This routine implements a common fixed-frequency oscillator
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+#define HUGE_PHASE 1256637061.43593
+
+void
+ComplexOSC(OSC p) {
+ int i;
+ COMPLEX z, delta_z;
+
+ if (OSCphase(p) > HUGE_PHASE) OSCphase(p) -= HUGE_PHASE;
+
+ z = Cmplx(cos(OSCphase(p)), sin(OSCphase(p))),
+ delta_z = Cmplx(cos(OSCfreq(p)), sin(OSCfreq(p)));
+
+ for (i = 0; i < OSCsize(p); i++)
+ z = CXBdata((CXB) OSCbase(p), i)
+ = Cmul(z, delta_z),
+ OSCphase(p) += OSCfreq(p);
+}
+
+#ifdef notdef
+void
+ComplexOSC(OSC p) {
+ int i;
+ if (OSCphase(p) > 1256637061.43593)
+ OSCphase(p) -= 1256637061.43593;
+ for (i = 0; i < OSCsize(p); i++) {
+ OSCreal(p, i) = cos(OSCphase(p));
+ OSCimag(p, i) = sin(OSCphase(p));
+ OSCphase(p) += OSCfreq(p);
+ }
+}
+#endif
+
+PRIVATE REAL
+_phasemod(REAL angle) {
+ while (angle >= TWOPI) angle -= TWOPI;
+ while (angle < 0.0) angle += TWOPI;
+ return angle;
+}
+
+void
+RealOSC(OSC p) {
+ int i;
+ for (i = 0; i < OSCsize(p); i++) {
+ OSCRdata(p, i) = sin(OSCphase(p));
+ OSCphase(p) = _phasemod(OSCfreq(p) + OSCphase(p));
+ }
+}
+
+OSC
+newOSC(int size,
+ OscType TypeOsc,
+ REAL Frequency,
+ REAL Phase,
+ REAL SampleRate,
+ char *tag) {
+ OSC p = (OSC) safealloc(1, sizeof(oscillator), tag);
+ if ((OSCtype(p) = TypeOsc) == ComplexTone)
+ OSCbase(p) = (void *) newCXB(size,
+ NULL,
+ "complex buffer for oscillator output");
+ else
+ OSCbase(p) = (void *) newRLB(size,
+ NULL,
+ "real buffer for oscillator output");
+ OSCsize(p) = size;
+ OSCfreq(p) = 2.0 * M_PI * Frequency / SampleRate;
+ OSCphase(p) = Phase;
+ return p;
+}
+
+void
+delOSC(OSC p) {
+ if (p->OscillatorType == ComplexTone)
+ delCXB((CXB) p->signalpoints);
+ else
+ delRLB((RLB) p->signalpoints);
+ if (p)
+ safefree((char *) p);
+}
+
--- /dev/null
+/* oscillator.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+
+#ifndef _oscillator_h
+#define _oscillator_h
+
+#define ComplexTone 1
+#define RealTone 0
+typedef int OscType;
+
+typedef struct _oscillator {
+ int size;
+ void *signalpoints;
+ REAL Phase;
+ REAL Frequency;
+ OscType OscillatorType;
+} oscillator, *OSC;
+
+
+#define OSCbase(p) ((p)->signalpoints)
+#define OSCCbase(p) (CXBbase((CXB)((p)->signalpoints)))
+#define OSCCdata(p, i) (CXBbase((CXB)((p)->signalpoints))[(i)])
+#define OSCreal(p, i) (CXBbase((CXB)((p)->signalpoints))[(i)].re)
+#define OSCimag(p, i) (CXBbase((CXB)((p)->signalpoints))[(i)].im)
+
+#define OSCRbase(p) (RLBbase((RLB)((p)->signalpoints)))
+#define OSCRdata(p, i) (RLBbase((RLB)((p)->signalpoints))[(i)])
+
+#define OSCsize(p) ((p)->size)
+#define OSCphase(p) ((p)->Phase)
+#define OSCfreq(p) ((p)->Frequency)
+#define OSCtype(p) ((p)->OscillatorType)
+
+extern void ComplexOSC(OSC);
+extern void RealOSC(OSC);
+extern OSC newOSC(int size, OscType TypeOsc, REAL Frequency, REAL Phase,
+ REAL SampleRate, char *tag);
+extern void delOSC(OSC);
+extern void fixOSC(OSC p, REAL Frequency, REAL Phase, REAL SampleRate);
+
+#endif
--- /dev/null
+/* ovsv.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+/*------------------------------------------------------------*/
+/* run the filter */
+
+void
+filter_OvSv(FiltOvSv pflt) {
+ int i,
+ j,
+ m = pflt->fftlen,
+ n = pflt->buflen;
+ COMPLEX *zfvec = pflt->zfvec,
+ *zivec = pflt->zivec,
+ *zovec = pflt->zovec,
+ *zrvec = pflt->zrvec;
+ REAL scl = pflt->scale;
+
+ /* input sig -> z */
+ fftw_one(pflt->pfwd, (fftw_complex *) zrvec, (fftw_complex *) zivec);
+
+ /* convolve in z */
+ for (i = 0; i < m; i++) zivec[i] = Cmul(zivec[i], zfvec[i]);
+
+ /* z convolved sig -> time output sig */
+ fftw_one(pflt->pinv, (fftw_complex *) zivec, (fftw_complex *) zovec);
+
+ /* scale */
+ for (i = 0; i < n; i++) zovec[i].re *= scl, zovec[i].im *= scl;
+
+ /* prepare input sig vec for next fill */
+ for (i = 0, j = n; i < n; i++, j++) zrvec[i] = zrvec[j];
+}
+
+void
+filter_OvSv_par(FiltOvSv pflt) {
+ int i,
+ j,
+ m = pflt->fftlen,
+ n = pflt->buflen;
+ COMPLEX *zfvec = pflt->zfvec,
+ *zivec = pflt->zivec,
+ *zovec = pflt->zovec,
+ *zrvec = pflt->zrvec;
+ REAL scl = pflt->scale;
+
+ /* input sig -> z */
+ fftw_one(pflt->pfwd,(fftw_complex *) zrvec, (fftw_complex *) zivec);
+
+ /* convolve in z */
+ for (i = 0; i < m; i++) zivec[i] = Cmul(zivec[i], zfvec[i]);
+
+ /* z convolved sig -> time output sig */
+ fftw_one(pflt->pinv, (fftw_complex *) zivec, (fftw_complex *) zovec);
+
+ /* scale */
+ for (i = 0; i < n; i++) zovec[i].re *= scl, zovec[i].im *= scl;
+
+ /* prepare input sig vec for next fill */
+ for (i = 0, j = n; i < n; i++, j++) zrvec[i] = zrvec[j];
+}
+
+/*------------------------------------------------------------*/
+/* info: */
+/* NB strategy. This is the address we pass to newCXB as
+ the place to read samples into. It's the right half of
+ the true buffer. Old samples get slid from here to
+ left half after each go-around. */
+COMPLEX *
+FiltOvSv_initpoint(FiltOvSv pflt) { return &(pflt->zrvec[pflt->buflen]); }
+
+/* how many to put there */
+int
+FiltOvSv_initsize(FiltOvSv pflt) { return (pflt->fftlen - pflt->buflen); }
+
+/* where to put next batch of samples to filter */
+COMPLEX *
+FiltOvSv_fetchpoint(FiltOvSv pflt) { return &(pflt->zrvec[pflt->buflen]); }
+
+/* how many samples to put there */
+
+int
+FiltOvSv_fetchsize(FiltOvSv pflt) { return (pflt->fftlen - pflt->buflen); }
+
+/* where samples should be taken from after filtering */
+#ifdef LHS
+COMPLEX *
+FiltOvSv_storepoint(FiltOvSv plft) { return ((pflt->zovec) + buflen); }
+#else
+COMPLEX *
+FiltOvSv_storepoint(FiltOvSv pflt) { return ((pflt->zovec)); }
+#endif
+
+/* alternating parity fetch/store */
+
+COMPLEX *
+FiltOvSv_fetchpt_par(FiltOvSv pflt, int parity) {
+ if (parity & 01)
+ return pflt->zovec + pflt->buflen;
+ else
+ return pflt->zovec;
+}
+
+COMPLEX *
+FiltOvSv_storept_par(FiltOvSv pflt, int parity) {
+ if (parity & 01)
+ return pflt->zovec;
+ else
+ return pflt->zovec + pflt->buflen;
+}
+
+/* how many samples to take */
+/* NB strategy. This is the number of good samples in the
+ left half of the true buffer. Samples in right half
+ are circular artifacts and are ignored. */
+int
+FiltOvSv_storesize(FiltOvSv pflt) { return (pflt->fftlen - pflt->buflen); }
+
+/*------------------------------------------------------------*/
+/* create a new overlap/save filter from complex coefficients */
+
+FiltOvSv
+newFiltOvSv(COMPLEX *coefs, int ncoef, int pbits) {
+ int buflen, fftlen;
+ FiltOvSv p;
+ fftw_plan pfwd,pinv;
+ COMPLEX *zrvec, *zfvec, *zivec, *zovec;
+ p = (FiltOvSv) safealloc(1, sizeof(filt_ov_sv), "new overlap/save filter");
+ buflen = nblock2(ncoef-1), fftlen = 2 * buflen;
+ zrvec = newvec_COMPLEX(fftlen, "raw signal vec in newFiltOvSv");
+ zfvec = newvec_COMPLEX(fftlen, "filter z vec in newFiltOvSv");
+ zivec = newvec_COMPLEX(fftlen, "signal in z vec in newFiltOvSv");
+ zovec = newvec_COMPLEX(fftlen, "signal out z vec in newFiltOvSv");
+
+ /* prepare frequency response from filter coefs */
+ {
+ int i;
+ COMPLEX *zcvec;
+ fftw_plan ptmp;
+
+ zcvec = newvec_COMPLEX(fftlen, "temp filter z vec in newFiltOvSv");
+ ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, pbits);
+
+#ifdef LHS
+ for (i = 0; i < ncoef; i++) zcvec[i] = coefs[i];
+#else
+ for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef - 1 + i] = coefs[i];
+#endif
+
+ fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) zfvec);
+ fftw_destroy_plan(ptmp);
+ delvec_COMPLEX(zcvec);
+ }
+
+ /* prepare transforms for signal */
+ pfwd = fftw_create_plan(fftlen, FFTW_FORWARD, pbits);
+ pinv = fftw_create_plan(fftlen, FFTW_BACKWARD, pbits);
+ /* stuff values */
+ p->buflen = buflen;
+ p->fftlen = fftlen;
+ p->zfvec = zfvec;
+ p->zivec = zivec;
+ p->zovec = zovec;
+ p->zrvec = zrvec;
+ p->pfwd = pfwd;
+ p->pinv = pinv;
+ p->scale = 1.0 / fftlen;
+
+ return p;
+}
+
+/* deep-six the filter */
+void
+delFiltOvSv(FiltOvSv p) {
+ if (p) {
+ delvec_COMPLEX(p->zfvec);
+ delvec_COMPLEX(p->zivec);
+ delvec_COMPLEX(p->zovec);
+ delvec_COMPLEX(p->zrvec);
+ fftw_destroy_plan(p->pfwd);
+ fftw_destroy_plan(p->pinv);
+ safefree((char *) p);
+ }
+}
+
+/*------------------------------------------------------------*/
+
+
--- /dev/null
+/* ovsv.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _ovsv_h
+#define _ovsv_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <update.h>
+#include <lmadf.h>
+#include <fftw.h>
+
+typedef
+struct _filt_ov_sav {
+ int buflen, fftlen;
+ COMPLEX *zfvec, *zivec, *zovec, *zrvec;
+ fftw_plan pfwd, pinv;
+ REAL scale;
+} filt_ov_sv, *FiltOvSv;
+
+extern FiltOvSv newFiltOvSv(COMPLEX *coefs,
+ int ncoef,
+ int pbits);
+extern void delFiltOvSv(FiltOvSv p);
+
+extern COMPLEX *FiltOvSv_initpoint(FiltOvSv pflt);
+extern int FiltOvSv_initsize(FiltOvSv pflt);
+
+extern COMPLEX *FiltOvSv_fetchpoint(FiltOvSv pflt);
+extern int FiltOvSv_fetchsize(FiltOvSv pflt);
+
+extern COMPLEX *FiltOvSv_storepoint(FiltOvSv pflt);
+extern int FiltOvSv_storesize(FiltOvSv pflt);
+
+extern COMPLEX *FiltOvSv_fetchpt_par(FiltOvSv pflt, int parity);
+extern COMPLEX *FiltOvSv_storept_par(FiltOvSv pflt, int parity);
+
+extern void filter_OvSv(FiltOvSv pflt);
+extern void filter_OvSv_par(FiltOvSv pflt);
+#endif
--- /dev/null
+/*
+ Memory-mapped ringbuffer
+ Derived from jack/ringbuffer.h
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Original
+ Copyright (C) 2000 Paul Davis
+ Copyright (C) 2003 Rohan Drape
+
+ Derived
+ Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ringb.h>
+
+ringb_t *
+ringb_create(char *usemem, size_t sz2) {
+ ringb_t *rb = (ringb_t *) usemem;
+ rb->buf = usemem + sizeof(ringb_t);
+ rb->size = sz2; // power-of-2-sized
+ rb->mask = rb->size - 1;
+ rb->wptr = rb->rptr = 0;
+ return rb;
+}
+
+void
+ringb_reset(ringb_t *rb) {
+ // NB not thread-safe
+ rb->rptr = 0;
+ rb->wptr = 0;
+}
+
+size_t
+ringb_read_space(const ringb_t *rb) {
+ size_t w = rb->wptr, r = rb->rptr;
+ if (w > r) return w - r;
+ else return (w - r + rb->size) & rb->mask;
+}
+
+size_t
+ringb_write_space(const ringb_t *rb) {
+ size_t w = rb->wptr, r = rb->rptr;
+ if (w > r) return ((r - w + rb->size) & rb->mask) - 1;
+ else if (w < r) return r - w - 1;
+ else return rb->size - 1;
+}
+
+size_t
+ringb_read(ringb_t *rb, char *dest, size_t cnt) {
+ size_t free_cnt, cnt2, to_read, n1, n2;
+ if ((free_cnt = ringb_read_space(rb)) == 0) return 0;
+ to_read = cnt > free_cnt ? free_cnt : cnt;
+ if ((cnt2 = rb->rptr + to_read) > rb->size)
+ n1 = rb->size - rb->rptr, n2 = cnt2 & rb->mask;
+ else
+ n1 = to_read, n2 = 0;
+ memcpy(dest, &(rb->buf[rb->rptr]), n1);
+ rb->rptr = (rb->rptr + n1) & rb->mask;
+ if (n2) {
+ memcpy(dest + n1, &(rb->buf[rb->rptr]), n2);
+ rb->rptr = (rb->rptr + n2) & rb->mask;
+ }
+ return to_read;
+}
+
+size_t
+ringb_peek(ringb_t *rb, char *dest, size_t cnt) {
+ size_t free_cnt, cnt2, to_read, n1, n2, tmp_rptr;
+ tmp_rptr = rb->rptr;
+ if ((free_cnt = ringb_read_space(rb)) == 0) return 0;
+ to_read = cnt > free_cnt ? free_cnt : cnt;
+ if ((cnt2 = tmp_rptr + to_read) > rb->size)
+ n1 = rb->size - tmp_rptr, n2 = cnt2 & rb->mask;
+ else
+ n1 = to_read, n2 = 0;
+ memcpy(dest, &(rb->buf[tmp_rptr]), n1);
+ tmp_rptr = (tmp_rptr + n1) & rb->mask;
+ if (n2)
+ memcpy(dest + n1, &(rb->buf[tmp_rptr]), n2);
+ return to_read;
+}
+
+size_t
+ringb_write(ringb_t *rb, const char *src, size_t cnt) {
+ size_t free_cnt, cnt2, to_write, n1, n2;
+ if ((free_cnt = ringb_write_space(rb)) == 0) return 0;
+ to_write = cnt > free_cnt ? free_cnt : cnt;
+ if ((cnt2 = rb->wptr + to_write) > rb->size)
+ n1 = rb->size - rb->wptr, n2 = cnt2 & rb->mask;
+ else
+ n1 = to_write, n2 = 0;
+ memcpy(&(rb->buf[rb->wptr]), src, n1);
+ rb->wptr = (rb->wptr + n1) & rb->mask;
+ if (n2) {
+ memcpy(&(rb->buf[rb->wptr]), src + n1, n2);
+ rb->wptr = (rb->wptr + n2) & rb->mask;
+ }
+ return to_write;
+}
+
+void
+ringb_read_advance(ringb_t *rb, size_t cnt) {
+ rb->rptr = (rb->rptr + cnt) & rb->mask;
+}
+
+void
+ringb_write_advance(ringb_t *rb, size_t cnt) {
+ rb->wptr = (rb->wptr + cnt) & rb->mask;
+}
+
+void
+ringb_get_read_vector(const ringb_t *rb, ringb_data_t *vec) {
+ size_t free_cnt, cnt2,
+ w = rb->wptr, r = rb->rptr;
+ if (w > r) free_cnt = w - r;
+ else free_cnt = (w - r + rb->size) & rb->mask;
+ if ((cnt2 = r + free_cnt) > rb->size) {
+ vec[0].buf = &(rb->buf[r]), vec[0].len = rb->size - r;
+ vec[1].buf = rb->buf, vec[1].len = cnt2 & rb->mask;
+ } else {
+ vec[0].buf = &(rb->buf[r]), vec[0].len = free_cnt;
+ vec[1].len = 0;
+ }
+}
+
+void
+ringb_get_write_vector(const ringb_t *rb, ringb_data_t *vec) {
+ size_t free_cnt, cnt2,
+ w = rb->wptr, r = rb->rptr;
+ if (w > r) free_cnt = ((r - w + rb->size) & rb->mask) - 1;
+ else if (w < r) free_cnt = r - w - 1;
+ else free_cnt = rb->size - 1;
+ if ((cnt2 = w + free_cnt) > rb->size) {
+ vec[0].buf = &(rb->buf[w]), vec[0].len = rb->size - w;
+ vec[1].buf = rb->buf, vec[1].len = cnt2 & rb->mask;
+ } else {
+ vec[0].buf = &(rb->buf[w]), vec[0].len = free_cnt;
+ vec[1].len = 0;
+ }
+}
--- /dev/null
+/*
+ Memory-mapped ringbuffer
+ Derived from jack/ringbuffer.h
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Original
+ Copyright (C) 2000 Paul Davis
+ Copyright (C) 2003 Rohan Drape
+
+ Derived
+ Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+*/
+
+#ifndef _ringb_h
+#define _ringb_h
+
+#include <sys/types.h>
+
+typedef struct {
+ char *buf;
+ size_t len;
+} ringb_data_t;
+
+typedef struct {
+ char *buf;
+ size_t wptr,
+ rptr,
+ size,
+ mask;
+} ringb_t;
+
+/* Sets up a ringbuffer data structure of a specified size
+ * in pre-allocated memory.
+ * sz is requested ringbuffer size in bytes,
+ * MUST be a power of 2.
+ * pre-allocated memory must be large enough to
+ * accommodate (ringb header + stipulated memory size).
+ * return a pointer to a new ringb_t, if successful,
+ * 0 otherwise. */
+
+extern ringb_t *ringb_create(char *usemem, size_t sz2);
+
+/*
+ * There is no corresponding 'free' function
+ * since memory is all pre-allocated
+ */
+
+//void ringb_free(ringb_t *rb);
+
+/* Fill a data structure with a description of the current readable
+ * data held in the ringbuffer. This description is returned in a two
+ * element array of ringb_data_t. Two elements are needed
+ * because the data to be read may be split across the end of the
+ * ringbuffer.
+ *
+ * The first element will always contain a valid len field, which
+ * may be zero or greater. If the len field is non-zero, then data
+ * can be read in a contiguous fashion using the address given in the
+ * corresponding @a buf field.
+ *
+ * If the second element has a non-zero len field, then a second
+ * contiguous stretch of data can be read from the address given in
+ * its corresponding buf field.
+ *
+ * rb a pointer to the ringbuffer structure.
+ * vec a pointer to a 2 element array of ringb_data_t. */
+
+extern void ringb_get_read_vector(const ringb_t *rb, ringb_data_t *vec);
+
+/* Fill a data structure with a description of the current writable
+ * space in the ringbuffer. The description is returned in a two
+ * element array of ringb_data_t. Two elements are needed
+ * because the space available for writing may be split across the end
+ * of the ringbuffer.
+ * The first element will always contain a valid len field, which
+ * may be zero or greater. If the @a len field is non-zero, then data
+ * can be written in a contiguous fashion using the address given in
+ * the corresponding buf field.
+ * If the second element has a non-zero len field, then a second
+ * contiguous stretch of data can be written to the address given in
+ * the corresponding buf field.
+ * rb a pointer to the ringbuffer structure.
+ * vec a pointer to a 2 element array of ringb_data_t. */
+
+extern void ringb_get_write_vector(const ringb_t *rb, ringb_data_t *vec);
+
+/*
+ * Read data from the ringbuffer.
+ * rb a pointer to the ringbuffer structure.
+ * dest a pointer to a buffer where data read from the
+ * ringbuffer will go.
+ * cnt the number of bytes to read.
+ *
+ * return the number of bytes read, which may range from 0 to cnt. */
+
+extern size_t ringb_read(ringb_t *rb, char *dest, size_t cnt);
+
+/* Read data from the ringbuffer. Opposed to ringb_read()
+ * this function does not move the read pointer. Thus it's
+ * a convenient way to inspect data in the ringbuffer in a
+ * continous fashion. The price is that the data is copied
+ * into a user provided buffer. For "raw" non-copy inspection
+ * of the data in the ringbuffer use ringb_get_read_vector().
+ * rb a pointer to the ringbuffer structure.
+ * dest a pointer to a buffer where data read from the
+ * ringbuffer will go.
+ * cnt the number of bytes to read.
+ * return the number of bytes read, which may range from 0 to cnt.
+ */
+
+extern size_t ringb_peek(ringb_t *rb, char *dest, size_t cnt);
+
+/* Advance the read pointer.
+ * After data have been read from the ringbuffer using the pointers
+ * returned by ringb_get_read_vector(), use this function to
+ * advance the buffer pointers, making that space available for future
+ * write operations.
+ *
+ * rb a pointer to the ringbuffer structure.
+ * cnt the number of bytes read. */
+
+extern void ringb_read_advance(ringb_t *rb, size_t cnt);
+
+/* Return the number of bytes available for reading.
+ * rb a pointer to the ringbuffer structure.
+ * return the number of bytes available to read. */
+
+extern size_t ringb_read_space(const ringb_t *rb);
+
+/* Reset the read and write pointers, making an empty buffer.
+ * This is not thread safe. */
+
+extern void ringb_reset(ringb_t *rb);
+
+/* Write data into the ringbuffer.
+ * rb a pointer to the ringbuffer structure.
+ * src a pointer to the data to be written to the ringbuffer.
+ * cnt the number of bytes to write.
+ * return the number of bytes write, which may range from 0 to cnt */
+
+extern size_t ringb_write(ringb_t *rb, const char *src, size_t cnt);
+
+/* Advance the write pointer.
+ * After data have been written the ringbuffer using the pointers
+ * returned by ringb_get_write_vector(), use this function
+ * to advance the buffer pointer, making the data available for future
+ * read operations.
+ * rb a pointer to the ringbuffer structure.
+ * cnt the number of bytes written. */
+
+extern void ringb_write_advance(ringb_t *rb, size_t cnt);
+
+/* Return the number of bytes available for writing.
+ * rb a pointer to the ringbuffer structure.
+ * return the amount of free space (in bytes) available for writing. */
+
+extern size_t ringb_write_space(const ringb_t *rb);
+
+#endif
--- /dev/null
+/* sdr.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+//========================================================================
+/* initialization and termination */
+
+/* global and general info,
+ not specifically attached to
+ tx, rx, or scheduling */
+
+PRIVATE void
+setup_all(void) {
+
+ uni.samplerate = loc.def.rate;
+ uni.buflen = loc.def.size;
+ uni.mode.sdr = loc.def.mode;
+ uni.mode.trx = RX;
+
+ if (uni.meter.flag) {
+ uni.meter.chan.path = loc.path.meter;
+ uni.meter.chan.size = loc.mult.ring * sizeof(REAL);
+ uni.meter.val = -200.0;
+ uni.meter.chan.c = openChan(uni.meter.chan.path, uni.meter.chan.size);
+ }
+
+ uni.wisdom.path = loc.path.wisdom;
+ uni.wisdom.bits = FFTW_OUT_OF_PLACE | FFTW_ESTIMATE;
+ {
+ FILE *f = fopen(uni.wisdom.path, "r");
+ if (f) {
+#define WBUFLEN 2048
+#define WSTRLEN 64
+ char *line = alloca(WBUFLEN);
+ fgets(line, WBUFLEN, f);
+ if ((strlen(line) > WSTRLEN) &&
+ (fftw_import_wisdom_from_string(line) != FFTW_FAILURE))
+ uni.wisdom.bits = FFTW_OUT_OF_PLACE | FFTW_MEASURE | FFTW_USE_WISDOM;
+#undef WSTRLEN
+#undef WBUFLEN
+ fclose(f);
+ }
+ }
+
+ uni.tick = 0;
+}
+
+/* purely rx */
+
+PRIVATE void
+setup_rx(void) {
+
+ /* conditioning */
+ rx.iqfix = newCorrectIQ(0.0, 1.0);
+ rx.filt.coef = newFIR_Bandpass_COMPLEX(-4800.0,
+ 4800.0,
+ uni.samplerate,
+ uni.buflen + 1);
+ rx.filt.ovsv = newFiltOvSv(FIRcoef(rx.filt.coef),
+ FIRsize(rx.filt.coef),
+ uni.wisdom.bits);
+ normalize_vec_COMPLEX(rx.filt.ovsv->zfvec,
+ rx.filt.ovsv->fftlen);
+
+ // hack for EQ
+ rx.filt.save = newvec_COMPLEX(rx.filt.ovsv->fftlen, "RX filter cache");
+ memcpy((char *) rx.filt.save,
+ (char *) rx.filt.ovsv->zfvec,
+ rx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ /* buffers */
+ /* note we overload the internal filter buffers
+ we just created */
+ rx.buf.i = newCXB(FiltOvSv_fetchsize(rx.filt.ovsv),
+ FiltOvSv_fetchpoint(rx.filt.ovsv),
+ "init rx.buf.i");
+ rx.buf.o = newCXB(FiltOvSv_storesize(rx.filt.ovsv),
+ FiltOvSv_storepoint(rx.filt.ovsv),
+ "init rx.buf.o");
+
+ /* conversion */
+ rx.osc.freq = -11025.0;
+ rx.osc.phase = 0.0;
+ rx.osc.gen = newOSC(uni.buflen,
+ ComplexTone,
+ rx.osc.freq,
+ rx.osc.phase,
+ uni.samplerate,
+ "SDR RX Oscillator");
+
+ rx.agc.gen = newDigitalAgc(agcMED, // Mode
+ 7, // Hang
+ 7, // Size
+ 48, // Ramp
+ 3, // Over
+ 3, // Rcov
+ CXBsize(rx.buf.o), // BufSize
+ 100.0, // MaxGain
+ 0.707, // Limit
+ 1.0, // CurGain
+ CXBbase(rx.buf.o));
+ rx.agc.flag = TRUE;
+
+ /* demods */
+ rx.am.gen = newAMD(48000.0, // REAL samprate
+ 0.0, // REAL f_initial
+ -500.0, // REAL f_lobound,
+ 500.0, // REAL f_hibound,
+ 400.0, // REAL f_bandwid,
+ CXBsize(rx.buf.o), // int size,
+ CXBbase(rx.buf.o), // COMPLEX *ivec,
+ CXBbase(rx.buf.o), // COMPLEX *ovec,
+ AMdet, // AM Mode AMdet == rectifier,
+ // SAMdet == synchronous detector
+ "AM detector blew"); // char *tag
+ rx.fm.gen = newFMD(48000, // REAL samprate
+ 0.0, // REAL f_initial
+ -6000.0, // REAL f_lobound
+ 6000.0, // REAL f_hibound
+ 10000.0, // REAL f_bandwid
+ CXBsize(rx.buf.o), // int size
+ CXBbase(rx.buf.o), // COMPLEX *ivec
+ CXBbase(rx.buf.o), // COMPLEX *ovec
+ "New FM Demod structure"); // char *error message;
+
+ /* noise reduction */
+ rx.anf.gen = new_lmsr(rx.buf.o, // CXB signal,
+ 64, // int delay,
+ 0.01, // REAL adaptation_rate,
+ 0.00001, // REAL leakage,
+ 45, // int adaptive_filter_size,
+ LMADF_INTERFERENCE);
+ rx.anf.flag = FALSE;
+ rx.anr.gen = new_lmsr(rx.buf.o, // CXB signal,
+ 64, // int delay,
+ 0.01, // REAL adaptation_rate,
+ 0.00001, // REAL leakage,
+ 45, // int adaptive_filter_size,
+ LMADF_NOISE);
+ rx.anr.flag = FALSE;
+
+ rx.nb.thresh = 3.3;
+ rx.nb.gen = new_noiseblanker(rx.buf.i, rx.nb.thresh);
+ rx.nb.flag = FALSE;
+
+ rx.nb_sdrom.thresh = 2.5;
+ rx.nb_sdrom.gen = new_noiseblanker(rx.buf.i, rx.nb_sdrom.thresh);
+ rx.nb_sdrom.flag = FALSE;
+
+ rx.spot.gen = newSpotToneGen(-12.0, // gain
+ 700.0, // freq
+ 5.0, // ms rise
+ 5.0, // ms fall
+ uni.buflen,
+ uni.samplerate);
+
+ rx.scl.pre.val = 1.0;
+ rx.scl.pre.flag = FALSE;
+ rx.scl.post.val = 1.0;
+ rx.scl.post.flag = FALSE;
+
+ memset((char *) &rx.squelch, 0, sizeof(rx.squelch));
+ rx.squelch.thresh = -30.0;
+ rx.squelch.power = 0.0;
+ rx.squelch.flag = rx.squelch.running = rx.squelch.set = FALSE;
+ rx.squelch.num = (int) (0.0395 * uni.samplerate + 0.5);
+
+ rx.mode = uni.mode.sdr;
+ rx.bin.flag = FALSE;
+
+ rx.tick = 0;
+}
+
+/* purely tx */
+
+PRIVATE void
+setup_tx(void) {
+
+ /* conditioning */
+ tx.iqfix = newCorrectIQ(0.0, 1.0);
+ tx.filt.coef = newFIR_Bandpass_COMPLEX(300.0,
+ 3000.0,
+ uni.samplerate,
+ uni.buflen + 1);
+ tx.filt.ovsv = newFiltOvSv(FIRcoef(tx.filt.coef),
+ FIRsize(tx.filt.coef),
+ uni.wisdom.bits);
+ normalize_vec_COMPLEX(tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen);
+
+ // hack for EQ
+ tx.filt.save = newvec_COMPLEX(tx.filt.ovsv->fftlen, "TX filter cache");
+ memcpy((char *) tx.filt.save,
+ (char *) tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ /* buffers */
+ tx.buf.i = newCXB(FiltOvSv_fetchsize(tx.filt.ovsv),
+ FiltOvSv_fetchpoint(tx.filt.ovsv),
+ "init tx.buf.i");
+ tx.buf.o = newCXB(FiltOvSv_storesize(tx.filt.ovsv),
+ FiltOvSv_storepoint(tx.filt.ovsv),
+ "init tx.buf.o");
+
+ /* conversion */
+ tx.osc.freq = 0.0;
+ tx.osc.phase = 0.0;
+ tx.osc.gen = newOSC(uni.buflen,
+ ComplexTone,
+ tx.osc.freq,
+ tx.osc.phase,
+ uni.samplerate,
+ "SDR TX Oscillator");
+
+ tx.agc.gen = newDigitalAgc(agcFAST, // Mode
+ 3, // Hang
+ 3, // Size
+ 3, // Over
+ 3, // Rcov
+ 48, // Ramp
+ CXBsize(tx.buf.o), // BufSize
+ 1.0, // MaxGain
+ 0.900, // Limit
+ 1.0, // CurGain
+ CXBbase(tx.buf.o));
+ tx.agc.flag = TRUE;
+
+ tx.spr.gen = newSpeechProc(0.4, 10.0, CXBbase(tx.buf.i), CXBsize(tx.buf.i));
+ tx.spr.flag = FALSE;
+
+ tx.scl.dc = cxzero;
+ tx.scl.pre.val = 1.0;
+ tx.scl.pre.flag = FALSE;
+ tx.scl.post.val = 1.0;
+ tx.scl.post.flag = FALSE;
+
+ tx.mode = uni.mode.sdr;
+
+ tx.tick = 0;
+ /* not much else to do for TX */
+}
+
+/* how the outside world sees it */
+
+void
+setup_workspace(void) {
+ setup_all(), setup_rx(), setup_tx();
+}
+
+void
+destroy_workspace(void) {
+
+ /* TX */
+ delSpeechProc(tx.spr.gen);
+ delDigitalAgc(tx.agc.gen);
+ delOSC(tx.osc.gen);
+ delvec_COMPLEX(tx.filt.save);
+ delFiltOvSv(tx.filt.ovsv);
+ delFIR_Bandpass_COMPLEX(tx.filt.coef);
+ delCorrectIQ(tx.iqfix);
+ delCXB(tx.buf.o);
+ delCXB(tx.buf.i);
+
+ /* RX */
+ delSpotToneGen(rx.spot.gen);
+ delDigitalAgc(rx.agc.gen);
+ del_nb(rx.nb_sdrom.gen);
+ del_nb(rx.nb.gen);
+ del_lmsr(rx.anf.gen);
+ del_lmsr(rx.anr.gen);
+ delAMD(rx.am.gen);
+ delFMD(rx.fm.gen);
+ delOSC(rx.osc.gen);
+ delvec_COMPLEX(rx.filt.save);
+ delFiltOvSv(rx.filt.ovsv);
+ delFIR_Bandpass_COMPLEX(rx.filt.coef);
+ delCorrectIQ(rx.iqfix);
+ delCXB(rx.buf.o);
+ delCXB(rx.buf.i);
+
+ /* all */
+ if (uni.meter.flag)
+ closeChan(uni.meter.chan.c);
+}
+
+//////////////////////////////////////////////////////////////////////////
+// execution
+//////////////////////////////////////////////////////////////////////////
+
+//========================================================================
+/* all */
+
+/* tap off S-meter from some buf */
+
+PRIVATE void
+do_meter(COMPLEX *vec, int len) {
+ int i;
+
+ uni.meter.val = 0;
+
+ switch (uni.meter.type) {
+ case AVG_SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.val += Csqrmag(vec[i]);
+ uni.meter.val =
+ uni.meter.avgval = 0.9 * uni.meter.avgval + log10(uni.meter.val + 1e-20);
+ break;
+ case SIGNAL_STRENGTH:
+ for (i = 0; i < len; i++)
+ uni.meter.val += Csqrmag(vec[i]);
+ uni.meter.avgval = uni.meter.val = 10.0 * log10(uni.meter.val + 1e-20);
+ break;
+ case ADC_REAL:
+ for(i = 0; i < len; i++)
+ uni.meter.val = max(fabs(vec[i].re), uni.meter.val);
+ uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+ break;
+ case ADC_IMAG:
+ for(i = 0; i < len; i++)
+ uni.meter.val = max(fabs(vec[i].im), uni.meter.val);
+ uni.meter.val = 20.0 * log10(uni.meter.val + 1e-10);
+ break;
+ default:
+ break;
+ }
+
+ putChan_nowait(uni.meter.chan.c,
+ (char *) &uni.meter.val,
+ sizeof(uni.meter.val));
+}
+
+//========================================================================
+/* RX processing */
+
+PRIVATE BOOLEAN
+should_do_rx_squelch(void) {
+ if (rx.squelch.flag) {
+ int i, n = CXBhave(rx.buf.o);
+ REAL tst;
+ rx.squelch.power = 0.0;
+ for (i = 0; i < n; i++)
+ rx.squelch.power += Csqrmag(CXBdata(rx.buf.o, i));
+ tst = (10.0 * log10(rx.squelch.power)
+ + rx.squelch.offset.meter
+ + rx.squelch.offset.att
+ + rx.squelch.offset.gain);
+ return rx.squelch.thresh > tst;
+ } else
+ return rx.squelch.set = FALSE;
+}
+
+// apply squelch
+// slew into silence first time
+
+PRIVATE void
+do_squelch(void) {
+ rx.squelch.set = TRUE;
+ if (!rx.squelch.running) {
+ int i, m = rx.squelch.num, n = CXBhave(rx.buf.o) - m;
+ for (i = 0; i < m; i++)
+ CXBdata(rx.buf.o, i) = Cscl(CXBdata(rx.buf.o, i), 1.0 - (REAL) i / m);
+ memset((void *) (CXBbase(rx.buf.o) + m), 0, n * sizeof(COMPLEX));
+ rx.squelch.running = TRUE;
+ } else
+ memset((void *) CXBbase(rx.buf.o), 0, CXBhave(rx.buf.o) * sizeof(COMPLEX));
+}
+
+// lift squelch
+// slew out from silence to full scale
+
+PRIVATE void
+no_squelch(void) {
+ if (rx.squelch.running) {
+ int i, m = rx.squelch.num;
+ for (i = 0; i < m; i++)
+ CXBdata(rx.buf.o, i) = Cscl(CXBdata(rx.buf.o, i), (REAL) i / m);
+ rx.squelch.running = FALSE;
+ }
+}
+
+/* pre-condition for (nearly) all RX modes */
+
+PRIVATE void
+do_rx_pre(void) {
+ int i, n = min(CXBhave(rx.buf.i), uni.buflen);
+
+ //
+ // do shrinkage here
+ //
+
+ if (rx.scl.pre.flag)
+ for (i = 0; i < n; i++)
+ CXBdata(rx.buf.i, i) = Cscl(CXBdata(rx.buf.i, i),
+ rx.scl.pre.val);
+
+ if (rx.nb.flag) noiseblanker(rx.nb.gen);
+ if (rx.nb_sdrom.flag) SDROMnoiseblanker(rx.nb_sdrom.gen);
+
+ correctIQ(rx.buf.i, rx.iqfix);
+
+ /* 2nd if conversion happens here */
+ if (rx.osc.gen->Frequency != 0.0) {
+ ComplexOSC(rx.osc.gen);
+ for (i = 0; i < n; i++)
+ CXBdata(rx.buf.i, i) = Cmul(CXBdata(rx.buf.i, i),
+ OSCCdata(rx.osc.gen, i));
+ }
+
+ /* filtering, metering, & AGC */
+ if (rx.mode != SPEC) {
+ filter_OvSv(rx.filt.ovsv);
+ CXBhave(rx.buf.o) = CXBhave(rx.buf.i);
+ if (uni.meter.flag) do_meter(CXBbase(rx.buf.o), uni.buflen);
+ if (rx.agc.flag) DigitalAgc(rx.agc.gen, rx.tick);
+ } else if (uni.meter.flag)
+ do_meter(CXBbase(rx.buf.o), uni.buflen);
+}
+
+PRIVATE void
+do_rx_post(void) {
+ int i, n = CXBhave(rx.buf.o);;
+
+ if (!rx.squelch.set) {
+ no_squelch();
+ // spotting tone
+ if (rx.spot.flag) {
+ // remember whether it's turned itself off during this pass
+ rx.spot.flag = SpotTone(rx.spot.gen);
+ for (i = 0; i < n; i++)
+ CXBdata(rx.buf.o, i) = Cadd(CXBdata(rx.buf.o, i),
+ CXBdata(rx.spot.gen->buf, i));
+ }
+ }
+
+ //
+ // mix in sidetone here
+ //
+
+ if (rx.scl.post.flag)
+ for (i = 0; i < n; i++)
+ CXBdata(rx.buf.o, i) = Cscl(CXBdata(rx.buf.o, i),
+ rx.scl.post.val);
+
+ // not binaural? collapse
+ if (!rx.bin.flag)
+ for (i = 0; i < n; i++)
+ CXBimag(rx.buf.o, i) = CXBreal(rx.buf.o, i);
+}
+
+/* demod processing */
+
+PRIVATE void
+do_rx_SBCW(void) {
+ if (rx.anr.flag) lmsr_adapt(rx.anr.gen);
+ if (rx.anf.flag) lmsr_adapt(rx.anf.gen);
+}
+
+PRIVATE void
+do_rx_AM(void) { AMDemod(rx.am.gen); }
+
+PRIVATE void
+do_rx_FM(void) { FMDemod(rx.fm.gen); }
+
+PRIVATE void
+do_rx_DRM(void) {}
+
+PRIVATE void
+do_rx_SPEC(void) {
+ memcpy(CXBbase(rx.buf.o),
+ CXBbase(rx.buf.i),
+ sizeof(COMPLEX) * CXBhave(rx.buf.i));
+ if (rx.agc.flag) DigitalAgc(rx.agc.gen, rx.tick);
+}
+
+PRIVATE void
+do_rx_NIL(void) {
+ int i, n = min(CXBhave(rx.buf.i), uni.buflen);
+ for (i = 0; i < n; i++) CXBdata(rx.buf.o, i) = cxzero;
+}
+
+/* overall dispatch for RX processing */
+
+PRIVATE void
+do_rx(void) {
+ do_rx_pre();
+ switch (rx.mode) {
+ case USB:
+ case LSB:
+ case CWU:
+ case CWL:
+ case DSB: do_rx_SBCW(); break;
+ case AM:
+ case SAM: do_rx_AM(); break;
+ case FMN: do_rx_FM(); break;
+ case DRM: do_rx_DRM(); break;
+ case SPEC:
+ default: do_rx_SPEC(); break;
+ }
+ do_rx_post();
+}
+
+//==============================================================
+/* TX processing */
+
+/* pre-condition for (nearly) all TX modes */
+
+PRIVATE void
+do_tx_pre(void) {
+ if (tx.scl.pre.flag) {
+ int i, n = CXBhave(tx.buf.i);
+ for (i = 0; i < n; i++)
+ CXBdata(tx.buf.i, i) = Cmplx(CXBreal(tx.buf.i, i) * tx.scl.pre.val, 0.0);
+ }
+
+ //
+ // mix in CW tone here
+ //
+
+ correctIQ(tx.buf.i, tx.iqfix);
+
+ if (tx.spr.flag) SpeechProcessor(tx.spr.gen);
+ filter_OvSv(tx.filt.ovsv);
+}
+
+PRIVATE void
+do_tx_post(void) {
+ CXBhave(tx.buf.o) = CXBhave(tx.buf.i);
+
+ if (tx.agc.flag) DigitalAgc(tx.agc.gen, tx.tick);
+ if (tx.scl.post.flag) {
+ int i, n = CXBhave(tx.buf.o);
+ for (i = 0; i < n; i++)
+ CXBdata(tx.buf.o, i) = Cscl(CXBdata(tx.buf.o, i), tx.scl.post.val);
+ }
+ if (uni.meter.flag) do_meter(CXBbase(tx.buf.o), uni.buflen);
+ if (tx.osc.gen->Frequency != 0.0) {
+ int i;
+ ComplexOSC(tx.osc.gen);
+ for (i = 0; i < CXBhave(tx.buf.o); i++)
+ CXBdata(tx.buf.o, i) = Cmul(CXBdata(tx.buf.o, i), OSCCdata(tx.osc.gen, i));
+ }
+}
+
+/* modulator processing */
+
+PRIVATE void
+do_tx_SBCW(void) {
+ int i, n = min(CXBhave(tx.buf.i), uni.buflen);
+ for (i = 0; i < n; i++) {
+ tx.scl.dc = Cadd(Cscl(tx.scl.dc, 0.99),
+ Cscl(CXBdata(tx.buf.o,i), -0.01));
+ CXBdata(tx.buf.o, i) = Cadd(CXBdata(tx.buf.o,i), tx.scl.dc);
+ }
+}
+
+PRIVATE void
+do_tx_AM(void) {
+ int i, n = min(CXBhave(tx.buf.i), uni.buflen);
+ for (i = 0; i < n; i++) {
+ tx.scl.dc = Cadd(Cscl(tx.scl.dc, 0.999),
+ Cscl(CXBdata(tx.buf.o,i), -0.001));
+ CXBreal(tx.buf.o, i) =
+ 0.49995 + 0.49995 * (CXBreal(tx.buf.o,i) - tx.scl.dc.re);
+ CXBimag(tx.buf.o, i) = 0.0;
+ }
+}
+
+PRIVATE void
+do_tx_FM(void) {
+ int i, n = min(CXBhave(tx.buf.i), uni.buflen);
+ for (i = 0; i < n; i++) {
+ tx.scl.dc = Cadd(Cscl(tx.scl.dc,0.999),
+ Cscl(CXBdata(tx.buf.o,i), 0.001));
+ tx.osc.phase += (CXBreal(tx.buf.o, i)- tx.scl.dc.re) * CvtMod2Freq;
+ if (tx.osc.phase >= TWOPI) tx.osc.phase -= TWOPI;
+ if (tx.osc.phase < 0.0) tx.osc.phase += TWOPI;
+ CXBdata(tx.buf.o, i) =
+ Cscl(Cmplx(cos(tx.osc.phase), sin(tx.osc.phase)), 0.99999);
+ }
+}
+
+PRIVATE void
+do_tx_NIL(void) {
+ int i, n = min(CXBhave(tx.buf.i), uni.buflen);
+ for (i = 0; i < n; i++) CXBdata(tx.buf.o, i) = cxzero;
+}
+
+/* general TX processing dispatch */
+
+PRIVATE void
+do_tx(void) {
+ do_tx_pre();
+ switch (tx.mode) {
+ case USB:
+ case LSB:
+ case CWU:
+ case CWL:
+ case DSB: do_tx_SBCW(); break;
+ case AM:
+ case SAM: do_tx_AM(); break;
+ case FMN: do_tx_FM(); break;
+ case DRM:
+ case SPEC:
+ default: do_tx_NIL(); break;
+ }
+ do_tx_post();
+}
+
+//========================================================================
+/* overall buffer processing;
+ come here when there are buffers to work on */
+
+void
+process_samples(float *bufl, float *bufr, int n) {
+ int i;
+
+ switch (uni.mode.trx) {
+
+ case RX:
+ for (i = 0; i < n; i++)
+ CXBimag(rx.buf.i, i) = bufl[i], CXBreal(rx.buf.i, i) = bufr[i];
+ CXBhave(rx.buf.i) = n;
+
+ do_rx(), rx.tick++;
+
+ for (i = 0; i < n; i++)
+ bufl[i] = (float)CXBimag(rx.buf.o, i), bufr[i] = (float)CXBreal(rx.buf.o, i);
+ CXBhave(rx.buf.o) = n;
+ break;
+
+ case TX:
+ for (i = 0; i < n; i++)
+ CXBimag(tx.buf.i, i) = bufl[i], CXBreal(tx.buf.i, i) = bufr[i];
+ CXBhave(tx.buf.i) = n;
+
+ do_tx(), tx.tick++;
+
+ for (i = 0; i < n; i++)
+ bufl[i] = (float)CXBimag(tx.buf.o, i), bufr[i] = (float)CXBreal(tx.buf.o, i);
+ CXBhave(rx.buf.o) = n;
+ break;
+ }
+
+ uni.tick++;
+}
--- /dev/null
+/* sdrexport.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+struct _uni uni;
+struct _rx rx;
+struct _tx tx;
+struct _top top;
--- /dev/null
+/* sdrexport.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _sdrexport_h
+#define _sdrexport_h
+
+#include <common.h>
+
+//------------------------------------------------------------------------
+/* modulation types, modes */
+typedef enum _sdrmode {
+ LSB, // 0
+ USB, // 1
+ DSB, // 2
+ CWL, // 3
+ CWU, // 4
+ FMN, // 5
+ AM, // 6
+ PSK, // 7
+ SPEC, // 8
+ RTTY, // 9
+ SAM, // 10
+ DRM // 11
+} SDRMODE;
+
+typedef enum _trxmode { RX, TX } TRXMODE;
+
+//========================================================================
+/* RX/TX both */
+//------------------------------------------------------------------------
+extern struct _uni {
+ REAL samplerate;
+ int buflen;
+
+ struct {
+ SDRMODE sdr;
+ TRXMODE trx;
+ } mode;
+
+ struct {
+ BOOLEAN flag;
+ struct {
+ char *path;
+ size_t size;
+ Chan c;
+ } chan;
+ REAL val, avgval;
+ METERTYPE type;
+ } meter;
+
+ struct {
+ BOOLEAN flag;
+ struct {
+ char *path;
+ size_t size;
+ Chan c;
+ } chan;
+ splitfld splt;
+ } update;
+
+ struct {
+ char *path;
+ int bits;
+ } wisdom;
+
+ long tick;
+
+} uni;
+
+//------------------------------------------------------------------------
+/* RX */
+//------------------------------------------------------------------------
+
+extern struct _rx {
+ struct {
+ CXB i, o;
+ } buf;
+ IQ iqfix;
+ struct {
+ REAL freq, phase;
+ OSC gen;
+ } osc;
+ struct {
+ ComplexFIR coef;
+ FiltOvSv ovsv;
+ COMPLEX *save;
+ } filt;
+ struct {
+ REAL thresh;
+ NB gen;
+ BOOLEAN flag;
+ } nb;
+ struct {
+ REAL thresh;
+ NB gen;
+ BOOLEAN flag;
+ } nb_sdrom;
+ struct {
+ LMSR gen;
+ BOOLEAN flag;
+ } anr, anf;
+ struct {
+ DIGITALAGC gen;
+ BOOLEAN flag;
+ } agc;
+ struct { AMD gen; } am;
+ struct { FMD gen; } fm;
+ struct {
+ BOOLEAN flag;
+ SpotToneGen gen;
+ } spot;
+ struct {
+ struct {
+ REAL val;
+ BOOLEAN flag;
+ } pre, post;
+ } scl;
+ struct {
+ REAL thresh, power;
+ struct {
+ REAL meter, att, gain;
+ } offset;
+ BOOLEAN flag, running, set;
+ int num;
+ } squelch;
+ SDRMODE mode;
+ struct { BOOLEAN flag; } bin;
+ long tick;
+} rx;
+
+//------------------------------------------------------------------------
+/* TX */
+//------------------------------------------------------------------------
+extern struct _tx {
+ struct {
+ CXB i, o;
+ } buf;
+ IQ iqfix;
+ struct {
+ REAL freq, phase;
+ OSC gen;
+ } osc;
+ struct {
+ ComplexFIR coef;
+ FiltOvSv ovsv;
+ COMPLEX *save;
+ } filt;
+ struct {
+ ComplexFIR coef;
+ FiltOvSv ovsv;
+ CXB in, out;
+ } fm;
+ struct {
+ DIGITALAGC gen;
+ BOOLEAN flag;
+ } agc;
+ struct {
+ SpeechProc gen;
+ BOOLEAN flag;
+ } spr;
+ struct {
+ COMPLEX dc;
+ struct {
+ REAL val;
+ BOOLEAN flag;
+ } pre, post;
+ } scl;
+ SDRMODE mode;
+ long tick;
+} tx;
+
+//------------------------------------------------------------------------
+
+typedef enum _runmode {
+ RUN_MUTE, RUN_PASS, RUN_PLAY, RUN_SWCH
+} RUNMODE;
+
+extern struct _top {
+ pid_t pid;
+ uid_t uid;
+
+ struct timeval start_tv;
+
+ BOOLEAN running, verbose;
+ RUNMODE state;
+
+ // audio io
+ struct {
+ struct {
+ float *l, *r;
+ } buf;
+ struct {
+ unsigned int frames, bytes;
+ } size;
+ } hold;
+ struct {
+ char *path;
+ int fd;
+ FILE *fp;
+ char buff[4096];
+ } parm;
+
+ struct {
+ char name[256];
+ jack_client_t *client;
+ struct {
+ struct {
+ jack_port_t *l, *r;
+ } i, o;
+ } port;
+ struct {
+ struct {
+ jack_ringbuffer_t *l, *r;
+ } i, o;
+ } ring;
+ jack_nframes_t size;
+ struct {
+ int cb;
+ struct {
+ int i, o;
+ } rb;
+ int xr;
+ } blow;
+ } jack;
+
+ // update io
+ // multiprocessing & synchronization
+ struct {
+ struct {
+ pthread_t id;
+ } trx, upd, mon;
+ } thrd;
+ struct {
+ struct {
+ sem_t sem;
+ } buf, upd, mon;
+ } sync;
+
+ // TRX switching
+ struct {
+ struct {
+ int want, have;
+ } bfct;
+ struct {
+ TRXMODE next;
+ } trx;
+ struct {
+ RUNMODE last;
+ } run;
+ int fade, tail;
+ } swch;
+} top;
+
+#endif
--- /dev/null
+#!/bin/sh
+
+if [ ! -d ./IPC ]; then mkdir ./IPC; fi
+
+(cd ./IPC
+ if [ ! -p SDR-1000-0-commands.fifo ]; then
+ mkfifo SDR-1000-0-commands.fifo
+ fi
+
+ # 192 = METERMULT * sizeof(REAL)
+ if [ ! -f SDR-1000-0-meter.chan ]; then
+ ../mkchan SDR-1000-0-meter.chan 192
+ fi)
+
+ls -ld IPC
+ls -l IPC
--- /dev/null
+/* speechproc.c
+
+ This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <speechproc.h>
+
+SpeechProc
+newSpeechProc(REAL K, REAL MaxCompression, COMPLEX *spdat, int size) {
+ SpeechProc sp = (SpeechProc) safealloc(1, sizeof(speech_proc), "new speech processor");
+ sp->CG = newRLB(size, NULL, "CG buffer in Speech Processor");
+ sp->K = K;
+ sp->MaxGain = pow(10.0, MaxCompression * 0.05);
+ sp->LastCG = 1.0;
+ sp->SpeechProcessorBuffer = newCXB(size, spdat, "speech processor data");
+ sp->size = size;
+ return sp;
+}
+
+void
+delSpeechProc(SpeechProc sp) {
+ if (sp) {
+ delCXB(sp->SpeechProcessorBuffer);
+ safefree((char *) sp);
+ }
+}
+
+void
+SpeechProcessor(SpeechProc sp) {
+ int i;
+ REAL r = 0.0, Mag;
+ for (i = 0; i < sp->size; i++)
+ r = max(r, Cmag(CXBdata(sp->SpeechProcessorBuffer, i)));
+ Mag = Cmag(CXBdata(sp->SpeechProcessorBuffer, 0));
+ if (Mag > 0.0) {
+ RLBdata(sp->CG, 0) = sp->LastCG * (1.0 - sp->K) + (sp->K * r / Mag);
+ if (RLBdata(sp->CG, 0) > sp->MaxGain)
+ RLBdata(sp->CG, 0) = sp->MaxGain;
+ } else
+ RLBdata(sp->CG, 0) = 1.0;
+ for (i = 1; i < sp->size; i++) {
+ Mag = Cmag(CXBdata(sp->SpeechProcessorBuffer, i));
+ if (Mag > 0.0) {
+ RLBdata(sp->CG, i) =
+ RLBdata(sp->CG, i - 1) * (1 - sp->K) + (sp->K * r / Mag);
+ if (RLBdata(sp->CG, i) > sp->MaxGain)
+ RLBdata(sp->CG, i) = sp->MaxGain;
+ } else
+ RLBdata(sp->CG, i) = 1.0;
+ }
+ sp->LastCG = RLBdata(sp->CG, sp->size - 1);
+ for (i = 0; i < sp->size; i++)
+ CXBdata(sp->SpeechProcessorBuffer, i) =
+ Cscl(CXBdata(sp->SpeechProcessorBuffer, i), RLBdata(sp->CG, i));
+}
--- /dev/null
+/* speechproc.h
+
+ This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _speechproc_h
+#define _speechproc_h
+
+#include <fromsys.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <banal.h>
+
+typedef struct _speechprocessor {
+ int size;
+ RLB CG;
+ CXB SpeechProcessorBuffer;
+ REAL LastCG, K, MaxGain;
+} speech_proc, *SpeechProc;
+
+extern SpeechProc newSpeechProc(REAL, REAL, COMPLEX *, int);
+extern void delSpeechProc(SpeechProc);
+extern void SpeechProcessor(SpeechProc);
+
+#endif
--- /dev/null
+/* splitfields.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <splitfields.h>
+
+static char *_white = " \t\n";
+
+SPLIT
+newSPLIT(void) {
+ return (SPLIT) safealloc(1, sizeof(splitfld), "splitfield");
+}
+
+void
+delSPLIT(SPLIT s) { if (s) free((char *) s); }
+
+char *
+F(SPLIT s, int i) { return s->f[i]; }
+
+char **
+Fptr(SPLIT s, int i) { return &(s->f[i]); }
+
+int
+NF(SPLIT s) { return s->n; }
+
+int
+splitonto(SPLIT s, char *str, char *delim, char **fld, int fmx) {
+ int i = 0;
+ char *p = strtok(str, delim);
+ while (p) {
+ fld[i] = p;
+ if (++i >= fmx) break;
+ p = strtok(0, delim);
+ }
+ return i;
+}
+
+int
+spliton(SPLIT s, char *str, char *delim) {
+ return (s->n = splitonto(s, str, delim, s->f, MAXFLD));
+}
+
+void
+split(SPLIT s, char *str) { spliton(s, str, _white); }
--- /dev/null
+/* splitfields.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _splitfields_h
+#define _splitfields_h
+
+#include <fromsys.h>
+#include <bufvec.h>
+#include <banal.h>
+
+#define MAXFLD 16384
+
+typedef struct _splitfld {
+ char *f[MAXFLD];
+ int n;
+} splitfld, *SPLIT;
+
+extern char *F(SPLIT, int);
+extern char **Fptr(SPLIT, int);
+extern int NF(SPLIT);
+
+extern int splitonto(SPLIT, char *, char *, char **, int);
+extern int spliton(SPLIT, char *, char *);
+extern void split(SPLIT, char *);
+
+#endif
--- /dev/null
+/* spottone.c */
+
+#include <spottone.h>
+
+//------------------------------------------------------------------------
+// An ASR envelope on a complex phasor,
+// with asynchronous trigger for R stage.
+// A/R use sine shaping.
+//------------------------------------------------------------------------
+
+BOOLEAN
+SpotTone(SpotToneGen st) {
+ int i, n = st->size;
+
+ ComplexOSC(st->osc.gen);
+
+ for (i = 0; i < n; i++) {
+
+ // in an envelope stage?
+
+ if (st->stage == SpotTone_RISE) {
+
+ // still going?
+ if (st->rise.have++ < st->rise.want) {
+ st->curr += st->rise.incr;
+ st->mul = st->scl * sin(st->curr * M_PI / 2.0);
+ } else {
+ // no, assert steady-state, force level
+ st->curr = 1.0;
+ st->mul = st->scl;
+ st->stage = SpotTone_STDY;
+ // won't come back into envelopes
+ // until FALL asserted from outside
+ }
+
+ } else if (st->stage == SpotTone_FALL) {
+
+ // still going?
+ if (st->fall.have++ < st->fall.want) {
+ st->curr -= st->fall.incr;
+ st->mul = st->scl * sin(st->curr * M_PI / 2.0);
+ } else {
+ // no, assert trailing, force level
+ st->curr = 0.0;
+ st->mul = 0.0;
+ st->stage = SpotTone_HOLD;
+ // won't come back into envelopes hereafter
+ }
+ }
+
+ // apply envelope
+ // (same base as osc.gen internal buf)
+ CXBdata(st->buf, i) = Cscl(CXBdata(st->buf, i), st->mul);
+ }
+
+ // indicate whether it's turned itself off
+ // sometime during this pass
+
+ return st->stage != SpotTone_HOLD;
+}
+
+//------------------------------------------------------------------------
+// turn spotting on with current settings
+
+void
+SpotToneOn(SpotToneGen st) {
+
+ // gain is in dB
+
+ st->scl = pow(10.0, st->gain / 20.0);
+ st->curr = st->mul = 0.0;
+
+ // A/R times are in msec
+
+ st->rise.want = (int) (0.5 + st->sr * (st->rise.dur / 1e3));
+ st->rise.have = 0;
+ if (st->rise.want <= 1)
+ st->rise.incr = 1.0;
+ else
+ st->rise.incr = 1.0 / (st->rise.want - 1);
+
+ st->fall.want = (int) (0.5 + st->sr * (st->fall.dur / 1e3));
+ st->fall.have = 0;
+ if (st->fall.want <= 1)
+ st->fall.incr = 1.0;
+ else
+ st->fall.incr = 1.0 / (st->fall.want - 1);
+
+ // freq is in Hz
+
+ OSCfreq(st->osc.gen) = 2.0 * M_PI * st->osc.freq / st->sr;
+ OSCphase(st->osc.gen) = 0.0;
+
+ st->stage = SpotTone_RISE;
+}
+
+//------------------------------------------------------------------------
+// initiate turn-off
+
+void
+SpotToneOff(SpotToneGen st) { st->stage = SpotTone_FALL; }
+
+//------------------------------------------------------------------------
+
+void
+setSpotToneGenVals(SpotToneGen st,
+ REAL gain,
+ REAL freq,
+ REAL rise,
+ REAL fall) {
+ st->gain = gain;
+ st->osc.freq = freq;
+ st->rise.dur = rise;
+ st->fall.dur = fall;
+}
+
+SpotToneGen
+newSpotToneGen(REAL gain, // dB
+ REAL freq,
+ REAL rise, // ms
+ REAL fall, // ms
+ int size,
+ REAL samplerate) {
+
+ SpotToneGen st = (SpotToneGen) safealloc(1,
+ sizeof(SpotToneGenDesc),
+ "SpotToneGenDesc");
+
+ setSpotToneGenVals(st, gain, freq, rise, fall);
+ st->size = size;
+ st->sr = samplerate;
+
+ st->osc.gen = newOSC(st->size,
+ ComplexTone,
+ st->osc.freq,
+ 0.0,
+ st->sr,
+ "SpotTone osc");
+
+ // overload oscillator buf
+ st->buf = newCXB(st->size, OSCCbase(st->osc.gen), "SpotToneGen buf");
+
+ return st;
+}
+
+void
+delSpotToneGen(SpotToneGen st) {
+ if (st) {
+ delCXB(st->buf);
+ delOSC(st->osc.gen);
+ safefree((char *) st);
+ }
+}
--- /dev/null
+/* spottone.h */
+
+#ifndef _spottone_h
+#define _spottone_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <oscillator.h>
+
+#define SpotTone_IDLE (0)
+#define SpotTone_WAIT (1)
+#define SpotTone_RISE (2)
+#define SpotTone_STDY (3)
+#define SpotTone_FALL (4)
+#define SpotTone_HOLD (5)
+
+typedef struct _spot_tone_gen {
+ REAL curr, gain, mul, scl, sr;
+ struct {
+ REAL freq;
+ OSC gen;
+ } osc;
+ struct {
+ REAL dur, incr;
+ int want, have;
+ } rise, fall;
+ int size, stage;
+ CXB buf;
+} SpotToneGenDesc, *SpotToneGen;
+
+extern SpotToneGen newSpotToneGen(REAL gain, // dB
+ REAL freq, // Hz
+ REAL rise, // msec
+ REAL fall, // msec
+ int size, // buflen
+ REAL samplerate);
+extern void delSpotToneGen(SpotToneGen gen);
+extern void setSpotToneGenVals(SpotToneGen gen,
+ REAL gain,
+ REAL freq,
+ REAL rise,
+ REAL fall);
+extern void SpotToneOn(SpotToneGen gen);
+extern void SpotToneOff(SpotToneGen gen);
+extern BOOLEAN SpotTone(SpotToneGen gen);
+
+#endif
--- /dev/null
+/* thunk.c */
+
+#include <common.h>
+#include <thunk.h>
+
+PRIVATE BOOLEAN
+streq(char *p, char *q) { return !strcmp(p, q); }
+
+/* somewhere along the line
+ we'll kick this up a notch
+ with gperf */
+
+Thunk
+Thunk_lookup(CTB ctb, char *key) {
+ if (key && *key) {
+ for (;;) {
+ if (!ctb || !ctb->key || !ctb->thk) break;
+ if (streq(key, ctb->key)) return ctb->thk;
+ ctb++;
+ }
+ }
+ return (Thunk) 0;
+}
--- /dev/null
+/* thunk.c */
+
+#ifndef _thunk_h
+#define _thunk_h
+
+typedef int (*Thunk)(int n, char **p);
+
+typedef struct _cmd_tbl_entry { char *key; Thunk thk; } CTE, *CTB;
+
+extern Thunk Thunk_lookup(CTB ctb, char *key);
+
+#endif
--- /dev/null
+/* update.c
+
+common defs and code for parm update
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+////////////////////////////////////////////////////////////////////////////
+
+PRIVATE REAL
+dB2lin(REAL dB) { return pow(10.0, dB / 20.0); }
+
+PRIVATE int
+setRXFilter(int n, char **p) {
+ REAL low_frequency = atof(p[0]),
+ high_frequency = atof(p[1]);
+ int ncoef = uni.buflen + 1;
+ int i, fftlen = 2 * uni.buflen;
+ fftw_plan ptmp;
+ COMPLEX *zcvec;
+
+ if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
+ if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
+ if ((low_frequency + 10) >= high_frequency) return -3;
+ delFIR_COMPLEX(rx.filt.coef);
+
+ rx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
+ high_frequency,
+ uni.samplerate,
+ ncoef);
+
+ zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
+ ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
+#ifdef LHS
+ for (i = 0; i < ncoef; i++) zcvec[i] = rx.filt.coef->coef[i];
+#else
+ for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = rx.filt.coef->coef[i];
+#endif
+ fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) rx.filt.ovsv->zfvec);
+ fftw_destroy_plan(ptmp);
+ delvec_COMPLEX(zcvec);
+ normalize_vec_COMPLEX(rx.filt.ovsv->zfvec,
+ rx.filt.ovsv->fftlen);
+ memcpy((char *) rx.filt.save,
+ (char *) rx.filt.ovsv->zfvec,
+ rx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ return 0;
+}
+
+
+PRIVATE int
+setTXFilter(int n, char **p) {
+ REAL low_frequency = atof(p[0]),
+ high_frequency = atof(p[1]);
+ int ncoef = uni.buflen + 1;
+ int i, fftlen = 2 * uni.buflen;
+ fftw_plan ptmp;
+ COMPLEX *zcvec;
+
+ if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
+ if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
+ if ((low_frequency + 10) >= high_frequency) return -3;
+ delFIR_COMPLEX(tx.filt.coef);
+ tx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
+ high_frequency,
+ uni.samplerate,
+ ncoef);
+
+ zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
+ ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, uni.wisdom.bits);
+#ifdef LHS
+ for (i = 0; i < ncoef; i++) zcvec[i] = tx.filt.coef->coef[i];
+#else
+ for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = tx.filt.coef->coef[i];
+#endif
+ fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) tx.filt.ovsv->zfvec);
+ fftw_destroy_plan(ptmp);
+ delvec_COMPLEX(zcvec);
+ normalize_vec_COMPLEX(tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen);
+ memcpy((char *) tx.filt.save,
+ (char *) tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ return 0;
+}
+
+PRIVATE int
+setFilter(int n, char **p) {
+ if (n == 2) return setRXFilter(n, p);
+ else {
+ int trx = atoi(p[2]);
+ if (trx == RX) return setRXFilter(n, p);
+ else if (trx == TX) return setTXFilter(n, p);
+ else return -1;
+ }
+}
+
+// setMode <mode> [TRX]
+
+PRIVATE int
+setMode(int n, char **p) {
+ int mode = atoi(p[0]);
+ if (n > 1) {
+ int trx = atoi(p[1]);
+ switch (trx) {
+ case TX: tx.mode = mode; break;
+ case RX:
+ default: rx.mode = mode; break;
+ }
+ } else
+ tx.mode = rx.mode = uni.mode.sdr = mode;
+ if (rx.mode == AM) rx.am.gen->mode = AMdet;
+ if (rx.mode == SAM) rx.am.gen->mode = SAMdet;
+ return 0;
+}
+
+// setOsc <freq> [TRX]
+PRIVATE int
+setOsc(int n, char **p) {
+ REAL newfreq = atof(p[0]);
+ if (fabs(newfreq) >= 0.5 * uni.samplerate) return -1;
+ newfreq *= 2.0 * M_PI / uni.samplerate;
+ if (n > 1) {
+ int trx = atoi(p[1]);
+ switch (trx) {
+ case TX: tx.osc.gen->Frequency = newfreq; break;
+ case RX:
+ default: rx.osc.gen->Frequency = newfreq; break;
+ }
+ } else
+ tx.osc.gen->Frequency = rx.osc.gen->Frequency = newfreq;
+ return 0;
+}
+
+PRIVATE int
+setSampleRate(int n, char **p) {
+ REAL samplerate = atof(p[0]);
+ uni.samplerate = samplerate;
+ return 0;
+}
+
+PRIVATE int
+setNR(int n, char **p) {
+ rx.anr.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setANF(int n, char **p) {
+ rx.anf.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setNB(int n, char **p) {
+ rx.nb.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setNBvals(int n, char **p) {
+ REAL threshold = atof(p[0]);
+ rx.nb.gen->threshold = rx.nb.thresh = threshold;
+ return 0;
+}
+
+PRIVATE int
+setSDROM(int n, char **p) {
+ rx.nb_sdrom.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setSDROMvals(int n, char **p) {
+ REAL threshold = atof(p[0]);
+ rx.nb_sdrom.gen->threshold = rx.nb_sdrom.thresh = threshold;
+ return 0;
+}
+
+PRIVATE int
+setBIN(int n, char **p) {
+ rx.bin.flag = atoi(p[0]);
+ return 0;
+}
+
+// setfixedAGC <gain> [TRX]
+PRIVATE int
+setfixedAGC(int n, char **p) {
+ REAL gain = atof(p[0]);
+ if (n > 1) {
+ int trx = atoi(p[1]);
+ switch(trx) {
+ case TX: tx.agc.gen->gain.now = gain; break;
+ case RX:
+ default: rx.agc.gen->gain.now = gain; break;
+ }
+ } else
+ tx.agc.gen->gain.now = rx.agc.gen->gain.now = gain;
+ return 0;
+}
+
+PRIVATE int
+setRXAGC(int n, char **p) {
+ int setit = atoi(p[0]);
+ switch (setit) {
+ case agcOFF:
+ rx.agc.gen->mode = agcOFF;
+ rx.agc.flag = TRUE;
+ break;
+ case agcSLOW:
+ rx.agc.gen->mode = agcSLOW;
+ rx.agc.gen->hang = 10;
+ rx.agc.flag = TRUE;
+ break;
+ case agcMED:
+ rx.agc.gen->mode = agcMED;
+ rx.agc.gen->hang = 6;
+ rx.agc.flag = TRUE;
+ break;
+ case agcFAST:
+ rx.agc.gen->mode = agcFAST;
+ rx.agc.gen->hang = 3;
+ rx.agc.flag = TRUE;
+ break;
+ case agcLONG:
+ rx.agc.gen->mode = agcLONG;
+ rx.agc.gen->hang = 23;
+ rx.agc.flag = TRUE;
+ break;
+ }
+ return 0;
+}
+
+PRIVATE int
+setRXAGCCompression(int n, char **p) {
+ REAL rxcompression = atof(p[0]);
+ rx.agc.gen->gain.top = pow(10.0 , rxcompression * 0.05);
+ return 0;
+}
+
+PRIVATE int
+setRXAGCHang(int n, char **p) {
+ int hang = atoi(p[0]);
+ rx.agc.gen->hang =
+ max(1,
+ min(23,
+ hang * uni.samplerate / (1e3 * uni.buflen)));
+ return 0;
+}
+
+PRIVATE int
+setRXAGCLimit(int n, char **p) {
+ REAL limit = atof(p[0]);
+ rx.agc.gen->gain.lim = 0.001 * limit;
+ return 0;
+}
+
+PRIVATE int
+setTXAGC(int n, char **p) {
+ int setit = atoi(p[0]);
+ switch (setit) {
+ case agcOFF:
+ tx.agc.gen->mode = agcOFF;
+ tx.agc.flag = FALSE;
+ break;
+ case agcSLOW:
+ tx.agc.gen->mode = agcSLOW;
+ tx.agc.gen->hang = 10;
+ tx.agc.flag = TRUE;
+ break;
+ case agcMED:
+ tx.agc.gen->mode = agcMED;
+ tx.agc.gen->hang = 6;
+ tx.agc.flag = TRUE;
+ break;
+ case agcFAST:
+ tx.agc.gen->mode = agcFAST;
+ tx.agc.gen->hang = 3;
+ tx.agc.flag = TRUE;
+ break;
+ case agcLONG:
+ tx.agc.gen->mode = agcLONG;
+ tx.agc.gen->hang = 23;
+ tx.agc.flag = TRUE;
+ break;
+ }
+ return 0;
+}
+
+PRIVATE int
+setTXAGCCompression(int n, char **p) {
+ REAL txcompression = atof(p[0]);
+ tx.agc.gen->gain.top = pow(10.0 , txcompression * 0.05);
+ return 0;
+}
+
+PRIVATE int
+setTXAGCFF(int n, char **p) {
+ tx.spr.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTXAGCFFCompression(int n, char **p) {
+ REAL txcompression = atof(p[0]);
+ tx.spr.gen->MaxGain = pow(10.0 , txcompression * 0.05);
+ return 0;
+}
+
+PRIVATE int
+setTXAGCHang(int n, char **p) {
+ int hang = atoi(p[0]);
+ tx.agc.gen->hang =
+ max(1,
+ min(23,
+ hang * uni.samplerate / (1e3 * uni.buflen)));
+ return 0;
+}
+
+PRIVATE int
+setTXAGCLimit(int n, char **p) {
+ REAL limit = atof(p[0]);
+ tx.agc.gen->gain.lim = 0.001 * limit;
+ return 0;
+}
+
+PRIVATE int
+setTXSpeechCompression(int n, char **p) {
+ tx.spr.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTXSpeechCompressionGain(int n, char **p) {
+ tx.spr.gen->MaxGain = dB2lin(atof(p[0]));
+ return 0;
+}
+
+//============================================================
+
+PRIVATE int
+f2x(REAL f) {
+ REAL fix = tx.filt.ovsv->fftlen * f / uni.samplerate;
+ return (int) (fix + 0.5);
+}
+
+//------------------------------------------------------------
+
+PRIVATE void
+apply_txeq_band(REAL lof, REAL dB, REAL hif) {
+ int i,
+ lox = f2x(lof),
+ hix = f2x(hif),
+ l = tx.filt.ovsv->fftlen;
+ REAL g = dB2lin(dB);
+ COMPLEX *src = tx.filt.save,
+ *trg = tx.filt.ovsv->zfvec;
+ for (i = lox; i < hix; i++) {
+ trg[i] = Cscl(src[i], g);
+ if (i) {
+ int j = l - i;
+ trg[j] = Cscl(src[j], g);
+ }
+ }
+}
+
+// typical:
+// 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600
+// approximates W2IHY bandcenters.
+// no args, revert to no EQ.
+PRIVATE int
+setTXEQ(int n, char **p) {
+ if (n < 3) {
+ // revert to no EQ
+ memcpy((char *) tx.filt.ovsv->zfvec,
+ (char *) tx.filt.save,
+ tx.filt.ovsv->fftlen * sizeof(COMPLEX));
+ return 0;
+ } else {
+ int i;
+ REAL lof = atof(p[0]);
+ for (i = 0; i < n - 2; i += 2) {
+ REAL dB = atof(p[i + 1]),
+ hif = atof(p[i + 2]);
+ if (lof < 0.0 || hif <= lof) return -1;
+ apply_txeq_band(lof, dB, hif);
+ lof = hif;
+ }
+ return 0;
+ }
+}
+
+//------------------------------------------------------------
+
+PRIVATE void
+apply_rxeq_band(REAL lof, REAL dB, REAL hif) {
+ int i,
+ lox = f2x(lof),
+ hix = f2x(hif),
+ l = rx.filt.ovsv->fftlen;
+ REAL g = dB2lin(dB);
+ COMPLEX *src = rx.filt.save,
+ *trg = rx.filt.ovsv->zfvec;
+ for (i = lox; i < hix; i++) {
+ trg[i] = Cscl(src[i], g);
+ if (i) {
+ int j = l - i;
+ trg[j] = Cscl(src[j], g);
+ }
+ }
+}
+
+PRIVATE int
+setRXEQ(int n, char **p) {
+ if (n < 3) {
+ // revert to no EQ
+ memcpy((char *) rx.filt.ovsv->zfvec,
+ (char *) rx.filt.save,
+ rx.filt.ovsv->fftlen * sizeof(COMPLEX));
+ return 0;
+ } else {
+ int i;
+ REAL lof = atof(p[0]);
+ for (i = 0; i < n - 2; i += 2) {
+ REAL dB = atof(p[i + 1]),
+ hif = atof(p[i + 2]);
+ if (lof < 0.0 || hif <= lof) return -1;
+ apply_rxeq_band(lof, dB, hif);
+ lof = hif;
+ }
+ return 0;
+ }
+}
+
+//============================================================
+
+PRIVATE int
+setANFvals(int n, char **p) {
+ int taps = atoi(p[0]),
+ delay = atoi(p[1]);
+ REAL gain = atof(p[2]),
+ leak = atof(p[3]);
+ rx.anf.gen->adaptive_filter_size = taps;
+ rx.anf.gen->delay = delay;
+ rx.anf.gen->adaptation_rate = gain;
+ rx.anf.gen->leakage = leak;
+ return 0;
+}
+
+PRIVATE int
+setNRvals(int n, char **p) {
+ int taps = atoi(p[0]),
+ delay = atoi(p[1]);
+ REAL gain = atof(p[2]),
+ leak = atof(p[3]);
+ rx.anr.gen->adaptive_filter_size = taps;
+ rx.anr.gen->delay = delay;
+ rx.anr.gen->adaptation_rate = gain;
+ rx.anr.gen->leakage = leak;
+ return 0;
+}
+
+PRIVATE int
+setcorrectIQ(int n, char **p) {
+ int phaseadjustment = atoi(p[0]),
+ gainadjustment = atoi(p[1]);
+ rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
+ rx.iqfix->gain = 1.0+ 0.001 * (REAL) gainadjustment;
+ return 0;
+}
+
+PRIVATE int
+setcorrectIQphase(int n, char **p) {
+ int phaseadjustment = atoi(p[0]);
+ rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
+ return 0;
+}
+
+PRIVATE int
+setcorrectIQgain(int n, char **p) {
+ int gainadjustment = atoi(p[0]);
+ rx.iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
+ return 0;
+}
+
+PRIVATE int
+setSquelch(int n, char **p) {
+ rx.squelch.thresh = -atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setMeterOffset(int n, char **p) {
+ rx.squelch.offset.meter = atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setATTOffset(int n, char **p) {
+ rx.squelch.offset.att = atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setGainOffset(int n, char **p) {
+ rx.squelch.offset.gain = atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setSquelchSt(int n, char **p) {
+ rx.squelch.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTRX(int n, char **p) {
+ uni.mode.trx = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setRunState(int n, char **p) {
+ RUNMODE rs = (RUNMODE) atoi(p[0]);
+ top.state = rs;
+ return 0;
+}
+
+PRIVATE int
+setSpotToneVals(int n, char **p) {
+ REAL gain = atof(p[0]),
+ freq = atof(p[1]),
+ rise = atof(p[2]),
+ fall = atof(p[3]);
+ setSpotToneGenVals(rx.spot.gen, gain, freq, rise, fall);
+ return 0;
+}
+
+PRIVATE int
+setSpotTone(int n, char **p) {
+ if (atoi(p[0])) {
+ SpotToneOn(rx.spot.gen);
+ rx.spot.flag = TRUE;
+ } else
+ SpotToneOff(rx.spot.gen);
+ return 0;
+}
+
+PRIVATE int
+setRXPreScl(int n, char **p) {
+ rx.scl.pre.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setRXPreSclVal(int n, char **p) {
+ rx.scl.pre.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setTXPreScl(int n, char **p) {
+ tx.scl.pre.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTXPreSclVal(int n, char **p) {
+ tx.scl.pre.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setRXPostScl(int n, char **p) {
+ rx.scl.post.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setRXPostSclVal(int n, char **p) {
+ rx.scl.post.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setTXPostScl(int n, char **p) {
+ tx.scl.post.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTXPostSclVal(int n, char **p) {
+ tx.scl.post.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setFinished(int n, char **p) {
+ top.running = FALSE;
+ pthread_cancel(top.thrd.trx.id);
+ pthread_cancel(top.thrd.upd.id);
+ pthread_cancel(top.thrd.mon.id);
+ return 0;
+}
+
+// next-trx-mode [nbufs-to-zap]
+PRIVATE int
+setSWCH(int n, char **p) {
+ top.swch.trx.next = atoi(p[0]);
+ if (n > 1) top.swch.bfct.want = atoi(p[1]);
+ else top.swch.bfct.want = 0;
+ top.swch.bfct.have = 0;
+ top.swch.run.last = top.state;
+ top.state = RUN_SWCH;
+ return 0;
+}
+
+PRIVATE int
+setMonDump(int n, char **p) {
+ sem_post(&top.sync.mon.sem);
+ return 0;
+}
+
+PRIVATE int
+setRingBufferReset(int n, char **p) {
+ extern void clear_jack_ringbuffer(jack_ringbuffer_t *rb, int nbytes);
+ jack_ringbuffer_reset(top.jack.ring.i.l);
+ jack_ringbuffer_reset(top.jack.ring.i.r);
+ jack_ringbuffer_reset(top.jack.ring.o.l);
+ jack_ringbuffer_reset(top.jack.ring.o.r);
+ clear_jack_ringbuffer(top.jack.ring.o.l, top.hold.size.bytes);
+ clear_jack_ringbuffer(top.jack.ring.o.r, top.hold.size.bytes);
+ return 0;
+}
+
+//========================================================================
+
+#include <thunk.h>
+
+CTE update_cmds[] = {
+ {"setANF", setANF},
+ {"setANFvals", setANFvals},
+ {"setATTOffset", setATTOffset},
+ {"setBIN", setBIN},
+ {"setFilter", setFilter},
+ {"setFinished", setFinished},
+ {"setGainOffset", setGainOffset},
+ {"setMeterOffset", setMeterOffset},
+ {"setMode", setMode},
+ {"setNB", setNB},
+ {"setNBvals", setNBvals},
+ {"setNR", setNR},
+ {"setNRvals", setNRvals},
+ {"setOsc", setOsc},
+ {"setRXAGC", setRXAGC},
+ {"setRXAGCCompression", setRXAGCCompression},
+ {"setRXAGCHang", setRXAGCHang},
+ {"setRXAGCLimit", setRXAGCLimit},
+ {"setRXEQ", setRXEQ},
+ {"setRXPostScl", setRXPostScl},
+ {"setRXPostSclVal", setRXPostSclVal},
+ {"setRXPreScl", setRXPreScl},
+ {"setRXPreSclVal", setRXPreSclVal},
+ {"setRunState", setRunState},
+ {"setSDROM", setSDROM},
+ {"setSDROMvals",setSDROMvals},
+ {"setSWCH", setSWCH},
+ {"setSampleRate", setSampleRate},
+ {"setSpotTone", setSpotTone},
+ {"setSpotToneVals", setSpotToneVals},
+ {"setSquelch", setSquelch},
+ {"setSquelchSt", setSquelchSt},
+ {"setTRX", setTRX},
+ {"setTXAGC", setTXAGC},
+ {"setTXAGCCompression", setTXAGCCompression},
+ {"setTXAGCFFCompression",setTXAGCFFCompression},
+ {"setTXAGCHang", setTXAGCHang},
+ {"setTXAGCLimit", setTXAGCLimit},
+ {"setTXEQ", setTXEQ},
+ {"setTXPostScl", setTXPostScl},
+ {"setTXPostSclVal", setTXPostSclVal},
+ {"setTXPreScl", setTXPreScl},
+ {"setTXPreSclVal", setTXPreSclVal},
+ {"setTXSpeechCompression", setTXSpeechCompression},
+ {"setTXSpeechCompressionGain", setTXSpeechCompressionGain},
+ {"setcorrectIQ", setcorrectIQ},
+ {"setcorrectIQgain", setcorrectIQgain},
+ {"setcorrectIQphase", setcorrectIQphase},
+ {"setfixedAGC", setfixedAGC},
+ {"setMonDump", setMonDump},
+ {"setRingBufferReset", setRingBufferReset},
+ { 0, 0 }
+};
+
+//........................................................................
+
+int
+do_update(char *str, FILE *log) {
+ SPLIT splt = &uni.update.splt;
+
+ split(splt, str);
+
+ if (NF(splt) < 1) return -1;
+
+ else {
+ Thunk thk = Thunk_lookup(update_cmds, F(splt, 0));
+ if (!thk) return -1;
+ else {
+ int val;
+
+ sem_wait(&top.sync.upd.sem);
+ val = (*thk)(NF(splt) - 1, Fptr(splt, 1));
+ sem_post(&top.sync.upd.sem);
+
+ if (log) {
+ int i;
+ char *s = since(&top.start_tv);
+ fprintf(log, "update[%s]: returned %d from", s, val);
+ for (i = 0; i < NF(splt); i++)
+ fprintf(log, " %s", F(splt, i));
+ putc('\n', log);
+ fflush(log);
+ }
+
+ return val;
+ }
+ }
+}
--- /dev/null
+/* update.h
+
+common defs and code for parm update
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _update_h
+#define _update_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <datatypes.h>
+
+extern int do_update(char *str, FILE *log);
+
+#endif
--- /dev/null
+/* banal.c\r
+\r
+This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807\r
+*/\r
+\r
+#include <fromsys.h>\r
+#include <banal.h>\r
+\r
+int\r
+in_blocks(int count, int block_size) {\r
+ if (block_size < 1) {\r
+ fprintf(stderr, "block_size zero in in_blocks\n");\r
+ exit(1);\r
+ }\r
+ return (1 + ((count - 1) / block_size));\r
+}\r
+\r
+FILE *\r
+efopen(char *path, char *mode) {\r
+ FILE *iop = fopen(path, mode);\r
+ if (!iop) {\r
+ fprintf(stderr, "can't open \"%s\" in mode \"%s\"\n", path, mode);\r
+ exit(1);\r
+ }\r
+ return iop;\r
+}\r
+\r
+FILE *\r
+efreopen(char *path, char *mode, FILE *strm) {\r
+ FILE *iop = freopen(path, mode, strm);\r
+ if (!iop) {\r
+ fprintf(stderr, "can't reopen \"%s\" in mode \"%s\"\n", path, mode);\r
+ exit(1);\r
+ }\r
+ return iop;\r
+}\r
+\r
+size_t\r
+filesize(char *path) {\r
+ struct stat sbuf;\r
+ if (stat(path, &sbuf) == -1) return -1;\r
+ return sbuf.st_size;\r
+}\r
+\r
+size_t\r
+fdsize(int fd) {\r
+ struct stat sbuf;\r
+ if (fstat(fd, &sbuf) == -1) return -1;\r
+ return sbuf.st_size;\r
+}\r
+\r
+#define MILLION (1000000)\r
+#ifndef _WINDOWS\r
+// return current tv\r
+struct timeval\r
+now_tv(void) {\r
+ struct timeval tv;\r
+ gettimeofday(&tv, 0);\r
+ return tv;\r
+}\r
+\r
+// return ta - tb\r
+struct timeval\r
+diff_tv(struct timeval *ta, struct timeval *tb) {\r
+ struct timeval tv;\r
+ if (tb->tv_usec > ta->tv_usec) {\r
+ ta->tv_sec--;\r
+ ta->tv_usec += MILLION;\r
+ }\r
+ tv.tv_sec = ta->tv_sec - tb->tv_sec;\r
+ if ((tv.tv_usec = ta->tv_usec - tb->tv_usec) >= MILLION) {\r
+ tv.tv_usec -= MILLION;\r
+ tv.tv_sec++;\r
+ }\r
+ return tv;\r
+}\r
+\r
+// return ta + tb\r
+struct timeval\r
+sum_tv(struct timeval *ta, struct timeval *tb) {\r
+ struct timeval tv; \r
+ tv.tv_sec = ta->tv_sec + tb->tv_sec;\r
+ if ((tv.tv_usec = ta->tv_usec + tb->tv_usec) >= MILLION) {\r
+ tv.tv_usec -= MILLION;\r
+ tv.tv_sec++;\r
+ }\r
+ return tv;\r
+}\r
+\r
+char *\r
+fmt_tv(struct timeval *tv) {\r
+#ifndef _WINDOWS\r
+ static char buff[256];\r
+ snprintf(buff, sizeof(buff), "%ds%du", tv->tv_sec, tv->tv_usec);\r
+#else\r
+ static char buff[512];\r
+ sprintf(buff, "%ds%du", tv->tv_sec, tv->tv_usec);\r
+#endif\r
+ return buff;\r
+}\r
+\r
+char *\r
+since(struct timeval *tv) {\r
+ struct timeval nt = now_tv(),\r
+ dt = diff_tv(&nt, tv);\r
+ return fmt_tv(&dt);\r
+}\r
+#endif\r
+\r
+int\r
+hinterp_vec(REAL *u, int m, REAL *v, int n) {\r
+ if (!u || !v || (n < 2) || (m < n) || (m % n)) return 0;\r
+ else {\r
+ int div = m / n, i, j = 0;\r
+ for (i = 1; i < n; i++) {\r
+ int k;\r
+ REAL vl = v[i - 1], del = (v[i] - vl) / div;\r
+ u[j++] = vl;\r
+ for (k = 1; k < div; k++) u[j++] = vl + k * del;\r
+ }\r
+ u[j++] = v[n - 1];\r
+ return j;\r
+ }\r
+}\r
--- /dev/null
+/* banal.h\r
+ stuff we're too embarrassed to declare otherwise\r
+ \r
+ This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807\r
+*/\r
+\r
+#ifndef _banal_h\r
+\r
+#define _banal_h\r
+\r
+#include <fromsys.h>\r
+#ifndef min\r
+#define min(a, b) ((a) < (b) ? (a) : (b))\r
+#endif\r
+#ifndef max\r
+#define max(a, b) ((a) > (b) ? (a) : (b))\r
+#endif\r
+#define abs(a) ((a) >= 0 ? (a) : -(a))\r
+\r
+#define MONDO 1e15\r
+#define BITSY 1e-15\r
+\r
+#define TRUE 1\r
+#define FALSE 0\r
+\r
+_inline void\r
+nilfunc(void) {}\r
+\r
+_inline double\r
+sqr(double x) { return x * x; }\r
+\r
+_inline int\r
+popcnt(int k) {\r
+ int c, i;\r
+ c = k & 01;\r
+ for (i = 1; i < 32; i++) c += (k >> i) & 01;\r
+ return c;\r
+}\r
+\r
+_inline int\r
+npoof2(int n) {\r
+ int i = 0;\r
+ --n;\r
+ while (n > 0) n >>= 1, i++;\r
+ return i;\r
+}\r
+\r
+_inline int\r
+nblock2(int n) { return 1 << npoof2(n); }\r
+\r
+extern int in_blocks(int count, int block_size);\r
+extern FILE *efopen(char *path, char *mode);\r
+extern FILE *efreopen(char *path, char *mode, FILE *strm);\r
+extern size_t filesize(char *path);\r
+extern size_t fdsize(int fd);\r
+#ifndef _WINDOWS\r
+extern struct timeval now_tv(void);\r
+extern struct timeval diff_tv(struct timeval *, struct timeval *);\r
+extern struct timeval sum_tv(struct timeval *, struct timeval *);\r
+extern char *fmt_tv(struct timeval *);\r
+extern char *since(struct timeval *);\r
+extern struct timeval now_tv(void);\r
+#endif\r
+extern int hinterp_vec(REAL *, int, REAL *, int);\r
+#endif\r
+\r
+\r
--- /dev/null
+/* chan.c\r
+\r
+fast inter-user-process single-reader/single-writer channels\r
+using a modified version of jack ringbuffers and memory-mapped files.\r
+ \r
+This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807 \r
+*/\r
+\r
+#include <chan.h>\r
+\r
+//------------------------------------------------------------------------\r
+\r
+size_t\r
+putChan(Chan c, char *data, size_t size) {\r
+ return ringb_write(c->rb, data, size);\r
+}\r
+\r
+size_t\r
+getChan(Chan c, char *data, size_t size) {\r
+ return ringb_read(c->rb, data, size);\r
+}\r
+\r
+BOOLEAN\r
+putChan_nowait(Chan c, char *data, size_t size) {\r
+ if (ringb_write_space(c->rb) >= size) {\r
+ ringb_write(c->rb, data, size);\r
+ return TRUE;\r
+ } else return FALSE;\r
+}\r
+\r
+BOOLEAN\r
+getChan_nowait(Chan c, char *data, size_t size) {\r
+ if (ringb_read_space(c->rb) >= size) {\r
+ ringb_read(c->rb, data, size);\r
+ return TRUE;\r
+ } else return FALSE;\r
+}\r
+\r
+Chan\r
+openChan(char *path,size_t want) {\r
+ Chan c = (Chan) safealloc(sizeof(ChanDesc), 1, "Chan header");\r
+ c->size.rib = sizeof(ringb_t);\r
+ c->size.buf = (size_t) nblock2((int) want);\r
+#ifndef _WINDOWS\r
+ c->file.path = path;\r
+ if ((c->file.desc = open(c->file.path, O_RDWR)) == -1) {\r
+ fprintf(stderr, "can't open Chan file %s\n", c->file.path);\r
+ exit(1);\r
+ }\r
+ c->size.tot = c->size.rib + c->size.buf;\r
+ if ((c->size.tru = fdsize(c->file.desc)) < c->size.tot) {\r
+ fprintf(stderr,\r
+ "Chan file %s is too small (%d) for required size (%s)\n",\r
+ c->file.path, c->size.tru, c->size.tot);\r
+ exit(1);\r
+ }\r
+ if (!(c->map.base = (char *) mmap(0,\r
+ c->size.tot,\r
+ PROT_READ | PROT_WRITE,\r
+ MAP_SHARED,\r
+ c->file.desc,\r
+ 0))) {\r
+ fprintf(stderr, "can't memory map %s for Chan\n",\r
+ c->file.path);\r
+ exit(1);\r
+ }\r
+#endif\r
+ if (!(c->rb = ringb_create(c->size.buf))) {\r
+ fprintf(stderr, "can't make RB for Chan\n");\r
+ exit(1);\r
+ }\r
+ return c;\r
+}\r
+\r
+void\r
+closeChan(Chan c) {\r
+ if (c) {\r
+#ifndef _WINDOWS\r
+ munmap(c->map.base, c->size.tot);\r
+ close(c->file.desc);\r
+#endif\r
+ ringb_destroy(c->rb);\r
+ safefree((char *) c);\r
+ }\r
+}\r
--- /dev/null
+/* chan.h\r
+\r
+fast inter-user-process single-reader/single-writer channels\r
+using a modified version of jack ringbuffers and memory-mapped files.\r
+\r
+This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807\r
+*/\r
+\r
+#ifndef _chan_h\r
+#define _chan_h\r
+\r
+#include <sys/types.h>\r
+#include <stdlib.h>\r
+#include <banal.h>\r
+#include <bufvec.h>\r
+#ifndef _WINDOWS\r
+#include <values.h>\r
+#else\r
+#include <windows.h>\r
+#endif\r
+#include <stdio.h>\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include <ringb.h>\r
+\r
+\r
+typedef\r
+struct _chan {\r
+ struct {\r
+ size_t buf, rib, tot, tru;\r
+ } size;\r
+ struct {\r
+ char *path;\r
+ int desc;\r
+ } file;\r
+ struct {\r
+ char *base;\r
+ } map;\r
+ ringb_t *rb;\r
+} ChanDesc, *Chan;\r
+\r
+extern size_t putChan(Chan c, char *data, size_t size);\r
+extern size_t getChan(Chan c, char *data, size_t size);\r
+extern BOOLEAN putChan_nowait(Chan c, char *data, size_t size);\r
+extern BOOLEAN getChan_nowait(Chan c, char *data, size_t size);\r
+extern Chan openChan(char *path,size_t want);\r
+extern void closeChan(Chan c);\r
+\r
+#endif\r
--- /dev/null
+/* common.h\r
+a simple way to get all the necessary includes\r
+ \r
+This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807\r
+*/\r
+\r
+#ifndef _common_h\r
+\r
+#define _common_h\r
+\r
+#include <fromsys.h>\r
+#include <banal.h>\r
+#include <splitfields.h>\r
+#include <datatypes.h>\r
+#include <bufvec.h>\r
+#include <cxops.h>\r
+#include <ringb.h>\r
+#include <chan.h>\r
+#include <fft.h>\r
+#include <lmadf.h>\r
+#include <fftw.h>\r
+#include <ovsv.h>\r
+#include <filter.h>\r
+#include <oscillator.h>\r
+#include <digitalagc.h>\r
+#include <am_demod.h>\r
+#include <fm_demod.h>\r
+#include <noiseblanker.h>\r
+#include <correctIQ.h>\r
+#include <crc16.h>\r
+#include <speechproc.h>\r
+#include <spottone.h>\r
+#include <update.h>\r
+#include <power_spectrum.h>\r
+#include <meter.h>\r
+#ifdef _WINDOWS\r
+#include <ringb.h>\r
+#include <windows.h>\r
+typedef long pid_t;\r
+typedef long uid_t;\r
+typedef LPDWORD pthread_t;\r
+typedef HANDLE sem_t;\r
+#define DLLVERS\r
+//#define PROCESSVERS\r
+#define NEWSPLIT\r
+#endif\r
+\r
+#include <sdrexport.h>\r
+#endif\r
+\r
--- /dev/null
+/* datatypes.h\r
+ local definitions and aliases for our data\r
+This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807\r
+*/\r
+\r
+#ifndef _datatypes_h\r
+\r
+#define _datatypes_h\r
+\r
+#include <fromsys.h>\r
+#include <banal.h>\r
+#ifndef _WINDOWS\r
+typedef int BOOLEAN;\r
+#else\r
+typedef unsigned char BOOLEAN;\r
+#endif\r
+typedef double REAL;\r
+typedef double IMAG;\r
+typedef short SAMPLE_16t;\r
+\r
+#include <complex.h>\r
+\r
+#ifndef PRIVATE\r
+#define PRIVATE static\r
+#endif\r
+\r
+#endif\r
+\r
--- /dev/null
+/* fromsys.h\r
+ stuff we need to import everywhere \r
+ This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807\r
+*/\r
+\r
+#ifndef _fromsys_h\r
+#define _fromsys_h\r
+#ifndef _WINDOWS \r
+\r
+#include <sys/types.h>\r
+#include <sys/param.h>\r
+#include <sys/stat.h>\r
+#include <sys/time.h>\r
+#include <sys/wait.h> \r
+#include <sys/mman.h>\r
+#include <sys/ioctl.h>\r
+#include <sys/socket.h> \r
+#include <signal.h>\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+#include <setjmp.h>\r
+\r
+#include <stdlib.h>\r
+#include <values.h>\r
+#include <stdio.h>\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include <math.h>\r
+#include <assert.h>\r
+#include <libgen.h>\r
+\r
+#include <pthread.h>\r
+#include <semaphore.h>\r
+\r
+#include <jack/jack.h>\r
+#include <jack/ringbuffer.h>\r
+#define DttSP_EXP\r
+\r
+#else\r
+\r
+#include <sys/types.h>\r
+//#include <sys/param.h> // WINBLOWS\r
+#define MAXPATHLEN (260-1 /* NULL */)\r
+#include <sys/stat.h>\r
+#include <time.h>\r
+//#include <unistd.h>\r
+#include <fcntl.h>\r
+\r
+#include <stdlib.h>\r
+#include <windows.h>\r
+#include <stdio.h>\r
+#include <ctype.h>\r
+#include <string.h>\r
+#include <math.h>\r
+#ifndef M_PI\r
+#define M_PI 3.14159265358928\r
+#endif\r
+#include <assert.h>\r
+#define DttSP_EXP __declspec(dllexport)\r
+#define DttSP_IMP __declspec(dllimport)\r
+\r
+#define sem_wait(p) WaitForSingleObject(p,INFINITE)\r
+#define sem_post(p) ReleaseSemaphore(p,1,NULL);\r
+#define pthread_exit(p) ExitThread((DWORD)p)\r
+\r
+#endif // _WINDOWS\r
+#endif // _fromsys_h\r
--- /dev/null
+/* main.c
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+/////////////////////////////////////////////////////////////////////////
+extern void process_samples(float *, float *, int);
+extern void setup_workspace(void);
+
+#ifdef _WINDOWS
+
+#define PARMPATH NULL
+#define RINGMULT (4)
+#define METERPATH NULL
+#define METERMULT (2)
+#define PWSPATH NULL
+#define PWSMULT (32768)
+#define TEST
+
+#else
+
+#define PARMPATH "./IPC/SDR-1000-0-commands.fifo"
+#define RINGMULT (4)
+#define METERPATH "./IPC/SDR-1000-0-meter.chan"
+#define METERMULT (2)
+#define PWSPATH "./IPC/SDR-1000-0-pws.chan"
+#define PWSMULT (32768)
+
+#endif
+//------------------------------------------------------------------------
+
+#ifdef _WINDOWS
+PRIVATE DWORD WINAPI
+process_updates_thread(void) {
+ size_t tmp;
+ while (top.running) {
+ while (newupdates()) {
+ tmp = ringb_read_space(uni.update.chan.c->rb);
+ getChan_nowait(uni.update.chan.c, top.parm.buff, tmp);
+ do_update(top.parm.buff);
+ }
+ }
+ ExitThread(0);
+}
+
+//========================================================================
+
+PRIVATE void
+gethold(void) {
+ ringb_write(top.jack.ring.o.l, (char *) top.hold.buf.l, top.hold.size.bytes);
+ ringb_write(top.jack.ring.o.r, (char *) top.hold.buf.r, top.hold.size.bytes);
+ ringb_read(top.jack.ring.i.l, (char *) top.hold.buf.l, top.hold.size.bytes);
+ ringb_read(top.jack.ring.i.r, (char *) top.hold.buf.r, top.hold.size.bytes);
+}
+
+PRIVATE BOOLEAN canhold(void) {
+ return ringb_read_space(top.jack.ring.i.l) >= top.hold.size.bytes;
+}
+
+
+#else
+
+//========================================================================
+
+PRIVATE void
+process_updates_thread(void) {
+ while (top.running) {
+ while (fgets(top.parm.buff, sizeof(top.parm.buff), top.parm.fp))
+ do_update(top.parm.buff, top.verbose ? stderr : 0);
+ }
+ pthread_exit(0);
+}
+
+PRIVATE void
+gethold(void) {
+ jack_ringbuffer_write(top.jack.ring.o.l, (char *) top.hold.buf.l, top.hold.size.bytes);
+ jack_ringbuffer_write(top.jack.ring.o.r, (char *) top.hold.buf.r, top.hold.size.bytes);
+ jack_ringbuffer_read(top.jack.ring.i.l, (char *) top.hold.buf.l, top.hold.size.bytes);
+ jack_ringbuffer_read(top.jack.ring.i.r, (char *) top.hold.buf.r, top.hold.size.bytes);
+}
+
+PRIVATE BOOLEAN canhold(void) {
+ return jack_ringbuffer_read_space(top.jack.ring.i.l) >= top.hold.size.bytes;
+}
+
+#endif
+
+PRIVATE void
+run_mute(void) {
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+}
+
+PRIVATE void
+run_pass(void) {}
+
+PRIVATE void
+run_play(void) {
+ process_samples(top.hold.buf.l, top.hold.buf.r, top.hold.size.frames);
+}
+
+// NB do not set RUN_SWCH directly via setRunState;
+// use setSWCH instead
+
+PRIVATE void
+run_swch(void) {
+ if (top.swch.bfct.have == 0) {
+ // first time
+ // apply ramp down
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) 1.0 - (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ memset((char *) (top.hold.buf.l + m), 0, n);
+ memset((char *) (top.hold.buf.r + m), 0, n);
+ top.swch.bfct.have++;
+ } else if (top.swch.bfct.have < top.swch.bfct.want) {
+ // in medias res
+ memset((char *) top.hold.buf.l, 0, top.hold.size.bytes);
+ memset((char *) top.hold.buf.r, 0, top.hold.size.bytes);
+ top.swch.bfct.have++;
+ } else {
+ // last time
+ // apply ramp up
+ int i, m = top.swch.fade, n = top.swch.tail;
+ for (i = 0; i < m; i++) {
+ float w = (float) i / m;
+ top.hold.buf.l[i] *= w, top.hold.buf.r[i] *= w;
+ }
+ uni.mode.trx = top.swch.trx.next;
+ top.state = top.swch.run.last;
+ top.swch.bfct.want = top.swch.bfct.have = 0;
+ }
+
+ process_samples(top.hold.buf.l, top.hold.buf.r, top.hold.size.frames);
+}
+
+//========================================================================
+
+#ifdef _WINDOWS
+
+static int exchptr = 0;
+DttSP_EXP void
+exchange_samples(float *input, float *output, int nframes) {
+ int i, j;
+ for (i = 0, j = 0; i < nframes; i++, j += 2) {
+ ringb_read(top.jack.ring.o.l, (char *) &output[j], sizeof(float));
+ ringb_read(top.jack.ring.o.r, (char *) &output[j + 1], sizeof(float));
+ ringb_write(top.jack.ring.i.l, (char *) &input[j], sizeof(float));
+ ringb_write(top.jack.ring.i.r, (char *) &input[j + 1], sizeof(float));
+ }
+ if (ringb_read_space(top.jack.ring.i.l) >= top.hold.size.bytes)
+ ReleaseSemaphore(top.sync.buf.sem, 1L, NULL);
+}
+
+DttSP_EXP void
+audioreset(void) { exchptr = 0; }
+
+PRIVATE DWORD WINAPI
+process_samples_thread(void) {
+ while (top.running) {
+ WaitForSingleObject(top.sync.buf.sem, INFINITE);
+ WaitForSingleObject(top.sync.upd.sem, INFINITE);
+ do {
+ gethold();
+ switch (top.state) {
+ case RUN_MUTE:
+ run_mute();
+ break;
+ case RUN_PASS:
+ run_pass();
+ break;
+ case RUN_PLAY:
+ run_play();
+ break;
+ case RUN_SWCH:
+ run_swch();
+ break;
+ }
+ } while (canhold());
+ ReleaseSemaphore(top.sync.upd.sem, 1L, NULL);
+ }
+ ExitThread(0);
+ return 1;
+}
+
+#else /* */
+
+PRIVATE void
+audio_callback(jack_nframes_t nframes, void *arg) {
+ float *lp, *rp;
+ int nbytes = nframes * sizeof(float);
+
+ // output: copy from ring to port
+ lp = (float *) jack_port_get_buffer(top.jack.port.o.l, nframes);
+ rp = (float *) jack_port_get_buffer(top.jack.port.o.r, nframes);
+ jack_ringbuffer_read(top.jack.ring.o.l, (char *) lp, nbytes);
+ jack_ringbuffer_read(top.jack.ring.o.r, (char *) rp, nbytes);
+
+ // input: copy from port to ring
+ lp = (float *) jack_port_get_buffer(top.jack.port.i.l, nframes);
+ rp = (float *) jack_port_get_buffer(top.jack.port.i.r, nframes);
+ jack_ringbuffer_write(top.jack.ring.i.l, (char *) lp, nbytes);
+ jack_ringbuffer_write(top.jack.ring.i.r, (char *) rp, nbytes);
+
+ // if enough accumulated in ring, fire dsp
+ if (jack_ringbuffer_read_space(top.jack.ring.i.l) >= top.hold.size.bytes)
+ sem_post(&top.sync.buf.sem);
+}
+
+PRIVATE void
+process_samples_thread(void) {
+ while (top.running) {
+ sem_wait(&top.sync.buf.sem);
+ do {
+ gethold();
+ sem_wait(&top.sync.upd.sem);
+ switch (top.state) {
+ case RUN_MUTE:
+ run_mute();
+ break;
+ case RUN_PASS:
+ run_pass();
+ break;
+ case RUN_PLAY:
+ run_play();
+ break;
+ case RUN_SWCH:
+ run_swch();
+ break;
+ }
+ sem_post(&top.sync.upd.sem);
+ } while (canhold());
+ }
+ pthread_exit(0);
+}
+
+#endif
+
+//========================================================================
+
+#ifdef _WINDOWS
+DttSP_EXP void
+execute(void) {
+ ResumeThread(top.thrd.trx.thrd);
+}
+
+DttSP_EXP void
+closeup(void) {
+ extern void destroy_workspace();
+ TerminateThread(top.thrd.trx.thrd, 0L);
+ CloseHandle(top.thrd.trx.thrd);
+ CloseHandle(top.thrd.upd.thrd);
+ CloseHandle(top.sync.buf.sem);
+ CloseHandle(top.sync.upd.sem);
+ destroy_workspace();
+}
+
+#else
+
+PRIVATE void
+execute(void) {
+ sem_post(&top.sync.upd.sem);
+
+ // start audio processing
+ if (jack_activate(top.jack.client))
+ perror("cannot activate jack client"), exit(1);
+
+ // wait for threads to terminate
+ pthread_join(top.thrd.trx.id, 0);
+ pthread_join(top.thrd.upd.id, 0);
+
+ // stop audio processing
+ jack_client_close(top.jack.client);
+}
+
+PRIVATE void
+closeup(void) { exit(0); }
+
+PRIVATE void
+usage(void) {
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, "-m\n");
+ fprintf(stderr, "-v\n");
+ exit(1);
+}
+
+PRIVATE void
+nonblock(int fd) {
+ long arg;
+ arg = fcntl(fd, F_GETFL);
+ arg |= O_NONBLOCK;
+/* if (fcntl(fd, F_GETFL, &arg) >= 0)
+ fcntl(fd, F_SETFL, arg | O_NONBLOCK); */
+ fcntl(fd, F_SETFL, arg);
+}
+
+#endif
+
+//........................................................................
+
+PRIVATE void
+setup_meter(void) {
+ uni.meter.flag = TRUE;
+ uni.meter.chan.path = METERPATH;
+ uni.meter.chan.size = METERMULT * sizeof(REAL);
+ uni.meter.val = -200.0;
+ uni.meter.chan.c = openChan(uni.meter.chan.path, uni.meter.chan.size);
+}
+
+PRIVATE void
+setup_powerspectrum(void) {
+ uni.powsp.flag = TRUE;
+ uni.powsp.chan.path = PWSPATH;
+ uni.powsp.chan.size = 8192 * sizeof(COMPLEX);
+ uni.powsp.buf = newCXB(4096, NULL, "PowerSpectrum Chan Buffer");
+ uni.powsp.fftsize = 4096;
+ uni.powsp.chan.c = openChan(uni.powsp.chan.path, uni.powsp.chan.size);
+}
+
+PRIVATE void
+setup_switching(void) {
+ top.swch.fade = (int) (0.1 * uni.buflen + 0.5);
+ top.swch.tail = (top.hold.size.frames - top.swch.fade) * sizeof(float);
+}
+
+PRIVATE void
+setup_local_audio(void) {
+ top.hold.size.frames = uni.buflen;
+ top.hold.size.bytes = top.hold.size.frames * sizeof(float);
+ top.hold.buf.l = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer left");
+ top.hold.buf.r = (float *) safealloc(top.hold.size.frames, sizeof(float),
+ "main hold buffer right");
+}
+
+#ifdef _WINDOWS
+
+PRIVATE void
+setup_updates(void) {
+ uni.update.flag = TRUE;
+ uni.update.chan.path = NULL;
+ uni.update.chan.size = 4096;
+ uni.update.chan.c = openChan(uni.update.chan.path, uni.update.chan.size);
+} PRIVATE void
+
+setup_system_audio(void) {
+ sprintf(top.jack.name, "sdr-%d", top.pid);
+ top.jack.ring.i.l = ringb_create(top.hold.size.bytes * RINGMULT);
+ top.jack.ring.i.r = ringb_create(top.hold.size.bytes * RINGMULT);
+ top.jack.ring.o.l = ringb_create(top.hold.size.bytes * RINGMULT);
+ top.jack.ring.o.r = ringb_create(top.hold.size.bytes * RINGMULT);
+ {
+ unsigned int i;
+ char zero = 0;
+ for (i = 0; i < top.hold.size.bytes; i++) {
+ ringb_write(top.jack.ring.o.l, &zero, 1);
+ ringb_write(top.jack.ring.o.r, &zero, 1);
+ }
+ }
+}
+
+DttSP_EXP void
+release_update(void) {}
+
+DttSP_EXP void
+suspend_sdr(void) { SuspendThread(top.thrd.trx.thrd); }
+
+PRIVATE void
+setup_threading(void) {
+ top.sync.upd.sem = CreateSemaphore(NULL, 1L, 1L, "UpdateSemaphore");
+ top.sync.buf.sem = CreateSemaphore(NULL, 0L, 1L, "Process Samples Semaphore");
+ top.thrd.trx.thrd = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0L, process_samples_thread,
+ NULL, CREATE_SUSPENDED, &top.thrd.trx.id);
+ SetThreadPriority(top.thrd.trx.thrd, THREAD_PRIORITY_HIGHEST);
+}
+
+DttSP_EXP void
+setup_sdr(void) {
+ top.pid = GetCurrentThreadId();
+ top.uid = 0L;
+ top.running = TRUE;
+ top.state = RUN_PLAY;
+ setup_meter();
+ setup_powerspectrum();
+ setup_updates();
+ uni.meter.flag = TRUE;
+ top.verbose = FALSE;
+ setup_workspace();
+ setup_local_audio();
+ setup_system_audio();
+ setup_threading();
+ setup_switching();
+}
+
+#else
+
+PRIVATE void
+setup_updates(void) {
+ top.parm.path = PARMPATH;
+ if ((top.parm.fd = open(top.parm.path, O_RDWR)) == -1)
+ perror(top.parm.path), exit(1);
+ if (!(top.parm.fp = fdopen(top.parm.fd, "r+"))) {
+ fprintf(stderr, "can't fdopen parm pipe %s\n", PARMPATH);
+ exit(1);
+ }
+}
+
+PRIVATE void
+setup_system_audio(void) {
+ sprintf(top.jack.name, "sdr-%d", top.pid);
+ if (!(top.jack.client = jack_client_new(top.jack.name)))
+ perror("can't make client -- jack not running?"), exit(1);
+ jack_set_process_callback(top.jack.client, (void *) audio_callback, 0);
+ top.jack.port.i.l = jack_port_register(top.jack.client,
+ "il",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput,
+ 0);
+ top.jack.port.i.r = jack_port_register(top.jack.client,
+ "ir",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput,
+ 0);
+ top.jack.port.o.l = jack_port_register(top.jack.client,
+ "ol",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ top.jack.port.o.r = jack_port_register(top.jack.client,
+ "or",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ top.jack.ring.i.l = jack_ringbuffer_create(top.hold.size.bytes * RINGMULT);
+ top.jack.ring.i.r = jack_ringbuffer_create(top.hold.size.bytes * RINGMULT);
+ top.jack.ring.o.l = jack_ringbuffer_create(top.hold.size.bytes * RINGMULT);
+ top.jack.ring.o.r = jack_ringbuffer_create(top.hold.size.bytes * RINGMULT);
+ {
+ int i;
+ char zero = 0;
+ for (i = 0; i < top.hold.size.bytes * RINGMULT / 2; i++) {
+ jack_ringbuffer_write(top.jack.ring.o.l, &zero, 1);
+ jack_ringbuffer_write(top.jack.ring.o.r, &zero, 1);
+ }
+ }
+}
+
+PRIVATE void
+setup_threading(void) {
+ sem_init(&top.sync.upd.sem, 0, 0);
+ pthread_create(&top.thrd.upd.id, NULL, (void *) process_updates_thread, NULL);
+ sem_init(&top.sync.buf.sem, 0, 0);
+ pthread_create(&top.thrd.trx.id, NULL, (void *) process_samples_thread, NULL);
+}
+
+//========================================================================
+
+PRIVATE void
+setup(int argc, char **argv) {
+ int i;
+ top.pid = getpid();
+ top.uid = getuid();
+ top.start_tv = now_tv();
+ top.running = TRUE;
+ top.verbose = FALSE;
+ top.state = RUN_PLAY;
+ setup_meter();
+ setup_updates();
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1]) {
+ case 'm':
+ uni.meter.flag = TRUE;
+ break;
+ case 'v':
+ top.verbose = TRUE;
+ break;
+ default:
+ usage();
+ }
+ else break;
+ if (i < argc) {
+ if (!freopen(argv[i], "r", stdin))
+ perror(argv[i]), exit(1);
+ i++;
+ }
+ setup_workspace();
+ setup_local_audio();
+ setup_system_audio();
+ setup_threading();
+ setup_switching();
+}
+
+
+//========================================================================
+
+int
+main(int argc, char **argv) {
+ setup(argc, argv), execute(), closeup();
+}
+
+#endif
--- /dev/null
+#include <common.h>
+#ifdef _WINDOWS
+
+DttSP_EXP float
+calculate_meters(METERTYPE mt) {
+ float result;
+ REAL tmp;
+ uni.meter.type = mt;
+ if (getChan_nowait(uni.meter.chan.c, (char *) &tmp, sizeof(REAL)) != 0)
+ uni.meter.val = tmp;
+ result = (float) uni.meter.val;
+ return result;
+}
+
+#endif
--- /dev/null
+#include <common.h>
+
+#ifdef _WINDOWS
+
+PWS
+newPowerSpectrum(int size, SPECTRUMTYPE type) {
+ PWS p = (PWS) safealloc(1, sizeof(powerspectrum), "New Power Spectrum");
+
+ p->buf.win = newRLB(size, NULL, "Power Spectrum Window Buffer");
+ p->buf.res = newRLB(32768, NULL, "Save buffer");
+ p->buf.wdat = newCXB(size, NULL, "Power Spectrum Windowed Signal buffer");
+ p->buf.zdat = newCXB(size, NULL, "Power Spectrum FFT Results Buffer");
+ p->fft.size = size;
+ p->flav.spec = type;
+
+ makewindow(BLACKMANHARRIS_WINDOW, size, RLBbase(p->buf.win));
+
+#ifdef notdef
+ {
+ REAL *tmp = (REAL *) alloca(size * sizeof(REAL));
+ int n = size / 2, nb = n * sizeof(REAL);
+ memcpy(&tmp[n], RLBbase(p->buf.win), nb);
+ memcpy(tmp, &RLBdata(p->buf.win, n), nb);
+ }
+#endif
+
+ p->fft.plan = fftw_create_plan(size, FFTW_FORWARD, uni.wisdom.bits);
+
+ return p;
+}
+
+void
+delPowerSpectrum(PWS pws) {
+ delCXB(pws->buf.wdat);
+ delCXB(pws->buf.zdat);
+ delRLB(pws->buf.win);
+ delRLB(pws->buf.win2);
+ fftw_destroy_plan(pws->fft.plan);
+ safefree((char *) pws);
+}
+
+DttSP_EXP BOOLEAN
+process_spectrum(float *results) {
+ int i, j, n = CXBsize(uni.powsp.buf);
+
+ if (getChan_nowait(uni.powsp.chan.c,
+ (char *) CXBbase(uni.powsp.buf),
+ uni.powsp.fft.size * sizeof(COMPLEX))
+ == TRUE) {
+
+ // Window the data to minimize "splatter" in the powerspectrum
+ for (i = 0; i < uni.powsp.fft.size; i++)
+ CXBdata(uni.powsp.gen->buf.wdat, i) = Cscl(CXBdata(uni.powsp.buf, i),
+ RLBdata(uni.powsp.gen->buf.win, i));
+
+ // Compute the FFT
+ fftw_one(uni.powsp.gen->fft.plan,
+ (fftw_complex *) CXBbase(uni.powsp.gen->buf.wdat),
+ (fftw_complex *) CXBbase(uni.powsp.gen->buf.zdat));
+ for (i = 0; i < n / 2; i++) {
+ RLBdata(uni.powsp.gen->buf.res, 8 * i) =
+ results[8 * i] =
+ (float) (10.0 *
+ log10(1e-160 +
+ Csqrmag(CXBdata(uni.powsp.gen->buf.zdat,
+ (i + uni.buflen)))));
+ RLBdata(uni.powsp.gen->buf.res, 8 * (i + uni.buflen)) =
+ results[8 * (i + uni.buflen)] =
+ (float) (10.0 *
+ log10(1e-160 +
+ Csqrmag(CXBdata(uni.powsp.gen->buf.zdat, i))));
+ }
+
+ // Interpolate for display on high resolution monitors
+
+ for (i = 0; i < 32768; i += 8)
+ for (j = 1; j < 8; j++)
+ RLBdata(uni.powsp.gen->buf.res, i + j) =
+ results[i + j] = (float) 0.125 * (results[i] * (float) (8 - j)
+ + results[i + 8] * (float) j);
+ return TRUE;
+ } else {
+ for (i = 0; i < 32768; i++)
+ results[i] = (float) RLBdata(uni.powsp.gen->buf.res, i);
+ return FALSE;
+ }
+}
+
+DttSP_EXP BOOLEAN
+process_phase(float *results, int numpoints) {
+ int i, j;
+ if (getChan_nowait(uni.powsp.chan.c,
+ (char *) CXBbase(uni.powsp.buf),
+ uni.powsp.fft.size * sizeof(COMPLEX))
+ == TRUE) {
+ for (i = 0, j = 0; i < numpoints; i++, j += 2) {
+ RLBdata(uni.powsp.gen->buf.res, j) =
+ results[j] = (float) CXBreal(uni.powsp.buf, i);
+ RLBdata(uni.powsp.gen->buf.res, j + 1) =
+ results[j + 1] = (float) CXBimag(uni.powsp.buf, i);
+ } return TRUE;
+ } else {
+ for (i = 0; i < 2 * numpoints; i++)
+ results[i] = (float) RLBdata(uni.powsp.gen->buf.res, i);
+ return FALSE;
+ }
+}
+
+// Send out Real Signal, reals only
+
+DttSP_EXP BOOLEAN
+process_scope(float *results) {
+ int i;
+ if (getChan_nowait(uni.powsp.chan.c,
+ (char *) CXBbase(uni.powsp.buf),
+ uni.powsp.fft.size * sizeof(COMPLEX))
+ == TRUE) {
+ for (i = 0; i < uni.powsp.fft.size; i++) {
+ results[i] = (float) CXBreal(uni.powsp.buf, i);
+ } return TRUE;
+ } else {
+ for (i = 0; i < uni.powsp.fft.size; i++)
+ results[i] = (float) CXBreal(uni.powsp.buf, i);
+ return FALSE;
+ }
+}
+
+#endif
--- /dev/null
+#ifndef _power_spectrum_h
+#define _power_spectrum_h
+
+#include <fftw.h>
+#include <complex.h>
+#include <bufvec.h>
+
+#ifndef _PWSMODE
+#define _PWSMODE
+
+typedef enum { MAG, DB } SPECTRUMTYPE;
+
+typedef enum _powerspectrummode {
+ POSTFILTER, PREFILTER, AUDIO
+} PWSMODE;
+
+typedef enum _pws_submode {
+ OFF, SPECTRUM, PANADAPTER, SCOPE, PHASE, PHASE2, WATERFALL, HISTOGRAM
+} PWSSUBMODE;
+
+typedef struct _powerspectrum {
+ struct {
+ int size;
+ fftw_plan plan;
+ } fft;
+ RLB WindowBuf, WindowBuf2, results;
+ CXB WindowedDataBuf, PowerSpectrumFFTresults;
+ struct {
+ RLB win, res;
+ CXB wdat, zdat;
+ } buf;
+ struct {
+ PWSMODE main;
+ PWSSUBMODE sub;
+ SPECTRUMTYPE spec;
+ } flav;
+} *PWS, powerspectrum;
+
+typedef struct _powerspectrum {
+ fftw_plan pwrspecfft;
+ int fftsize;
+ RLB WindowBuf, WindowBuf2, results;
+ CXB WindowedDataBuf, PowerSpectrumFFTresults;
+ PWSMODE Mode;
+ PWSSUBMODE SubMode;
+ SPECTRUMTYPE SpectrumType;
+} *PWS, powerspectrum;
+
+extern PWS newPowerSpectrum(int size, SPECTRUMTYPE SpectrumType);
+extern void delPowerSpectrum(PWS pws);
+extern void process_powerspectrum(float *results, int numpoints);
+
+#endif
--- /dev/null
+/* sdrexport.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _sdrexport_h
+#define _sdrexport_h
+
+#include <common.h>
+//------------------------------------------------------------------------
+/* modulation types, modes */
+typedef enum _sdrmode {
+ LSB, // 0
+ USB, // 1
+ DSB, // 2
+ CWL, // 3
+ CWU, // 4
+ FMN, // 5
+ AM, // 6
+ PSK, // 7
+ SPEC, // 8
+ RTTY, // 9
+ SAM, // 10
+ DRM // 11
+} SDRMODE;
+typedef enum _trxmode { RX, TX } TRXMODE;
+
+//========================================================================
+/* RX/TX both */
+//------------------------------------------------------------------------
+extern struct _uni {
+ REAL samplerate;
+ int buflen;
+
+ struct {
+ SDRMODE sdr;
+ TRXMODE trx;
+ } mode;
+
+ struct {
+ BOOLEAN flag;
+ struct {
+ char *path;
+ size_t size;
+ Chan c;
+ } chan;
+ REAL val, avgval;
+ METERTYPE type;
+ } meter;
+
+ struct {
+ BOOLEAN flag;
+ PWS gen;
+ struct {
+ char *path;
+ size_t size;
+ Chan c;
+ } chan;
+ CXB buf;
+ int fftsize;
+ } powsp;
+
+ struct {
+ BOOLEAN flag;
+ struct {
+ char *path;
+ size_t size;
+ Chan c;
+ } chan;
+ splitfld splt;
+ } update;
+
+ struct {
+ char *path;
+ int bits;
+ } wisdom;
+
+} uni;
+
+//------------------------------------------------------------------------
+/* RX */
+//------------------------------------------------------------------------
+extern struct _rx {
+ struct {
+ CXB i, o;
+ } buf;
+ struct {
+ REAL freq, phase;
+ OSC gen;
+ } osc;
+ struct {
+ ComplexFIR coef;
+ FiltOvSv ovsv;
+ COMPLEX * save;
+ } filt;
+ IQ iqfix;
+ struct {
+ REAL thresh;
+ NB gen;
+ BOOLEAN flag;
+ } nb;
+ struct {
+ REAL thresh;
+ NB gen;
+ BOOLEAN flag;
+ } nb_sdrom;
+ struct {
+ LMSR gen;
+ BOOLEAN flag;
+ } anr, anf;
+ struct {
+ DIGITALAGC gen;
+ BOOLEAN flag;
+ } agc;
+ struct { AMD gen; } am;
+ struct { FMD gen; } fm;
+ struct {
+ BOOLEAN flag;
+ SpotToneGen gen;
+ } spot;
+ struct {
+ struct {
+ REAL val;
+ BOOLEAN flag;
+ } pre, post;
+ } scl;
+ struct {
+ REAL thresh, power;
+ struct {
+ REAL meter, att, gain;
+ } offset;
+ BOOLEAN flag, running, set;
+ int num;
+ } squelch;
+ SDRMODE mode;
+ struct { BOOLEAN flag; } bin;
+} rx;
+
+//------------------------------------------------------------------------
+/* TX */
+//------------------------------------------------------------------------
+extern struct _tx {
+ struct {
+ CXB i, o;
+ } buf;
+ struct {
+ REAL freq, phase;
+ OSC gen;
+ } osc;
+ struct {
+ ComplexFIR coef;
+ FiltOvSv ovsv;
+ COMPLEX * save;
+ } filt;
+ struct {
+ ComplexFIR coef;
+ FiltOvSv ovsv;
+ CXB in, out;
+ } fm;
+ struct {
+ DIGITALAGC gen;
+ BOOLEAN flag;
+ } agc;
+ struct {
+ SpeechProc gen;
+ BOOLEAN flag;
+ } spr;
+ struct {
+ COMPLEX dc;
+ struct {
+ REAL val;
+ BOOLEAN flag;
+ } pre, post;
+ } scl;
+ SDRMODE mode;
+} tx;
+
+//------------------------------------------------------------------------
+
+typedef enum _runmode {
+ RUN_MUTE, RUN_PASS, RUN_PLAY, RUN_SWCH
+} RUNMODE;
+
+#ifndef _WINDOWS
+
+extern struct _top {
+ pid_t pid;
+ uid_t uid;
+
+ struct timeval start_tv;
+
+ BOOLEAN running, verbose;
+ RUNMODE state;
+
+ // audio io
+ struct {
+ struct {
+ float *l, *r;
+ } buf;
+ struct {
+ unsigned int frames, bytes;
+ } size;
+ } hold;
+ struct {
+ char *path;
+ int fd;
+ FILE * fp;
+ char buff[4096];
+ } parm;
+
+ struct {
+ char name[256];
+ jack_client_t * client;
+ struct {
+ struct {
+ jack_port_t *l, *r;
+ } i, o;
+ } port;
+ struct {
+ struct {
+ jack_ringbuffer_t *l, *r;
+ } i, o;
+ } ring;
+ } jack;
+
+ // update io
+ // multiprocessing & synchronization
+ struct {
+ struct {
+ pthread_t id;
+ } trx, upd, pws, meter;
+ } thrd;
+ struct {
+ struct {
+ sem_t sem;
+ } buf, upd;
+ } sync;
+
+ // TRX switching
+ struct {
+ struct {
+ int want, have;
+ } bfct;
+ struct {
+ TRXMODE next;
+ } trx;
+ struct {
+ RUNMODE last;
+ } run;
+ int fade, tail;
+ } swch;
+} top;
+
+#else
+
+extern struct _top {
+ pid_t pid;
+ uid_t uid;
+
+ BOOLEAN running, verbose;
+ RUNMODE state;
+
+ // audio io
+ struct {
+ struct {
+ float *l, *r;
+ } buf;
+ struct {
+ unsigned int frames, bytes;
+ } size;
+ } hold;
+ struct {
+ char *path;
+ int fd;
+ HANDLE *fpr;
+ HANDLE *fpw;
+ char buff[4096];
+ } parm;
+
+ struct {
+ char name[256];
+ struct {
+ struct {
+ ringb_t *l, *r;
+ } i, o;
+ } ring;
+ } jack;
+
+ // update io
+ // multiprocessing & synchronization
+ struct {
+ struct {
+ DWORD id;
+ HANDLE thrd;
+ } trx, upd, pws, meter;
+ } thrd;
+ struct {
+ struct {
+ HANDLE sem;
+ } buf, upd, upd2;
+ } sync;
+
+ // TRX switching
+ struct {
+ struct {
+ int want, have;
+ } bfct;
+ struct {
+ TRXMODE next;
+ } trx;
+ struct {
+ RUNMODE last;
+ } run;
+ int fade, tail;
+ } swch;
+} top;
+
+#endif
--- /dev/null
+/* update.c
+
+common defs and code for parm update
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <common.h>
+
+////////////////////////////////////////////////////////////////////////////
+
+PRIVATE REAL
+dB2lin(REAL dB) { return pow(10.0, dB / 20.0); }
+
+
+PRIVATE int
+setRXFilter(int n, char **p) {
+ REAL low_frequency = atof(p[0]),
+ high_frequency = atof(p[1]);
+ int ncoef = uni.buflen + 1;
+ int i, fftlen = 2 * uni.buflen;
+ fftw_plan ptmp;
+ COMPLEX *zcvec;
+
+ if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
+ if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
+ if ((low_frequency + 10) >= high_frequency) return -3;
+ delFIR_COMPLEX(rx.filt.coef);
+
+ rx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
+ high_frequency,
+ uni.samplerate,
+ ncoef);
+
+ zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
+ ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, FFTW_OUT_OF_PLACE);
+#ifdef LHS
+ for (i = 0; i < ncoef; i++) zcvec[i] = rx.filt.coef->coef[i];
+#else
+ for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = rx.filt.coef->coef[i];
+#endif
+ fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) rx.filt.ovsv->zfvec);
+ fftw_destroy_plan(ptmp);
+ delvec_COMPLEX(zcvec);
+ memcpy((char *) rx.filt.save,
+ (char *) rx.filt.ovsv->zfvec,
+ rx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ return 0;
+}
+
+
+PRIVATE int
+setTXFilter(int n, char **p) {
+ REAL low_frequency = atof(p[0]),
+ high_frequency = atof(p[1]);
+ int ncoef = uni.buflen + 1;
+ int i, fftlen = 2 * uni.buflen;
+ fftw_plan ptmp;
+ COMPLEX *zcvec;
+
+ if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
+ if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
+ if ((low_frequency + 10) >= high_frequency) return -3;
+ delFIR_COMPLEX(tx.filt.coef);
+ tx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
+ high_frequency,
+ uni.samplerate,
+ ncoef);
+
+ zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
+ ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, FFTW_OUT_OF_PLACE);
+#ifdef LHS
+ for (i = 0; i < ncoef; i++) zcvec[i] = tx.filt.coef->coef[i];
+#else
+ for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = tx.filt.coef->coef[i];
+#endif
+ fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) tx.filt.ovsv->zfvec);
+ fftw_destroy_plan(ptmp);
+ delvec_COMPLEX(zcvec);
+ memcpy((char *) tx.filt.save,
+ (char *) tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ return 0;
+}
+
+PRIVATE int
+setFilter(int n, char **p) {
+ if (n == 2) return setRXFilter(n, p);
+ else {
+ int trx = atoi(p[2]);
+ if (trx == RX) return setRXFilter(n, p);
+ else if (trx == TX) return setTXFilter(n, p);
+ else return -1;
+ }
+}
+
+// setMode <mode> [TRX]
+
+PRIVATE int
+setMode(int n, char **p) {
+ int mode = atoi(p[0]);
+ if (n > 1) {
+ int trx = atoi(p[1]);
+ switch (trx) {
+ case TX: tx.mode = mode; break;
+ case RX:
+ default: rx.mode = mode; break;
+ }
+ } else
+ tx.mode = rx.mode = uni.mode.sdr = mode;
+ if (rx.mode == AM) rx.am.gen->mode = AMdet;
+ if (rx.mode == SAM) rx.am.gen->mode = SAMdet;
+ return 0;
+}
+
+// setOsc <freq> [TRX]
+PRIVATE int
+setOsc(int n, char **p) {
+ REAL newfreq = atof(p[0]);
+// fprintf(stderr,"freq =%lf, samplerate = %lf\n",newfreq,uni.samplerate);
+ if (fabs(newfreq) >= 0.5 * uni.samplerate) return -1;
+ newfreq *= 2.0 * M_PI / uni.samplerate;
+ if (n > 1) {
+ int trx = atoi(p[1]);
+ switch (trx) {
+ case TX: tx.osc.gen->Frequency = newfreq; break;
+ case RX:
+ default: rx.osc.gen->Frequency = newfreq; break;
+ }
+ } else
+ tx.osc.gen->Frequency = rx.osc.gen->Frequency = newfreq;
+ return 0;
+}
+
+PRIVATE int
+setSampleRate(int n, char **p) {
+ REAL samplerate = atof(p[0]);
+ uni.samplerate = samplerate;
+ return 0;
+}
+
+PRIVATE int
+setNR(int n, char **p) {
+ rx.anr.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setANF(int n, char **p) {
+ rx.anf.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setNB(int n, char **p) {
+ rx.nb.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setNBvals(int n, char **p) {
+ REAL threshold = atof(p[0]);
+ rx.nb.gen->threshold = rx.nb.thresh = threshold;
+ return 0;
+}
+
+PRIVATE int
+setSDROM(int n, char **p) {
+ rx.nb_sdrom.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setSDROMvals(int n, char **p) {
+ REAL threshold = atof(p[0]);
+ rx.nb_sdrom.gen->threshold = rx.nb_sdrom.thresh = threshold;
+ return 0;
+}
+
+PRIVATE int
+setBIN(int n, char **p) {
+ rx.bin.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE
+// setfixedAGC <gain> [TRX]
+int
+setfixedAGC(int n, char **p) {
+ REAL gain = atof(p[0]);
+ if (n > 1) {
+ int trx = atoi(p[1]);
+ switch(trx) {
+ case TX: tx.agc.gen->AgcFixedGain = gain; break;
+ case RX:
+ default: rx.agc.gen->AgcFixedGain = gain; break;
+ }
+ } else
+ tx.agc.gen->AgcFixedGain = rx.agc.gen->AgcFixedGain = gain;
+ return 0;
+}
+
+PRIVATE int
+setTXAGC(int n, char **p) {
+ int setit = atoi(p[0]);
+ switch (setit) {
+ case agcOFF:
+ tx.agc.gen->AgcMode = agcOFF;
+ tx.agc.flag = FALSE;
+ break;
+ case agcSLOW:
+ tx.agc.gen->AgcMode = agcSLOW;
+ tx.agc.gen->Hang = 10;
+ tx.agc.flag = TRUE;
+ break;
+ case agcMED:
+ tx.agc.gen->AgcMode = agcMED;
+ tx.agc.gen->Hang = 6;
+ tx.agc.flag = TRUE;
+ break;
+ case agcFAST:
+ tx.agc.gen->AgcMode = agcFAST;
+ tx.agc.gen->Hang = 3;
+ tx.agc.flag = TRUE;
+ break;
+ case agcLONG:
+ tx.agc.gen->AgcMode = agcLONG;
+ tx.agc.gen->Hang = 23;
+ tx.agc.flag = TRUE;
+ break;
+ }
+ return 0;
+}
+
+PRIVATE int
+setTXAGCCompression(int n, char **p) {
+ REAL txcompression = atof(p[0]);
+ tx.agc.gen->MaxGain = pow(10.0 , txcompression * 0.05);
+ return 0;
+}
+
+PRIVATE int
+setTXAGCFF(int n, char **p) {
+ int setit = atoi(p[0]);
+ tx.spr.flag = setit;
+ return 0;
+}
+
+PRIVATE int
+setTXAGCFFCompression(int n, char **p) {
+ REAL txcompression = atof(p[0]);
+ tx.spr.gen->MaxGain = pow(10.0 , txcompression * 0.05);
+ return 0;
+}
+
+PRIVATE int
+setTXAGCHang(int n, char **p) {
+ int hang = atoi(p[0]);
+ tx.agc.gen->Hang =
+ (int) max(1, min(23, ((REAL) hang) * uni.samplerate / (1000.0 * uni.buflen)));
+ return 0;
+}
+
+PRIVATE int
+setTXAGCLimit(int n, char **p) {
+ REAL limit = atof(p[0]);
+ tx.agc.gen->AgcLimit = 0.001 * limit;
+ return 0;
+}
+
+PRIVATE int
+setTXSpeechCompression(int n, char **p) {
+ tx.spr.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTXSpeechCompressionGain(int n, char **p) {
+ tx.spr.gen->MaxGain = dB2lin(atof(p[0]));
+ return 0;
+}
+
+//============================================================
+
+PRIVATE int
+f2x(REAL f) {
+ REAL fix = tx.filt.ovsv->fftlen * f / uni.samplerate;
+ return (int) (fix + 0.5);
+}
+
+//------------------------------------------------------------
+
+PRIVATE void
+apply_txeq_band(REAL lof, REAL dB, REAL hif) {
+ int i,
+ lox = f2x(lof),
+ hix = f2x(hif),
+ l = tx.filt.ovsv->fftlen;
+ REAL g = dB2lin(dB);
+ COMPLEX *src = tx.filt.save,
+ *trg = tx.filt.ovsv->zfvec;
+ for (i = lox; i < hix; i++) {
+ trg[i] = Cscl(src[i], g);
+ if (i) {
+ int j = l - i;
+ trg[j] = Cscl(src[j], g);
+ }
+ }
+}
+
+// typical:
+// 0 dB1 75 dB2 150 dB3 300 dB4 600 dB5 1200 dB6 2000 dB7 2800 dB8 3600
+// approximates W2IHY bandcenters.
+// no args, revert to no EQ.
+PRIVATE int
+setTXEQ(int n, char **p) {
+ if (n < 3) {
+ // revert to no EQ
+ memcpy((char *) tx.filt.ovsv->zfvec,
+ (char *) tx.filt.save,
+ tx.filt.ovsv->fftlen * sizeof(COMPLEX));
+ return 0;
+ } else {
+ int i;
+ REAL lof = atof(p[0]);
+ for (i = 0; i < n - 2; i += 2) {
+ REAL dB = atof(p[i + 1]),
+ hif = atof(p[i + 2]);
+ if (lof < 0.0 || hif <= lof) return -1;
+ apply_txeq_band(lof, dB, hif);
+ lof = hif;
+ }
+ return 0;
+ }
+}
+
+//------------------------------------------------------------
+
+PRIVATE void
+apply_rxeq_band(REAL lof, REAL dB, REAL hif) {
+ int i,
+ lox = f2x(lof),
+ hix = f2x(hif),
+ l = rx.filt.ovsv->fftlen;
+ REAL g = dB2lin(dB);
+ COMPLEX *src = rx.filt.save,
+ *trg = rx.filt.ovsv->zfvec;
+ for (i = lox; i < hix; i++) {
+ trg[i] = Cscl(src[i], g);
+ if (i) {
+ int j = l - i;
+ trg[j] = Cscl(src[j], g);
+ }
+ }
+}
+
+PRIVATE int
+setRXEQ(int n, char **p) {
+ if (n < 3) {
+ // revert to no EQ
+ memcpy((char *) rx.filt.ovsv->zfvec,
+ (char *) rx.filt.save,
+ rx.filt.ovsv->fftlen * sizeof(COMPLEX));
+ return 0;
+ } else {
+ int i;
+ REAL lof = atof(p[0]);
+ for (i = 0; i < n - 2; i += 2) {
+ REAL dB = atof(p[i + 1]),
+ hif = atof(p[i + 2]);
+ if (lof < 0.0 || hif <= lof) return -1;
+ apply_rxeq_band(lof, dB, hif);
+ lof = hif;
+ }
+ return 0;
+ }
+}
+
+//============================================================
+PRIVATE int
+setRXAGC(int n, char **p) {
+ int setit = atoi(p[0]);
+ switch (setit) {
+ case agcOFF:
+ rx.agc.gen->AgcMode = agcOFF;
+ rx.agc.flag = TRUE;
+ break;
+ case agcSLOW:
+ rx.agc.gen->AgcMode = agcSLOW;
+ rx.agc.gen->Hang = 10;
+ rx.agc.flag = TRUE;
+ break;
+ case agcMED:
+ rx.agc.gen->AgcMode = agcMED;
+ rx.agc.gen->Hang = 6;
+ rx.agc.flag = TRUE;
+ break;
+ case agcFAST:
+ rx.agc.gen->AgcMode = agcFAST;
+ rx.agc.gen->Hang = 3;
+ rx.agc.flag = TRUE;
+ break;
+ case agcLONG:
+ rx.agc.gen->AgcMode = agcLONG;
+ rx.agc.gen->Hang = 23;
+ rx.agc.flag = TRUE;
+ break;
+ }
+ return 0;
+}
+
+PRIVATE int
+setANFvals(int n, char **p) {
+ int taps = atoi(p[0]),
+ delay = atoi(p[1]);
+ REAL gain = atof(p[2]),
+ leak = atof(p[3]);
+ rx.anf.gen->adaptive_filter_size = taps;
+ rx.anf.gen->delay = delay;
+ rx.anf.gen->adaptation_rate = gain;
+ rx.anf.gen->leakage = leak;
+ return 0;
+}
+
+PRIVATE int
+setNRvals(int n, char **p) {
+ int taps = atoi(p[0]),
+ delay = atoi(p[1]);
+ REAL gain = atof(p[2]),
+ leak = atof(p[3]);
+ rx.anr.gen->adaptive_filter_size = taps;
+ rx.anr.gen->delay = delay;
+ rx.anr.gen->adaptation_rate = gain;
+ rx.anr.gen->leakage = leak;
+ return 0;
+}
+
+PRIVATE int
+setcorrectIQ(int n, char **p) {
+ int phaseadjustment = atoi(p[0]),
+ gainadjustment = atoi(p[1]);
+ rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
+ rx.iqfix->gain = 1.0+ 0.001 * (REAL) gainadjustment;
+ return 0;
+}
+
+PRIVATE int
+setcorrectIQphase(int n, char **p) {
+ int phaseadjustment = atoi(p[0]);
+ rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
+ return 0;
+}
+
+PRIVATE int
+setcorrectIQgain(int n, char **p) {
+ int gainadjustment = atoi(p[0]);
+ rx.iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
+ return 0;
+}
+
+PRIVATE int
+setSquelch(int n, char **p) {
+ rx.squelch.thresh = -atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setMeterOffset(int n, char **p) {
+ rx.squelch.offset.meter = atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setATTOffset(int n, char **p) {
+ rx.squelch.offset.att = atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setGainOffset(int n, char **p) {
+ rx.squelch.offset.gain = atof(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setSquelchSt(int n, char **p) {
+ rx.squelch.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTRX(int n, char **p) {
+ uni.mode.trx = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setRunState(int n, char **p) {
+ RUNMODE rs = (RUNMODE) atoi(p[0]);
+ top.state = rs;
+ return 0;
+}
+
+PRIVATE int
+setSpotToneVals(int n, char **p) {
+ REAL gain = atof(p[0]),
+ freq = atof(p[1]),
+ rise = atof(p[2]),
+ fall = atof(p[3]);
+ setSpotToneGenVals(rx.spot.gen, gain, freq, rise, fall);
+ return 0;
+}
+
+PRIVATE int
+setSpotTone(int n, char **p) {
+ if (atoi(p[0])) {
+ SpotToneOn(rx.spot.gen);
+ rx.spot.flag = TRUE;
+ } else
+ SpotToneOff(rx.spot.gen);
+ return 0;
+}
+
+PRIVATE int
+setRXPreScl(int n, char **p) {
+ rx.scl.pre.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setRXPreSclVal(int n, char **p) {
+ rx.scl.pre.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setTXPreScl(int n, char **p) {
+ tx.scl.pre.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTXPreSclVal(int n, char **p) {
+ tx.scl.pre.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setRXPostScl(int n, char **p) {
+ rx.scl.post.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setRXPostSclVal(int n, char **p) {
+ rx.scl.post.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setTXPostScl(int n, char **p) {
+ tx.scl.post.flag = atoi(p[0]);
+ return 0;
+}
+
+PRIVATE int
+setTXPostSclVal(int n, char **p) {
+ tx.scl.post.val = dB2lin(atof(p[0]));
+ return 0;
+}
+
+PRIVATE int
+setFinished(int n, char **p) {
+ top.running = FALSE;
+ return 0;
+}
+
+PRIVATE int
+setPWSmode(int n,char **p) {
+ int setit = atoi(p[0]);
+ uni.powerspectrum.pws->Mode = setit;
+ return 0;
+}
+
+PRIVATE int
+setPWSSubmode(int n,char **p) {
+ int setit = atoi(p[0]);
+ uni.powerspectrum.pws->SubMode = setit;
+ return 0;
+}
+
+// next-trx-mode [nbufs-to-zap]
+PRIVATE int
+setSWCH(int n, char **p) {
+ top.swch.trx.next = atoi(p[0]);
+ if (n > 1) top.swch.bfct.want = atoi(p[1]);
+ else top.swch.bfct.want = 0;
+ top.swch.bfct.have = 0;
+ top.swch.run.last = top.state;
+ top.state = RUN_SWCH;
+ return 0;
+}
+
+//========================================================================
+
+#include <thunk.h>
+
+CTE update_cmds[] = {
+ {"setANF", setANF},
+ {"setANFvals", setANFvals},
+ {"setATTOffset", setATTOffset},
+ {"setBIN", setBIN},
+ {"setcorrectIQ", setcorrectIQ},
+ {"setcorrectIQgain", setcorrectIQgain},
+ {"setcorrectIQphase", setcorrectIQphase},
+ {"setFilter", setFilter},
+ {"setfixedAGC", setfixedAGC},
+ {"setGainOffset", setGainOffset},
+ {"setMeterOffset", setMeterOffset},
+ {"setMode", setMode},
+ {"setNB", setNB},
+ {"setNBvals", setNBvals},
+ {"setNR", setNR},
+ {"setNRvals", setNRvals},
+ {"setOsc", setOsc},
+ {"setRXAGC", setRXAGC},
+ {"setRunState", setRunState},
+ {"setSampleRate", setSampleRate},
+ {"setSquelch", setSquelch},
+ {"setSquelchSt", setSquelchSt},
+ {"setTXAGC", setTXAGC},
+ {"setTXAGCCompression", setTXAGCCompression},
+ {"setTXAGCFFCompression",setTXAGCFFCompression},
+ {"setTXAGCHang", setTXAGCHang},
+ {"setTXAGCLimit", setTXAGCLimit},
+ {"setTXSpeechCompression", setTXSpeechCompression},
+ {"setTXSpeechCompressionGain", setTXSpeechCompressionGain},
+ {"setRXEQ", setRXEQ},
+ {"setTXEQ", setTXEQ},
+ {"setTRX", setTRX},
+ {"setRXPreScl", setRXPreScl},
+ {"setRXPreSclVal", setRXPreSclVal},
+ {"setTXPreScl", setTXPreScl},
+ {"setTXPreSclVal", setTXPreSclVal},
+ {"setRXPostScl", setRXPostScl},
+ {"setRXPostSclVal", setRXPostSclVal},
+ {"setTXPostScl", setTXPostScl},
+ {"setTXPostSclVal", setTXPostSclVal},
+ {"setFinished", setFinished},
+ {"setSWCH", setSWCH},
+ {"setSpotToneVals", setSpotToneVals},
+ {"setSpotTone", setSpotTone},
+ {"setPWSmode", setPWSmode},
+ {"setPWSSubmode",setPWSSubmode},
+ {"setSDROM", setSDROM},
+ {"setSDROMvals",setSDROMvals},
+ { 0, 0 }
+};
+
+//........................................................................
+
+int do_update(char *str) {
+
+ SPLIT splt = &uni.update.splt;
+
+ split(splt, str);
+
+ if (NF(splt) < 1) return -1;
+ else {
+ Thunk thk = Thunk_lookup(update_cmds, F(splt, 0));
+ if (!thk) {
+ fprintf(stderr,"-1\n");
+ return -1;
+ } else {
+ int val;
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ val = (*thk)(NF(splt) - 1, Fptr(splt, 1));
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ return val;
+ }
+ }
+}
+
+BOOLEAN newupdates() {
+ WaitForSingleObject(top.sync.upd2.sem,INFINITE);
+ return TRUE;
+}
+
+PRIVATE void
+sendcommand(char *str) {
+ putChan_nowait(uni.update.chan.c,str,strlen(str)+1);;
+ ReleaseSemaphore(top.sync.upd2.sem,1L,NULL);
+ Sleep(0);
+}
+
+#ifdef PROCESSVERS
+DttSP_EXP int
+changeMode(SDRMODE mode) {
+ char str[128];
+ switch(mode) {
+ case LSB:
+ sprintf(str,"setMode %d",LSB);
+ sendcommand(str);
+ break;
+ case USB:
+ sprintf(str,"setMode %d",USB);
+ sendcommand(str);
+ break;
+ case DSB:
+ sprintf(str,"setMode %d",DSB);
+ sendcommand(str);
+ break;
+ case CWL:
+ sprintf(str,"setMode %d",CWL);
+ sendcommand(str);
+ break;
+ case CWU:
+ sprintf(str,"setMode %d",CWU);
+ sendcommand(str);
+ break;
+ case AM:
+ sprintf(str,"setMode %d",AM);
+ sendcommand(str);
+ break;
+ case PSK:
+ sprintf(str,"setMode %d",PSK);
+ sendcommand(str);
+ break;
+ case SPEC:
+ sprintf(str,"setMode %d",SPEC);
+ sendcommand(str);
+ break;
+ case RTTY:
+ sprintf(str,"setMode %d",RTTY);
+ sendcommand(str);
+ break;
+ case SAM:
+ sprintf(str,"setMode %d",SAM);
+ sendcommand(str);
+ break;
+ case DRM:
+ sprintf(str,"setMode %d",DRM);
+ sendcommand(str);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+DttSP_EXP int
+changeOsc(REAL newfreq){
+ char str[64];
+ if (fabs(newfreq) >= 0.5* uni.samplerate) return -1;
+ sprintf(str,"setOsc %lf RX",newfreq);
+ sendcommand(str);
+ return 0;
+}
+
+DttSP_EXP int
+changeTXOsc(REAL newfreq){
+ char str[64];
+ if (fabs(newfreq) >= 0.5* uni.samplerate) return -1;
+ sprintf(str,"setOsc %lf TX",newfreq);
+ sendcommand(str);
+ return 0;
+}
+
+DttSP_EXP int
+changeSampleRate(REAL newSampleRate) {
+ char str[64];
+ sprintf(str,"setSampleRate %9.0lf",newSampleRate);
+ sendcommand(str);
+ return 0;
+}
+
+DttSP_EXP void changeNR(int setit) {
+ char str[64];
+ sprintf(str,"setNR %d",setit);
+ sendcommand(str);
+}
+
+DttSP_EXP void changeANF(int setit) {
+ char str[64];
+ sprintf(str,"setANF %d",setit);
+ sendcommand(str);
+}
+
+DttSP_EXP void changeNB(int setit) {
+ char str[64];
+ sprintf(str,"setNB %d",setit);
+ sendcommand(str);
+}
+
+DttSP_EXP void changeNBvals(REAL threshold) {
+ char str[64];
+ sprintf(str,"setNBvals %lf",threshold);
+ sendcommand(str);
+}
+
+
+DttSP_EXP void changeBIN(int setit) {
+ char str[64];
+ sprintf(str,"setBIN %d",setit);
+ sendcommand(str);
+}
+
+DttSP_EXP void changeAGC(AGCMODE setit) {
+ char str[64];
+ switch (setit) {
+ case agcOFF:
+ sprintf(str,"setRXAGC %d",agcOFF);
+ break;
+ case agcLONG:
+ sprintf(str,"setRXAGC %d",agcLONG);
+ break;
+ case agcSLOW:
+ sprintf(str,"setRXAGC %d",agcSLOW);
+ break;
+ case agcMED:
+ sprintf(str,"setRXAGC %d",agcMED);
+ break;
+ case agcFAST:
+ sprintf(str,"setRXAGC %d",agcFAST);
+ break;
+ }
+ sendcommand(str);
+}
+
+DttSP_EXP void changeANFvals(int taps, int delay, REAL gain, REAL leak) {
+ char str[128];
+ sprintf(str,"setANFvals %3d %3d %9.7lf %9.7lf",taps,delay,gain,leak);
+ sendcommand(str);
+}
+
+DttSP_EXP void changeNRvals(int taps, int delay, REAL gain, REAL leak) {
+ char str[128];
+ sprintf(str,"setNRvals %3d %3d %9.7lf %9.7lf",taps,delay,gain,leak);
+ sendcommand(str);
+}
+
+DttSP_EXP void setcorrectIQcmd(int phaseadjustment,int gainadjustment) {
+ char str[64];
+ sprintf(str,"setcorrectIQ %d %d",phaseadjustment,gainadjustment);
+ sendcommand(str);
+}
+
+DttSP_EXP void changecorrectIQphase(int phaseadjustment){
+ char str[64];
+ sprintf(str,"setcorrectIQphase %d",phaseadjustment);
+ sendcommand(str);
+}
+
+DttSP_EXP void changecorrectIQgain(int gainadjustment){
+ char str[64];
+ sprintf(str,"setcorrectIQgain %d",gainadjustment);
+ sendcommand(str);
+}
+
+DttSP_EXP int
+changeFilter(REAL low_frequency,REAL high_frequency,int ncoef, TRXMODE trx) {
+ char str[64];
+ if (trx == RX) sprintf(str,"setFilter %6.0lf %6.0lf RX",low_frequency,high_frequency);
+ else sprintf(str,"setFilter %6.0lf %6.0lf TX",low_frequency,high_frequency);
+ sendcommand(str);
+ return 0;
+}
+
+DttSP_EXP void
+changePWSmode(PWSMODE setit) {
+ char str[64];
+ switch (setit) {
+ case PREFILTER:
+ sprintf(str,"setPWSmode %d",PREFILTER);
+ break;
+ case POSTFILTER:
+ sprintf(str,"setPWSmode %d",POSTFILTER);
+ break;
+ case AUDIO:
+ sprintf(str,"setPWSmode %d",AUDIO);
+ break;
+ default:
+ return;
+ }
+ sendcommand(str);
+}
+
+DttSP_EXP void
+changePWSsubmode(PWSSUBMODE setit) {
+ char str[64];
+ switch (setit) {
+ case SPECTRUM:
+ sprintf(str,"setPWSSubmode %d",SPECTRUM);
+ break;
+ case PHASE:
+ sprintf(str,"setPWSSubmode %d",PHASE);
+ break;
+ case SCOPE:
+ sprintf(str,"setPWSSubmode %d",SCOPE);
+ break;
+ case PHASE2:
+ sprintf(str,"setPWSSubmode %d",PHASE);
+ break;
+ case WATERFALL:
+ sprintf(str,"setPWSSubmode %d",WATERFALL);
+ break;
+ case HISTOGRAM:
+ sprintf(str,"setPWSSubmode %d",HISTOGRAM);
+ break;
+ default:
+ return;
+ }
+ sendcommand(str);
+}
+
+DttSP_EXP void
+changeWindow(Windowtype Windowset){
+}
+
+DttSP_EXP void
+oldsetTXEQ(int *txeq) {
+ char str[256];
+ sprintf(str,
+ "setTXEQ 0 %d 450 %d 800 %d 1150 %d 1450 %d 1800 %d 2150 %d 2450 %d 2800 %d 3600",
+ txeq[0],
+ txeq[1],
+ txeq[2],
+ txeq[3],
+ txeq[4],
+ txeq[5],
+ txeq[6],
+ txeq[7],
+ txeq[8]);
+ sendcommand(str);
+}
+
+DttSP_EXP void
+changeTXAGCCompression(double txc) {
+ char str[64];
+ sprintf(str,"setTXAGCCompression %lf",txc);
+ sendcommand(str);
+}
+
+DttSP_EXP void
+changeTXAGCFFCompression(double txc) {
+ char str[64];
+ sprintf(str,"setTXAGCFFCompression %lf",txc);
+ sendcommand(str);
+}
+
+DttSP_EXP void oldsetGainOffset(float val) {
+ char str[64];
+ sprintf(str,"setGainOffset %f",val);
+ sendcommand(str);
+}
+
+DttSP_EXP void setTXScale(REAL scale) {
+ char str[32];
+ sprintf(str,"setTXPreScl 1 ");
+ sendcommand(str);
+ Sleep(0);
+ sprintf(str,"setTXPreSclVal %lf",20.0*log10(scale));
+ sendcommand(str);
+}
+
+DttSP_EXP void oldsetATTOffset(float val){
+ char str[64];
+ sprintf(str,"setATTOffset %f",val);
+ sendcommand(str);
+}
+
+DttSP_EXP setRXScale(float val) {
+ char str[64];
+ sprintf(str,"setRXPostScl 1");
+ sendcommand(str);
+ Sleep(0);
+ sprintf(str,"setRXPostSclVal %f",val);
+ sendcommand(str);
+}
+
+DttSP_EXP oldsetMeterOffset(float val){
+ char str[64];
+ sprintf(str,"setMeterOffset %f",val);
+ sendcommand(str);
+}
+
+DttSP_EXP changeSquelch(float setit) {
+ char str[64];
+ sprintf(str,"setSquelch %f",setit);
+ sendcommand(str);
+}
+
+DttSP_EXP changeSquelchSt(BOOLEAN setit) {
+ char str[64];
+ sprintf(str,"setSquelch %d",setit);
+ sendcommand(str);
+}
+
+DttSP_EXP void changeSDROM(BOOLEAN setit) {
+ char str[64];
+ sprintf(str,"setSDROM %d",setit);
+ sendcommand(str);
+}
+
+DttSP_EXP void changeSDROMvals(REAL threshold) {
+ char str[64];
+ sprintf(str,"setSDROMvals %lf",threshold);
+ sendcommand(str);
+}
+
+
+#endif // END PROCESSVERS
+
+
+
+#ifdef DLLVERS
+DttSP_EXP int
+changeMode(SDRMODE mode) {
+ switch(mode) {
+ case LSB:
+ case USB:
+ case DSB:
+ case CWL:
+ case CWU:
+ case FMN:
+ case AM:
+ case PSK:
+ case SPEC:
+ case RTTY:
+ case SAM:
+ case DRM:
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.mode = tx.mode = uni.mode.sdr = mode;
+ if (mode == SAM) rx.am.gen->mode = SAMdet;
+ if (mode == AM) rx.am.gen->mode = AMdet;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+DttSP_EXP int
+changeOsc(REAL newfreq){
+ if (fabs(newfreq) >= 0.5* uni.samplerate) return -1;
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.osc.gen->Frequency = rx.osc.freq = 2.0*M_PI*newfreq/uni.samplerate;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ return 0;
+}
+
+DttSP_EXP int
+changeTXOsc(REAL newfreq){
+ if (fabs(newfreq) >= 0.5* uni.samplerate) return -1;
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ tx.osc.gen->Frequency = tx.osc.freq = 2.0*M_PI*newfreq/uni.samplerate;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ return 0;
+}
+
+DttSP_EXP int
+changeSampleRate(REAL newSampleRate) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ uni.samplerate = newSampleRate;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ return 0;
+}
+
+DttSP_EXP void changeNR(BOOLEAN setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.anr.flag = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeANF(BOOLEAN setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.anf.flag = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeNB(BOOLEAN setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.nb.flag = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeNBvals(REAL threshold) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.nb.gen->threshold = rx.nb.thresh = threshold;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeSDROM(BOOLEAN setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.nb_sdrom.flag = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeSDROMvals(REAL threshold) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.nb_sdrom.gen->threshold = rx.nb_sdrom.thresh = threshold;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+
+DttSP_EXP void changeBIN(BOOLEAN setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.bin.flag= setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeAGC(AGCMODE setit) {
+ switch (setit) {
+ case agcOFF:
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcMode = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ break;
+ case agcLONG:
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcMode = setit;
+ rx.agc.gen->Hang = 23;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ break;
+ case agcSLOW:
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcMode = setit;
+ rx.agc.gen->Hang = 7;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ break;
+ case agcMED:
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcMode = setit;
+ rx.agc.gen->Hang = 4;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ break;
+ case agcFAST:
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcMode = setit;
+ rx.agc.gen->Hang = 2;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ break;
+ default:
+ break;
+ }
+}
+
+DttSP_EXP void changefixedAGC(REAL fixed_agc) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcFixedGain = dB2lin(fixed_agc);
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changemaxAGC(REAL max_agc) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->MaxGain = dB2lin(max_agc);
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeRXAGCAttackTimeScale(int limit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcAttackTimeScale = limit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+
+}
+
+DttSP_EXP void changeRXAGCHang(int limit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->Hang = limit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+
+}
+
+DttSP_EXP void changeRXAGCLimit(int limit){
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.agc.gen->AgcLimit = 0.001 * (double)limit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeANFvals(int taps, int delay, REAL gain, REAL leak) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.anf.gen->adaptation_rate = gain;
+ rx.anf.gen->adaptive_filter_size = taps;
+ rx.anf.gen->delay = delay;
+ rx.anf.gen->leakage = leak;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void changeNRvals(int taps, int delay, REAL gain, REAL leak) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.anr.gen->adaptation_rate = gain;
+ rx.anr.gen->adaptive_filter_size = taps;
+ rx.anr.gen->delay = delay;
+ rx.anr.gen->leakage = leak;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+setcorrectIQcmd(int phaseadjustment,int gainadjustment) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
+ rx.iqfix->gain = 1.0 + 0.001 * (REAL) gainadjustment;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changecorrectIQphase(int phaseadjustment) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.iqfix->phase = 0.001 * (REAL) phaseadjustment;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changecorrectIQgain(int gainadjustment) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.iqfix->gaina = 1.0 + 0.001 * (REAL) gainadjustment;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP int
+changeFilter(REAL low_frequency,REAL high_frequency,int ncoef, TRXMODE trx) {
+ int i, fftlen = 2 * uni.buflen;
+ fftw_plan ptmp;
+ COMPLEX *zcvec;
+ ncoef = uni.buflen + 1;
+
+ if (fabs(low_frequency) >= 0.5 * uni.samplerate) return -1;
+ if (fabs(high_frequency) >= 0.5 * uni.samplerate) return -2;
+ if ((low_frequency + 10) >= high_frequency) return -3;
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ if (trx == RX) {
+ delFIR_COMPLEX(rx.filt.coef);
+
+ rx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
+ high_frequency,
+ uni.samplerate,
+ ncoef + 1);
+
+ zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
+ ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, FFTW_OUT_OF_PLACE);
+#ifdef LHS
+ for (i = 0; i < ncoef; i++) zcvec[i] = rx.filt.coef->coef[i];
+#else
+ for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = rx.filt.coef->coef[i];
+#endif
+ fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) rx.filt.ovsv->zfvec);
+ fftw_destroy_plan(ptmp);
+ delvec_COMPLEX(zcvec);
+ memcpy((char *) rx.filt.save,
+ (char *) rx.filt.ovsv->zfvec,
+ rx.filt.ovsv->fftlen * sizeof(COMPLEX));
+ } else {
+ delFIR_COMPLEX(tx.filt.coef);
+
+ tx.filt.coef = newFIR_Bandpass_COMPLEX(low_frequency,
+ high_frequency,
+ uni.samplerate,
+ ncoef + 1);
+
+ zcvec = newvec_COMPLEX(fftlen, "filter z vec in setFilter");
+ ptmp = fftw_create_plan(fftlen, FFTW_FORWARD, FFTW_OUT_OF_PLACE);
+#ifdef LHS
+ for (i = 0; i < ncoef; i++) zcvec[i] = tx.filt.coef->coef[i];
+#else
+ for (i = 0; i < ncoef; i++) zcvec[fftlen - ncoef + i] = tx.filt.coef->coef[i];
+#endif
+ fftw_one(ptmp, (fftw_complex *) zcvec, (fftw_complex *) tx.filt.ovsv->zfvec);
+ fftw_destroy_plan(ptmp);
+ delvec_COMPLEX(zcvec);
+ memcpy((char *) tx.filt.save,
+ (char *) tx.filt.ovsv->zfvec,
+ tx.filt.ovsv->fftlen * sizeof(COMPLEX));
+
+ }
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+ return 0;
+}
+
+DttSP_EXP void
+changePWSmode(PWSMODE setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ uni.powerspectrum.pws->Mode = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+
+}
+
+DttSP_EXP void
+changePWSsubmode(PWSSUBMODE setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ uni.powerspectrum.pws->SubMode = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changeWindow(Windowtype Windowset){
+}
+
+DttSP_EXP void
+oldsetTXEQ(int *txeq) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ apply_txeq_band(0.0 ,txeq[ 0],120.0);
+ apply_txeq_band(120.0 ,txeq[ 1],230.0);
+ apply_txeq_band(230.0 ,txeq[ 2],450.0);
+ apply_txeq_band(450.0 ,txeq[ 3],800.0);
+ apply_txeq_band(800.0 ,txeq[ 4],1150.0);
+ apply_txeq_band(1150.0,txeq[ 5],1450.0);
+ apply_txeq_band(1450.0,txeq[ 6],1800.0);
+ apply_txeq_band(1800.0,txeq[ 7],2150.0);
+ apply_txeq_band(2150.0,txeq[ 8],2450.0);
+ apply_txeq_band(2450.0,txeq[ 9],2800.0);
+ apply_txeq_band(2800.0,txeq[10],3250.0);
+ apply_txeq_band(3250.0,txeq[11],6000.0);
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changeTXAGCCompression(double txc) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ tx.agc.gen->MaxGain = pow(10.0 , txc * 0.05);
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changeTXAGCFF(BOOLEAN setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ tx.spr.flag = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changeTXAGCLimit(int setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ tx.agc.gen->AgcLimit = 0.001*(REAL)setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changeTXAGCHang(int hang) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ tx.agc.gen->Hang = (int)max(1,min(23,((REAL)hang) * uni.samplerate /(1000.0*uni.buflen)));
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void
+changeTXAGCFFCompression(REAL txc) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ tx.spr.gen->MaxGain = pow(10.0 , txc * 0.05);
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void setTXScale(REAL scale) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ tx.scl.post.flag = TRUE;
+ tx.scl.post.val = scale;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void oldsetGainOffset(float val) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.squelch.offset.gain = (REAL)val;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP void oldsetATTOffset(float val){
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.squelch.offset.att = (REAL)val;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP oldsetMeterOffset(float val){
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.squelch.offset.meter = (REAL)val;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+
+DttSP_EXP setRXScale(REAL val) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.scl.post.flag = TRUE;
+ rx.scl.post.val = val;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP changeSquelch(int setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.squelch.thresh = -(REAL)setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+
+DttSP_EXP changeSquelchSt(BOOLEAN setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ rx.squelch.flag = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+
+}
+
+DttSP_EXP void oldsetTRX(TRXMODE setit) {
+ WaitForSingleObject(top.sync.upd.sem,INFINITE);
+ /* top.swch.trx.next = setit;
+ top.swch.bfct.want = 2;
+ top.swch.bfct.have = 0;
+ top.swch.run.last = top.state;
+ top.state = RUN_SWCH; */
+ uni.mode.trx = setit;
+ ReleaseSemaphore(top.sync.upd.sem,1L,NULL);
+}
+#endif // END DLLVERS
+
+
+
--- /dev/null
+/* update.h\r
+\r
+common defs and code for parm update\r
+ \r
+This file is part of a program that implements a Software-Defined Radio.\r
+\r
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY\r
+\r
+This program is free software; you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation; either version 2 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
+\r
+The authors can be reached by email at\r
+\r
+ab2kt@arrl.net\r
+or\r
+rwmcgwier@comcast.net\r
+\r
+or by paper mail at\r
+\r
+The DTTS Microwave Society\r
+6 Kathleen Place\r
+Bridgewater, NJ 08807\r
+*/\r
+\r
+#ifndef _update_h\r
+#define _update_h\r
+\r
+#include <fromsys.h>\r
+#include <banal.h>\r
+#include <datatypes.h>\r
+\r
+extern int do_update(char *str);\r
+extern BOOLEAN newupdates(void);\r
+\r
+#endif\r
--- /dev/null
+/* Old compatibility names for <limits.h> and <float.h> constants.\r
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.\r
+ This file is part of the GNU C Library.\r
+\r
+ The GNU C Library is free software; you can redistribute it and/or\r
+ modify it under the terms of the GNU Lesser General Public\r
+ License as published by the Free Software Foundation; either\r
+ version 2.1 of the License, or (at your option) any later version.\r
+\r
+ The GNU C Library is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ Lesser General Public License for more details.\r
+\r
+ You should have received a copy of the GNU Lesser General Public\r
+ License along with the GNU C Library; if not, write to the Free\r
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA\r
+ 02111-1307 USA. */\r
+\r
+/* This interface is obsolete. New programs should use\r
+ <limits.h> and/or <float.h> instead of <values.h>. */\r
+\r
+#ifndef _VALUES_H\r
+#define _VALUES_H 1\r
+\r
+//#include <features.h>\r
+\r
+#include <limits.h>\r
+\r
+#define _TYPEBITS(type) (sizeof (type) * CHAR_BIT)\r
+\r
+#define CHARBITS _TYPEBITS (char)\r
+#define SHORTBITS _TYPEBITS (short int)\r
+#define INTBITS _TYPEBITS (int)\r
+#define LONGBITS _TYPEBITS (long int)\r
+#define PTRBITS _TYPEBITS (char *)\r
+#define DOUBLEBITS _TYPEBITS (double)\r
+#define FLOATBITS _TYPEBITS (float)\r
+\r
+//#ifndef MINSHORT\r
+//#define MINSHORT SHRT_MIN\r
+//#endif\r
+\r
+#ifndef MININT\r
+#define MININT INT_MIN\r
+#endif\r
+\r
+//#ifndef MINLONG\r
+//#define MINLONG LONG_MIN\r
+//#endif\r
+//\r
+//#ifndef MAXSHORT\r
+//#define MAXSHORT SHRT_MAX\r
+//#endif\r
+\r
+#define MAXINT INT_MAX\r
+\r
+//#ifndef MAXLONG\r
+//#define MAXLONG LONG_MAX\r
+//#endif\r
+\r
+#define HIBITS MINSHORT\r
+#define HIBITL MINLONG\r
+\r
+\r
+#include <float.h>\r
+\r
+#define MAXDOUBLE DBL_MAX\r
+#define MAXFLOAT FLT_MAX\r
+#define MINDOUBLE DBL_MIN\r
+#define MINFLOAT FLT_MIN\r
+#define DMINEXP DBL_MIN_EXP\r
+#define FMINEXP FLT_MIN_EXP\r
+#define DMAXEXP DBL_MAX_EXP\r
+#define FMAXEXP FLT_MAX_EXP\r
+\r
+\r
+#ifdef __USE_MISC\r
+/* Some systems define this name instead of CHAR_BIT or CHARBITS. */\r
+# define BITSPERBYTE CHAR_BIT\r
+#endif\r
+\r
+#endif /* values.h */\r
--- /dev/null
+/* window.c
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+Implemented from code by Bill Schottstaedt of Snd Editor at CCRMA
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#include <window.h>
+
+/* shamelessly stolen from Bill Schottstaedt's clm.c */
+/* made worse in the process, but enough for our purposes here */
+
+//static double
+//sqr(double x) { return (x * x); }
+
+/* mostly taken from
+ * Fredric J. Harris, "On the Use of Windows for Harmonic Analysis with the
+ * Discrete Fourier Transform," Proceedings of the IEEE, Vol. 66, No. 1,
+ * January 1978.
+ * Albert H. Nuttall, "Some Windows with Very Good Sidelobe Behaviour",
+ * IEEE Transactions of Acoustics, Speech, and Signal Processing, Vol. ASSP-29,
+ * No. 1, February 1981, pp 84-91
+ *
+ * JOS had slightly different numbers for the Blackman-Harris windows.
+ */
+
+double *
+makewindow(Windowtype type, int size, double *window) {
+ int i, j, midn, midp1, midm1;
+ double freq, rate, sr1, angle, expn, expsum, cx, two_pi;
+
+ midn = size >> 1;
+ midp1 = (size + 1) / 2;
+ midm1 = (size - 1) / 2;
+ two_pi = 8.0 * atan(1.0);
+ freq = two_pi / (double) size;
+ rate = 1.0 / (double) midn;
+ angle = 0.0;
+ expn = log(2.0) / (double) midn + 1.0;
+ expsum = 1.0;
+
+ switch (type) {
+ case RECTANGULAR_WINDOW:
+ for (i = 0; i < size; i++) window[i] = 1.0;
+ break;
+ case HANNING_WINDOW: /* Hann would be more accurate */
+ for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
+ window[j] = (window[i] = 0.5 - 0.5 * cos(angle));
+ break;
+ case WELCH_WINDOW:
+ for (i = 0, j = size - 1; i <= midn; i++, j--)
+ window[j] =
+ (window[i] = 1.0 - sqr((double) (i - midm1) / (double) midp1));
+ break;
+ case PARZEN_WINDOW:
+ for (i = 0, j = size - 1; i <= midn; i++, j--)
+ window[j] =
+ (window[i] = 1.0 - fabs((double) (i - midm1) / (double) midp1));
+ break;
+ case BARTLETT_WINDOW:
+ for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += rate)
+ window[j] = (window[i] = angle);
+ break;
+ case HAMMING_WINDOW:
+ for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq)
+ window[j] = (window[i] = 0.54 - 0.46 * cos(angle));
+ break;
+ case BLACKMAN2_WINDOW: /* using Chebyshev polynomial equivalents here */
+ for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq) {
+ cx = cos(angle);
+ window[j] = (window[i] = (.34401 + (cx * (-.49755 + (cx * .15844)))));
+ }
+ break;
+ case BLACKMAN3_WINDOW:
+ for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq) {
+ cx = cos(angle);
+ window[j] =
+ (window[i] = (.21747 + (cx * (-.45325 + (cx * (.28256 - (cx * .04672)))))));
+ }
+ break;
+ case BLACKMAN4_WINDOW:
+ for (i = 0, j = size - 1, angle = 0.0; i <= midn; i++, j--, angle += freq) {
+ cx = cos(angle);
+ window[j] = (window[i] =
+ (.084037 +
+ (cx *
+ (-.29145 +
+ (cx *
+ (.375696 + (cx * (-.20762 + (cx * .041194)))))))));
+ }
+ break;
+ case EXPONENTIAL_WINDOW:
+ for (i = 0, j = size - 1; i <= midn; i++, j--) {
+ window[j] = (window[i] = expsum - 1.0);
+ expsum *= expn;
+ }
+ break;
+ case RIEMANN_WINDOW:
+ sr1 = two_pi / (double) size;
+ for (i = 0, j = size - 1; i <= midn; i++, j--) {
+ if (i == midn) window[j] = (window[i] = 1.0);
+ else {
+ /* split out because NeXT C compiler can't handle the full expression */
+ cx = sr1 * (midn - i);
+ window[i] = sin(cx) / cx;
+ window[j] = window[i];
+ }
+ }
+ break;
+ case BLACKMANHARRIS_WINDOW:
+ {
+ double
+ a0 = 0.35875,
+ a1 = 0.48829,
+ a2 = 0.14128,
+ a3 = 0.01168;
+
+
+ for (i = 0; i<size;i++) {
+ window[i] = a0 - a1*cos(two_pi*(double)(i+0.5)/(double)size)
+ + a2*cos(2.0*two_pi*(double)(i+0.5)/(double)size)
+ - a3*cos(3.0*two_pi*(double)(i+0.5)/(double)size);
+ }
+ }
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ return window;
+}
--- /dev/null
+/* window.h
+
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
+Implemented from code by Bill Schottstaedt of Snd Editor at CCRMA
+
+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 2 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, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+The authors can be reached by email at
+
+ab2kt@arrl.net
+or
+rwmcgwier@comcast.net
+
+or by paper mail at
+
+The DTTS Microwave Society
+6 Kathleen Place
+Bridgewater, NJ 08807
+*/
+
+#ifndef _window_h
+#define _window_h
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+
+/* #define RECTANGULAR_WINDOW 1
+#define HANNING_WINDOW 2
+#define WELCH_WINDOW 3
+#define PARZEN_WINDOW 4
+#define BARTLETT_WINDOW 5
+#define HAMMING_WINDOW 6
+#define BLACKMAN2_WINDOW 7
+#define BLACKMAN3_WINDOW 8
+#define BLACKMAN4_WINDOW 9
+#define EXPONENTIAL_WINDOW 10
+#define RIEMANN_WINDOW 11 */
+
+typedef enum _windowtype {
+ RECTANGULAR_WINDOW,
+ HANNING_WINDOW,
+ WELCH_WINDOW,
+ PARZEN_WINDOW,
+ BARTLETT_WINDOW,
+ HAMMING_WINDOW,
+ BLACKMAN2_WINDOW,
+ BLACKMAN3_WINDOW,
+ BLACKMAN4_WINDOW,
+ EXPONENTIAL_WINDOW,
+ RIEMANN_WINDOW,
+ BLACKMANHARRIS_WINDOW,
+} Windowtype;
+
+extern double *makewindow(Windowtype type, int size, double *window);
+//extern char *window_name(int n);
+extern double sqr(double x);
+
+#endif
--- /dev/null
+python:
+ swig -python hardware.i
+ gcc -fPIC -I. -I/usr/include/python -c hardware_wrap.c
+ gcc -fPIC -I. -c hardware.c
+ ld -shared hardware.o hardware_wrap.o -o _sdr1khw.so
+clean:
+ /bin/rm -f hardware_wrap.c sdr1khw.py *.o *.so *.pyc
+
--- /dev/null
+========================================================================
+Simple stuff.
+
+To use, run python interactively. Then
+
+>>> execfile("sdr1k-setup.py")
+
+to get the interface started.
+
+To set the frequency, do
+
+>>> setDDSFreq(14.077)
+
+To toggle the mute relay,
+
+>>> setMuteRelay(not getMuteRelay())
+
+etc.
+
+To shut down,
+
+>>> closeRig()
+
+and exit python. (The startup script, which is crude and will be
+replaced shortly, does an openRig("/dev/parport0")
+========================================================================
+
+To build:
+
+There is a simple Makefile that does just the following --
+
+swig -python hardware.i
+gcc -fPIC -I. -I/usr/include/python -c hardware_wrap.c
+gcc -fPIC -I. -c hardware.c
+ld -shared hardware.o hardware_wrap.o -o _sdr1khw.so
+
+Ready to go.
--- /dev/null
+/* hardware.c */
+
+#include <hardware.h>
+
+Rig myRig;
+
+PRIVATE void CalcClock(void);
+PRIVATE void Latch(CtrlPin vCtrlPin);
+PRIVATE void PWrite(BYTE data);
+PRIVATE void DDSWrite(BYTE data, BYTE addr);
+PRIVATE void SetRadioFreq(double f);
+PRIVATE void Delay(void);
+PRIVATE void ResetLatches(void);
+PRIVATE void ResetDDS(void);
+BOOLEAN InputPin(StatusPin vStatusPin);
+
+static int counter = 0;
+
+// ======================================================
+// Properties
+// ======================================================
+
+BOOLEAN
+getExtended(void) {
+ return myRig.extended;
+}
+
+void
+setExtended(BOOLEAN value) {
+ myRig.extended = value;
+}
+
+BOOLEAN
+getRFE_Enabled(void) {
+ return myRig.rfe_enabled;
+}
+
+void
+setRFE_Enabled(BOOLEAN value) {
+ myRig.rfe_enabled = value;
+}
+
+BOOLEAN
+getXVTR_Enabled(void) {
+ return myRig.xvtr_enabled;
+}
+
+void
+setXVTR_Enabled(BOOLEAN value) {
+ myRig.xvtr_enabled = value;
+ if (myRig.xvtr_enabled)
+ myRig.max_freq = 146.0;
+ else
+ myRig.max_freq = 65.0;
+}
+
+// private BOOLEANxvtr_tr_logic = FALSE;
+BOOLEAN
+getXVTR_TR_Logic(void) {
+ return myRig.xvtr_tr_logic;
+}
+
+void
+setXVTR_TR_Logic(BOOLEAN value) {
+ myRig.xvtr_tr_logic = value;
+}
+
+int
+getLatchDelay(void) {
+ return myRig.latch_delay;
+}
+
+void
+setLatchDelay(int value) {
+ myRig.latch_delay = value;
+}
+
+double
+getMinFreq(void) {
+ return myRig.min_freq;
+}
+
+double
+getMaxFreq(void) {
+ return myRig.max_freq;
+}
+
+/* unsigned short
+getBaseAddr(void) {
+ return myRig.baseAdr;
+}
+
+void
+setBaseAddr(unsigned short value) {
+ myRig.baseAdr = value;
+ }*/
+
+BandSetting
+getBandRelay(void) {
+ return myRig.band_relay;
+}
+
+void
+setBandRelay(BandSetting value) {
+
+ extern void Pwrite(unsigned char);
+ myRig.band_relay = value;
+ PWrite((unsigned char) (myRig.band_relay + myRig.transmit_relay +
+ myRig.mute_relay));
+ Latch(BPF);
+}
+
+BOOLEAN
+getTransmitRelay(void) {
+ //Get state of TR relay on BPF board
+ if (myRig.transmit_relay == TR)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void
+setTransmitRelay(BOOLEAN value) {
+ //If in valid Amateur BandRelay Save and output new TR Relay setting
+ BYTE tmpLatch = 0;
+ BOOLEAN tmpATTN = FALSE;
+ if (value == TRUE) {
+ if (IsHamBand(myRig.curBandPlan) == TRUE) {
+ myRig.transmit_relay = TR; // Set to TX
+ if (getRFE_Enabled()) {
+ tmpATTN = getATTN_Relay();
+ if (getXVTR_Enabled() && (myRig.dds_freq >= 144))
+ setXVTR_TR_Relay(myRig.xvtr_tr_logic); //Set XVTR TR to transmit
+ else
+ setAMP_Relay(TRUE); //Switch RFE to transmit
+
+ // TODO: REMOVE THE AMP RELAY SWITCH ON THE PRODUCTION RFE
+
+ tmpLatch = (BYTE) (myRig.transmit_relay + myRig.mute_relay);
+ } else
+ tmpLatch =
+ (BYTE) (myRig.band_relay + myRig.transmit_relay +
+ myRig.mute_relay);
+ }
+ } else {
+ myRig.transmit_relay = 0; // Set to RX
+ if (getRFE_Enabled()) {
+ setAMP_Relay(FALSE);
+ tmpLatch = (BYTE) (myRig.transmit_relay + myRig.mute_relay);
+ if (getXVTR_Enabled())
+ setXVTR_TR_Relay(!myRig.xvtr_tr_logic); // Set XVTR TR to receive
+ setATTN_Relay(tmpATTN);
+ } else
+ tmpLatch =
+ (BYTE) (myRig.band_relay + myRig.transmit_relay +
+ myRig.mute_relay);
+ }
+ PWrite(tmpLatch);
+ Latch(BPF);
+}
+
+BOOLEAN
+getMuteRelay(void) {
+//Get state of MUTE relay on TRX board
+ if (myRig.mute_relay == MUTE)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+void
+setMuteRelay(BOOLEAN value) {
+ //Mute the speaker relay if TRUE
+ if (value == TRUE)
+ myRig.mute_relay = 0;
+ else
+ myRig.mute_relay = MUTE;
+ PWrite((BYTE)
+ (myRig.band_relay + myRig.transmit_relay + myRig.mute_relay));
+ Latch(BPF);
+}
+
+BOOLEAN
+getGainRelay(void) {
+ //Get state of GAIN relay on TRX board
+ if (myRig.gain_relay == GAIN)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+void
+setGainRelay(BOOLEAN value) { //Save and output state of GAIN relay on TRX board
+ if (value == TRUE)
+ myRig.gain_relay = 0; // 40dB or 0dB w/RFE
+ else
+ myRig.gain_relay = GAIN; // 26dB
+ PWrite((BYTE) (myRig.external_output + myRig.gain_relay));
+ Latch(EXT);
+}
+
+int
+getExternalOutput(void) { //Get state of External Control outputs on PIO board
+ return myRig.external_output;
+}
+
+void
+setExternalOutput(int value) {
+ //Save and output state of External Control outputs on PIO board
+ myRig.external_output = value;
+ PWrite((BYTE) (myRig.external_output + myRig.gain_relay));
+ Latch(EXT);
+}
+
+double
+getDDSClockCorrection(void) {
+ return myRig.dds_clock_correction;
+}
+
+void
+setDDSClockCorrection(double value) {
+ myRig.dds_clock_correction = value;
+ CalcClock();
+ SetRadioFreq(myRig.dds_freq);
+}
+
+int
+getPLLMult(void) {
+ return myRig.pll_mult;
+}
+
+PRIVATE void
+CalcClock(void) {
+ //sysClock = (pll_mult * dds_clock);
+ myRig.sysClock = (myRig.pll_mult * myRig.dds_clock)
+ + myRig.dds_clock_correction;
+ //Calculates step size for 16 bit frequency step size
+ myRig.dds_step_size = myRig.sysClock / pow(2.0, 48.0);
+}
+
+void
+setPLLMult(int value) {
+ myRig.pll_mult = value;
+ CalcClock();
+}
+
+double
+getDDSClock(void) {
+ return myRig.dds_clock;
+}
+
+void
+setDDSClock(double value) {
+ //Compute internal DDS System Clock and Phase Truncation Elimination Step
+ myRig.dds_clock = value;
+ CalcClock();
+}
+
+BOOLEAN
+getIFShift(void) {
+ return myRig.if_shift;
+}
+
+void
+setIFShift(BOOLEAN value) {
+ //Turns IF shift on and off
+ myRig.if_shift = value;
+ if (!myRig.spur_reduction) {
+ if (myRig.if_shift) {
+ myRig.OSC_change = -11025.0;
+ myRig.needs_OSC_change = TRUE;
+ } else {
+ myRig.OSC_change = 0.0;
+ myRig.needs_OSC_change = TRUE;
+ }
+ } else
+ myRig.needs_OSC_change = FALSE;
+ SetRadioFreq(myRig.dds_freq);
+}
+
+BOOLEAN
+getSpurReduction(void) {
+ return myRig.spur_reduction;
+}
+
+void
+setSpurReduction(BOOLEAN value) {
+ //Turns DDS Phase Truncation Spur reduction on and off
+ myRig.spur_reduction = value;
+ if (!myRig.spur_reduction) {
+ if (myRig.if_shift) {
+ myRig.OSC_change = -11025.0;
+ myRig.needs_OSC_change = TRUE;
+ } else {
+ myRig.OSC_change = 0.0;
+ myRig.needs_OSC_change = TRUE;
+ }
+ } else
+ myRig.needs_OSC_change = FALSE;
+ SetRadioFreq(myRig.dds_freq);
+}
+
+double
+getIFFreq(void) {
+ return myRig.if_freq;
+}
+
+void
+setIFFreq(double value) {
+ //Sets the offset frequency for the IF in MHz
+ myRig.if_freq = value;
+}
+
+double
+getDDSFreq(void) {
+ return myRig.dds_freq;
+}
+
+void
+setDDSFreq(double value) {
+ myRig.dds_freq = value;
+ SetRadioFreq(myRig.dds_freq);
+}
+
+int
+getSampleRate(void) {
+ return myRig.sample_rate;
+}
+
+void
+setSampleRate(int value) {
+ myRig.sample_rate = value;
+ //Compute bandwidth of FFT bin
+ if (myRig.fft_length > 0)
+ myRig.FFT_Bin_Size = (myRig.sample_rate / myRig.fft_length) * 1e-6;
+}
+
+int
+getFFTLength(void) {
+ return myRig.fft_length;
+}
+
+void
+setFFTLength(int value) {
+ myRig.fft_length = value;
+ //Compute bandwidth of FFT bin
+ if (myRig.fft_length > 0)
+ myRig.FFT_Bin_Size = (myRig.sample_rate / myRig.fft_length) * 1e-6;
+}
+
+int
+getTuneFFT(void) {
+ return myRig.tune_fft;
+}
+
+double
+getTuneFracRel(void) {
+ return myRig.tune_frac_rel;
+}
+
+double
+getVFOOffset(void) {
+ return myRig.vfo_offset;
+}
+
+void
+setVFOOffset(double value) {
+ myRig.vfo_offset = value;
+ SetRadioFreq(myRig.dds_freq);
+}
+
+int
+getIOUDClock(void) {
+ return myRig.ioud_clock;
+}
+
+void
+setIOUDClock(int value) {
+ double bitVal, bytVal;
+ int i;
+ BYTE lWord;
+ myRig.ioud_clock = value; //Save value
+
+ bitVal = value; //Compute Numeric Value
+
+ for (i = 24; i >= 0; i -= 8) //Convert to binary strings
+ {
+ // bytVal = bitVal / (Math.Pow(2, i)); //Compute binary byte Value
+ bytVal = bitVal / pow(2.0, (double) i); //Compute binary byte Value
+ lWord = (BYTE) bytVal; //Truncate fractional portion
+ bitVal -= lWord * pow(2.0, (double) i); //Reduce value
+ switch (i) //Write to byte position
+ {
+ case 32:
+ DDSWrite(lWord, 22);
+ break;
+ case 16:
+ DDSWrite(lWord, 23);
+ break;
+ case 8:
+ DDSWrite(lWord, 24);
+ break;
+ case 0:
+ DDSWrite(lWord, 25);
+ break;
+ }
+ }
+}
+
+unsigned short
+getDACMult(void) {
+ return myRig.dac_mult;
+}
+
+void
+setDACMult(unsigned short value) {
+ double bitVal, bytVal;
+ int i;
+ BYTE lWord;
+ //Send new I DAC Multiplier value to DDS
+ myRig.dac_mult = value;
+ bitVal = value; //Compute Numeric Value
+ for (i = 8; i >= 0; i -= 8) //Convert to binary strings
+ {
+ bytVal = bitVal / pow(2.0, (double) i); //Compute binary byte Value
+ lWord = (BYTE) bytVal; //Truncate fractional portion
+ bitVal -= lWord * pow(2.0, (double) i); //Reduce value
+ switch (i) {
+ case 8:
+ DDSWrite(lWord, 33);
+ break;
+ case 0:
+ DDSWrite(lWord, 34);
+ break;
+ }
+ }
+
+ bitVal = value; //Compute Numeric Value
+ for (i = 8; i >= 0; i -= 8) //Convert to binary strings
+ {
+ bytVal = bitVal / pow(2.0, (double) i); //Compute binary byte Value
+ lWord = (BYTE) bytVal; //Truncate fractional portion
+ bitVal -= lWord * pow(2.0, (double) i); //Reduce value
+ switch (i) {
+ case 8:
+ DDSWrite(lWord, 35);
+ break;
+ case 0:
+ DDSWrite(lWord, 36);
+ break;
+ }
+ }
+}
+
+// ======================================================
+// Private Member Functions
+// ======================================================
+
+PRIVATE void
+Delay(void) {
+ usleep(1000 * myRig.latch_delay);
+}
+
+PRIVATE void
+Latch(CtrlPin vCtrlPin) {
+ unsigned char mask;
+ //Strobe the specified pin to latch data
+ switch (vCtrlPin) {
+ case EXT:
+ mask = 0xA, ioctl(myRig.fd, PPWCONTROL, &mask);
+ Delay();
+ mask = 0xB, ioctl(myRig.fd, PPWCONTROL, &mask);
+ break;
+ case BPF:
+ mask = 0x9, ioctl(myRig.fd, PPWCONTROL, &mask);
+ Delay();
+ mask = 0xB, ioctl(myRig.fd, PPWCONTROL, &mask);
+ break;
+ case DAT:
+ mask = 0xF, ioctl(myRig.fd, PPWCONTROL, &mask);
+ Delay();
+ mask = 0xB, ioctl(myRig.fd, PPWCONTROL, &mask);
+ break;
+ case ADR:
+ mask = 0x3, ioctl(myRig.fd, PPWCONTROL, &mask);
+ Delay();
+ mask = 0xB, ioctl(myRig.fd, PPWCONTROL, &mask);
+ break;
+ }
+}
+
+PRIVATE void
+ResetLatches(void) { //Set all latch outputs to logic zero (relays off)
+ PWrite(0);
+ Latch(ADR);
+ Latch(DAT);
+
+ myRig.gain_relay = GAIN;
+ myRig.external_output = 0;
+ PWrite((BYTE) (myRig.external_output + myRig.gain_relay));
+ Latch(EXT);
+
+ setBandRelay(bsnone);
+ myRig.transmit_relay = 0;
+ myRig.mute_relay = MUTE;
+
+ PWrite((BYTE)
+ (myRig.band_relay + myRig.transmit_relay + myRig.mute_relay));
+ Latch(BPF);
+}
+
+PRIVATE void
+PWrite(BYTE data) { //Write data Byte to parallel port
+ ioctl(myRig.fd, PPWDATA, &data);
+ Delay(); //Delay to allow data line setup
+}
+
+PRIVATE void
+ResetDDS(void) {
+ PWrite(RESET + WRB); //Reset the DDS chip
+ Latch(ADR);
+ PWrite(WRB); //Leave WRB high
+ Latch(ADR);
+ DDSWrite(COMP_PD, 29); //Power down comparator
+ //TODO: ADD PLL MULTIPLIER PROPERTY AND LOGIC
+ DDSWrite(BYPASS_PLL, 30); //Bypass PLL
+ //DDSWrite(BYPASS_SINC + OSK_EN, 32);//Bypass Inverse Sinc and enable DAC Mult
+ DDSWrite(BYPASS_SINC, 32);
+ setDACMult(4095); //Set DAC multiplier value
+}
+
+PRIVATE void
+DDSWrite(BYTE data, BYTE addr) {
+ //Set up data bits
+ PWrite(data);
+ Latch(DAT);
+
+ //Set up address bits with WRB high
+ PWrite((BYTE) (addr + WRB));
+ Latch(ADR);
+
+ //Send write command with WRB low
+ PWrite(addr);
+ Latch(ADR);
+
+ //Return WRB high
+ PWrite(WRB);
+ Latch(ADR);
+}
+
+PRIVATE void
+SetRadioFreq(double f) {
+ double vfoFreq = f;
+ int i;
+ // calculate software frequency to program
+ if (getXVTR_Enabled() && f >= 144 && f <= 146) //If transverter enabled compute 28MHz IF frequency
+ f -= 116; //Subtract 116MHz (144-28) from VFO display frequency
+
+ if (myRig.if_shift)
+ f -= myRig.if_freq; // adjust for IF shift
+
+ f += myRig.vfo_offset; // adjust for vfo offset
+
+ unsigned long long int tuning_word =
+ (unsigned long long int) (f / myRig.sysClock * pow(2.0, 48.0));
+
+ // start with current tuning word
+ // clear first bit, low 31 bits; set bit 31
+ if (myRig.spur_reduction) {
+ unsigned long long int sr_tuning_word =
+ (tuning_word & ~(0x80007fffffffLL)) | 0x000080000000LL;
+ double software_offset =
+ (sr_tuning_word - tuning_word) * myRig.dds_step_size;
+
+ if (myRig.if_shift) //Convert the tuning fraction to rel frq
+ myRig.tune_frac_rel = 1000000.0 * (software_offset) - 11025.0;
+ else
+ myRig.tune_frac_rel = 1000000.0 * (software_offset);
+ myRig.OSC_change = myRig.tune_frac_rel;
+ myRig.needs_OSC_change = TRUE;
+
+ tuning_word = sr_tuning_word;
+ }
+ // program hardware
+ SetBPF(vfoFreq);
+
+ if (tuning_word != myRig.last_tuning_word) {
+ //Debug.WriteLine("tuning_word != last_tuning_word");
+ //Debug.Write("tuning word: ");
+
+ myRig.last_tuning_word = tuning_word; //save new tuning word
+
+ for (i = 0; i < 6; i++) {
+ BYTE b =
+ (BYTE) (tuning_word >> (unsigned long long int) (40 - i * 8)) &
+ 0xFFLL;
+ //Debug.Write(b+" ");
+ DDSWrite(b, (BYTE) (4 + i));
+ }
+ //Debug.WriteLine("");
+ }
+}
+
+// ======================================================
+// Public Member Functions
+// ======================================================
+
+BOOLEAN
+InputPin(StatusPin vStatusPin) { //Readback state and mask specified status pin
+ unsigned char status;
+ ioctl(myRig.fd, PPRSTATUS, &status);
+ if (vStatusPin == PIN_11) //Pin 11 is inverted
+ return (((BYTE) vStatusPin & status) == 0);
+ else
+ return (((BYTE) vStatusPin & status) != 0);
+}
+
+BYTE
+StatusPort(void) {
+ unsigned char status;
+ ioctl(myRig.fd, PPRSTATUS, &status);
+ return status;
+}
+
+void
+RigInit(void) {
+ setIFShift(TRUE);
+
+ // user setable through the setup form
+ //DDSClockCorrection = 0.000;
+ setPLLMult(1);
+ setDDSClock(200.0);
+ setIFFreq(0.011025);
+ setSampleRate(48000);
+ setFFTLength(4096);
+ setDACMult(4095);
+
+ // ResetLatches(void); //Reset all control latches
+ //
+ // if(RFE_Enabled)
+ // {
+ // ResetRFE(void);
+ // if(XVTR_Enabled)
+ // XVTR_TR_Relay = TRUE; //Set transverter to receive mode
+ // }
+ // ResetDDS(void); //Hardware reset for DDS
+}
+
+void
+PowerOn(void) {
+ // set mute/gain relays based on console
+ if (getXVTR_Enabled())
+ setXVTR_TR_Relay(!myRig.xvtr_tr_logic);
+ setDDSFreq(myRig.dds_freq);
+}
+
+void
+StandBy(void) {
+ ResetLatches();
+ if (getRFE_Enabled())
+ ResetRFE();
+ if (getXVTR_Enabled())
+ setXVTR_TR_Relay(FALSE);
+ ResetDDS();
+}
+
+void
+SetExt(ExtPin pin) {
+ //Set the designated external pin high
+ myRig.external_output += (BYTE) pin;
+ PWrite((BYTE) (myRig.external_output + myRig.gain_relay));
+ Latch(EXT);
+}
+
+void
+ResExt(ExtPin pin) {
+ //Reset the designated external pin high
+ myRig.external_output -= (BYTE) pin;
+ PWrite((BYTE) (myRig.external_output + myRig.gain_relay));
+ Latch(EXT);
+}
+
+BOOLEAN
+PinValue(ExtPin pin) {
+ //Return TRUE if Pin is set
+ if ((myRig.external_output & (int) pin) != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+void
+SetBPF(double VFOValue) {
+ if (getRFE_Enabled()) // RFE is present
+ {
+ //Use shift registers on RFE to control BPF and LPF banks
+ if (VFOValue <= 2) // DC to 2MHz
+ {
+ SRLoad(IC10, LPF9 + BPF0);
+ SRLoad(IC9, 0);
+ } else if (VFOValue <= 4) // 2MHz to 4MHz
+ {
+ SRLoad(IC10, BPF1);
+ SRLoad(IC9, LPF7);
+ } else if (VFOValue <= 6) // 4MHz to 6MHz
+ {
+ SRLoad(IC10, BPF1);
+ SRLoad(IC9, LPF2);
+ } else if (VFOValue <= 7.3) // 6MHz to 7.3MHz
+ {
+ SRLoad(IC10, BPF2);
+ SRLoad(IC9, LPF5);
+ } else if (VFOValue <= 10.2) // 7.3MHz to 10.2MHz
+ {
+ SRLoad(IC10, BPF2);
+ SRLoad(IC9, LPF4);
+ } else if (VFOValue <= 12) // 10.2MHz to 12MHz
+ {
+ SRLoad(IC10, BPF2);
+ SRLoad(IC9, LPF3);
+ } else if (VFOValue <= 14.5) // 12MHz to 14.5MHz
+ {
+ SRLoad(IC10, BPF3);
+ SRLoad(IC9, LPF3);
+ } else if (VFOValue <= 21.5) // 14.5MHz to 21.5MHz
+ {
+ SRLoad(IC10, BPF3 + LPF8);
+ SRLoad(IC9, 0);
+ } else if (VFOValue <= 24) // 21.5MHz to 24MHz
+ {
+ SRLoad(IC10, BPF3);
+ SRLoad(IC9, LPF6);
+ } else if (VFOValue <= 30) // 24MHz to 30MHz
+ {
+ SRLoad(IC10, BPF4);
+ SRLoad(IC9, LPF6);
+ } else if (VFOValue <= 36) // 30MHz to 36MHz
+ {
+ SRLoad(IC10, BPF4);
+ SRLoad(IC9, LPF1);
+ } else if (VFOValue <= 65) // 36MHz to 65Mhz
+ {
+ SRLoad(IC10, BPF5);
+ SRLoad(IC9, LPF1);
+ } else if (getXVTR_Enabled() && VFOValue >= 144 && VFOValue <= 146) //28MHz IF for transverter
+ {
+ SRLoad(IC10, BPF4);
+ SRLoad(IC9, LPF6);
+ setXVTR_Relay(TRUE);
+ }
+ if (getXVTR_Enabled() && VFOValue < 144)
+ setXVTR_Relay(FALSE);
+ } else // RFE is not present
+ {
+ //Select the BPF relays using the high frequency cutoff
+ if (VFOValue < 2) //DC to 2MHz
+ setBandRelay(bs0);
+ else if (VFOValue < 6) //2MHz to 6MHz
+ setBandRelay(bs1);
+ else if (VFOValue < 12) //6MHz to 12MHz
+ setBandRelay(bs2);
+ else if (VFOValue < 24) //12MHz to 24MHz
+ setBandRelay(bs3);
+ else if (VFOValue < 36) //24MHz to 36MHz
+ setBandRelay(bs4);
+ else //36MHz to 65Mhz
+ setBandRelay(bs5);
+ }
+}
+
+BOOLEAN
+IsHamBand(BandPlan b) {
+ if (myRig.extended)
+ return TRUE;
+
+ switch (b) {
+ case IARU1:
+ if (myRig.dds_freq >= 1.8 && myRig.dds_freq <= 2.0)
+ return TRUE;
+ else if (myRig.dds_freq >= 3.5 && myRig.dds_freq <= 4.0)
+ return TRUE;
+ else if (myRig.dds_freq == 5.3305)
+ return TRUE;
+ else if (myRig.dds_freq == 5.3465)
+ return TRUE;
+ else if (myRig.dds_freq == 5.3665)
+ return TRUE;
+ else if (myRig.dds_freq == 5.3715)
+ return TRUE;
+ else if (myRig.dds_freq == 5.4035)
+ return TRUE;
+ else if (myRig.dds_freq >= 7.0 && myRig.dds_freq <= 7.3)
+ return TRUE;
+ else if (myRig.dds_freq >= 10.1 && myRig.dds_freq <= 10.15)
+ return TRUE;
+ else if (myRig.dds_freq >= 14.0 && myRig.dds_freq <= 14.35)
+ return TRUE;
+ else if (myRig.dds_freq >= 18.068 && myRig.dds_freq <= 18.168)
+ return TRUE;
+ else if (myRig.dds_freq >= 21.0 && myRig.dds_freq <= 21.45)
+ return TRUE;
+ else if (myRig.dds_freq >= 24.89 && myRig.dds_freq <= 24.99)
+ return TRUE;
+ else if (myRig.dds_freq >= 21.0 && myRig.dds_freq <= 21.45)
+ return TRUE;
+ else if (myRig.dds_freq >= 28.0 && myRig.dds_freq <= 29.7)
+ return TRUE;
+ else if (myRig.dds_freq >= 50.0 && myRig.dds_freq <= 54.0)
+ return TRUE;
+ else if (myRig.dds_freq >= 144.0 && myRig.dds_freq <= 146.0) {
+ if (getRFE_Enabled() && getXVTR_Enabled())
+ return TRUE;
+ else
+ return FALSE;
+ } else
+ return FALSE;
+ default:
+ return FALSE;
+ // TODO: Implement other bandplans here
+ }
+}
+
+void
+TestPort(void) {
+ //Toggle 1 and 0 to each of the four parallel port latches
+ PWrite(0);
+ Latch(BPF);
+ Latch(ADR);
+ Latch(DAT);
+ Latch(EXT);
+ PWrite(255);
+ Latch(BPF);
+ Latch(ADR);
+ Latch(DAT);
+ Latch(EXT);
+}
+
+void
+RCKStrobe(BOOLEAN ClearReg, RFE_RCK Reg) {
+ //Strobe the RFE 1:4 decoder output to transfer contents of shift register to output latches
+ if (ClearReg) //Clear the shift register contents
+ PWrite((BYTE) (Reg)); //Strobe decoder output low and clear register
+ else
+ PWrite((BYTE) (SCLR_NOT + Reg + myRig.transmit_relay + myRig.mute_relay)); //Strobe decoder output low
+ Latch(BPF);
+ PWrite((BYTE) (SCLR_NOT + DCDR_NE + myRig.transmit_relay + myRig.mute_relay)); //Disable 1:4 decoder outputs
+ Latch(BPF);
+}
+
+void
+SRLoad(RFE_RCK Reg, int Data) {
+ //Shift data into shift registers on RFE
+ int choose[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
+ int i;
+
+ for (i = 0; i < 8; i++) {
+ int mask = choose[i]; //Mask the current bit
+ if ((mask & Data) == 0) //Current bit = 0
+ {
+ PWrite((BYTE) (SCLR_NOT + DCDR_NE + myRig.transmit_relay + myRig.mute_relay)); //Output 0 bit
+ Latch(BPF);
+ PWrite((BYTE) (SCLR_NOT + DCDR_NE + SCK + myRig.transmit_relay + myRig.mute_relay)); //Clock 0 into shift register
+ } else //Current bit = 1
+ {
+ PWrite((BYTE) (SCLR_NOT + DCDR_NE + SER + myRig.transmit_relay + myRig.mute_relay)); //Output 1 bit
+ Latch(BPF);
+ PWrite((BYTE) (SCLR_NOT + DCDR_NE + SER + SCK + myRig.transmit_relay + myRig.mute_relay)); //Clock 1 into shift register
+ }
+ Latch(BPF);
+ PWrite((BYTE) (SCLR_NOT + DCDR_NE + myRig.transmit_relay + myRig.mute_relay)); //Return SCK low
+ Latch(BPF);
+ }
+ RCKStrobe(FALSE, Reg); //Strobe Register Clock
+}
+
+void
+ResetRFE(void) {
+ //Reset all RFE shift registers to zero output
+ RCKStrobe(TRUE, IC11);
+ RCKStrobe(TRUE, IC7);
+ RCKStrobe(TRUE, IC10);
+ RCKStrobe(TRUE, IC9);
+}
+
+BOOLEAN
+getAMP_Relay(void) {
+ return (myRig.m_IC7_Memory & AMP_RLYS) != 0;
+}
+
+void
+setAMP_Relay(BOOLEAN value) {
+ //Set or reset LNA relay
+ if (value)
+ myRig.m_IC7_Memory = (myRig.m_IC7_Memory | AMP_RLYS);
+ else
+ myRig.m_IC7_Memory = (myRig.m_IC7_Memory & (AMP_RLYS ^ 255));
+ SRLoad(IC7, myRig.m_IC7_Memory);
+}
+
+
+BOOLEAN
+getATTN_Relay(void) {
+ return (myRig.m_IC7_Memory & ATTN_RLY) != 0;
+}
+
+void
+setATTN_Relay(BOOLEAN value) {
+ //Set or reset attenuator relay
+ if (value)
+ myRig.m_IC7_Memory = (myRig.m_IC7_Memory | ATTN_RLY);
+ else
+ myRig.m_IC7_Memory = (myRig.m_IC7_Memory & (ATTN_RLY ^ 255));
+ SRLoad(IC7, myRig.m_IC7_Memory);
+}
+
+BOOLEAN
+getXVTR_TR_Relay(void) {
+ return (myRig.m_IC7_Memory & XVTR_TR_RLY) != 0;
+}
+
+void
+setXVTR_TR_Relay(BOOLEAN value) {
+ //Set or reset transverter relay
+ if (value)
+ myRig.m_IC7_Memory = (myRig.m_IC7_Memory | XVTR_TR_RLY);
+ else
+ myRig.m_IC7_Memory = myRig.m_IC7_Memory & (XVTR_TR_RLY ^ 255);
+ SRLoad(IC7, myRig.m_IC7_Memory);
+}
+
+BOOLEAN
+getXVTR_Relay(void) {
+ return (myRig.m_IC7_Memory & XVTR_RLY) != 0;
+}
+
+void
+setXVTR_Relay(BOOLEAN value) {
+ //Set or reset XVTR 8R (TR) relay
+ if (value)
+ myRig.m_IC7_Memory = myRig.m_IC7_Memory | XVTR_RLY;
+ else
+ myRig.m_IC7_Memory = myRig.m_IC7_Memory & (XVTR_RLY ^ 255);
+ SRLoad(IC7, myRig.m_IC7_Memory);
+}
+
+BOOLEAN
+getIMPULSE_Relay(void) {
+ return (myRig.m_IC7_Memory & IMPULSE_RLY) != 0;
+}
+
+void
+setIMPULSE_Relay(BOOLEAN value) {
+ //Set or reset Impulse relay
+ if (value)
+ myRig.m_IC7_Memory = myRig.m_IC7_Memory | IMPULSE_RLY;
+ else
+ myRig.m_IC7_Memory = myRig.m_IC7_Memory & (IMPULSE_RLY ^ 255);
+ SRLoad(IC7, myRig.m_IC7_Memory);
+}
+
+void
+Impulse(void) {
+ //Send a single impulse to the QSD
+ SRLoad(IC7, (myRig.m_IC7_Memory | 128));
+ SRLoad(IC7, myRig.m_IC7_Memory);
+}
+
+BOOLEAN
+openRig(char *port) {
+ int mode = IEEE1284_MODE_COMPAT;
+ if (!port) port = "/dev/parport0";
+ if ((myRig.fd = open(port, O_RDWR)) < 0) {
+ perror("open parallel port");
+ return FALSE;
+ }
+ ioctl(myRig.fd, PPCLAIM);
+ ioctl(myRig.fd, PPSETMODE, &mode);
+ return TRUE;
+}
+
+void
+closeRig(void) {
+ ioctl(myRig.fd, PPRELEASE);
+ close(myRig.fd);
+}
--- /dev/null
+/* hardware.h */
+
+#ifndef _HARDWARE_H
+#define _HARDWARE_H
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <setjmp.h>
+
+#include <stdlib.h>
+#include <values.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <libgen.h>
+
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <linux/ppdev.h>
+#include <linux/parport.h>
+
+#ifndef PRIVATE
+#define PRIVATE static
+#endif
+
+typedef int BOOLEAN;
+typedef unsigned char BYTE;
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+// ======================================================
+// Constants and PRIVATE Variables
+// ======================================================
+
+typedef enum _bandplan
+{
+ IARU1 = 1,
+ IARU2 = 2,
+ IARU3 = 3,
+} BandPlan;
+
+//Constants for BPF relays
+
+typedef enum _bandsetting
+{
+ bsnone = 0, //none
+ bs0 = 0x01, //2.5MHz LPF
+ bs1 = 0x02, //2-6MHz BPF
+ bs2 = 0x08, //5-12MHz BPF
+ bs3 = 0x04, //10-24MHz BPF
+ bs4 = 0x10, //20-40MHz BPF
+ bs5 = 0x20, //35-60MHz BPF
+} BandSetting;
+
+//PIO Control Pin Numbers
+
+typedef enum _ctrlpin
+{
+ EXT = 1, //C0
+ BPF = 14, //C1
+ DAT = 16, //C2
+ ADR = 17, //C3
+} CtrlPin;
+
+//PIO Status Mask
+
+typedef enum _statuspin
+{
+ PIN_12 = 0x08, //S3
+ Dash = 0x10, //S4
+ Dot = 0x20, //S5
+ PTT = 0x40, //S6
+ PIN_11 = 0x80, //S7
+} StatusPin;
+
+//External control port mask
+
+typedef enum _extpin
+{
+ P1 = 0x01,
+ P2 = 0x02,
+ P3 = 0x04,
+ P4 = 0x08,
+ P5 = 0x10,
+ P6 = 0x20,
+ P7 = 0x40,
+} ExtPin;
+
+//BEGIN RFE CONTROLS =====================================================
+
+//Control and data lines for RFE serial decoders
+#define SER 1
+#define SCK 2
+#define SCLR_NOT 4
+#define DCDR_NE 32
+
+//RFE 1:4 Decoder (74HC139) values to drive shift register RCK lines
+typedef enum _rfe_rck
+{
+ IC11 = 0,
+ IC7 = 8,
+ IC9 = 24,
+ IC10 = 16,
+} RFE_RCK;
+
+//RFE control constants
+#define LPF0 1 //On board low pass filter relays
+#define LPF1 2
+#define LPF2 4
+#define LPF3 8
+#define LPF4 16
+#define LPF5 32
+#define LPF6 64
+#define LPF7 128
+#define LPF8 1
+#define LPF9 2
+
+#define BPF0 128 //Band pass filter relays
+#define BPF1 64
+#define BPF2 16 //Note: BPF2 and BPF3 are reverse order
+#define BPF3 32 //on BPF board
+#define BPF4 8
+#define BPF5 4
+
+#define PAF0 1 //Power Amplifier low pass filters
+#define PAF1 2
+#define PAF2 4
+#define PAF3 8
+#define PAF4 16
+#define PAF5 32
+#define PAFR 64 //Power amplifier TR relay
+
+#define ATUCTL 128 //Automatic Tuning Unit control
+
+#define AMP_RLYS 3 //Controls both AMP1 and AMP2 relays
+#define XVTR_RLY 8 //Switches 2M transverter switching relayinto signal path
+#define ATTN_RLY 16 //Attenuator relay
+#define XVTR_TR_RLY 4 //2M transverter TR relay (on for RX) XVRX on schematic
+#define IMPULSE_RLY 32 //Impulse circuit switching relay
+#define SPARE_CTRL 64 //Spare control line to PA
+
+
+//Constants latch outputs
+
+#define TR 0x40
+#define MUTE 0x80
+#define GAIN 0x80
+#define WRB 0x40
+#define RESET 0x80
+
+//DDS Control Constants
+#define COMP_PD 0x10 //DDS Comparator power down
+#define DIG_PD 0x01 //DDS Digital Power down
+#define BYPASS_PLL 0x20 //Bypass DDS PLL
+#define INT_IOUD 0x01 //Internal IO Update
+#define OSK_EN 0x20 //Offset Shift Keying enable
+#define OSK_INT 0x10 //Offset Shift Keying
+#define BYPASS_SINC 0x40 //Bypass Inverse Sinc Filter
+#define PLL_RANGE 0x40 //Set PLL Range
+
+typedef struct _rig
+{
+ //PIO register base address
+// unsigned short baseAdr;
+ double min_freq; // minimum allowable tuning frequency
+ double max_freq; // maximum allowable tuning frequency
+ unsigned radio_number;
+ unsigned short Adr;
+ int m_IC7_Memory;
+ //RFE relay memory
+ BOOLEAN rfe_enabled; //True if RFE board is enabled
+ BOOLEAN xvtr_enabled; //Transverter is enabled
+ BOOLEAN extended;
+ BOOLEAN xvtr_tr_logic;
+
+ // END RFE controls
+ //Latch Memories
+
+ BandSetting band_relay;
+ int external_output;
+ int mute_relay;
+ int transmit_relay;
+ int gain_relay;
+ int latch_delay;
+
+ //DDS Clock properties
+ double dds_clock;
+ int pll_mult;
+ double dds_clock_correction;
+ double sysClock;
+ int ioud_clock;
+ unsigned short dac_mult;
+
+ //DDS Frequency Control properties
+ double dds_freq;
+ double if_freq;
+ BOOLEAN if_shift;
+ BOOLEAN spur_reduction;
+ double dds_step_size;
+ int sample_rate;
+ int fft_length;
+ double FFT_Bin_Size;
+ int tune_fft;
+ double tune_frac_rel;
+ double vfo_offset;
+ double last_VFO;
+
+ //Current Bandplan
+ BandPlan curBandPlan;
+
+ double TWO_TO_THE_48_DIVIDED_BY_200;
+ long last_tuning_word;
+
+ int fd;
+ BOOLEAN needs_OSC_change;
+ double OSC_change;
+} Rig;
+
+extern Rig myRig;
+
+extern BOOLEAN openRig(char *port);
+extern void closeRig(void);
+
+extern BOOLEAN getExtended(void);
+extern void setExtended(BOOLEAN value);
+extern BOOLEAN getRFE_Enabled(void);
+extern void setRFE_Enabled(BOOLEAN value);
+extern BOOLEAN getXVTR_Enabled(void);
+extern void setXVTR_Enabled(BOOLEAN value);
+extern BOOLEAN getXVTR_TR_Logic(void);
+extern void setXVTR_TR_Logic(BOOLEAN value);
+extern int getLatchDelay(void);
+extern void setLatchDelay(int value);
+extern double getMinFreq(void);
+extern double getMaxFreq(void);
+//extern unsigned short getBaseAddr(void);
+//extern void setBaseAddr(unsigned short value);
+extern BandSetting getBandRelay(void);
+extern void setBandRelay(BandSetting value);
+extern BOOLEAN getTransmitRelay(void);
+extern void setTransmitRelay(BOOLEAN value);
+extern BOOLEAN getMuteRelay(void);
+extern void setMuteRelay(BOOLEAN value);
+extern BOOLEAN getGainRelay(void);
+extern void setGainRelay(BOOLEAN value);
+extern int getExternalOutput(void);
+extern void setExternalOutput(int value);
+extern double getDDSClockCorrection(void);
+extern void setDDSClockCorrection(double value);
+extern int getPLLMult(void);
+extern void setPLLMult(int value);
+extern double getDDSClock(void);
+extern void setDDSClock(double value);
+extern BOOLEAN getIFShift(void);
+extern void setIFShift(BOOLEAN value);
+extern BOOLEAN getSpurReduction(void);
+extern void setSpurReduction(BOOLEAN value);
+extern double getIFFreq(void);
+extern void setIFFreq(double value);
+extern double getDDSFreq(void);
+extern void setDDSFreq(double value);
+extern int getSampleRate(void);
+extern void setSampleRate(int value);
+extern int getFFTLength(void);
+extern void setFFTLength(int value);
+extern int getTuneFFT(void);
+extern double getTuneFracRel(void);
+extern double getVFOOffset(void);
+extern void setVFOOffset(double value);
+extern int getIOUDClock(void);
+extern void setIOUDClock(int value);
+extern unsigned short getDACMult(void);
+extern void setDACMult(unsigned short value);
+extern BOOLEAN InputPin(StatusPin vStatusPin);
+extern BYTE StatusPort(void);
+extern void RigInit(void);
+extern void PowerOn(void);
+extern void StandBy(void);
+extern void SetExt(ExtPin pin);
+extern void ResExt(ExtPin pin);
+extern BOOLEAN PinValue(ExtPin pin);
+extern void SetBPF(double VFOValue);
+extern BOOLEAN IsHamBand(BandPlan b);
+extern void TestPort(void);
+extern void RCKStrobe(BOOLEAN ClearReg, RFE_RCK Reg);
+extern void SRLoad(RFE_RCK Reg, int Data);
+extern void ResetRFE(void);
+extern BOOLEAN getAMP_Relay(void);
+extern void setAMP_Relay(BOOLEAN value);
+extern BOOLEAN getATTN_Relay(void);
+extern void setATTN_Relay(BOOLEAN value);
+extern BOOLEAN getXVTR_TR_Relay(void);
+extern void setXVTR_TR_Relay(BOOLEAN value);
+extern BOOLEAN getXVTR_Relay(void);
+extern void setXVTR_Relay(BOOLEAN value);
+extern BOOLEAN getIMPULSE_Relay(void);
+extern void setIMPULSE_Relay(BOOLEAN);
+extern void Impulse(void);
+#endif
--- /dev/null
+%module sdr1khw
+%{
+#include "hardware.h"
+%}
+%include "hardware.h"
--- /dev/null
+from sdr1khw import *
+
+openRig("/dev/parport0")
+setRFE_Enabled(TRUE)
+ResetRFE()
+setXVTR_Enabled(FALSE)
+setExtended(FALSE)
+setXVTR_TR_Logic(FALSE)
+setBandRelay(bs0)
+RigInit()
+setVFOOffset(0.0)
+setATTN_Relay(TRUE)
+setTransmitRelay(FALSE)
+setGainRelay(TRUE)
+setSpurReduction(FALSE)
+setExternalOutput(FALSE)
+setDDSClockCorrection(0.0)
+setDDSFreq(13.845)
+setMuteRelay(FALSE)