3 This file is part of a program that implements a Software-Defined Radio.
5 Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
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.
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.
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
21 The authors can be reached by email at
29 The DTTS Microwave Society
34 #include <linux/rtc.h>
37 #include <splitfields.h>
38 #include <datatypes.h>
43 #include <oscillator.h>
47 #define SAMP_RATE (48000)
49 // # times key is sampled per sec
50 // > 64 requires root on Linux
51 //#define RTC_RATE (128)
54 // # samples generated during 1 clock tick at RTC_RATE
55 #define TONE_SIZE (SAMP_RATE / RTC_RATE)
57 // ring buffer size; > 1 sec at this sr
58 #define RING_SIZE (01 << 020)
64 sem_t clock_fired, keyer_started;
68 jack_client_t *client;
69 jack_port_t *lport, *rport;
70 jack_ringbuffer_t *lring, *rring;
74 BOOLEAN playing = FALSE, iambic = FALSE;
75 double wpm = 18.0, freq = 750.0;
77 //------------------------------------------------------------
80 jack_ringbuffer_clear(jack_ringbuffer_t *ring, int nbytes) {
83 for (i = 0; i < nbytes; i++)
84 jack_ringbuffer_write(ring, &zero, 1);
88 jack_ringbuffer_restart(jack_ringbuffer_t *ring, int nbytes) {
89 jack_ringbuffer_reset(ring);
90 jack_ringbuffer_clear(ring, nbytes);
93 //------------------------------------------------------------
95 // generated tone -> output ringbuffer
98 if (jack_ringbuffer_write_space(lring) < TONE_SIZE * sizeof(float)) {
99 write(2, "overrun tone\n", 13);
100 jack_ringbuffer_restart(lring, TONE_SIZE * sizeof(float));
101 jack_ringbuffer_restart(rring, TONE_SIZE * sizeof(float));
104 for (i = 0; i < gen->size; i++) {
105 float l = CXBreal(gen->buf, i),
106 r = CXBimag(gen->buf, i);
107 jack_ringbuffer_write(lring, (char *) &l, sizeof(float));
108 jack_ringbuffer_write(rring, (char *) &r, sizeof(float));
113 // silence -> output ringbuffer
116 if (jack_ringbuffer_write_space(lring) < TONE_SIZE * sizeof(float)) {
117 write(2, "overrun zero\n", 13);
118 jack_ringbuffer_restart(lring, TONE_SIZE * sizeof(float));
119 jack_ringbuffer_restart(rring, TONE_SIZE * sizeof(float));
122 for (i = 0; i < gen->size; i++) {
124 jack_ringbuffer_write(lring, (char *) &zero, sizeof(float));
125 jack_ringbuffer_write(rring, (char *) &zero, sizeof(float));
130 // sound/silence generation
131 // tone turned on/off asynchronously
135 sem_wait(&clock_fired);
138 // CWTone keeps playing for awhile after it's turned off,
139 // in order to allow for a decay envelope;
140 // returns FALSE when it's actually done.
141 playing = CWTone(gen);
151 // returns actual dur in msec since last tick;
152 // uses Linux rtc interrupts.
153 // other strategies will work too, so long as they
154 // provide a measurable delay in msec.
157 double del, std = 1000 / (double) RTC_RATE;
161 if (read(fdrtc, &data, sizeof(unsigned long)) == -1) {
165 // indicate whether an interrupt was missed
166 // not really important except for performance tweaks
167 if ((del = (data >> 010) * 1000 / (double) RTC_RATE) != std)
168 fprintf(stderr, "%d %g ms\n", ++cnt, del);
172 // key down? (real or via keyer logic)
174 read_key(double del) {
176 return read_iambic_key_serial(ks, fdser, kl, del);
178 return read_straight_key_serial(ks, fdser);
186 sem_wait(&keyer_started);
189 // wait for next tick, get actual dur since last one
190 double del = timed_delay();
191 // read key; tell keyer elapsed time since last call
192 BOOLEAN keydown = read_key(del);
194 if (!playing && keydown)
195 CWToneOn(gen), playing = TRUE;
196 else if (playing && !keydown)
199 sem_post(&clock_fired);
206 jack_xrun(void *arg) {
208 write(2, str, strlen(str));
212 jack_shutdown(void *arg) {}
215 jack_callback(jack_nframes_t nframes, void *arg) {
217 int nbytes = nframes * sizeof(float);
218 if (nframes == size) {
219 // output: copy from ring to port
220 lp = (float *) jack_port_get_buffer(lport, nframes);
221 rp = (float *) jack_port_get_buffer(rport, nframes);
222 if (jack_ringbuffer_read_space(lring) >= nbytes) {
223 jack_ringbuffer_read(lring, (char *) lp, nbytes);
224 jack_ringbuffer_read(rring, (char *) rp, nbytes);
225 } else { // rb pathology
226 memset((char *) lp, 0, nbytes);
227 memset((char *) rp, 0, nbytes);
228 jack_ringbuffer_reset(lring);
229 jack_ringbuffer_reset(rring);
230 jack_ringbuffer_clear(lring, nbytes);
231 jack_ringbuffer_clear(rring, nbytes);
232 //write(2, "underrun\n", 9);
238 main(int argc, char **argv) {
240 char *serialdev = "/dev/ttyS0",
241 *clockdev = "/dev/rtc";
244 for (i = 1; i < argc; i++)
245 if (argv[i][0] == '-')
246 switch (argv[i][1]) {
248 freq = atof(argv[++i]);
254 wpm = atof(argv[++i]);
257 fprintf(stderr, "keyd [-i] [-w wpm]\n");
262 //------------------------------------------------------------
264 gen = newCWToneGen(-3.0, freq, 5.0, 5.0, TONE_SIZE, 48000.0);
266 //------------------------------------------------------------
268 kl = newKeyerLogic();
269 ks = newKeyerState();
270 ks->flag.iambic = TRUE;
271 ks->flag.revpdl = TRUE; // depends on port wiring
272 ks->flag.autospace.khar = ks->flag.autospace.word = FALSE;
273 ks->debounce = 1; // could be more if sampled faster
278 //------------------------------------------------------------
280 if (!(client = jack_client_new("keyd")))
281 fprintf(stderr, "can't make client -- jack not running?\n"), exit(1);
282 jack_set_process_callback(client, (void *) jack_callback, 0);
283 jack_on_shutdown(client, (void *) jack_shutdown, 0);
284 jack_set_xrun_callback(client, (void *) jack_xrun, 0);
285 size = jack_get_buffer_size(client);
286 lport = jack_port_register(client,
288 JACK_DEFAULT_AUDIO_TYPE,
291 rport = jack_port_register(client,
293 JACK_DEFAULT_AUDIO_TYPE,
296 lring = jack_ringbuffer_create(RING_SIZE);
297 rring = jack_ringbuffer_create(RING_SIZE);
298 jack_ringbuffer_clear(lring, size * sizeof(float));
299 jack_ringbuffer_clear(rring, size * sizeof(float));
301 //------------------------------------------------------------
304 if ((fdser = open(serialdev, O_WRONLY)) == -1) {
305 fprintf(stderr, "cannot open serial device %s", serialdev);
308 if (ioctl(fdser, TIOCMGET, &serstatus) == -1) {
310 fprintf(stderr, "cannot get serial device status");
313 serstatus |= TIOCM_DTR;
314 if (ioctl(fdser, TIOCMSET, &serstatus) == -1) {
316 fprintf(stderr, "cannot set serial device status");
321 if ((fdrtc = open(clockdev, O_RDONLY)) == -1) {
325 if (ioctl(fdrtc, RTC_IRQP_SET, RTC_RATE) == -1) {
326 perror("ioctl irqp");
329 if (ioctl(fdrtc, RTC_PIE_ON, 0) == -1) {
330 perror("ioctl pie on");
334 //------------------------------------------------------------
336 sem_init(&clock_fired, 0, 0);
337 sem_init(&keyer_started, 0, 0);
338 pthread_create(&play, 0, (void *) sound_thread, 0);
339 pthread_create(&key, 0, (void *) key_thread, 0);
341 //------------------------------------------------------------
343 jack_activate(client);
346 if (!(ports = jack_get_ports(client, 0, 0, JackPortIsPhysical | JackPortIsInput))) {
347 fprintf(stderr, "can't find any physical playback ports\n");
350 if (jack_connect(client, jack_port_name(lport), ports[0])) {
351 fprintf(stderr, "can't connect left output\n");
354 if (jack_connect(client, jack_port_name(rport), ports[1])) {
355 fprintf(stderr, "can't connect left output\n");
360 sem_post(&keyer_started);
362 pthread_join(play, 0);
363 pthread_join(key, 0);
364 jack_client_close(client);
366 //------------------------------------------------------------
368 if (ioctl(fdrtc, RTC_PIE_OFF, 0) == -1) {
369 perror("ioctl pie off");
375 jack_ringbuffer_free(lring);
376 jack_ringbuffer_free(rring);
378 sem_destroy(&clock_fired);
379 sem_destroy(&keyer_started);
385 //------------------------------------------------------------