WrathPak
·
2025-08-18
keyers.cpp
1#include <stddef.h>
2#include "keyers.h"
3
4#define len(t) (sizeof(t)/sizeof(*t))
5
6// Queue Set: A Set you can shift and pop.
7class QSet {
8 int arr[MAX_KEYER_QUEUE];
9 unsigned int arrlen = 0;
10
11public:
12 int shift() {
13 if (arrlen == 0) {
14 return -1;
15 }
16 int ret = arr[0];
17 arrlen--;
18 for (int i = 0; i < arrlen; i++) {
19 arr[i] = arr[i+1];
20 }
21 return ret;
22 }
23
24 int pop() {
25 if (arrlen == 0) {
26 return -1;
27 }
28 int ret = arr[arrlen];
29 arrlen--;
30 return ret;
31 }
32
33 void add(int val) {
34 if (arrlen == MAX_KEYER_QUEUE) {
35 return;
36 }
37 for (int i = 0; i < arrlen; i++) {
38 if (arr[i] == val) {
39 return;
40 }
41 }
42 arr[arrlen] = val;
43 arrlen++;
44 }
45};
46
47
48class StraightKeyer: public Keyer {
49public:
50 Transmitter *output;
51 unsigned int ditDuration;
52 bool txRelays[2];
53
54 StraightKeyer() {
55 this->Reset();
56 }
57
58 void SetOutput(Transmitter *output) {
59 this->output = output;
60 }
61
62 void Reset() {
63 if (this->output) {
64 this->output->EndTx();
65 }
66 this->ditDuration = 100;
67 }
68
69 void SetDitDuration(unsigned int duration) {
70 this->ditDuration = duration;
71 }
72
73 void Release() {
74 this->Reset();
75 }
76
77 bool TxClosed() {
78 for (int i = 0; i < len(this->txRelays); i++) {
79 if (this->TxClosed(i)) {
80 return true;
81 }
82 }
83 return false;
84 }
85
86 bool TxClosed(int relay) {
87 return this->txRelays[relay];
88 }
89
90 void Tx(int relay, bool closed) {
91 bool wasClosed = this->TxClosed();
92 this->txRelays[relay] = closed;
93 bool nowClosed = this->TxClosed();
94
95 if (wasClosed != nowClosed) {
96 if (nowClosed) {
97 this->output->BeginTx();
98 } else {
99 this->output->EndTx();
100 }
101 }
102 }
103
104 void Key(Paddle key, bool pressed) {
105 this->Tx(key, pressed);
106 }
107
108 void Tick(unsigned int millis) {};
109};
110
111class BugKeyer: public StraightKeyer {
112public:
113 unsigned int nextPulse = 0;
114 bool keyPressed[2];
115
116 using StraightKeyer::StraightKeyer;
117
118 void Reset() {
119 StraightKeyer::Reset();
120 this->nextPulse = 0;
121 this->keyPressed[0] = false;
122 this->keyPressed[1] = false;
123 }
124
125 void Key(Paddle key, bool pressed) {
126 this->keyPressed[key] = pressed;
127 if (key == 0) {
128 this->beginPulsing();
129 } else {
130 StraightKeyer::Key(key, pressed);
131 }
132 }
133
134 void Tick(unsigned int millis) {
135 if (this->nextPulse && (millis >= this->nextPulse)) {
136 this->pulse(millis);
137 }
138 }
139
140 void beginPulsing() {
141 if (!this->nextPulse) {
142 this->nextPulse = 1;
143 }
144 }
145
146 virtual void pulse(unsigned int millis) {
147 if (this->TxClosed(0)) {
148 this->Tx(0, false);
149 } else if (this->keyPressed[0]) {
150 this->Tx(0, true);
151 } else {
152 this->nextPulse = 0;
153 return;
154 }
155 this->nextPulse = millis + this->ditDuration;
156 }
157};
158
159class ElBugKeyer: public BugKeyer {
160public:
161 unsigned int nextRepeat;
162
163 using BugKeyer::BugKeyer;
164
165 void Reset() {
166 BugKeyer::Reset();
167 this->nextRepeat = -1;
168 }
169
170 // Return which key is pressed. If none, return -1.
171 int whichKeyPressed() {
172 for (int i = 0; i < len(this->keyPressed); i++) {
173 if (this->keyPressed[i]) {
174 return i;
175 }
176 }
177 return -1;
178 }
179
180 void Key(Paddle key, bool pressed) {
181 this->keyPressed[key] = pressed;
182 if (pressed) {
183 this->nextRepeat = key;
184 this->beginPulsing();
185 } else {
186 this->nextRepeat = this->whichKeyPressed();
187 }
188 }
189
190 unsigned int keyDuration(int key) {
191 switch (key) {
192 case PADDLE_DIT:
193 return this->ditDuration;
194 case PADDLE_DAH:
195 return 3 * (this->ditDuration);
196 }
197 return this->ditDuration; // XXX
198 }
199
200 virtual int nextTx() {
201 if (this->whichKeyPressed() == -1) {
202 return -1;
203 }
204 return this->nextRepeat;
205 }
206
207 virtual void pulse(unsigned int millis) {
208 int nextPulse = 0;
209 if (this->TxClosed(0)) {
210 // Pause if we're currently transmitting
211 nextPulse = this->keyDuration(PADDLE_DIT);
212 this->Tx(0, false);
213 } else {
214 int next = this->nextTx();
215 if (next >= 0) {
216 nextPulse = this->keyDuration(next);
217 this->Tx(0, true);
218 }
219 }
220
221 if (nextPulse) {
222 this->nextPulse = millis + nextPulse;
223 } else {
224 this->nextPulse = 0;
225 }
226 }
227};
228
229class UltimaticKeyer: public ElBugKeyer {
230public:
231 QSet queue;
232
233 using ElBugKeyer::ElBugKeyer;
234
235 void Key(Paddle key, bool pressed) {
236 if (pressed) {
237 this->queue.add(key);
238 }
239 ElBugKeyer::Key(key, pressed);
240 }
241
242 virtual int nextTx() {
243 int key = this->queue.shift();
244 if (key != -1) {
245 return key;
246 }
247 return ElBugKeyer::nextTx();
248 }
249};
250
251class SingleDotKeyer: public ElBugKeyer {
252public:
253 QSet queue;
254
255 using ElBugKeyer::ElBugKeyer;
256
257 void Key(Paddle key, bool pressed) {
258 if (pressed && (key == PADDLE_DIT)) {
259 this->queue.add(key);
260 }
261 ElBugKeyer::Key(key, pressed);
262 }
263
264 virtual int nextTx() {
265 int key = this->queue.shift();
266 if (key != -1) {
267 return key;
268 }
269 if (this->keyPressed[1]) return 1;
270 if (this->keyPressed[0]) return 0;
271 return -1;
272 }
273};
274
275class IambicKeyer: public ElBugKeyer {
276public:
277
278 using ElBugKeyer::ElBugKeyer;
279
280 virtual int nextTx() {
281 int next = ElBugKeyer::nextTx();
282 if (this->keyPressed[PADDLE_DIT] && this->keyPressed[PADDLE_DAH]) {
283 this->nextRepeat = 1 - this->nextRepeat;
284 }
285 return next;
286 }
287};
288
289class IambicAKeyer: public IambicKeyer {
290public:
291 QSet queue;
292
293 using IambicKeyer::IambicKeyer;
294
295 void Key(Paddle key, bool pressed) {
296 if (pressed && (key == PADDLE_DIT)) {
297 this->queue.add(key);
298 }
299 IambicKeyer::Key(key, pressed);
300 }
301
302 virtual int nextTx() {
303 int next = IambicKeyer::nextTx();
304 int key = this->queue.shift();
305 if (key != -1) {
306 return key;
307 }
308 return next;
309 }
310};
311
312class IambicBKeyer: public IambicKeyer {
313public:
314 QSet queue;
315
316 using IambicKeyer::IambicKeyer;
317
318 void Reset() {
319 IambicKeyer::Reset();
320 }
321
322 void Key(Paddle key, bool pressed) {
323 if (pressed) {
324 this->queue.add(key);
325 }
326 IambicKeyer::Key(key, pressed);
327 }
328
329 virtual int nextTx() {
330 for (int key = 0; key < len(this->keyPressed); key++) {
331 if (this->keyPressed[key]) {
332 this->queue.add(key);
333 }
334 }
335
336 return this->queue.shift();
337 }
338};
339
340class KeyaheadKeyer: public ElBugKeyer {
341public:
342 int queue[MAX_KEYER_QUEUE];
343 unsigned int qlen;
344
345 using ElBugKeyer::ElBugKeyer;
346
347 void Reset() {
348 ElBugKeyer::Reset();
349 this->qlen = 0;
350 }
351
352 void Key(Paddle key, bool pressed) {
353 if (pressed) {
354 if (this->qlen < MAX_KEYER_QUEUE) {
355 this->queue[this->qlen++] = key;
356 }
357 }
358 ElBugKeyer::Key(key, pressed);
359 }
360
361 virtual int nextTx() {
362 if (this->qlen > 0) {
363 int next = this->queue[0];
364 this->qlen--;
365 for (int i = 0; i < this->qlen; i++) {
366 this->queue[i] = this->queue[i+1];
367 }
368 return next;
369 }
370 return ElBugKeyer::nextTx();
371 }
372};
373
374StraightKeyer straightKeyer = StraightKeyer();
375BugKeyer bugKeyer = BugKeyer();
376ElBugKeyer elBugKeyer = ElBugKeyer();
377SingleDotKeyer singleDotKeyer = SingleDotKeyer();
378UltimaticKeyer ultimaticKeyer = UltimaticKeyer();
379IambicKeyer iambicKeyer = IambicKeyer();
380IambicAKeyer iambicAKeyer = IambicAKeyer();
381IambicBKeyer iambicBKeyer = IambicBKeyer();
382KeyaheadKeyer keyaheadKeyer = KeyaheadKeyer();
383
384Keyer *keyers[] = {
385 NULL,
386 &straightKeyer,
387 &bugKeyer,
388 &elBugKeyer,
389 &singleDotKeyer,
390 &ultimaticKeyer,
391 &iambicKeyer,
392 &iambicAKeyer,
393 &iambicBKeyer,
394 &keyaheadKeyer,
395};
396
397Keyer *GetKeyerByNumber(int n, Transmitter *output) {
398 if (n >= len(keyers)) {
399 return NULL;
400 }
401
402 Keyer *k = keyers[n];
403 k->SetOutput(output);
404 return k;
405}
406
407int getKeyerNumber(Keyer* k) {
408 if (k == NULL) {
409 return 1; // Default to straight key if NULL
410 }
411
412 for (int i = 1; i < len(keyers); i++) {
413 if (keyers[i] == k) {
414 return i;
415 }
416 }
417 return 1; // Default to straight key if not found
418}