]> git.rkrishnan.org Git - dttsp.git/commitdiff
Initial revision
authorroot <root>
Wed, 16 Mar 2005 20:49:59 +0000 (20:49 +0000)
committerroot <root>
Wed, 16 Mar 2005 20:49:59 +0000 (20:49 +0000)
86 files changed:
jDttSP/DttSPrc [new file with mode: 0644]
jDttSP/Makefile [new file with mode: 0644]
jDttSP/am_demod.c [new file with mode: 0644]
jDttSP/am_demod.h [new file with mode: 0644]
jDttSP/banal.c [new file with mode: 0644]
jDttSP/banal.h [new file with mode: 0644]
jDttSP/bufvec.c [new file with mode: 0644]
jDttSP/bufvec.h [new file with mode: 0644]
jDttSP/chan.c [new file with mode: 0644]
jDttSP/chan.h [new file with mode: 0644]
jDttSP/chap.c [new file with mode: 0644]
jDttSP/chap.h [new file with mode: 0644]
jDttSP/cmdr [new file with mode: 0755]
jDttSP/command-vocabulary [new file with mode: 0644]
jDttSP/common.h [new file with mode: 0644]
jDttSP/complex.h [new file with mode: 0644]
jDttSP/correctIQ.c [new file with mode: 0644]
jDttSP/correctIQ.h [new file with mode: 0644]
jDttSP/crc16.c [new file with mode: 0644]
jDttSP/crc16.h [new file with mode: 0644]
jDttSP/cxops.c [new file with mode: 0644]
jDttSP/cxops.h [new file with mode: 0644]
jDttSP/datatypes.h [new file with mode: 0644]
jDttSP/digitalagc.c [new file with mode: 0644]
jDttSP/digitalagc.h [new file with mode: 0644]
jDttSP/enums.m4 [new file with mode: 0644]
jDttSP/fastrig.c [new file with mode: 0644]
jDttSP/fastrig.h [new file with mode: 0644]
jDttSP/fftw.h [new file with mode: 0644]
jDttSP/filter.c [new file with mode: 0644]
jDttSP/filter.h [new file with mode: 0644]
jDttSP/fm_demod.c [new file with mode: 0644]
jDttSP/fm_demod.h [new file with mode: 0644]
jDttSP/fromsys.h [new file with mode: 0644]
jDttSP/lmadf.c [new file with mode: 0644]
jDttSP/lmadf.h [new file with mode: 0644]
jDttSP/local.h [new file with mode: 0644]
jDttSP/main.c [new file with mode: 0644]
jDttSP/meter.h [new file with mode: 0644]
jDttSP/metermon.c [new file with mode: 0644]
jDttSP/mkchan.c [new file with mode: 0644]
jDttSP/noiseblanker.c [new file with mode: 0644]
jDttSP/noiseblanker.h [new file with mode: 0644]
jDttSP/oscillator.c [new file with mode: 0644]
jDttSP/oscillator.h [new file with mode: 0644]
jDttSP/ovsv.c [new file with mode: 0644]
jDttSP/ovsv.h [new file with mode: 0644]
jDttSP/ringb.c [new file with mode: 0644]
jDttSP/ringb.h [new file with mode: 0644]
jDttSP/sdr.c [new file with mode: 0644]
jDttSP/sdrexport.c [new file with mode: 0644]
jDttSP/sdrexport.h [new file with mode: 0644]
jDttSP/setup-ipc [new file with mode: 0755]
jDttSP/speechproc.c [new file with mode: 0644]
jDttSP/speechproc.h [new file with mode: 0644]
jDttSP/splitfields.c [new file with mode: 0644]
jDttSP/splitfields.h [new file with mode: 0644]
jDttSP/spottone.c [new file with mode: 0644]
jDttSP/spottone.h [new file with mode: 0644]
jDttSP/thunk.c [new file with mode: 0644]
jDttSP/thunk.h [new file with mode: 0644]
jDttSP/update.c [new file with mode: 0644]
jDttSP/update.h [new file with mode: 0644]
jDttSP/win/banal.c [new file with mode: 0644]
jDttSP/win/banal.h [new file with mode: 0644]
jDttSP/win/chan.c [new file with mode: 0644]
jDttSP/win/chan.h [new file with mode: 0644]
jDttSP/win/common.h [new file with mode: 0644]
jDttSP/win/datatypes.h [new file with mode: 0644]
jDttSP/win/fromsys.h [new file with mode: 0644]
jDttSP/win/main.c [new file with mode: 0644]
jDttSP/win/meter.c [new file with mode: 0644]
jDttSP/win/power_spectrum.c [new file with mode: 0644]
jDttSP/win/power_spectrum.h [new file with mode: 0644]
jDttSP/win/sdrexport.h [new file with mode: 0644]
jDttSP/win/update.c [new file with mode: 0644]
jDttSP/win/update.h [new file with mode: 0644]
jDttSP/win/valueswin.h [new file with mode: 0644]
jDttSP/window.c [new file with mode: 0644]
jDttSP/window.h [new file with mode: 0644]
pyhw/Makefile [new file with mode: 0644]
pyhw/README [new file with mode: 0644]
pyhw/hardware.c [new file with mode: 0644]
pyhw/hardware.h [new file with mode: 0644]
pyhw/hardware.i [new file with mode: 0644]
pyhw/sdr1k-setup.py [new file with mode: 0644]

diff --git a/jDttSP/DttSPrc b/jDttSP/DttSPrc
new file mode 100644 (file)
index 0000000..84a0397
--- /dev/null
@@ -0,0 +1,2 @@
+setMode CWL
+setFilter -1000 -500
diff --git a/jDttSP/Makefile b/jDttSP/Makefile
new file mode 100644 (file)
index 0000000..4c39051
--- /dev/null
@@ -0,0 +1,62 @@
+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
diff --git a/jDttSP/am_demod.c b/jDttSP/am_demod.c
new file mode 100644 (file)
index 0000000..61750ca
--- /dev/null
@@ -0,0 +1,134 @@
+/* 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);
+  }
+}
diff --git a/jDttSP/am_demod.h b/jDttSP/am_demod.h
new file mode 100644 (file)
index 0000000..8b63460
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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
diff --git a/jDttSP/banal.c b/jDttSP/banal.c
new file mode 100644 (file)
index 0000000..a5e8447
--- /dev/null
@@ -0,0 +1,197 @@
+/* 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;
+}
+
diff --git a/jDttSP/banal.h b/jDttSP/banal.h
new file mode 100644 (file)
index 0000000..1ca3ffe
--- /dev/null
@@ -0,0 +1,82 @@
+/* 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
diff --git a/jDttSP/bufvec.c b/jDttSP/bufvec.c
new file mode 100644 (file)
index 0000000..606992b
--- /dev/null
@@ -0,0 +1,203 @@
+/* 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);
+}
+
+
diff --git a/jDttSP/bufvec.h b/jDttSP/bufvec.h
new file mode 100644 (file)
index 0000000..3da0db6
--- /dev/null
@@ -0,0 +1,99 @@
+/* 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
+
diff --git a/jDttSP/chan.c b/jDttSP/chan.c
new file mode 100644 (file)
index 0000000..651274c
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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);
+  }
+}
diff --git a/jDttSP/chan.h b/jDttSP/chan.h
new file mode 100644 (file)
index 0000000..bf92625
--- /dev/null
@@ -0,0 +1,83 @@
+/* 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
diff --git a/jDttSP/chap.c b/jDttSP/chap.c
new file mode 100644 (file)
index 0000000..474e81c
--- /dev/null
@@ -0,0 +1,109 @@
+/* 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);
+  }
+}
+
+
diff --git a/jDttSP/chap.h b/jDttSP/chap.h
new file mode 100644 (file)
index 0000000..a201ad9
--- /dev/null
@@ -0,0 +1,79 @@
+/* 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
diff --git a/jDttSP/cmdr b/jDttSP/cmdr
new file mode 100755 (executable)
index 0000000..e979db5
--- /dev/null
@@ -0,0 +1,14 @@
+#!/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
diff --git a/jDttSP/command-vocabulary b/jDttSP/command-vocabulary
new file mode 100644 (file)
index 0000000..f927b5d
--- /dev/null
@@ -0,0 +1,54 @@
+[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
diff --git a/jDttSP/common.h b/jDttSP/common.h
new file mode 100644 (file)
index 0000000..0f71b86
--- /dev/null
@@ -0,0 +1,66 @@
+/* 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
+
diff --git a/jDttSP/complex.h b/jDttSP/complex.h
new file mode 100644 (file)
index 0000000..cf66d35
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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
+
diff --git a/jDttSP/correctIQ.c b/jDttSP/correctIQ.c
new file mode 100644 (file)
index 0000000..3fc3e52
--- /dev/null
@@ -0,0 +1,57 @@
+/* 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;
+  }
+}
diff --git a/jDttSP/correctIQ.h b/jDttSP/correctIQ.h
new file mode 100644 (file)
index 0000000..0077a0a
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/jDttSP/crc16.c b/jDttSP/crc16.c
new file mode 100644 (file)
index 0000000..a38e6c9
--- /dev/null
@@ -0,0 +1,110 @@
+/* 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
diff --git a/jDttSP/crc16.h b/jDttSP/crc16.h
new file mode 100644 (file)
index 0000000..a244b1c
--- /dev/null
@@ -0,0 +1,57 @@
+/* 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
diff --git a/jDttSP/cxops.c b/jDttSP/cxops.c
new file mode 100644 (file)
index 0000000..b54dbef
--- /dev/null
@@ -0,0 +1,109 @@
+/* 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));
+}
diff --git a/jDttSP/cxops.h b/jDttSP/cxops.h
new file mode 100644 (file)
index 0000000..83d2e26
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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
+
diff --git a/jDttSP/datatypes.h b/jDttSP/datatypes.h
new file mode 100644 (file)
index 0000000..6bc3a4e
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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
+
diff --git a/jDttSP/digitalagc.c b/jDttSP/digitalagc.c
new file mode 100644 (file)
index 0000000..5d559a1
--- /dev/null
@@ -0,0 +1,127 @@
+/* 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;
+  }
+}
diff --git a/jDttSP/digitalagc.h b/jDttSP/digitalagc.h
new file mode 100644 (file)
index 0000000..ae886a7
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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
diff --git a/jDttSP/enums.m4 b/jDttSP/enums.m4
new file mode 100644 (file)
index 0000000..f9669f7
--- /dev/null
@@ -0,0 +1,64 @@
+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
diff --git a/jDttSP/fastrig.c b/jDttSP/fastrig.c
new file mode 100644 (file)
index 0000000..5c4d8ff
--- /dev/null
@@ -0,0 +1,259 @@
+
+/****************************************************************
+ *   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
diff --git a/jDttSP/fastrig.h b/jDttSP/fastrig.h
new file mode 100644 (file)
index 0000000..ae8485b
--- /dev/null
@@ -0,0 +1,99 @@
+/* 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
diff --git a/jDttSP/fftw.h b/jDttSP/fftw.h
new file mode 100644 (file)
index 0000000..9384082
--- /dev/null
@@ -0,0 +1,426 @@
+/* -*- 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 */
diff --git a/jDttSP/filter.c b/jDttSP/filter.c
new file mode 100644 (file)
index 0000000..a9bca9c
--- /dev/null
@@ -0,0 +1,504 @@
+/* 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
diff --git a/jDttSP/filter.h b/jDttSP/filter.h
new file mode 100644 (file)
index 0000000..47eb97e
--- /dev/null
@@ -0,0 +1,108 @@
+/* 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
diff --git a/jDttSP/fm_demod.c b/jDttSP/fm_demod.c
new file mode 100644 (file)
index 0000000..1735eaf
--- /dev/null
@@ -0,0 +1,103 @@
+/* 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);
+  }
+}
diff --git a/jDttSP/fm_demod.h b/jDttSP/fm_demod.h
new file mode 100644 (file)
index 0000000..136ba78
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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
diff --git a/jDttSP/fromsys.h b/jDttSP/fromsys.h
new file mode 100644 (file)
index 0000000..56e6a8f
--- /dev/null
@@ -0,0 +1,65 @@
+/* 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
diff --git a/jDttSP/lmadf.c b/jDttSP/lmadf.c
new file mode 100644 (file)
index 0000000..c472ec4
--- /dev/null
@@ -0,0 +1,286 @@
+/* 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;
+  }
+}  
diff --git a/jDttSP/lmadf.h b/jDttSP/lmadf.h
new file mode 100644 (file)
index 0000000..a3566a9
--- /dev/null
@@ -0,0 +1,101 @@
+/* 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
diff --git a/jDttSP/local.h b/jDttSP/local.h
new file mode 100644 (file)
index 0000000..942fc2b
--- /dev/null
@@ -0,0 +1,77 @@
+/* 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
diff --git a/jDttSP/main.c b/jDttSP/main.c
new file mode 100644 (file)
index 0000000..a4611e3
--- /dev/null
@@ -0,0 +1,528 @@
+/* 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(); } 
diff --git a/jDttSP/meter.h b/jDttSP/meter.h
new file mode 100644 (file)
index 0000000..57e7b71
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _meter_h
+#define _meter_h
+
+typedef enum {
+  SIGNAL_STRENGTH, 
+  AVG_SIGNAL_STRENGTH, 
+  ADC_REAL, 
+  ADC_IMAG,
+  AGC_GAIN
+} METERTYPE;
+
+#endif
diff --git a/jDttSP/metermon.c b/jDttSP/metermon.c
new file mode 100644 (file)
index 0000000..1bd875b
--- /dev/null
@@ -0,0 +1,44 @@
+/* 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);
+}
diff --git a/jDttSP/mkchan.c b/jDttSP/mkchan.c
new file mode 100644 (file)
index 0000000..2855980
--- /dev/null
@@ -0,0 +1,84 @@
+/* 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(); }
diff --git a/jDttSP/noiseblanker.c b/jDttSP/noiseblanker.c
new file mode 100644 (file)
index 0000000..406ebaa
--- /dev/null
@@ -0,0 +1,72 @@
+/* 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;
+  }
+}
diff --git a/jDttSP/noiseblanker.h b/jDttSP/noiseblanker.h
new file mode 100644 (file)
index 0000000..8270ed2
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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
diff --git a/jDttSP/oscillator.c b/jDttSP/oscillator.c
new file mode 100644 (file)
index 0000000..04c0b03
--- /dev/null
@@ -0,0 +1,117 @@
+/* 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);
+}
+
diff --git a/jDttSP/oscillator.h b/jDttSP/oscillator.h
new file mode 100644 (file)
index 0000000..7f45233
--- /dev/null
@@ -0,0 +1,72 @@
+/* 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
diff --git a/jDttSP/ovsv.c b/jDttSP/ovsv.c
new file mode 100644 (file)
index 0000000..3575ff4
--- /dev/null
@@ -0,0 +1,220 @@
+/* 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);
+  }
+}
+
+/*------------------------------------------------------------*/
+
+
diff --git a/jDttSP/ovsv.h b/jDttSP/ovsv.h
new file mode 100644 (file)
index 0000000..f4baa16
--- /dev/null
@@ -0,0 +1,74 @@
+/* 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
diff --git a/jDttSP/ringb.c b/jDttSP/ringb.c
new file mode 100644 (file)
index 0000000..1e6c31e
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+  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;
+  }
+}
diff --git a/jDttSP/ringb.h b/jDttSP/ringb.h
new file mode 100644 (file)
index 0000000..c92fd3c
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+  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
diff --git a/jDttSP/sdr.c b/jDttSP/sdr.c
new file mode 100644 (file)
index 0000000..f04d641
--- /dev/null
@@ -0,0 +1,676 @@
+/* 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++;
+}
diff --git a/jDttSP/sdrexport.c b/jDttSP/sdrexport.c
new file mode 100644 (file)
index 0000000..1830bd5
--- /dev/null
@@ -0,0 +1,39 @@
+/* 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;
diff --git a/jDttSP/sdrexport.h b/jDttSP/sdrexport.h
new file mode 100644 (file)
index 0000000..b561bf7
--- /dev/null
@@ -0,0 +1,284 @@
+/* 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
diff --git a/jDttSP/setup-ipc b/jDttSP/setup-ipc
new file mode 100755 (executable)
index 0000000..3a58d31
--- /dev/null
@@ -0,0 +1,16 @@
+#!/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
diff --git a/jDttSP/speechproc.c b/jDttSP/speechproc.c
new file mode 100644 (file)
index 0000000..505304d
--- /dev/null
@@ -0,0 +1,83 @@
+/* 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));
+}
diff --git a/jDttSP/speechproc.h b/jDttSP/speechproc.h
new file mode 100644 (file)
index 0000000..cd69331
--- /dev/null
@@ -0,0 +1,54 @@
+/* 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
diff --git a/jDttSP/splitfields.c b/jDttSP/splitfields.c
new file mode 100644 (file)
index 0000000..3e5adaf
--- /dev/null
@@ -0,0 +1,73 @@
+/* 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); }
diff --git a/jDttSP/splitfields.h b/jDttSP/splitfields.h
new file mode 100644 (file)
index 0000000..dba31f7
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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
diff --git a/jDttSP/spottone.c b/jDttSP/spottone.c
new file mode 100644 (file)
index 0000000..e4b2aa2
--- /dev/null
@@ -0,0 +1,153 @@
+/* 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);
+  }
+}
diff --git a/jDttSP/spottone.h b/jDttSP/spottone.h
new file mode 100644 (file)
index 0000000..1b46240
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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
diff --git a/jDttSP/thunk.c b/jDttSP/thunk.c
new file mode 100644 (file)
index 0000000..e52d80a
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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;
+}
diff --git a/jDttSP/thunk.h b/jDttSP/thunk.h
new file mode 100644 (file)
index 0000000..9a16c32
--- /dev/null
@@ -0,0 +1,12 @@
+/* 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
diff --git a/jDttSP/update.c b/jDttSP/update.c
new file mode 100644 (file)
index 0000000..6d2594a
--- /dev/null
@@ -0,0 +1,760 @@
+/* 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;
+    }
+  }
+}
diff --git a/jDttSP/update.h b/jDttSP/update.h
new file mode 100644 (file)
index 0000000..b0de3c7
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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
diff --git a/jDttSP/win/banal.c b/jDttSP/win/banal.c
new file mode 100644 (file)
index 0000000..154ba40
--- /dev/null
@@ -0,0 +1,152 @@
+/* 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
diff --git a/jDttSP/win/banal.h b/jDttSP/win/banal.h
new file mode 100644 (file)
index 0000000..4e4380d
--- /dev/null
@@ -0,0 +1,95 @@
+/* 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
diff --git a/jDttSP/win/chan.c b/jDttSP/win/chan.c
new file mode 100644 (file)
index 0000000..68889b0
--- /dev/null
@@ -0,0 +1,113 @@
+/* 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
diff --git a/jDttSP/win/chan.h b/jDttSP/win/chan.h
new file mode 100644 (file)
index 0000000..eecc507
--- /dev/null
@@ -0,0 +1,77 @@
+/* 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
diff --git a/jDttSP/win/common.h b/jDttSP/win/common.h
new file mode 100644 (file)
index 0000000..09121a2
--- /dev/null
@@ -0,0 +1,78 @@
+/* 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
diff --git a/jDttSP/win/datatypes.h b/jDttSP/win/datatypes.h
new file mode 100644 (file)
index 0000000..74b3dc6
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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
diff --git a/jDttSP/win/fromsys.h b/jDttSP/win/fromsys.h
new file mode 100644 (file)
index 0000000..c943da9
--- /dev/null
@@ -0,0 +1,95 @@
+/* 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
diff --git a/jDttSP/win/main.c b/jDttSP/win/main.c
new file mode 100644 (file)
index 0000000..96c3cda
--- /dev/null
@@ -0,0 +1,534 @@
+/* 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  
diff --git a/jDttSP/win/meter.c b/jDttSP/win/meter.c
new file mode 100644 (file)
index 0000000..c194fe1
--- /dev/null
@@ -0,0 +1,15 @@
+#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
diff --git a/jDttSP/win/power_spectrum.c b/jDttSP/win/power_spectrum.c
new file mode 100644 (file)
index 0000000..1f1977b
--- /dev/null
@@ -0,0 +1,128 @@
+#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
diff --git a/jDttSP/win/power_spectrum.h b/jDttSP/win/power_spectrum.h
new file mode 100644 (file)
index 0000000..9711186
--- /dev/null
@@ -0,0 +1,53 @@
+#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
diff --git a/jDttSP/win/sdrexport.h b/jDttSP/win/sdrexport.h
new file mode 100644 (file)
index 0000000..c6a337a
--- /dev/null
@@ -0,0 +1,346 @@
+/* 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
diff --git a/jDttSP/win/update.c b/jDttSP/win/update.c
new file mode 100644 (file)
index 0000000..baec77a
--- /dev/null
@@ -0,0 +1,1441 @@
+/* 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
+
+
+
diff --git a/jDttSP/win/update.h b/jDttSP/win/update.h
new file mode 100644 (file)
index 0000000..ea56405
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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
diff --git a/jDttSP/win/valueswin.h b/jDttSP/win/valueswin.h
new file mode 100644 (file)
index 0000000..1fa0230
--- /dev/null
@@ -0,0 +1,83 @@
+/* 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
diff --git a/jDttSP/window.c b/jDttSP/window.c
new file mode 100644 (file)
index 0000000..9807bfe
--- /dev/null
@@ -0,0 +1,158 @@
+/* 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;
+}
diff --git a/jDttSP/window.h b/jDttSP/window.h
new file mode 100644 (file)
index 0000000..1266db4
--- /dev/null
@@ -0,0 +1,75 @@
+/* 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
diff --git a/pyhw/Makefile b/pyhw/Makefile
new file mode 100644 (file)
index 0000000..d97d017
--- /dev/null
@@ -0,0 +1,8 @@
+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
+
diff --git a/pyhw/README b/pyhw/README
new file mode 100644 (file)
index 0000000..28307a7
--- /dev/null
@@ -0,0 +1,37 @@
+========================================================================
+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.
diff --git a/pyhw/hardware.c b/pyhw/hardware.c
new file mode 100644 (file)
index 0000000..65d8477
--- /dev/null
@@ -0,0 +1,985 @@
+/* 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);
+}
diff --git a/pyhw/hardware.h b/pyhw/hardware.h
new file mode 100644 (file)
index 0000000..99e81c7
--- /dev/null
@@ -0,0 +1,318 @@
+/* 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
diff --git a/pyhw/hardware.i b/pyhw/hardware.i
new file mode 100644 (file)
index 0000000..99a24ff
--- /dev/null
@@ -0,0 +1,5 @@
+%module sdr1khw
+%{
+#include "hardware.h"
+%}
+%include "hardware.h"
diff --git a/pyhw/sdr1k-setup.py b/pyhw/sdr1k-setup.py
new file mode 100644 (file)
index 0000000..ba50777
--- /dev/null
@@ -0,0 +1,19 @@
+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)