3 This file is part of a program that implements a Software-Defined Radio.
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
10 This derived version is
11 Copyright (C) 2004 by Frank Brickle, AB2KT and Bob McGwier, N4HY
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.
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.
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
27 The authors can be reached by email at
35 The DTTS Microwave Society
40 // see below for places where serial port is read
41 // and needs replacement for parallel port hookup
45 //========================================================================
46 // nothing affected by physical port connection here
54 BOOLEAN midelementmodeB,
57 BOOLEAN autocharspacing,
58 BOOLEAN autowordspacing,
62 double ditlen = 1200 / wpm;
63 int set_element_timeouts = NO_TIMEOUTS_SCHED;
65 /* Do we need to initialize the keyer? */
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;
75 kl->dlay_type = NO_DELAY;
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
86 if (kl->timeout.elem <= 0 &&
87 kl->dlay_type == CHAR_SPACING_DELAY &&
89 kl->timeout.dlay = ditlen * 4;
90 kl->dlay_type = WORD_SPACING_DELAY;
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;
99 /* Are both paddles squeezed? */
101 kl->element.iamb = PADDLES_SQUEEZED;
103 /* Are the paddles squeezed past the middle of the element? */
104 if (kl->timeout.midl <= 0)
105 kl->element.psqam = 1;
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;
111 /* Is the current element finished? */
112 if (kl->timeout.elem <= 0 && kl->element.curr != NO_ELEMENT) {
113 kl->element.last = kl->element.curr;
115 /* Should we insert an inverted element? */
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;
125 set_element_timeouts = kl->element.curr = DAH;
127 /* No more element */
128 kl->element.curr = NO_ELEMENT;
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;
137 kl->element.invtd = 0;
138 kl->element.iamb = NO_PADDLE_SQUEEZE;
139 kl->element.psqam = 0;
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;
150 /* Do the dah memory */
151 if (kl->element.curr == DIT &&
152 !kl->flag.prev.dah &&
155 kl->element.invtd = 1;
157 /* Do the dit memory */
158 if (kl->element.curr == DAH &&
159 !kl->flag.prev.dit &&
162 kl->element.invtd = 1;
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 */
168 if (kl->timeout.dlay > 0 &&
171 ((kl->element.curr == DIT &&
173 (kl->element.curr == DAH
175 set_element_timeouts = kl->element.curr = NO_ELEMENT;
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;
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;
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;
198 kl->flag.prev.dit = dit;
199 kl->flag.prev.dah = dah;
201 return kl->timeout.beep > 0 && kl->timeout.dlay <= 0;
204 //========================================================================
206 /* Read a straight key connected to a serial port, do debouncing, then
207 return the key state */
210 read_straight_key_serial(KeyerState ks, int fd) {
212 static BOOLEAN keystate = 0;
213 static int debounce_buf_i = 0,
214 debounce_buf[DEBOUNCE_BUF_MAX_SIZE];
216 //***************************************************
217 // replace this with parallel port logic if necessary
218 //***************************************************
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;
229 //***************************************************
230 // back to business as usual
231 //***************************************************
233 /* If the debounce buffer is full, determine the state of the key */
234 if (debounce_buf_i >= ks->debounce) {
238 for (i = 0; i < ks->debounce; i++)
241 keystate = (j > ks->debounce / 2) ? 1 : 0;
247 //------------------------------------------------------------------------
249 /* Read an iambic key connected to a serial port, do debouncing, emulate a
250 straight key, then return the emulated key state */
253 read_iambic_key_serial(KeyerState ks, int fd, KeyerLogic kl, double ticklen) {
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;
259 //***************************************************
260 // replace this with parallel port logic if necessary
261 //***************************************************
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;
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;
280 //***************************************************
281 // back to business as usual
282 //***************************************************
284 /* If the debounce buffer is full, determine the state of the keys */
285 if (debounce_buf_i >= ks->debounce) {
289 for (i = 0; i < ks->debounce; i++)
290 if (dah_debounce_buf[i]) j++;
291 dah = (j > ks->debounce / 2) ? 1 : 0;
294 for (i = 0; i < ks->debounce; i++)
295 if (dit_debounce_buf[i]) j++;
296 dit = (j > ks->debounce / 2) ? 1 : 0;
307 ks->flag.autospace.khar,
308 ks->flag.autospace.word,
313 //========================================================================
316 newKeyerState(void) {
317 return (KeyerState) safealloc(1, sizeof(KeyerStateInfo), "newKeyerState");
321 delKeyerState(KeyerState ks) {
322 safefree((char *) ks);
326 newKeyerLogic(void) {
327 return (KeyerLogic) safealloc(1, sizeof(KeyerLogicInfo), "newKeyerLogic");
331 delKeyerLogic(KeyerLogic kl) {
332 safefree((char *) kl);
335 //========================================================================