]> git.rkrishnan.org Git - dttsp.git/blob - jDttSP/win/keyd.c
Upgraded windows alternatives
[dttsp.git] / jDttSP / win / keyd.c
1 /* keyd.c */
2 /*
3 This file is part of a program that implements a Software-Defined Radio.
4
5 Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
21 The authors can be reached by email at
22
23 ab2kt@arrl.net
24 or
25 rwmcgwier@comcast.net
26
27 or by paper mail at
28
29 The DTTS Microwave Society
30 6 Kathleen Place
31 Bridgewater, NJ 08807
32 */  
33
34 //#include <linux/rtc.h>
35 #include <fromsys.h>
36 #include <banal.h>
37 #include <splitfields.h>
38 #include <datatypes.h>
39 #include <bufvec.h>
40 #include <cxops.h>
41 #include <ringb.h>
42 #include <chan.h>
43 #include <oscillator.h>
44 #include <cwtones.h>
45 #include <pthread.h>
46 #include <semaphore.h>
47 #include <keyer.h>
48
49 #define SAMP_RATE (48000)
50
51 // # times key is sampled per sec
52 // > 64 requires root on Linux
53 //#define RTC_RATE (128)
54 #define RTC_RATE (64)
55
56 // # samples generated during 1 clock tick at RTC_RATE
57 #define TONE_SIZE (SAMP_RATE / RTC_RATE)
58
59 // ring buffer size; > 1 sec at this sr
60 #define RING_SIZE (01 << 020)
61
62 KeyerState ks;
63 KeyerLogic kl;
64
65 static pthread_t play, key, update;
66 sem_t clock_fired, keyer_started, update_ok, poll_fired;
67
68 int fdser, fdrtc;
69 /*
70 jack_client_t *client;
71 jack_port_t *lport, *rport;
72 jack_ringbuffer_t *lring, *rring;
73 jack_nframes_t size; */
74 ringb_t *lring, *rring;
75 int size;
76
77 CWToneGen gen;
78 static BOOLEAN playing = FALSE, iambic = FALSE;
79 static double wpm = 18.0, freq = 750.0, ramp = 5.0, gain = 1.0;
80
81 //------------------------------------------------------------
82
83
84 DttSP_EXP void
85 CWtoneExchange(float *bufl,float*bufr,int nframes) {
86         size_t bytesize = nframes*4;
87         size_t numsamps;
88         if ((numsamps = ringb_read_space(lring)) < bytesize) {
89                 memset(bufl,0,bytesize);
90                 memset(bufr,0,bytesize);
91         } else {
92                 ringb_read(lring,(char *)bufl,bytesize);
93                 ringb_read(rring,(char *)bufr,bytesize);
94         }
95 }
96
97 //------------------------------------------------------------
98
99 // generated tone -> output ringbuffer
100 void
101 send_tone(void) {
102   if (ringb_write_space(lring) < TONE_SIZE * sizeof(float)) {
103     //write(2, "overrun tone\n", 13);
104     ringb_restart(lring, TONE_SIZE * sizeof(float));
105     ringb_restart(rring, TONE_SIZE * sizeof(float));
106   } else {
107     int i;
108     for (i = 0; i < gen->size; i++) {
109       float l = (float)CXBreal(gen->buf, i),
110             r = (float)CXBimag(gen->buf, i);
111       ringb_write(lring, (char *) &l, sizeof(float));
112       ringb_write(rring, (char *) &r, sizeof(float));
113     }
114   }
115 }
116
117 // silence -> output ringbuffer
118 void
119 send_silence(void) {
120   if (ringb_write_space(lring) < TONE_SIZE * sizeof(float)) {
121     //write(2, "overrun zero\n", 13);
122     ringb_restart(lring, TONE_SIZE * sizeof(float));
123     ringb_restart(rring, TONE_SIZE * sizeof(float));
124   } else {
125     int i;
126     for (i = 0; i < gen->size; i++) {
127       float zero = 0.0;
128       ringb_write(lring, (char *) &zero, sizeof(float));
129       ringb_write(rring, (char *) &zero, sizeof(float));
130     }
131   }
132 }
133
134 //------------------------------------------------------------------------
135
136 // sound/silence generation
137 // tone turned on/off asynchronously
138
139 DttSP_EXP void
140 sound_thread_keyd(void) {
141   for (;;) {
142     sem_wait(&clock_fired);
143
144     if (playing) {
145       // CWTone keeps playing for awhile after it's turned off,
146       // in order to allow for a decay envelope;
147       // returns FALSE when it's actually done.
148       playing = CWTone(gen);
149       send_tone();
150     } else {
151       send_silence();
152       // only let updates run when we've just generated silence
153 //      sem_post(&update_ok);
154     }
155   }
156
157   pthread_exit(0);
158 }
159
160
161 BOOLEAN
162 read_key(double del, BOOLEAN dot, BOOLEAN dash) {
163         extern BOOLEAN read_straight_key(KeyerState ks, BOOLEAN keyed);
164         extern BOOLEAN read_iambic_key(KeyerState ks, BOOLEAN dot, BOOLEAN dash, KeyerLogic kl, double ticklen);
165
166   if (iambic)
167     return read_iambic_key(ks, dot, dash, kl, del);
168   else
169     return read_straight_key(ks, dot^dash);
170 }
171
172 /// Main keyer function,  called by a thread in the C#
173 DttSP_EXP void
174 key_thread(double del, BOOLEAN dash, BOOLEAN dot) {
175         BOOLEAN keydown;
176
177     // called after next tick and passed the
178         // delay waitsince last one
179
180     // read key; tell keyer elapsed time since last call
181     keydown = read_key(del,dot,dash);
182
183
184     if (!playing && keydown)
185       CWToneOn(gen), playing = TRUE;
186     else if (playing && !keydown)
187       CWToneOff(gen);
188
189     sem_post(&clock_fired);
190 }
191
192 //------------------------------------------------------------------------
193
194 // update keyer parameters via text input from stdin
195 // <wpm xxx> -> set keyer speed to xxx
196 // <gain xxx> -> set gain to xxx (dB)
197 // <freq xxx> -> set freq to xxx
198 // <ramp xxx> -> set attack/decay times to xxx ms
199
200
201 #define MAX_ESC (512)
202 #define ESC_L '<'
203 #define ESC_R '>'
204
205 void
206 updater(void) {
207   for (;;) {
208     int c;
209
210     // get or wait for next input char
211     if ((c = getchar()) == EOF) goto finish;
212
213     // if we see the beginning of a command,
214     if (c == ESC_L) {
215       int i = 0;
216       char buf[MAX_ESC];
217
218       // gather up the remainder
219       while ((c = getchar()) != EOF) {
220         if (c == ESC_R) break;
221         buf[i] = c;
222         if (++i >= (MAX_ESC - 1)) break;
223       }
224       if (c == EOF) goto finish;
225       buf[i] = 0;
226
227       // wait until changes are safe
228       sem_wait(&update_ok);
229
230       if (!strncmp(buf, "wpm", 3))
231         ks->wpm = wpm = atof(buf + 3);
232       else if (!strncmp(buf, "ramp", 4)) {
233         ramp = atof(buf + 4);
234         setCWToneGenVals(gen, gain, freq, ramp, ramp);
235       } else if (!strncmp(buf, "freq", 4)) {
236         freq = atof(buf + 4);
237         setCWToneGenVals(gen, gain, freq, ramp, ramp);
238       } else if (!strncmp(buf, "gain", 4)) {
239         gain = atof(buf + 4);
240         setCWToneGenVals(gen, gain, freq, ramp, ramp);
241       } else if (!strncmp(buf, "quit", 4))
242         goto finish;
243
244     } // otherwise go around again
245   }
246
247   // we saw an EOF or quit; kill other threads and exit neatly
248
249  finish:
250   pthread_cancel(play);
251   pthread_cancel(key);
252   pthread_exit(0);
253 }
254 DttSP_EXP void
255 updateKeyer(double nfreq, BOOLEAN niambic, double ngain, double nramp, double nwpm,
256                         BOOLEAN revpdl, int weight, double SampleRate) {
257         ks->flag.iambic = niambic;
258         iambic = niambic;
259         ks->flag.revpdl = revpdl;
260         ks->weight = weight;
261         wpm = nwpm;
262         gain = ngain;
263         ramp = nramp;
264         freq = nfreq;
265         gen->osc.freq = 2.0 * M_PI * freq / SampleRate;
266 }
267 DttSP_EXP void
268 NewKeyer(double freq, BOOLEAN niambic, double gain, double ramp, double wpm, double SampleRate) {
269
270   void *usemem;
271
272  //------------------------------------------------------------
273
274   gen = newCWToneGen(gain, freq, ramp, ramp, TONE_SIZE, SampleRate);
275
276   //------------------------------------------------------------
277
278   kl = newKeyerLogic();
279   ks = newKeyerState();
280   ks->flag.iambic = niambic;
281   ks->flag.revpdl = TRUE; // depends on port wiring
282   ks->flag.autospace.khar = ks->flag.autospace.word = FALSE;
283   ks->debounce = 1; // could be more if sampled faster
284   ks->mode = MODE_B;
285   ks->weight = 50;
286   ks->wpm = wpm;
287   iambic = niambic;
288   size = 2048;
289   usemem = safealloc(1,4096*sizeof(float)+sizeof(ringb_t),"Keyer RB Left");
290   lring = ringb_create(usemem, 4096*sizeof(float));
291   usemem = safealloc(1,4096*sizeof(float)+sizeof(ringb_t),"Keyer RB Right");
292   rring = ringb_create(usemem,4096*sizeof(float));
293   ringb_clear(lring, size * sizeof(float));
294   ringb_clear(rring, size * sizeof(float));
295   sem_init(&clock_fired, 0, 0);
296   sem_init(&poll_fired , 0, 0);
297   sem_init(&keyer_started,0,0);
298 }
299
300 DttSP_EXP void
301 delKeyer() {
302   sem_destroy(&clock_fired);
303   sem_destroy(&poll_fired);
304   sem_destroy(&keyer_started);
305   delCWToneGen(gen);
306   delKeyerState(ks);
307   delKeyerLogic(kl);
308   safefree((char *)lring);
309   safefree((char *)rring);
310 }
311 DttSP_EXP void
312 KeyerClockFireWait()
313 {
314         sem_wait(&clock_fired);
315 }
316 DttSP_EXP void
317 KeyerClockFireRelease()
318 {
319         sem_post(&clock_fired);
320 }
321 DttSP_EXP void
322 KeyerStartedWait()
323 {
324         sem_wait(&keyer_started);
325 }
326 DttSP_EXP void
327 KeyerStartedRelease()
328 {
329         sem_post(&keyer_started);
330 }
331 DttSP_EXP void
332 PollTimerWait()
333 {
334         sem_wait(&poll_fired);
335 }
336 DttSP_EXP void
337 PollTimerRelease()
338 {
339         sem_post(&poll_fired);
340 }
341
342 //------------------------------------------------------------------------