]> git.rkrishnan.org Git - dttsp.git/blob - jDttSP/keyer.c
581e51e548b67341837290ff87cf0074a4537d33
[dttsp.git] / jDttSP / keyer.c
1 /* keyer.c */
2 /*
3 This file is part of a program that implements a Software-Defined Radio.
4
5 The code in this file is derived from routines originally written by
6 Pierre-Philippe Coupard for his CWirc X-chat program. That program
7 is issued under the GPL and is
8 Copyright (C) Pierre-Philippe Coupard - 18/06/2003
9
10 This derived version is
11 Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
27 The authors can be reached by email at
28
29 ab2kt@arrl.net
30 or
31 rwmcgwier@comcast.net
32
33 or by paper mail at
34
35 The DTTS Microwave Society
36 6 Kathleen Place
37 Bridgewater, NJ 08807
38 */  
39
40 // see below for places where serial port is read
41 // and needs replacement for parallel port hookup
42
43 #include <keyer.h>
44
45 //========================================================================
46 // nothing affected by physical port connection here
47
48 BOOLEAN
49 klogic(KeyerLogic kl,
50        BOOLEAN dit,
51        BOOLEAN dah,
52        double wpm,
53        int iambicmode,
54        BOOLEAN midelementmodeB,
55        BOOLEAN ditmemory,
56        BOOLEAN dahmemory,
57        BOOLEAN autocharspacing,
58        BOOLEAN autowordspacing,
59        int weight,
60        double ticklen) {
61
62   double ditlen = 1200 / wpm;
63   int set_element_timeouts = NO_TIMEOUTS_SCHED;
64
65   /* Do we need to initialize the keyer? */
66   if (!kl->flag.init) {
67     kl->flag.prev.dit = dit;
68     kl->flag.prev.dah = dah;
69     kl->element.last = kl->element.curr = NO_ELEMENT;
70     kl->element.iamb = NO_PADDLE_SQUEEZE;
71     kl->element.psqam = 0;
72     kl->element.invtd = 0;
73     kl->timeout.midl = kl->timeout.beep = kl->timeout.elem = 0;
74     kl->timeout.dlay = 0;
75     kl->dlay_type = NO_DELAY;
76     kl->flag.init = 1;
77   }
78
79   /* Decrement the timeouts */
80   kl->timeout.dlay -= kl->timeout.dlay > 0 ? ticklen : 0;
81   if (kl->timeout.dlay <= 0) {
82     /* If nothing is scheduled to play, and we just did a character
83        spacing delay, and we do auto word spacing, wait for a word
84        spacing delay, otherwise resume the normal element timeout
85        countdowns */
86     if (kl->timeout.elem <= 0 &&
87         kl->dlay_type == CHAR_SPACING_DELAY &&
88         autowordspacing) {
89       kl->timeout.dlay = ditlen * 4;
90       kl->dlay_type = WORD_SPACING_DELAY;
91     } else {
92       kl->dlay_type = NO_DELAY;
93       kl->timeout.midl -= kl->timeout.midl > 0 ? ticklen : 0;
94       kl->timeout.beep -= kl->timeout.beep > 0 ? ticklen : 0;
95       kl->timeout.elem -= kl->timeout.elem > 0 ? ticklen : 0;
96     }
97   }
98
99   /* Are both paddles squeezed? */
100   if (dit && dah) {
101     kl->element.iamb = PADDLES_SQUEEZED;
102
103     /* Are the paddles squeezed past the middle of the element? */
104     if (kl->timeout.midl <= 0)
105       kl->element.psqam = 1;
106   } else
107     /* Are both paddles released and we had gotten a squeeze in this element? */
108   if (!dit && !dah && kl->element.iamb == PADDLES_SQUEEZED)
109     kl->element.iamb = PADDLES_RELEASED;
110
111   /* Is the current element finished? */
112   if (kl->timeout.elem <= 0 && kl->element.curr != NO_ELEMENT) {
113     kl->element.last = kl->element.curr;
114
115     /* Should we insert an inverted element? */
116     if (((dit && dah) ||
117          (kl->element.invtd &&
118           kl->element.iamb != PADDLES_RELEASED) ||
119          (kl->element.iamb == PADDLES_RELEASED &&
120           iambicmode == MODE_B &&
121           (!midelementmodeB || kl->element.psqam)))) {
122       if (kl->element.last == DAH)
123         set_element_timeouts = kl->element.curr = DIT;
124       else
125         set_element_timeouts = kl->element.curr = DAH;
126     } else {
127       /* No more element */
128       kl->element.curr = NO_ELEMENT;
129
130       /* Do we do automatic character spacing? */
131       if (autocharspacing && !dit && !dah) {
132         kl->timeout.dlay = ditlen * 2;
133         kl->dlay_type = CHAR_SPACING_DELAY;
134       }
135     }
136
137     kl->element.invtd = 0;
138     kl->element.iamb = NO_PADDLE_SQUEEZE;
139     kl->element.psqam = 0;
140   }
141
142   /* Is an element currently being played? */
143   if (kl->element.curr == NO_ELEMENT) {
144     if (dah)                    /* Dah paddle down ? */
145       set_element_timeouts = kl->element.curr = DAH;
146     else if (dit)               /* Dit paddle down ? */
147       set_element_timeouts = kl->element.curr = DIT;
148   }
149
150   /* Do the dah memory */
151   if (kl->element.curr == DIT &&
152       !kl->flag.prev.dah &&
153       dah &&
154       dahmemory)
155     kl->element.invtd = 1;
156
157   /* Do the dit memory */
158   if (kl->element.curr == DAH &&
159       !kl->flag.prev.dit &&
160       dit &&
161       ditmemory)
162     kl->element.invtd = 1;
163
164   /* If we had a dit (or dah) scheduled to be played after a delay,
165      and the operator lifted both paddles before the end of the delay,
166      and we have no dit (or dah) memory, forget it */
167
168   if (kl->timeout.dlay > 0 &&
169       !dit &&
170       !dah &&
171       ((kl->element.curr == DIT &&
172         !ditmemory) ||
173        (kl->element.curr == DAH
174         && !dahmemory)))
175     set_element_timeouts = kl->element.curr = NO_ELEMENT;
176
177   /* Do we need to set the playing timeouts of an element? */
178   switch (set_element_timeouts) {
179   case NO_ELEMENT:              /* Cancel any dit or dah */
180     kl->timeout.beep = 0;
181     kl->timeout.midl = 0;
182     kl->timeout.elem = 0;
183     break;
184
185   case DIT:                     /* Schedule a dit? */
186     kl->timeout.beep = (ditlen * (double) weight) / 50;
187     kl->timeout.midl = kl->timeout.beep / 2;
188     kl->timeout.elem = ditlen * 2;
189     break;
190
191   case DAH:                     /* Schedule a dah? */
192     kl->timeout.beep = (ditlen * (double) weight) / 50 + ditlen * 2;
193     kl->timeout.midl = kl->timeout.beep / 2;
194     kl->timeout.elem = ditlen * 4;
195     break;
196   }
197
198   kl->flag.prev.dit = dit;
199   kl->flag.prev.dah = dah;
200
201   return kl->timeout.beep > 0 && kl->timeout.dlay <= 0;
202 }
203
204 //========================================================================
205
206 /* Read a straight key connected to a serial port, do debouncing, then
207    return the key state */
208
209 BOOLEAN
210 read_straight_key_serial(KeyerState ks, int fd) {
211   int i, j, serstatus;
212   static BOOLEAN keystate = 0;
213   static int debounce_buf_i = 0,
214              debounce_buf[DEBOUNCE_BUF_MAX_SIZE];
215
216   //***************************************************
217   // replace this with parallel port logic if necessary
218   //***************************************************
219   //
220   /* Read the key state */
221   if (ioctl(fd, TIOCMGET, &serstatus) != -1) {
222     debounce_buf[debounce_buf_i] =
223       (serstatus & (TIOCM_DSR | TIOCM_CTS)) ?
224       DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY;
225
226     debounce_buf_i++;
227   }
228   //
229   //***************************************************
230   // back to business as usual
231   //***************************************************
232
233   /* If the debounce buffer is full, determine the state of the key */
234   if (debounce_buf_i >= ks->debounce) {
235     debounce_buf_i = 0;
236
237     j = 0;
238     for (i = 0; i < ks->debounce; i++)
239       if (debounce_buf[i])
240         j++;
241     keystate = (j > ks->debounce / 2) ? 1 : 0;
242   }
243
244   return keystate;
245 }
246
247 //------------------------------------------------------------------------
248
249 /* Read an iambic key connected to a serial port, do debouncing, emulate a
250    straight key, then return the emulated key state */
251
252 BOOLEAN
253 read_iambic_key_serial(KeyerState ks, int fd, KeyerLogic kl, double ticklen) {
254   int i, j, serstatus;
255   static BOOLEAN dah_debounce_buf[DEBOUNCE_BUF_MAX_SIZE],
256                  dit_debounce_buf[DEBOUNCE_BUF_MAX_SIZE];
257   static int dah = 0, debounce_buf_i = 0, dit = 0;
258
259   //***************************************************
260   // replace this with parallel port logic if necessary
261   //***************************************************
262   //
263   /* Read the key states */
264   if (ioctl(fd, TIOCMGET, &serstatus) != -1) {
265     if (ks->flag.revpdl) {
266       dah_debounce_buf[debounce_buf_i] =
267         (serstatus & TIOCM_DSR) ? DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY;
268       dit_debounce_buf[debounce_buf_i] =
269         (serstatus & TIOCM_CTS) ? CTS_LINE_CLOSED_KEY : !CTS_LINE_CLOSED_KEY;
270     } else {
271       dit_debounce_buf[debounce_buf_i] =
272         (serstatus & TIOCM_DSR) ? DSR_LINE_CLOSED_KEY : !DSR_LINE_CLOSED_KEY;
273       dah_debounce_buf[debounce_buf_i] =
274         (serstatus & TIOCM_CTS) ? CTS_LINE_CLOSED_KEY : !CTS_LINE_CLOSED_KEY;
275     }
276
277     debounce_buf_i++;
278   }
279   //
280   //***************************************************
281   // back to business as usual
282   //***************************************************
283
284   /* If the debounce buffer is full, determine the state of the keys */
285   if (debounce_buf_i >= ks->debounce) {
286     debounce_buf_i = 0;
287
288     j = 0;
289     for (i = 0; i < ks->debounce; i++)
290       if (dah_debounce_buf[i]) j++;
291     dah = (j > ks->debounce / 2) ? 1 : 0;
292
293     j = 0;
294     for (i = 0; i < ks->debounce; i++)
295       if (dit_debounce_buf[i]) j++;
296     dit = (j > ks->debounce / 2) ? 1 : 0;
297   }
298
299   return klogic(kl,
300                 dit,
301                 dah,
302                 ks->wpm,
303                 ks->mode,
304                 ks->flag.mdlmdB,
305                 ks->flag.memory.dit,
306                 ks->flag.memory.dah,
307                 ks->flag.autospace.khar,
308                 ks->flag.autospace.word,
309                 ks->weight,
310                 ticklen);
311 }
312
313 //========================================================================
314
315 KeyerState
316 newKeyerState(void) {
317   return (KeyerState) safealloc(1, sizeof(KeyerStateInfo), "newKeyerState");
318 }
319
320 void
321 delKeyerState(KeyerState ks) {
322   safefree((char *) ks);
323 }
324
325 KeyerLogic
326 newKeyerLogic(void) {
327   return (KeyerLogic) safealloc(1, sizeof(KeyerLogicInfo), "newKeyerLogic");
328 }
329
330 void
331 delKeyerLogic(KeyerLogic kl) {
332   safefree((char *) kl);
333 }
334
335 //========================================================================