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
+LIBS = -L/usr/local/lib -ljack -lpthread -lgsl -lgslcblas -lfftw -lm
+#LIBS = -lefence -L/usr/local/lib -ljack -lpthread -lgsl -lgslcblas -lfftw -lm
staticlibname=libDttSP.a
window.o\
update.o
+KOBJ = oscillator.o cwtones.o chan.o ringb.o banal.o bufvec.o splitfields.o cxops.o
+
jsdr: main.o $(OBJ)
$(CC) -o jsdr main.o $(OBJ) $(LIBS)
+all: jsdr mkchan ipc metermon keyd keyb
+
+keyd: keyd.o keyer.o $(KOBJ)
+ $(CC) -o keyd keyd.o keyer.o $(KOBJ) $(LIBS)
+
+keyb: keyb.o keyer.o $(KOBJ)
+ $(CC) -o keyb keyb.o keyer.o $(KOBJ) $(LIBS)
+
+
$(OBJ): sdrexport.h
metermon: metermon.o chan.o ringb.o bufvec.o cxops.o banal.o
mkchan: mkchan.o bufvec.o banal.o cxops.o
$(CC) -o mkchan mkchan.o bufvec.o banal.o cxops.o $(LIBS)
-ipc:
+ipc: mkchan
./setup-ipc
obj: $(OBJ)
clean:
- /bin/rm *.o jsdr mkchan metermon $(staticlibname)
+ /bin/rm *.o jsdr mkchan metermon keyd keyb #$(staticlibname)
+ #/bin/rm IPC/*
staticlib: $(OBJ)
ar rcs $(staticlibname) $(OBJ)
# sharedlib=$(sharedlibname).$(sharedlibvers)
# sharedlib: $(OBJ)
# gcc -shared -Wl,-soname,$(sharedlib) -o $(sharedlib) $(OBJ) -lc
+
return 0;
}
+//------------------------------------------------------------------------
+
#define FALSE 0
extern void nilfunc(void);
-extern double sqr(double);
+extern INLINE double sqr(double);
extern int popcnt(int);
extern int npoof2(int);
extern int nblock2(int);
[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.
+setOsc freq [TRX] // freq in Hz (float)
+setSampleRate rate // Hz (float)
+setNR T|F // on/off, RX only
+setANF T|F // on/off, RX only
setNB T|F // on/off, RX only
+setBIN T|F // binaural mode, 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)
+setfixedAGC gain [TRX] // 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
+setTXSpeechCompression T|F // on/off
+setTXSpeechCompressionGain gain // float
+setRXEQ <bandspec> // f0 dB0 f1 dB1 f2 dB2 ... fN
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
+setRXAGC mode // mode = agcOFF, agcSLOW, etc.
+setANFvals taps delay gain leak // int, int, float, float, RX only
+setNRvals taps delay gain leak // int, int, float, float, RX only
setcorrectIQ phase gain // int, int
-setcorrectIQgain gain // int
setcorrectIQphase phase // int
-setfixedAGC gain [TRX] // float
+setcorrectIQgain gain // int
+setSquelch lev // float, gain, RX only; default -30dB
+setMeterOffset lev // float, RX only, appears only in squelch calc
+setATTOffset val // float, RX only, appears only in squelch calc
+setGainOffset // float, RX only, appears only in squelch calc
+setSquelchSt T|F // on/off, RX only
+setTRX trx // trx = RX|TX
+setRunState state // RUN_MUTE, RUN_PASS, RUN_PLAY
+setRXPreScl T|F // on/off
+setRXPreSclVal valQ // dB
+setTXPreScl T|F // on/off
+setTXPreSclVal valQ // dB
+setRXPostScl T|F // on/off
+setRXPostSclVal valQ // dB
+setTXPostScl T|F // on/off
+setTXPostSclVal valQ // dB
+setSWCH trx [zap] // trx = RX|TX, int (always zaps at least 1)
+setSpotToneVals gain freq rise fall // dB, Hz, msec, msec [-12, 700, 5, 5]
+setSpotTone T|F // turn on, off
+setFinished // shutdown gracefully
\ No newline at end of file
--- /dev/null
+/* cwtones.c */
+/*
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2005 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 <cwtones.h>
+
+//------------------------------------------------------------------------
+// An ASR envelope on a complex phasor,
+// with asynchronous trigger for R stage.
+// A/R use sine shaping.
+//------------------------------------------------------------------------
+
+BOOLEAN
+CWTone(CWToneGen cwt) {
+ int i, n = cwt->size;
+
+ ComplexOSC(cwt->osc.gen);
+
+ for (i = 0; i < n; i++) {
+
+ // in an envelope stage?
+
+ if (cwt->stage == CWTone_RISE) {
+
+ // still going?
+ if (cwt->rise.have++ < cwt->rise.want) {
+ cwt->curr += cwt->rise.incr;
+ cwt->mul = cwt->scl * sin(cwt->curr * M_PI / 2.0);
+ } else {
+ // no, assert steady-state, force level
+ cwt->curr = 1.0;
+ cwt->mul = cwt->scl;
+ cwt->stage = CWTone_STDY;
+ // won't come back into envelopes
+ // until FALL asserted from outside
+ }
+
+ } else if (cwt->stage == CWTone_FALL) {
+
+ // still going?
+ if (cwt->fall.have++ < cwt->fall.want) {
+ cwt->curr -= cwt->fall.incr;
+ cwt->mul = cwt->scl * sin(cwt->curr * M_PI / 2.0);
+ } else {
+ // no, assert trailing, force level
+ cwt->curr = 0.0;
+ cwt->mul = 0.0;
+ cwt->stage = CWTone_HOLD;
+ // won't come back into envelopes hereafter
+ }
+ }
+
+ // apply envelope
+ // (same base as osc.gen internal buf)
+ CXBdata(cwt->buf, i) = Cscl(CXBdata(cwt->buf, i), cwt->mul);
+ }
+
+ // indicate whether it's turned itself off
+ // sometime during this pass
+
+ return cwt->stage != CWTone_HOLD;
+}
+
+//------------------------------------------------------------------------
+// turn tone on with current settings
+
+void
+CWToneOn(CWToneGen cwt) {
+
+ // gain is in dB
+
+ cwt->scl = pow(10.0, cwt->gain / 20.0);
+ cwt->curr = cwt->mul = 0.0;
+
+ // A/R times are in msec
+
+ cwt->rise.want = (int) (0.5 + cwt->sr * (cwt->rise.dur / 1e3));
+ cwt->rise.have = 0;
+ if (cwt->rise.want <= 1)
+ cwt->rise.incr = 1.0;
+ else
+ cwt->rise.incr = 1.0 / (cwt->rise.want - 1);
+
+ cwt->fall.want = (int) (0.5 + cwt->sr * (cwt->fall.dur / 1e3));
+ cwt->fall.have = 0;
+ if (cwt->fall.want <= 1)
+ cwt->fall.incr = 1.0;
+ else
+ cwt->fall.incr = 1.0 / (cwt->fall.want - 1);
+
+ // freq is in Hz
+
+ OSCfreq(cwt->osc.gen) = 2.0 * M_PI * cwt->osc.freq / cwt->sr;
+ OSCphase(cwt->osc.gen) = 0.0;
+
+ cwt->stage = CWTone_RISE;
+}
+
+//------------------------------------------------------------------------
+// initiate turn-off
+
+void
+CWToneOff(CWToneGen cwt) { cwt->stage = CWTone_FALL; }
+
+//------------------------------------------------------------------------
+
+void
+setCWToneGenVals(CWToneGen cwt,
+ REAL gain,
+ REAL freq,
+ REAL rise,
+ REAL fall) {
+ cwt->gain = gain;
+ cwt->osc.freq = freq;
+ cwt->rise.dur = rise;
+ cwt->fall.dur = fall;
+}
+
+CWToneGen
+newCWToneGen(REAL gain, // dB
+ REAL freq,
+ REAL rise, // ms
+ REAL fall, // ms
+ int size,
+ REAL samplerate) {
+
+ CWToneGen cwt = (CWToneGen) safealloc(1, sizeof(CWToneGenDesc),
+ "CWToneGenDesc");
+
+ setCWToneGenVals(cwt, gain, freq, rise, fall);
+ cwt->size = size;
+ cwt->sr = samplerate;
+
+ cwt->osc.gen = newOSC(cwt->size,
+ ComplexTone,
+ cwt->osc.freq,
+ 0.0,
+ cwt->sr,
+ "CWTone osc");
+
+ // overload oscillator buf
+ cwt->buf = newCXB(cwt->size, OSCCbase(cwt->osc.gen), "CWToneGen buf");
+
+ return cwt;
+}
+
+void
+delCWToneGen(CWToneGen cwt) {
+ if (cwt) {
+ delCXB(cwt->buf);
+ delOSC(cwt->osc.gen);
+ safefree((char *) cwt);
+ }
+}
--- /dev/null
+/* spottone.h */
+/*
+This file is part of a program that implements a Software-Defined Radio.
+
+Copyright (C) 2005 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 _spottone_h
+#define _spottone_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+#include <oscillator.h>
+
+#define CWTone_IDLE (0)
+#define CWTone_WAIT (1)
+#define CWTone_RISE (2)
+#define CWTone_STDY (3)
+#define CWTone_FALL (4)
+#define CWTone_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;
+} CWToneGenDesc, *CWToneGen;
+
+extern CWToneGen newCWToneGen(REAL gain, // dB
+ REAL freq, // Hz
+ REAL rise, // msec
+ REAL fall, // msec
+ int size, // buflen
+ REAL samplerate);
+extern void delCWToneGen(CWToneGen gen);
+extern void setCWToneGenVals(CWToneGen gen,
+ REAL gain,
+ REAL freq,
+ REAL rise,
+ REAL fall);
+extern void CWToneOn(CWToneGen gen);
+extern void CWToneOff(CWToneGen gen);
+extern BOOLEAN CWTone(CWToneGen gen);
+
+#endif
REAL r = exp(z.re);
return Cmplx(r * cos(z.im), r * sin(z.im));
}
+
+COMPLEX
+Cp2r(COMPLEX z) {
+ return Cmplx(z.re * cos(z.im), z.re * sin(z.im));
+}
+
+COMPLEX
+Cr2p(COMPLEX z) {
+ return Cmplx(sqrt(sqr(z.re) + sqr(z.im)), ATAN2(z.im, z.re));
+}
#define _cxops_h
#include <datatypes.h>
+#include <fastrig.h>
extern COMPLEX cxzero;
extern COMPLEX cxone;
extern INLINE COMPLEX Conjg(COMPLEX);
extern INLINE COMPLEX Cexp(COMPLEX);
+extern INLINE COMPLEX Cp2r(COMPLEX);
+extern INLINE COMPLEX Cr2p(COMPLEX);
+
#endif
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 = max(a->hist[i], a->gain.now);
}
a->gain.now = min(a->gain.now, a->gain.top);
/* 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);
+ //z = (y_abs < x_abs ? y_abs / x_abs : x_abs / y_abs);
+ if (y_abs < x_abs)
+ z = y_abs / x_abs;
+ else
+ z = 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;
+ if (z < TAN_MAP_RES) base_angle = z;
else {
/* find index and interpolation value */
alpha = z * (REAL) TAN_MAP_SIZE - .5;
#include <splitfields.h>
#include <datatypes.h>
#include <bufvec.h>
+
+#ifdef notdef
#include <cxops.h>
+#endif
#define SIN_TABLE_SIZE 4096
#define SIN_TABLE_SIZE_M1 4095
#include <jack/jack.h>
#include <jack/ringbuffer.h>
+#include <gsl/gsl_errno.h>
+#include <gsl/gsl_interp.h>
+#include <gsl/gsl_spline.h>
+#include <gsl/gsl_wavelet.h>
+#include <gsl/gsl_sf_erf.h>
+#include <gsl/gsl_cdf.h>
+
#endif
--- /dev/null
+/* keyb.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>
+#include <splitfields.h>
+#include <datatypes.h>
+#include <bufvec.h>
+#include <cxops.h>
+
+#define SAMP_RATE (48000)
+#define HUGE_PHASE 1256637061.43593
+
+#define RING_SIZE (01 << 020)
+
+pthread_t input, play;
+sem_t ready, reader, writer;
+
+jack_client_t *client;
+jack_port_t *lport, *rport;
+jack_ringbuffer_t *lring, *rring;
+jack_nframes_t size;
+
+BOOLEAN playing = FALSE;
+double wpm = 18.0, freq = 750.0, gain = -6.0;
+
+COMPLEX *zout = 0;
+
+// basic mapping, chars -> morse strings
+char *morse_table[128];
+
+// CW tone segments
+#define ME_EOF (-1)
+#define ME_ZERO (0)
+#define ME_RAMP (1)
+#define ME_STDY (2)
+
+struct {
+ double wpm, rise, fall, curr, incr, rate;
+ int type, size;
+} morsel;
+
+int ditspacesize, dahspacesize,
+ ditstdysize, dahstdysize,
+ charspacesize, wordspacesize,
+ risesize, fallsize;
+double riseincr, fallincr;
+
+void jack_ringbuffer_clear(jack_ringbuffer_t *, int);
+void jack_ringbuffer_restart(jack_ringbuffer_t *, int);
+void send_sound(COMPLEX *, int);
+
+//------------------------------------------------------------
+
+// map char -> morse string
+char *
+get_morse(int c) { return morse_table[c & 0x7F]; }
+
+void
+reader_thread(void) {
+ BOOLEAN b = TRUE; // we're coming from silence
+ int c, e;
+ char *m;
+
+ // keep reading 1 char at a time
+ while ((c = getchar()) != EOF) {
+
+ // is char mapped to morse?
+ if (m = get_morse(c)) {
+
+ // yup
+ // for each sub-element (dit/dah)
+ while (e = *m++) {
+ // first segment is slew in...
+ sem_wait(&reader);
+ morsel.type = ME_RAMP, morsel.size = risesize;
+ morsel.curr = 0.0, morsel.incr = riseincr;
+ sem_post(&writer);
+
+ // ...then steady state...
+ sem_wait(&reader);
+ morsel.type = ME_STDY;
+ morsel.size = e == '.' ? ditstdysize : dahstdysize;
+ sem_post(&writer);
+
+ // ...then slew out...
+ sem_wait(&reader);
+ morsel.type = ME_RAMP, morsel.size = fallsize;
+ morsel.curr = 1.0, morsel.incr = fallincr;
+ sem_post(&writer);
+
+ // ...finally, post-element pause
+ sem_wait(&reader);
+ morsel.type = ME_ZERO;
+ morsel.size = ditspacesize;
+ sem_post(&writer);
+ }
+
+ // post-character pause
+ sem_wait(&reader);
+ morsel.type = ME_ZERO;
+ // (we already emitted a dit-sized space)
+ morsel.size = charspacesize - ditspacesize;
+ sem_post(&writer);
+
+ // wherever we go next, it won't have been from silence
+ b = FALSE;
+
+ } else {
+ // anything else treated as interword space
+ sem_wait(&reader);
+ morsel.type = ME_ZERO;
+ // was previous output also interword space?
+ if (b)
+ // yes, use full duration
+ morsel.size = wordspacesize;
+ else
+ // no, part of duration already played
+ morsel.size = wordspacesize - charspacesize;
+ b = TRUE;
+ sem_post(&writer);
+ }
+ }
+
+ // indicate EOF on input
+ sem_wait(&reader);
+ morsel.type = ME_EOF;
+ sem_post(&writer);
+ pthread_exit(0);
+}
+
+void
+sound_thread(void) {
+ int i, k = 0;
+ double ofreq = freq * 2.0 * M_PI / SAMP_RATE,
+ phase = 0.0,
+ scale = pow(10.0, gain / 20.0);
+ COMPLEX z, delta_z;
+
+ // as long as there's been no EOF on the input...
+ for (;;) {
+
+ // pause for next sub-element
+ sem_post(&reader);
+ sem_wait(&writer);
+
+ // no more data?
+ if (morsel.type == ME_EOF) break;
+
+ // interword space == silence?
+ if (morsel.type != ME_ZERO) {
+ // no, set up CORDIC tone generation
+ if (phase > HUGE_PHASE) phase -= HUGE_PHASE;
+ z = Cmplx(cos(phase), sin(phase));
+ delta_z = Cmplx(cos(ofreq), sin(ofreq));
+ }
+
+ // play out this sub-segment
+ for (i = 0; i < morsel.size; i++) {
+
+ // make silence
+ if (morsel.type == ME_ZERO) zout[k] = cxzero;
+
+ // make tone
+ else {
+ z = Cmul(z, delta_z);
+ phase += ofreq;
+ // slewing segment?
+ if (morsel.type == ME_RAMP) {
+ morsel.curr += morsel.incr;
+ zout[k] = Cscl(z, scale * sin(morsel.curr * M_PI / 2.0));
+ } else
+ zout[k] = Cscl(z, scale);
+ }
+
+ // one jack bufferful yet?
+ if (++k >= size) {
+ // yes, send to output
+ send_sound(zout, k);
+ // wait until it's been taken away
+ sem_wait(&ready);
+ k = 0;
+ // reset CORDIC
+ if (morsel.type != ME_ZERO) {
+ if (phase > HUGE_PHASE) phase -= HUGE_PHASE;
+ z = Cmplx(cos(phase), sin(phase));
+ delta_z = Cmplx(cos(ofreq), sin(ofreq));
+ }
+ }
+ }
+ }
+
+ // anything left unsent in buffer?
+ if (k > 0) send_sound(zout, k);
+
+ pthread_exit(0);
+}
+
+//------------------------------------------------------------------------
+
+void
+jack_ringbuffer_clear(jack_ringbuffer_t *ring, int nbytes) {
+ int i;
+ char zero = 0;
+ for (i = 0; i < nbytes; i++)
+ jack_ringbuffer_write(ring, &zero, 1);
+}
+
+void
+jack_ringbuffer_restart(jack_ringbuffer_t *ring, int nbytes) {
+ jack_ringbuffer_reset(ring);
+ jack_ringbuffer_clear(ring, nbytes);
+}
+
+void
+send_sound(COMPLEX *buff, int len) {
+ if (jack_ringbuffer_write_space(lring) < len * sizeof(float)) {
+ write(2, "overrun\n", 8);
+ jack_ringbuffer_restart(lring, size * sizeof(float));
+ jack_ringbuffer_restart(rring, size * sizeof(float));
+ } else {
+ int i;
+ for (i = 0; i < len; i++) {
+ float l = buff[i].re, r = buff[i].im;
+ jack_ringbuffer_write(lring, (char *) &l, sizeof(float));
+ jack_ringbuffer_write(rring, (char *) &r, sizeof(float));
+ }
+ }
+}
+
+PRIVATE void
+jack_xrun(void *arg) {
+ char *str = "xrun!\n";
+ write(2, str, strlen(str));
+}
+
+PRIVATE void
+jack_shutdown(void *arg) {}
+
+PRIVATE void
+jack_callback(jack_nframes_t nframes, void *arg) {
+ char *lp, *rp;
+ int nwant = nframes * sizeof(float),
+ nhave = jack_ringbuffer_read_space(lring);
+
+ lp = jack_port_get_buffer(lport, nframes);
+ rp = jack_port_get_buffer(rport, nframes);
+ if (nhave >= nwant) {
+ jack_ringbuffer_read(lring, lp, nwant);
+ jack_ringbuffer_read(rring, rp, nwant);
+ sem_post(&ready);
+ } else {
+ memset(lp, 0, nwant);
+ memset(rp, 0, nwant);
+ }
+}
+
+int
+main(int argc, char **argv) {
+ int i;
+
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1]) {
+ case 'f':
+ freq = atof(argv[++i]);
+ break;
+ case 'w':
+ wpm = atof(argv[++i]);
+ break;
+ default:
+ fprintf(stderr, "keyd [-w wpm] [-f freq] [infile]\n");
+ exit(1);
+ }
+ else break;
+
+ if (i < argc) {
+ if (!freopen(argv[i], "r", stdin))
+ perror(argv[i]), exit(1);
+ i++;
+ }
+
+ //------------------------------------------------------------
+
+ morsel.wpm = wpm;
+ morsel.rise = morsel.fall = 5.0; // ms
+ morsel.rate = SAMP_RATE;
+
+ ditspacesize = SAMP_RATE * 1.2 / morsel.wpm + 0.5;
+ dahspacesize = 3 * ditspacesize;
+ charspacesize = dahspacesize;
+ wordspacesize = 7 * ditspacesize;
+
+ risesize = SAMP_RATE * morsel.rise / 1e3 + 0.5;
+ if (risesize > 1)
+ riseincr = 1.0 / (risesize - 1);
+ else
+ riseincr = 1.0;
+
+ fallsize = SAMP_RATE * morsel.fall / 1e3 + 0.5;
+ if (fallsize > 1)
+ fallincr = -1.0 / (fallsize - 1);
+ else
+ fallincr = -1.0;
+
+ ditstdysize = ditspacesize - risesize - fallsize;
+ dahstdysize = dahspacesize - risesize - fallsize;
+
+ //------------------------------------------------------------
+
+ if (!(client = jack_client_new("keyb")))
+ fprintf(stderr, "can't make client -- jack not running?\n"), exit(1);
+ jack_set_process_callback(client, (void *) jack_callback, 0);
+ jack_on_shutdown(client, (void *) jack_shutdown, 0);
+ jack_set_xrun_callback(client, (void *) jack_xrun, 0);
+ size = jack_get_buffer_size(client);
+
+ lport = jack_port_register(client,
+ "ol",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ rport = jack_port_register(client,
+ "or",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ lring = jack_ringbuffer_create(RING_SIZE);
+ rring = jack_ringbuffer_create(RING_SIZE);
+ jack_ringbuffer_clear(lring, size * sizeof(float));
+ jack_ringbuffer_clear(rring, size * sizeof(float));
+
+ //------------------------------------------------------------
+
+ zout = newvec_COMPLEX(size, "keyb sample buffer");
+
+ //------------------------------------------------------------
+
+ sem_init(&ready, 0, 0);
+ sem_init(&reader, 0, 0);
+ sem_init(&writer, 0, 0);
+ pthread_create(&input, 0, (void *) reader_thread, 0);
+ pthread_create(&play, 0, (void *) sound_thread, 0);
+
+ //------------------------------------------------------------
+
+ jack_activate(client);
+ {
+ const char **ports;
+ if (!(ports = jack_get_ports(client, 0, 0, JackPortIsPhysical | JackPortIsInput))) {
+ fprintf(stderr, "can't find any physical playback ports\n");
+ exit(1);
+ }
+ if (jack_connect(client, jack_port_name(lport), ports[0])) {
+ fprintf(stderr, "can't connect left output\n");
+ exit(1);
+ }
+ if (jack_connect(client, jack_port_name(rport), ports[1])) {
+ fprintf(stderr, "can't connect left output\n");
+ exit(1);
+ }
+ free(ports);
+ }
+
+ pthread_join(input, 0);
+ pthread_join(play, 0);
+ jack_client_close(client);
+
+ //------------------------------------------------------------
+
+ delvec_COMPLEX(zout);
+
+ //------------------------------------------------------------
+
+ jack_ringbuffer_free(lring);
+ jack_ringbuffer_free(rring);
+ sem_destroy(&ready);
+ sem_destroy(&reader);
+ sem_destroy(&writer);
+
+ //------------------------------------------------------------
+
+ exit(0);
+}
+
+char *morse_table[128] = {
+ /* 000 NUL */ 0, /* 001 SOH */ 0, /* 002 STX */ 0, /* 003 ETX */ 0,
+ /* 004 EOT */ 0, /* 005 ENQ */ 0, /* 006 ACK */ 0, /* 007 BEL */ 0,
+ /* 008 BS */ 0, /* 009 HT */ 0, /* 010 LF */ 0, /* 011 VT */ 0,
+ /* 012 FF */ 0, /* 013 CR */ 0, /* 014 SO */ 0, /* 015 SI */ 0,
+ /* 016 DLE */ 0, /* 017 DC1 */ 0, /* 018 DC2 */ 0, /* 019 DC3 */ 0,
+ /* 020 DC4 */ 0, /* 021 NAK */ 0, /* 022 SYN */ 0, /* 023 ETB */ 0,
+ /* 024 CAN */ 0, /* 025 EM */ 0, /* 026 SUB */ 0, /* 027 ESC */ 0,
+ /* 028 FS */ 0, /* 029 GS */ 0, /* 030 RS */ 0, /* 031 US */ 0,
+ /* 032 SP */ 0,
+ /* 033 ! */ "...-.", // [SN]
+ /* 034 " */ 0, /* 035 # */ 0, /* 036 $ */ 0,
+ /* 037 % */ ".-...", // [AS]
+ /* 038 & */ 0, /* 039 ' */ 0,
+ /* 040 ( */ "-.--.", // [KN]
+ /* 041 ) */ 0,
+ /* 042 * */ "...-.-", // [SK]
+ /* 043 + */ ".-.-.", // [AR]
+ /* 044 , */ "--..--",
+ /* 045 - */ "-....-",
+ /* 046 . */ ".-.-.-",
+ /* 047 / */ "-..-.",
+ /* 048 0 */ "-----",
+ /* 049 1 */ ".----",
+ /* 050 2 */ "..---",
+ /* 051 3 */ "...--",
+ /* 052 4 */ "....-",
+ /* 053 5 */ ".....",
+ /* 054 6 */ "-....",
+ /* 055 7 */ "--...",
+ /* 056 8 */ "---..",
+ /* 057 9 */ "----.",
+ /* 058 : */ 0, /* 059 ; */ 0, /* 060 < */ 0,
+ /* 061 = */ "-...-", // [BT]
+ /* 062 > */ 0,
+ /* 063 ? */ "..__..", // [IMI]
+ /* 064 @ */ ".--.-.",
+ /* 065 A */ ".-",
+ /* 066 B */ "-...",
+ /* 067 C */ "-.-.",
+ /* 068 D */ "-..",
+ /* 069 E */ ".",
+ /* 070 F */ "..-.",
+ /* 071 G */ "--.",
+ /* 072 H */ "....",
+ /* 073 I */ "..",
+ /* 074 J */ ".---",
+ /* 075 K */ "-.-",
+ /* 076 L */ ".-..",
+ /* 077 M */ "--",
+ /* 078 N */ "-.",
+ /* 079 O */ "---",
+ /* 080 P */ ".--.",
+ /* 081 Q */ "--.-",
+ /* 082 R */ ".-.",
+ /* 083 S */ "...",
+ /* 084 T */ "-",
+ /* 085 U */ "..-",
+ /* 086 V */ "...-",
+ /* 087 W */ ".--",
+ /* 088 X */ "-..-",
+ /* 089 Y */ "-.--",
+ /* 090 Z */ "--..",
+ /* 091 [ */ 0, /* 092 \ */ 0, /* 093 ] */ 0, /* 094 ^ */ 0,
+ /* 095 _ */ 0, /* 096 ` */ 0,
+ /* 097 a */ ".-",
+ /* 098 b */ "-...",
+ /* 099 c */ "-.-.",
+ /* 100 d */ "-..",
+ /* 101 e */ ".",
+ /* 102 f */ "..-.",
+ /* 103 g */ "--.",
+ /* 104 h */ "....",
+ /* 105 i */ "..",
+ /* 106 j */ ".---",
+ /* 107 k */ "-.-",
+ /* 108 l */ ".-..",
+ /* 109 m */ "--",
+ /* 110 n */ "-.",
+ /* 111 o */ "---",
+ /* 112 p */ ".--.",
+ /* 113 q */ "--.-",
+ /* 114 r */ ".-.",
+ /* 115 s */ "...",
+ /* 116 t */ "-",
+ /* 117 u */ "..-",
+ /* 118 v */ "...-",
+ /* 119 w */ ".--",
+ /* 120 x */ "-..-",
+ /* 121 y */ "-.--",
+ /* 122 z */ "--..",
+ /* 123 { */ 0, /* 124 | */ 0, /* 125 } */ 0, /* 126 ~ */ 0,
+ /* 127 DEL */ 0
+};
--- /dev/null
+/* keyd.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 <linux/rtc.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 <oscillator.h>
+#include <cwtones.h>
+#include <keyer.h>
+
+#define SAMP_RATE (48000)
+
+// # times key is sampled per sec
+// > 64 requires root on Linux
+//#define RTC_RATE (128)
+#define RTC_RATE (64)
+
+// # samples generated during 1 clock tick at RTC_RATE
+#define TONE_SIZE (SAMP_RATE / RTC_RATE)
+
+// ring buffer size; > 1 sec at this sr
+#define RING_SIZE (01 << 020)
+
+KeyerState ks;
+KeyerLogic kl;
+
+pthread_t play, key;
+sem_t clock_fired, keyer_started;
+
+int fdser, fdrtc;
+
+jack_client_t *client;
+jack_port_t *lport, *rport;
+jack_ringbuffer_t *lring, *rring;
+jack_nframes_t size;
+
+CWToneGen gen;
+BOOLEAN playing = FALSE, iambic = FALSE;
+double wpm = 18.0, freq = 750.0;
+
+//------------------------------------------------------------
+
+void
+jack_ringbuffer_clear(jack_ringbuffer_t *ring, int nbytes) {
+ int i;
+ char zero = 0;
+ for (i = 0; i < nbytes; i++)
+ jack_ringbuffer_write(ring, &zero, 1);
+}
+
+void
+jack_ringbuffer_restart(jack_ringbuffer_t *ring, int nbytes) {
+ jack_ringbuffer_reset(ring);
+ jack_ringbuffer_clear(ring, nbytes);
+}
+
+//------------------------------------------------------------
+
+// generated tone -> output ringbuffer
+void
+send_tone(void) {
+ if (jack_ringbuffer_write_space(lring) < TONE_SIZE * sizeof(float)) {
+ write(2, "overrun tone\n", 13);
+ jack_ringbuffer_restart(lring, TONE_SIZE * sizeof(float));
+ jack_ringbuffer_restart(rring, TONE_SIZE * sizeof(float));
+ } else {
+ int i;
+ for (i = 0; i < gen->size; i++) {
+ float l = CXBreal(gen->buf, i),
+ r = CXBimag(gen->buf, i);
+ jack_ringbuffer_write(lring, (char *) &l, sizeof(float));
+ jack_ringbuffer_write(rring, (char *) &r, sizeof(float));
+ }
+ }
+}
+
+// silence -> output ringbuffer
+void
+send_silence(void) {
+ if (jack_ringbuffer_write_space(lring) < TONE_SIZE * sizeof(float)) {
+ write(2, "overrun zero\n", 13);
+ jack_ringbuffer_restart(lring, TONE_SIZE * sizeof(float));
+ jack_ringbuffer_restart(rring, TONE_SIZE * sizeof(float));
+ } else {
+ int i;
+ for (i = 0; i < gen->size; i++) {
+ float zero = 0.0;
+ jack_ringbuffer_write(lring, (char *) &zero, sizeof(float));
+ jack_ringbuffer_write(rring, (char *) &zero, sizeof(float));
+ }
+ }
+}
+
+// sound/silence generation
+// tone turned on/off asynchronously
+void
+sound_thread(void) {
+ for (;;) {
+ sem_wait(&clock_fired);
+
+ if (playing) {
+ // CWTone keeps playing for awhile after it's turned off,
+ // in order to allow for a decay envelope;
+ // returns FALSE when it's actually done.
+ playing = CWTone(gen);
+ send_tone();
+ } else
+ send_silence();
+ }
+
+ pthread_exit(0);
+}
+
+// basic heartbeat
+// returns actual dur in msec since last tick;
+// uses Linux rtc interrupts.
+// other strategies will work too, so long as they
+// provide a measurable delay in msec.
+double
+timed_delay(void) {
+ double del, std = 1000 / (double) RTC_RATE;
+ static int cnt = 0;
+ unsigned long data;
+
+ if (read(fdrtc, &data, sizeof(unsigned long)) == -1) {
+ perror("read");
+ exit(1);
+ }
+ // indicate whether an interrupt was missed
+ // not really important except for performance tweaks
+ if ((del = (data >> 010) * 1000 / (double) RTC_RATE) != std)
+ fprintf(stderr, "%d %g ms\n", ++cnt, del);
+ return del;
+}
+
+// key down? (real or via keyer logic)
+BOOLEAN
+read_key(double del) {
+ if (iambic)
+ return read_iambic_key_serial(ks, fdser, kl, del);
+ else
+ return read_straight_key_serial(ks, fdser);
+}
+
+// main keyer loop
+//
+void
+key_thread(void) {
+
+ sem_wait(&keyer_started);
+
+ for (;;) {
+ // wait for next tick, get actual dur since last one
+ double del = timed_delay();
+ // read key; tell keyer elapsed time since last call
+ BOOLEAN keydown = read_key(del);
+
+ if (!playing && keydown)
+ CWToneOn(gen), playing = TRUE;
+ else if (playing && !keydown)
+ CWToneOff(gen);
+
+ sem_post(&clock_fired);
+ }
+
+ pthread_exit(0);
+}
+
+PRIVATE void
+jack_xrun(void *arg) {
+ char *str = "xrun";
+ write(2, str, strlen(str));
+}
+
+PRIVATE void
+jack_shutdown(void *arg) {}
+
+PRIVATE void
+jack_callback(jack_nframes_t nframes, void *arg) {
+ float *lp, *rp;
+ int nbytes = nframes * sizeof(float);
+ if (nframes == size) {
+ // output: copy from ring to port
+ lp = (float *) jack_port_get_buffer(lport, nframes);
+ rp = (float *) jack_port_get_buffer(rport, nframes);
+ if (jack_ringbuffer_read_space(lring) >= nbytes) {
+ jack_ringbuffer_read(lring, (char *) lp, nbytes);
+ jack_ringbuffer_read(rring, (char *) rp, nbytes);
+ } else { // rb pathology
+ memset((char *) lp, 0, nbytes);
+ memset((char *) rp, 0, nbytes);
+ jack_ringbuffer_reset(lring);
+ jack_ringbuffer_reset(rring);
+ jack_ringbuffer_clear(lring, nbytes);
+ jack_ringbuffer_clear(rring, nbytes);
+ //write(2, "underrun\n", 9);
+ }
+ }
+}
+
+int
+main(int argc, char **argv) {
+ int i;
+ char *serialdev = "/dev/ttyS0",
+ *clockdev = "/dev/rtc";
+ int serstatus;
+
+ for (i = 1; i < argc; i++)
+ if (argv[i][0] == '-')
+ switch (argv[i][1]) {
+ case 'f':
+ freq = atof(argv[++i]);
+ break;
+ case 'i':
+ iambic = TRUE;
+ break;
+ case 'w':
+ wpm = atof(argv[++i]);
+ break;
+ default:
+ fprintf(stderr, "keyd [-i] [-w wpm]\n");
+ exit(1);
+ }
+ else break;
+
+ //------------------------------------------------------------
+
+ gen = newCWToneGen(-3.0, freq, 5.0, 5.0, TONE_SIZE, 48000.0);
+
+ //------------------------------------------------------------
+
+ kl = newKeyerLogic();
+ ks = newKeyerState();
+ ks->flag.iambic = TRUE;
+ ks->flag.revpdl = TRUE; // depends on port wiring
+ ks->flag.autospace.khar = ks->flag.autospace.word = FALSE;
+ ks->debounce = 1; // could be more if sampled faster
+ ks->mode = MODE_B;
+ ks->weight = 50;
+ ks->wpm = wpm;
+
+ //------------------------------------------------------------
+
+ if (!(client = jack_client_new("keyd")))
+ fprintf(stderr, "can't make client -- jack not running?\n"), exit(1);
+ jack_set_process_callback(client, (void *) jack_callback, 0);
+ jack_on_shutdown(client, (void *) jack_shutdown, 0);
+ jack_set_xrun_callback(client, (void *) jack_xrun, 0);
+ size = jack_get_buffer_size(client);
+ lport = jack_port_register(client,
+ "ol",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ rport = jack_port_register(client,
+ "or",
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+ lring = jack_ringbuffer_create(RING_SIZE);
+ rring = jack_ringbuffer_create(RING_SIZE);
+ jack_ringbuffer_clear(lring, size * sizeof(float));
+ jack_ringbuffer_clear(rring, size * sizeof(float));
+
+ //------------------------------------------------------------
+
+ // key
+ if ((fdser = open(serialdev, O_WRONLY)) == -1) {
+ fprintf(stderr, "cannot open serial device %s", serialdev);
+ exit(1);
+ }
+ if (ioctl(fdser, TIOCMGET, &serstatus) == -1) {
+ close(fdser);
+ fprintf(stderr, "cannot get serial device status");
+ exit(1);
+ }
+ serstatus |= TIOCM_DTR;
+ if (ioctl(fdser, TIOCMSET, &serstatus) == -1) {
+ close(fdser);
+ fprintf(stderr, "cannot set serial device status");
+ exit(1);
+ }
+
+ // rtc
+ if ((fdrtc = open(clockdev, O_RDONLY)) == -1) {
+ perror(clockdev);
+ exit(1);
+ }
+ if (ioctl(fdrtc, RTC_IRQP_SET, RTC_RATE) == -1) {
+ perror("ioctl irqp");
+ exit(1);
+ }
+ if (ioctl(fdrtc, RTC_PIE_ON, 0) == -1) {
+ perror("ioctl pie on");
+ exit(1);
+ }
+
+ //------------------------------------------------------------
+
+ sem_init(&clock_fired, 0, 0);
+ sem_init(&keyer_started, 0, 0);
+ pthread_create(&play, 0, (void *) sound_thread, 0);
+ pthread_create(&key, 0, (void *) key_thread, 0);
+
+ //------------------------------------------------------------
+
+ jack_activate(client);
+ {
+ const char **ports;
+ if (!(ports = jack_get_ports(client, 0, 0, JackPortIsPhysical | JackPortIsInput))) {
+ fprintf(stderr, "can't find any physical playback ports\n");
+ exit(1);
+ }
+ if (jack_connect(client, jack_port_name(lport), ports[0])) {
+ fprintf(stderr, "can't connect left output\n");
+ exit(1);
+ }
+ if (jack_connect(client, jack_port_name(rport), ports[1])) {
+ fprintf(stderr, "can't connect left output\n");
+ exit(1);
+ }
+ free(ports);
+ }
+ sem_post(&keyer_started);
+
+ pthread_join(play, 0);
+ pthread_join(key, 0);
+ jack_client_close(client);
+
+ //------------------------------------------------------------
+
+ if (ioctl(fdrtc, RTC_PIE_OFF, 0) == -1) {
+ perror("ioctl pie off");
+ exit(1);
+ }
+ close(fdrtc);
+ close(fdser);
+
+ jack_ringbuffer_free(lring);
+ jack_ringbuffer_free(rring);
+
+ sem_destroy(&clock_fired);
+ sem_destroy(&keyer_started);
+
+ delCWToneGen(gen);
+ delKeyerState(ks);
+ delKeyerLogic(kl);
+
+ //------------------------------------------------------------
+
+ exit(0);
+}
--- /dev/null
+/* keyer.c */
+/*
+This file is part of a program that implements a Software-Defined Radio.
+
+The code in this file is derived from routines originally written by
+Pierre-Philippe Coupard for his CWirc X-chat program. That program
+is issued under the GPL and is
+Copyright (C) Pierre-Philippe Coupard - 18/06/2003
+
+This derived version is
+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
+*/
+
+// see below for places where serial port is read
+// and needs replacement for parallel port hookup
+
+#include <keyer.h>
+
+//========================================================================
+// nothing affected by physical port connection here
+
+BOOLEAN
+klogic(KeyerLogic kl,
+ BOOLEAN dit,
+ BOOLEAN dah,
+ double wpm,
+ int iambicmode,
+ BOOLEAN midelementmodeB,
+ BOOLEAN ditmemory,
+ BOOLEAN dahmemory,
+ BOOLEAN autocharspacing,
+ BOOLEAN autowordspacing,
+ int weight,
+ double ticklen) {
+
+ double ditlen = 1200 / wpm;
+ int set_element_timeouts = NO_TIMEOUTS_SCHED;
+
+ /* Do we need to initialize the keyer? */
+ if (!kl->flag.init) {
+ kl->flag.prev.dit = dit;
+ kl->flag.prev.dah = dah;
+ kl->element.last = kl->element.curr = NO_ELEMENT;
+ kl->element.iamb = NO_PADDLE_SQUEEZE;
+ kl->element.psqam = 0;
+ kl->element.invtd = 0;
+ kl->timeout.midl = kl->timeout.beep = kl->timeout.elem = 0;
+ kl->timeout.dlay = 0;
+ kl->dlay_type = NO_DELAY;
+ kl->flag.init = 1;
+ }
+
+ /* Decrement the timeouts */
+ kl->timeout.dlay -= kl->timeout.dlay > 0 ? ticklen : 0;
+ if (kl->timeout.dlay <= 0) {
+ /* If nothing is scheduled to play, and we just did a character
+ spacing delay, and we do auto word spacing, wait for a word
+ spacing delay, otherwise resume the normal element timeout
+ countdowns */
+ if (kl->timeout.elem <= 0 &&
+ kl->dlay_type == CHAR_SPACING_DELAY &&
+ autowordspacing) {
+ kl->timeout.dlay = ditlen * 4;
+ kl->dlay_type = WORD_SPACING_DELAY;
+ } else {
+ kl->dlay_type = NO_DELAY;
+ kl->timeout.midl -= kl->timeout.midl > 0 ? ticklen : 0;
+ kl->timeout.beep -= kl->timeout.beep > 0 ? ticklen : 0;
+ kl->timeout.elem -= kl->timeout.elem > 0 ? ticklen : 0;
+ }
+ }
+
+ /* Are both paddles squeezed? */
+ if (dit && dah) {
+ kl->element.iamb = PADDLES_SQUEEZED;
+
+ /* Are the paddles squeezed past the middle of the element? */
+ if (kl->timeout.midl <= 0)
+ kl->element.psqam = 1;
+ } else
+ /* Are both paddles released and we had gotten a squeeze in this element? */
+ if (!dit && !dah && kl->element.iamb == PADDLES_SQUEEZED)
+ kl->element.iamb = PADDLES_RELEASED;
+
+ /* Is the current element finished? */
+ if (kl->timeout.elem <= 0 && kl->element.curr != NO_ELEMENT) {
+ kl->element.last = kl->element.curr;
+
+ /* Should we insert an inverted element? */
+ if (((dit && dah) ||
+ (kl->element.invtd &&
+ kl->element.iamb != PADDLES_RELEASED) ||
+ (kl->element.iamb == PADDLES_RELEASED &&
+ iambicmode == MODE_B &&
+ (!midelementmodeB || kl->element.psqam)))) {
+ if (kl->element.last == DAH)
+ set_element_timeouts = kl->element.curr = DIT;
+ else
+ set_element_timeouts = kl->element.curr = DAH;
+ } else {
+ /* No more element */
+ kl->element.curr = NO_ELEMENT;
+
+ /* Do we do automatic character spacing? */
+ if (autocharspacing && !dit && !dah) {
+ kl->timeout.dlay = ditlen * 2;
+ kl->dlay_type = CHAR_SPACING_DELAY;
+ }
+ }
+
+ kl->element.invtd = 0;
+ kl->element.iamb = NO_PADDLE_SQUEEZE;
+ kl->element.psqam = 0;
+ }
+
+ /* Is an element currently being played? */
+ if (kl->element.curr == NO_ELEMENT) {
+ if (dah) /* Dah paddle down ? */
+ set_element_timeouts = kl->element.curr = DAH;
+ else if (dit) /* Dit paddle down ? */
+ set_element_timeouts = kl->element.curr = DIT;
+ }
+
+ /* Do the dah memory */
+ if (kl->element.curr == DIT &&
+ !kl->flag.prev.dah &&
+ dah &&
+ dahmemory)
+ kl->element.invtd = 1;
+
+ /* Do the dit memory */
+ if (kl->element.curr == DAH &&
+ !kl->flag.prev.dit &&
+ dit &&
+ ditmemory)
+ kl->element.invtd = 1;
+
+ /* If we had a dit (or dah) scheduled to be played after a delay,
+ and the operator lifted both paddles before the end of the delay,
+ and we have no dit (or dah) memory, forget it */
+
+ if (kl->timeout.dlay > 0 &&
+ !dit &&
+ !dah &&
+ ((kl->element.curr == DIT &&
+ !ditmemory) ||
+ (kl->element.curr == DAH
+ && !dahmemory)))
+ set_element_timeouts = kl->element.curr = NO_ELEMENT;
+
+ /* Do we need to set the playing timeouts of an element? */
+ switch (set_element_timeouts) {
+ case NO_ELEMENT: /* Cancel any dit or dah */
+ kl->timeout.beep = 0;
+ kl->timeout.midl = 0;
+ kl->timeout.elem = 0;
+ break;
+
+ case DIT: /* Schedule a dit? */
+ kl->timeout.beep = (ditlen * (double) weight) / 50;
+ kl->timeout.midl = kl->timeout.beep / 2;
+ kl->timeout.elem = ditlen * 2;
+ break;
+
+ case DAH: /* Schedule a dah? */
+ kl->timeout.beep = (ditlen * (double) weight) / 50 + ditlen * 2;
+ kl->timeout.midl = kl->timeout.beep / 2;
+ kl->timeout.elem = ditlen * 4;
+ break;
+ }
+
+ kl->flag.prev.dit = dit;
+ kl->flag.prev.dah = dah;
+
+ return kl->timeout.beep > 0 && kl->timeout.dlay <= 0;
+}
+
+//========================================================================
+
+/* Read a straight key connected to a serial port, do debouncing, then
+ return the key state */
+
+BOOLEAN
+read_straight_key_serial(KeyerState ks, int fd) {
+ int i, j, serstatus;
+ static BOOLEAN keystate = 0;
+ static int debounce_buf_i = 0,
+ debounce_buf[DEBOUNCE_BUF_MAX_SIZE];
+
+ //***************************************************
+ // replace this with parallel port logic if necessary
+ //***************************************************
+ //
+ /* Read the key state */
+ if (ioctl(fd, TIOCMGET, &serstatus) != -1) {
+ debounce_buf[debounce_buf_i] =
+ (serstatus & (TIOCM_DSR | TIOCM_CTS)) ?
+ DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY;
+
+ debounce_buf_i++;
+ }
+ //
+ //***************************************************
+ // back to business as usual
+ //***************************************************
+
+ /* If the debounce buffer is full, determine the state of the key */
+ if (debounce_buf_i >= ks->debounce) {
+ debounce_buf_i = 0;
+
+ j = 0;
+ for (i = 0; i < ks->debounce; i++)
+ if (debounce_buf[i])
+ j++;
+ keystate = (j > ks->debounce / 2) ? 1 : 0;
+ }
+
+ return keystate;
+}
+
+//------------------------------------------------------------------------
+
+/* Read an iambic key connected to a serial port, do debouncing, emulate a
+ straight key, then return the emulated key state */
+
+BOOLEAN
+read_iambic_key_serial(KeyerState ks, int fd, KeyerLogic kl, double ticklen) {
+ int i, j, serstatus;
+ static BOOLEAN dah_debounce_buf[DEBOUNCE_BUF_MAX_SIZE],
+ dit_debounce_buf[DEBOUNCE_BUF_MAX_SIZE];
+ static int dah = 0, debounce_buf_i = 0, dit = 0;
+
+ //***************************************************
+ // replace this with parallel port logic if necessary
+ //***************************************************
+ //
+ /* Read the key states */
+ if (ioctl(fd, TIOCMGET, &serstatus) != -1) {
+ if (ks->flag.revpdl) {
+ dah_debounce_buf[debounce_buf_i] =
+ (serstatus & TIOCM_DSR) ? DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY;
+ dit_debounce_buf[debounce_buf_i] =
+ (serstatus & TIOCM_CTS) ? CTS_LINE_CLOSED_KEY : !CTS_LINE_CLOSED_KEY;
+ } else {
+ dit_debounce_buf[debounce_buf_i] =
+ (serstatus & TIOCM_DSR) ? DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY;
+ dah_debounce_buf[debounce_buf_i] =
+ (serstatus & TIOCM_CTS) ? CTS_LINE_CLOSED_KEY : !CTS_LINE_CLOSED_KEY;
+ }
+
+ debounce_buf_i++;
+ }
+ //
+ //***************************************************
+ // back to business as usual
+ //***************************************************
+
+ /* If the debounce buffer is full, determine the state of the keys */
+ if (debounce_buf_i >= ks->debounce) {
+ debounce_buf_i = 0;
+
+ j = 0;
+ for (i = 0; i < ks->debounce; i++)
+ if (dah_debounce_buf[i]) j++;
+ dah = (j > ks->debounce / 2) ? 1 : 0;
+
+ j = 0;
+ for (i = 0; i < ks->debounce; i++)
+ if (dit_debounce_buf[i]) j++;
+ dit = (j > ks->debounce / 2) ? 1 : 0;
+ }
+
+ return klogic(kl,
+ dit,
+ dah,
+ ks->wpm,
+ ks->mode,
+ ks->flag.mdlmdB,
+ ks->flag.memory.dit,
+ ks->flag.memory.dah,
+ ks->flag.autospace.khar,
+ ks->flag.autospace.word,
+ ks->weight,
+ ticklen);
+}
+
+//========================================================================
+
+KeyerState
+newKeyerState(void) {
+ return (KeyerState) safealloc(1, sizeof(KeyerStateInfo), "newKeyerState");
+}
+
+void
+delKeyerState(KeyerState ks) {
+ safefree((char *) ks);
+}
+
+KeyerLogic
+newKeyerLogic(void) {
+ return (KeyerLogic) safealloc(1, sizeof(KeyerLogicInfo), "newKeyerLogic");
+}
+
+void
+delKeyerLogic(KeyerLogic kl) {
+ safefree((char *) kl);
+}
+
+//========================================================================
--- /dev/null
+/* keyer.h */
+/*
+This file is part of a program that implements a Software-Defined Radio.
+
+The code in this file is derived from routines originally written by
+Pierre-Philippe Coupard for his CWirc X-chat program. That program
+is issued under the GPL and is
+Copyright (C) Pierre-Philippe Coupard - 18/06/2003
+
+This derived version is
+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 _keyer_h
+#define _keyer_h
+
+#include <fromsys.h>
+#include <banal.h>
+#include <splitfields.h>
+#include <datatypes.h>
+
+//========================================================================
+
+#define DSR_LINE_CLOSED_KEY (1)
+#define CTS_LINE_CLOSED_KEY (1)
+#define DTR_LINE_SET (0)
+#define RTS_LINE_SET (0)
+
+#define NO_TIMEOUTS_SCHED (-2)
+#define NO_ELEMENT (-1)
+#define DIT (0)
+#define DAH (1)
+#define MODE_A (0)
+#define MODE_B (1)
+#define NO_PADDLE_SQUEEZE (0)
+#define PADDLES_SQUEEZED (1)
+#define PADDLES_RELEASED (2)
+#define NO_DELAY (0)
+#define CHAR_SPACING_DELAY (1)
+#define WORD_SPACING_DELAY (2)
+#define DEBOUNCE_BUF_MAX_SIZE (30)
+
+//========================================================================
+
+typedef
+struct _keyer_state {
+
+ struct {
+
+ BOOLEAN iambic, // iambic or straight
+ mdlmdB,
+ revpdl; // paddles reversed
+
+ struct {
+ BOOLEAN dit, dah;
+ } memory;
+
+ struct {
+ BOOLEAN khar, word;
+ } autospace;
+
+ } flag;
+
+ int debounce, // # seconds to read paddles
+ mode, // 0 = mode A, 1 = mode B
+ weight; // 15 -> 85%
+
+ double wpm; // for iambic keyer
+
+} KeyerStateInfo, *KeyerState;
+
+extern KeyerState newKeyerState(void);
+extern void delKeyerState(KeyerState ks);
+
+//------------------------------------------------------------------------
+
+typedef
+struct _keyer_logic {
+
+ struct {
+ BOOLEAN init;
+
+ struct {
+ BOOLEAN dit, dah;
+ } prev;
+
+ } flag;
+
+ struct {
+ BOOLEAN invtd, // insert inverted element
+ psqam; // paddles squeezed after mid-element
+ int curr, // -1 = nothing, 0 = dit, 1 = dah
+ iamb, // 0 = none, 1 = squeezed, 2 = released
+ last; // -1 = nothing, 0 = dit, 1 = dah
+ } element;
+
+ struct {
+ double beep, dlay, elem, midl;
+ } timeout;
+
+ int dlay_type; // 0 = none, 1 = interchar, 2 = interword
+
+} KeyerLogicInfo, *KeyerLogic;
+
+extern KeyerLogic newKeyerLogic(void);
+extern void delKeyerLogic(KeyerLogic kl);
+
+//========================================================================
+
+extern BOOLEAN klogic(KeyerLogic kl,
+ BOOLEAN dit,
+ BOOLEAN dah,
+ double wpm,
+ int iambicmode,
+ BOOLEAN midelementmodeB,
+ BOOLEAN ditmemory,
+ BOOLEAN dahmemory,
+ BOOLEAN autocharspacing,
+ BOOLEAN autowordspacing,
+ int weight,
+ double ticklen);
+
+extern BOOLEAN read_straight_key_serial(KeyerState ks, int fd);
+extern BOOLEAN read_iambic_key_serial(KeyerState ks, int fd, KeyerLogic kl, double ticklen);
+
+//========================================================================
+
+#endif
//========================================================================
+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
monitor_thread(void) {
while (top.running) {
rx.tick = tx.tick = 0;
top.state = top.swch.run.last;
top.swch.bfct.want = top.swch.bfct.have = 0;
+
+ jack_ringbuffer_reset(top.jack.ring.o.l);
+ jack_ringbuffer_reset(top.jack.ring.o.r);
}
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) {
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);
+ clear_jack_ringbuffer(top.jack.ring.o.l, top.jack.size * sizeof(float));
+ clear_jack_ringbuffer(top.jack.ring.o.r, top.jack.size * sizeof(float));
}
PRIVATE void
for (i = 0, j = n; i < n; i++, j++) zrvec[i] = zrvec[j];
}
+void
+reset_OvSv(FiltOvSv pflt) {
+ memset((char *) pflt->zrvec, 0, pflt->fftlen * sizeof(COMPLEX));
+}
+
/*------------------------------------------------------------*/
/* info: */
/* NB strategy. This is the address we pass to newCXB as
extern void filter_OvSv(FiltOvSv pflt);
extern void filter_OvSv_par(FiltOvSv pflt);
+extern void reset_OvSv(FiltOvSv pflt);
+
#endif
// execution
//////////////////////////////////////////////////////////////////////////
+//========================================================================
+// util
+
+PRIVATE REAL
+CXBnorm(CXB buff) {
+ int i;
+ double sum = 0.0;
+ for (i = 0; i < CXBhave(buff); i++)
+ sum += Csqrmag(CXBdata(buff, i));
+ return sqrt(sum);
+}
+
//========================================================================
/* all */
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;
+ return rx.squelch.thresh > 10.0 * log10(rx.squelch.power);
} else
return rx.squelch.set = FALSE;
}
/* filtering, metering, & AGC */
if (rx.mode != SPEC) {
+ if (rx.tick == 0) reset_OvSv(rx.filt.ovsv);
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);
PRIVATE void
do_rx_post(void) {
- int i, n = CXBhave(rx.buf.o);;
+ int i, n = CXBhave(rx.buf.o);
if (!rx.squelch.set) {
no_squelch();
PRIVATE void
do_tx_pre(void) {
+
if (tx.scl.pre.flag) {
int i, n = CXBhave(tx.buf.i);
for (i = 0; i < n; i++)
}
//
- // mix in CW tone here
+ // mix in CW tone here?
//
correctIQ(tx.buf.i, tx.iqfix);
if (tx.spr.flag) SpeechProcessor(tx.spr.gen);
+
+ if (tx.tick == 0) reset_OvSv(tx.filt.ovsv);
filter_OvSv(tx.filt.ovsv);
}
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);
- }
+ int i, n = min(CXBhave(tx.buf.o), uni.buflen);
+
+ if ((tx.norm = CXBnorm(tx.buf.o)) > 0.0)
+ 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;
- }
+ int i, n = min(CXBhave(tx.buf.o), uni.buflen);
+
+ if ((tx.norm = CXBnorm(tx.buf.o)) > 0.0)
+ 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);
- }
+ int i, n = min(CXBhave(tx.buf.o), uni.buflen);
+ if ((tx.norm = CXBnorm(tx.buf.o)) > 0.0)
+ 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
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;
+ CXBhave(tx.buf.o) = n;
break;
}
} 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;
+ REAL norm;
} rx;
//------------------------------------------------------------------------
} scl;
SDRMODE mode;
long tick;
+ REAL norm;
} tx;
//------------------------------------------------------------------------
/* spottone.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 <spottone.h>
//------------------------------------------------------------------------
/* spottone.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 _spottone_h
#define _spottone_h
}
return (Thunk) 0;
}
+
+#ifdef notdef
+unsigned long
+hash(unsigned char *str) {
+ unsigned long hash = 5381;
+ int c;
+ while (c = *str++)
+ hash = ((hash << 5) + hash) + c; // (hash * 33 + c) better
+ return hash;
+}
+#endif
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]);
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},