Module morseToneGeneration
|
|
1
2
3 import subprocess;
4 import time;
5 import os;
6 import signal;
7 import threading;
8 from datetime import datetime;
9 from watchdogTimer import WatchdogTimer;
10 from morseCodeTranslationKey import codeKey;
11
15
20
22 '''
23 Manages non-UI issues for Morse code generation: Interacts with the
24 tone generator, regulates auto dot/dash generation speed.
25 '''
26
28 super(MorseGenerator, self).__init__();
29
30
31
32
33 self.frequency = 300;
34
35 self.callback = callback;
36
37 self.interLetterDelayExplicitlySet = False;
38 self.interWordDelayExplicitlySet = False;
39
40
41 self.setSpeed(3.3);
42 self.automaticMorse = True;
43
44 self.recentDots = 0;
45 self.recentDashes = 0;
46
47 self.morseResult = '';
48 self.alphaStr = '';
49 self.watchdog = WatchdogTimer(timeout=self.interLetterTime, callback=self.watchdogExpired);
50
51
52
53 self.morseDashEvent = threading.Event();
54 self.morseDotEvent = threading.Event();
55 self.morseStopEvent = threading.Event();
56
57
58 self.alphaStrLock = threading.Lock();
59
60
61 self.morseResultLock = threading.Lock();
62
63
64 self.keepRunning = True;
65
66 self.dotGenerator = MorseGenerator.DotGenerator(self).start();
67 self.DashGenerator = MorseGenerator.DashGenerator(self).start();
68
69
70
72 '''
73 Start a sequence of dots or dashes. If auto-morse is False,
74 only one dot or dash is produced per call. Else a dashes or
75 dots are produced at an adjustable speed until stopMorseSeq()
76 is called. Use setAutoMorse() to control whether single-shot
77 or automatic sequences are produced. Use setSpeed() to set
78 the speed at which the signals are generated.
79
80 After stopMorseSeq() is called, use getRecentDots() or
81 getRecentDashes() return the number of dots or dashes that
82 were generated.
83
84 @param morseElement: whether to produce dots or dashes
85 @type morseElement: Morse enum
86 '''
87
88 if not self.keepRunning:
89 raise RuntimeError("Called Morse generator method after stopMorseGenerator() was called.");
90
91
92
93
94 self.watchdog.stop();
95
96 if morseElement == Morse.DASH:
97 self.morseDashEvent.set();
98 elif morseElement == Morse.DOT:
99 self.morseDotEvent.set();
100
102 '''
103 Stop a running sequence of dots or dashes. After this call,
104 use getRecentDots() or getRecentDashes() to get a count of
105 Morse elements (dots or dashes) that were emitted. If automatic
106 Morse generation is disabled, it is not necessary to call this
107 method. See setAutoMorse(). Called when mouse cursor leaves
108
109 '''
110 if not self.keepRunning:
111 raise RuntimeError("Called Morse generator method after stopMorseGenerator() was called.");
112
113
114 self.morseDotEvent.clear();
115 self.morseDashEvent.clear();
116
117
118
119 self.watchdog.kick(_timeout=self.interLetterTime, callbackArg=TimeoutReason.END_OF_LETTER);
120
124
126 '''
127 Determine whether dots and dashes are generated one at
128 a time each time startMorseSeq() is called, or whether
129 each call generates sequences of signals until stopMorseGenerator()
130 is called.
131 @param yesNo:
132 @type yesNo:
133 '''
134 self.automaticMorse = yesNo;
135
137 return self.recentDots;
138
140 return self.recentDashes;
141
142 - def setSpeed(self, dotsPlusPausePerSec):
143 '''
144 Sets speed at which automatic dots and dashes are
145 generated. Units are Herz. One cycle is a single
146 dot, followed by the pause that separates two dots.
147 Since that pause is standardized to be equal to
148 a dot length, one can think of the speed as the
149 number times the letter "i" is generated per second.
150
151 The higher the number, the faster the dots/dashes are
152 generated. Default is 3.3.
153
154 @param dotsPlusPausePerSec: rate at which dots or dashes are produced in automatic mode.
155 @type dotsPlusPausePerSec: float
156 '''
157 self.dotDuration = 1.0/(2*dotsPlusPausePerSec);
158
159 self.dashDuration = 2*self.dotDuration;
160
161
162 self.interSigPauseDots = self.dotDuration;
163 self.interSigPauseDashes = self.dotDuration;
164
165
166
167 if not self.interLetterDelayExplicitlySet:
168 self.interLetterTime = 7.0*self.dotDuration;
169 if not self.interWordDelayExplicitlySet:
170
171 self.interWordTime = -1;
172
173 self.waitDashDotThreadsIdleTime = 0.5 * self.interLetterTime;
174
176 '''
177 Sets the time that must elapse between two letters.
178 @param secs: fractional seconds
179 @type secs: float
180 '''
181 self.interLetterTime = secs;
182 self.watchdog.changeTimeout(self.interLetterTime);
183 self.waitDashDotThreadsIdleTime = 0.5 * self.interLetterTime;
184 self.interLetterDelayExplicitlySet = True;
185
187 '''
188 Sets the time that must elapse between two words.
189 If negative, no word segmentation is performed.
190 @param secs: fractional seconds
191 @type secs: float
192 '''
193 self.interWordTime = secs;
194
195
196
197 self.interWordDelayExplicitlySet = True;
198
200 '''
201 Stop the entire generator. All threads are killed.
202 Subsequent calls to startMorseSeq() or stopMorseSeq()
203 generate exceptions.
204 '''
205 self.keepRunning = False;
206
207
208
209 self.morseDashEvent.set();
210 self.morseDotEvent.set();
211
213 res = self.alphaStr;
214 self.setAlphaStr('');
215 return res;
216
218 with self.alphaStrLock:
219 self.alphaStr = newAlphaStr
220
222 with self.morseResultLock:
223 self.morseResult = newMorseResult;
224
226 '''
227 Return the minimum amount of silence time required
228 for the system to conclude that the Morse code equivalent
229 of a letter has been generated. I.e.: end-of-letter pause.
230 '''
231 return self.interLetterTime;
232
234 '''
235 Return the minimum amount of silence time required
236 for the system to conclude that a word has ended.
237 I.e.: end-of-word pause.
238 '''
239 return self.interWordTime;
240
242 '''
243 Truly return only after specified time. Just using
244 time.sleep() sleeps shorter if any interrupts occur during
245 the sleep period.
246 @param secs: fractional seconds to sleep
247 @type secs: float
248 '''
249 sleepStop = time.time() + secs;
250 while True:
251 timeLeft = sleepStop - time.time();
252 if timeLeft <= 0:
253 return
254 time.sleep(timeLeft)
255
256
257
258
268
300
302 try:
303 letter = codeKey[self.morseResult];
304 if letter == 'BS':
305 letter = '\b';
306 elif letter == 'NL':
307 letter = '\r';
308 elif letter == 'HS':
309 letter = ' ';
310 except KeyError:
311
312 return None
313 return letter;
314
315
316
317
318
320
325
328
331
333
334
335 self.parent.morseDotEvent.wait();
336
337 numDots = 0;
338
339 while self.parent.keepRunning:
340
341 while self.parent.morseDotEvent.is_set():
342
343 self.idle = False;
344
345
346 proc = subprocess.Popen(['speaker-test',
347 "--test", "sine",
348 "--frequency", str(self.parent.frequency)],
349 stdout=subprocess.PIPE);
350 time.sleep(self.parent.dotDuration);
351 os.kill(proc.pid, signal.SIGUSR1)
352
353 numDots += 1;
354 if not self.parent.automaticMorse:
355
356
357
358
359
360 self.parent.morseDotEvent.clear();
361 else:
362
363
364 self.parent.reallySleep(self.parent.interSigPauseDots);
365
366 self.parent.addMorseElements(Morse.DOT, numDots);
367
368 numDots = 0;
369 self.idle = True;
370 self.parent.morseDotEvent.wait();
371
372
373
374
375
377
382
385
388
390
391
392 self.parent.morseDashEvent.wait();
393
394 numDashes = 0;
395
396 while self.parent.keepRunning:
397 while self.parent.morseDashEvent.is_set():
398
399 self.idle = False;
400
401
402 proc = subprocess.Popen(['speaker-test',
403 "--test", "sine",
404 "--frequency", str(self.parent.frequency)],
405 stdout=subprocess.PIPE);
406 time.sleep(self.parent.dashDuration);
407 os.kill(proc.pid, signal.SIGUSR1)
408
409 numDashes += 1;
410 if not self.parent.automaticMorse:
411
412
413
414
415
416 self.parent.morseDashEvent.clear();
417 else:
418
419
420 self.parent.reallySleep(self.parent.interSigPauseDashes);
421
422 self.parent.addMorseElements(Morse.DASH, numDashes);
423
424 numDashes = 0;
425 self.idle = True;
426 self.parent.morseDashEvent.wait();
427
428 if __name__ == "__main__":
429
430 generator = MorseGenerator();
431
432
433 generator.setAutoMorse(False);
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485