cw 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.cw_config +4 -1
- data/.gitignore +2 -0
- data/Gemfile +6 -0
- data/VERSION +1 -1
- data/cw.gemspec +6 -6
- data/lib/cw.rb +8 -2
- data/lib/cw/audio_player.rb +4 -1
- data/lib/cw/config.rb +3 -3
- data/lib/cw/coreaudio.rb +144 -0
- data/lib/cw/cw_dsl.rb +12 -12
- data/lib/cw/cw_threads.rb +54 -24
- data/lib/cw/key_input.rb +15 -8
- data/lib/cw/play.rb +1 -1
- data/lib/cw/print.rb +25 -1
- data/lib/cw/repeat_word.rb +9 -4
- data/lib/cw/rss.rb +23 -20
- data/lib/cw/tester.rb +6 -2
- data/lib/cw/tone_generator.rb +68 -83
- data/lib/cw/tone_helpers.rb +1 -1
- data/lib/cw/tx.rb +487 -0
- data/lib/cw/winkey.rb +121 -0
- data/lib/cw/words.rb +1 -1
- data/test/test_cw.rb +28 -27
- data/test/test_tone_generator.rb +141 -0
- metadata +42 -15
- data/calculator.rb +0 -63
- data/chart.rb +0 -33
- data/chart2.rb +0 -35
- data/chart3.rb +0 -47
- data/chart4.rb +0 -45
data/lib/cw/winkey.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'rubyserial'
|
2
|
+
|
3
|
+
module CWG
|
4
|
+
|
5
|
+
class Winkey
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@print = Print.new
|
9
|
+
STDERR.puts "Attempting to open winkey connection"
|
10
|
+
port_str = "/dev/cu.usbserial-AD01XY9H" #may be different for you
|
11
|
+
baud_rate = 1200
|
12
|
+
data_bits = 8
|
13
|
+
begin
|
14
|
+
@serial = Serial.new(port_str, baud_rate, data_bits)
|
15
|
+
@serial.closed?
|
16
|
+
rescue => e
|
17
|
+
p e
|
18
|
+
p @serial
|
19
|
+
STDERR.puts "Failed to open serial port - Exiting!"
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def write data
|
25
|
+
@serial.write data
|
26
|
+
end
|
27
|
+
|
28
|
+
def getbyte
|
29
|
+
@serial.getbyte
|
30
|
+
end
|
31
|
+
|
32
|
+
def close
|
33
|
+
puts 'Closing'
|
34
|
+
@serial.close
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_status byte
|
38
|
+
status = byte & 192
|
39
|
+
if status == 192
|
40
|
+
# puts "status"
|
41
|
+
true
|
42
|
+
elsif status == 128
|
43
|
+
# puts "wpm"
|
44
|
+
true
|
45
|
+
else
|
46
|
+
# puts "byte 0x#{byte.to_s()}"
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def string str
|
52
|
+
# puts str
|
53
|
+
write str
|
54
|
+
str.split('').each do |ip|
|
55
|
+
# puts "ip = #{ip}"
|
56
|
+
read ip.ord, "sent and received #{ip.chr}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def read match, match_msg
|
61
|
+
loop_delay = 0.05
|
62
|
+
count = 1
|
63
|
+
25.times do
|
64
|
+
byte = getbyte
|
65
|
+
unless byte.nil?
|
66
|
+
unless check_status(byte)
|
67
|
+
# puts "count is, #{count}, byte is #{byte.inspect}, match is #{match.inspect}"
|
68
|
+
if byte == match
|
69
|
+
# print byte.ord
|
70
|
+
# puts match_msg
|
71
|
+
return
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
count += 1
|
76
|
+
sleep loop_delay
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def command cmd
|
81
|
+
{
|
82
|
+
on: "\x00\x02",
|
83
|
+
no_weighting: "\x03\x32",
|
84
|
+
echo: "\x00\x04\x5A"
|
85
|
+
}[cmd]
|
86
|
+
end
|
87
|
+
|
88
|
+
def on
|
89
|
+
puts 'host on'
|
90
|
+
write command :on
|
91
|
+
read 23, "on ack"
|
92
|
+
end
|
93
|
+
|
94
|
+
def no_weighting
|
95
|
+
puts 'no weighting'
|
96
|
+
write command :no_weighting
|
97
|
+
end
|
98
|
+
|
99
|
+
def echo
|
100
|
+
puts 'echo test'
|
101
|
+
write command :echo
|
102
|
+
read 'Z'.ord, "echo success"
|
103
|
+
end
|
104
|
+
|
105
|
+
def wpm wpm
|
106
|
+
puts "set wpm to #{wpm}"
|
107
|
+
write "\x02"
|
108
|
+
write [wpm].pack('U')
|
109
|
+
end
|
110
|
+
|
111
|
+
def sent?
|
112
|
+
true
|
113
|
+
end
|
114
|
+
|
115
|
+
def wait_while_sending
|
116
|
+
until sent?
|
117
|
+
sleep 0.01
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/cw/words.rb
CHANGED
data/test/test_cw.rb
CHANGED
@@ -42,7 +42,7 @@ class TestCW < MiniTest::Test
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def test_loads_words_by_default
|
45
|
-
assert_equal
|
45
|
+
assert_equal %w(the of and to a), @cw.words.first(5)
|
46
46
|
end
|
47
47
|
|
48
48
|
def test_CW_takes_a_block
|
@@ -56,8 +56,8 @@ class TestCW < MiniTest::Test
|
|
56
56
|
no_run
|
57
57
|
}
|
58
58
|
assert_equal 1000, cw.words.size
|
59
|
-
cw.words =
|
60
|
-
assert_equal
|
59
|
+
cw.words = %w(some words)
|
60
|
+
assert_equal %w(some words), cw.words
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_no_run_aliases_no_run
|
@@ -65,7 +65,7 @@ class TestCW < MiniTest::Test
|
|
65
65
|
cw = CW.new {
|
66
66
|
no_run
|
67
67
|
}
|
68
|
-
cw.words =
|
68
|
+
cw.words = %w(some words)
|
69
69
|
assert (Time.now - time) < 1
|
70
70
|
end
|
71
71
|
|
@@ -73,10 +73,10 @@ class TestCW < MiniTest::Test
|
|
73
73
|
cw = CW.new {
|
74
74
|
no_run
|
75
75
|
}
|
76
|
-
cw.words =
|
77
|
-
assert_equal
|
76
|
+
cw.words = %w(some words)
|
77
|
+
assert_equal %w(some words), cw.words
|
78
78
|
cw.load_common_words
|
79
|
-
assert_equal
|
79
|
+
assert_equal %w(the of and to a), cw.words.first(5)
|
80
80
|
end
|
81
81
|
|
82
82
|
def test_load_words_loads_passed_filename
|
@@ -84,14 +84,14 @@ class TestCW < MiniTest::Test
|
|
84
84
|
temp << "some words"
|
85
85
|
temp.close
|
86
86
|
@cw.load_text temp
|
87
|
-
assert_equal
|
87
|
+
assert_equal %w(some words), @cw.words
|
88
88
|
end
|
89
89
|
|
90
90
|
def test_to_s_outputs_test_run_header_if_no_run
|
91
91
|
temp =
|
92
92
|
%q(========
|
93
93
|
WPM: 25
|
94
|
-
Word count:
|
94
|
+
Word count: 9999
|
95
95
|
========
|
96
96
|
)
|
97
97
|
assert_equal temp, @cw.to_s
|
@@ -142,35 +142,35 @@ Ending: x
|
|
142
142
|
|
143
143
|
def test_shuffle_shuffles_words
|
144
144
|
@cw.shuffle
|
145
|
-
refute_equal
|
145
|
+
refute_equal %w(the of and to a), @cw.words.first(5)
|
146
146
|
end
|
147
147
|
|
148
148
|
def test_word_size_returns_words_of_such_size
|
149
149
|
@cw.word_size 2
|
150
|
-
assert_equal
|
150
|
+
assert_equal %w(of to in is on), @cw.words.first(5)
|
151
151
|
end
|
152
152
|
|
153
153
|
def test_beginning_with_returns_words_beginning_with_letter
|
154
154
|
@cw.beginning_with 'l'
|
155
|
-
assert_equal
|
155
|
+
assert_equal %w(like list last links life), @cw.words.first(5)
|
156
156
|
end
|
157
157
|
|
158
158
|
def test_beginning_with_will_take_two_letters
|
159
159
|
@cw.load_words(1500)
|
160
160
|
@cw.beginning_with 'x','q'
|
161
|
-
assert_equal
|
161
|
+
assert_equal %w(x xml quality questions q quote),
|
162
162
|
@cw.words.first(6)
|
163
163
|
end
|
164
164
|
|
165
165
|
def test_ending_with_returns_words_ending_with_letter
|
166
166
|
@cw.ending_with 'l'
|
167
|
-
assert_equal
|
167
|
+
assert_equal %w(all will email well school), @cw.words.first(5)
|
168
168
|
end
|
169
169
|
|
170
170
|
def test_ending_with_will_take_two_letters
|
171
171
|
@cw.load_words 200
|
172
172
|
@cw.ending_with 'x', 'a'
|
173
|
-
assert_equal
|
173
|
+
assert_equal %w(x sex a data),
|
174
174
|
@cw.words
|
175
175
|
end
|
176
176
|
|
@@ -181,23 +181,23 @@ Ending: x
|
|
181
181
|
|
182
182
|
def test_including_returns_words_including_letter
|
183
183
|
@cw.including 'l'
|
184
|
-
assert_equal
|
184
|
+
assert_equal %w(all will only also help), @cw.words.first(5)
|
185
185
|
end
|
186
186
|
|
187
187
|
def test_including_will_take_two_letters
|
188
188
|
@cw.load_words(100)
|
189
189
|
@cw.including 'p','b'
|
190
|
-
assert_equal
|
190
|
+
assert_equal %w(page up help pm by be about but),@cw.words.first(8)
|
191
191
|
end
|
192
192
|
|
193
193
|
def test_no_longer_than_will_return_words_no_longer_than_x
|
194
194
|
@cw.no_longer_than 4
|
195
|
-
assert_equal
|
195
|
+
assert_equal %w(the of and to a), @cw.words.first(5)
|
196
196
|
end
|
197
197
|
|
198
198
|
def test_no_shorter_than_will_return_words_no_shorter_than_x
|
199
199
|
@cw.no_shorter_than 4
|
200
|
-
assert_equal
|
200
|
+
assert_equal %w(that this with from your), @cw.words.first(5)
|
201
201
|
end
|
202
202
|
|
203
203
|
def test_words_fn_adds_words
|
@@ -206,13 +206,13 @@ Ending: x
|
|
206
206
|
end
|
207
207
|
|
208
208
|
def test_words_fn_passes_in_an_array_of_words_as_is
|
209
|
-
@cw.words =
|
210
|
-
assert_equal
|
209
|
+
@cw.words = %w(one two three four)
|
210
|
+
assert_equal %w(one two three four), @cw.words
|
211
211
|
end
|
212
212
|
|
213
213
|
def test_random_letters_returns_words_of_size_4_by_default
|
214
214
|
@cw.random_letters
|
215
|
-
@cw.words.each { |w| assert_equal 4, w.length}
|
215
|
+
@cw.words.each { |w| assert_equal 4, w.length }
|
216
216
|
end
|
217
217
|
|
218
218
|
def test_random_letters_returns_word_count_of_50_by_default
|
@@ -222,7 +222,7 @@ Ending: x
|
|
222
222
|
|
223
223
|
def test_random_letters_can_take_size_option
|
224
224
|
@cw.random_letters(size: 5)
|
225
|
-
@cw.words.each { |w| assert_equal 5, w.length}
|
225
|
+
@cw.words.each { |w| assert_equal 5, w.length }
|
226
226
|
end
|
227
227
|
|
228
228
|
def test_random_letters_can_take_count_option
|
@@ -233,7 +233,7 @@ Ending: x
|
|
233
233
|
def test_random_letters_can_take_size_and_count_option
|
234
234
|
@cw.random_letters(count: 3, size: 4)
|
235
235
|
assert_equal 3, @cw.words.size
|
236
|
-
@cw.words.each { |w| assert_equal 4, w.length}
|
236
|
+
@cw.words.each { |w| assert_equal 4, w.length }
|
237
237
|
end
|
238
238
|
|
239
239
|
def test_random_letters_returns_random_letters
|
@@ -246,7 +246,7 @@ Ending: x
|
|
246
246
|
def test_random_numbers_can_take_size_and_count_option
|
247
247
|
@cw.random_numbers(count: 3, size: 4)
|
248
248
|
assert_equal 3, @cw.words.size
|
249
|
-
@cw.words.each { |w| assert_equal 4, w.length}
|
249
|
+
@cw.words.each { |w| assert_equal 4, w.length }
|
250
250
|
end
|
251
251
|
|
252
252
|
def test_random_numbers_returns_random_numbers
|
@@ -280,7 +280,7 @@ Ending: x
|
|
280
280
|
|
281
281
|
def test_alphabet_generates_alphabet
|
282
282
|
@cw.alphabet
|
283
|
-
assert_equal [
|
283
|
+
assert_equal ['a b c d e f g h i j k l m n o p q r s t u v w x y z'], @cw.words
|
284
284
|
end
|
285
285
|
|
286
286
|
def test_alphabet_generates_reversed_alphabet
|
@@ -290,7 +290,7 @@ Ending: x
|
|
290
290
|
|
291
291
|
def test_alphabet_shuffles_alphabet
|
292
292
|
@cw.alphabet(shuffle: true)
|
293
|
-
refute_equal [
|
293
|
+
refute_equal ['a b c d e f g h i j k l m n o p q r s t u v w x y z'], @cw.words
|
294
294
|
assert_equal "abcdefghijklmnopqrstuvwxyz", @cw.words.first.chars.sort.join.strip
|
295
295
|
end
|
296
296
|
|
@@ -353,6 +353,7 @@ Ending: x
|
|
353
353
|
assert @cw.method(:words_no_shorter_than), @cw.method(:no_shorter_than)
|
354
354
|
assert @cw.method(:random_alphanumeric), @cw.method(:random_letters_numbers)
|
355
355
|
assert @cw.method(:comment), @cw.method(:name)
|
356
|
+
assert @cw.method(:comment), @cw.method(:name)
|
356
357
|
end
|
357
358
|
|
358
359
|
def test_set_wpm_param
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
$VERBOSE = nil #FIXME
|
3
|
+
SimpleCov.start
|
4
|
+
|
5
|
+
require 'minitest/autorun'
|
6
|
+
require 'minitest/pride'
|
7
|
+
require_relative '../lib/cw'
|
8
|
+
|
9
|
+
class TestToneGenerator < MiniTest::Test
|
10
|
+
|
11
|
+
ROOT = File.expand_path File.dirname(__FILE__) + '/../'
|
12
|
+
|
13
|
+
def setup
|
14
|
+
CWG::Cfg.reset
|
15
|
+
@tg = CWG::ToneGenerator.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def teardown
|
19
|
+
@tg = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_assert
|
23
|
+
assert 1
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_refute
|
27
|
+
refute nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_code_filename
|
31
|
+
assert_equal File.join(ROOT, '.cw', 'audio', 'dot.wav'), @tg.code.filename(:dot)
|
32
|
+
assert_equal File.join(ROOT, '.cw', 'audio', 'dash.wav'), @tg.code.filename(:dash)
|
33
|
+
assert_equal File.join(ROOT, '.cw', 'audio', 'space.wav'), @tg.code.filename(:space)
|
34
|
+
assert_equal File.join(ROOT, '.cw', 'audio', 'e_space.wav'), @tg.code.filename(:e_space)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_code_spb_for_15_wpm
|
38
|
+
CWG::Cfg.config.params['wpm'] = 15
|
39
|
+
tg = CWG::ToneGenerator.new
|
40
|
+
element = 192
|
41
|
+
assert_equal element * 1, tg.code.spb(:dot)
|
42
|
+
assert_equal element * 3, tg.code.spb(:dash)
|
43
|
+
assert_equal element * 1, tg.code.spb(:space)
|
44
|
+
assert_equal element * 1, tg.code.spb(:e_space)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_code_spb_for_25_wpm
|
48
|
+
CWG::Cfg.config.params['wpm'] = 25
|
49
|
+
tg = CWG::ToneGenerator.new
|
50
|
+
element = 115
|
51
|
+
assert_equal element * 1, tg.code.spb(:dot)
|
52
|
+
assert_equal element * 3, tg.code.spb(:dash)
|
53
|
+
assert_equal element * 1, tg.code.spb(:space)
|
54
|
+
assert_equal element * 1, tg.code.spb(:e_space)
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_code_spb_for_40_wpm
|
58
|
+
CWG::Cfg.config.params['wpm'] = 40
|
59
|
+
tg = CWG::ToneGenerator.new
|
60
|
+
element = 72
|
61
|
+
assert_equal element * 1, tg.code.spb(:dot)
|
62
|
+
assert_equal element * 3, tg.code.spb(:dash)
|
63
|
+
assert_equal element * 1, tg.code.spb(:space)
|
64
|
+
assert_equal element * 1, tg.code.spb(:e_space)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_code_spb_for_20_wpm
|
68
|
+
CWG::Cfg.config.params['wpm'] = 20
|
69
|
+
tg = CWG::ToneGenerator.new
|
70
|
+
element = 144
|
71
|
+
assert_equal element * 1, tg.code.spb(:dot)
|
72
|
+
assert_equal element * 3, tg.code.spb(:dash)
|
73
|
+
assert_equal element * 1, tg.code.spb(:space)
|
74
|
+
assert_equal element * 1, tg.code.spb(:e_space)
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_elements
|
78
|
+
assert_equal :dot, @tg.elements.first
|
79
|
+
assert_equal :dash, @tg.elements.fetch(1)
|
80
|
+
assert_equal :space, @tg.elements.fetch(2)
|
81
|
+
assert_equal :e_space, @tg.elements.last
|
82
|
+
assert_equal 4, @tg.elements.size
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_generate_samples
|
86
|
+
CWG::Cfg.config.params['wpm'] = 40
|
87
|
+
tg = CWG::ToneGenerator.new
|
88
|
+
samples = tg.generate_samples(:dot)
|
89
|
+
assert_equal Array, samples.class
|
90
|
+
assert_equal 72, samples.size
|
91
|
+
assert_equal samples.size, tg.generate_samples(:space).size
|
92
|
+
assert_equal samples.size * 3, tg.generate_samples(:dash).size
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_space_or_espace_method_when_no_wpm_equals_ewpm
|
96
|
+
assert_equal({ name: :space }, @tg.space_or_espace)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_space_or_espace_method_when_ewpm_active
|
100
|
+
@tg.instance_variable_set :@effective_wpm, 10
|
101
|
+
assert_equal({ name: :e_space }, @tg.space_or_espace)
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_play_filename
|
105
|
+
assert_equal File.join(ROOT, 'audio', 'audio_output.wav'), @tg.play_filename
|
106
|
+
end
|
107
|
+
|
108
|
+
def test_cw_encoding_returns_a_cw_encoding_object
|
109
|
+
assert_equal CWG::CwEncoding, @tg.cw_encoding.class
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_cw_encoding_responds_to_fetch
|
113
|
+
assert_equal(true, @tg.cw_encoding.respond_to?(:fetch))
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_cw_encoding_fetch_returns_dot_dash_given_the_letter_a
|
117
|
+
assert_equal [:dot, :dash], @tg.cw_encoding.fetch('a')
|
118
|
+
assert_equal [:dash, :dot], @tg.cw_encoding.fetch('n')
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_push_enc_does_something
|
122
|
+
# p @tg.push_enc([nil]).class
|
123
|
+
# p @tg.push_enc(['a','b'])
|
124
|
+
assert_equal 4, @tg.push_enc([nil]).size
|
125
|
+
assert_equal 4, @tg.push_enc(['a']).size
|
126
|
+
assert_equal 6, @tg.push_enc(['a','b']).size
|
127
|
+
assert_equal 8, @tg.push_enc(['a','b','c']).size
|
128
|
+
assert_equal 'a', @tg.push_enc(['a','b']).first
|
129
|
+
assert_equal Hash, @tg.push_enc(['a','b']).fetch(1).class
|
130
|
+
assert_equal 'b', @tg.push_enc(['a','b']).fetch(2)
|
131
|
+
assert_equal Hash, @tg.push_enc(['a','b']).last.class
|
132
|
+
assert_equal :space, @tg.push_enc(['a','b']).last[:name] = :space
|
133
|
+
assert_equal 'b', @tg.push_enc(['a','b']).fetch(2)
|
134
|
+
assert_equal Array, @tg.push_enc(['a','b']).class
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_word_space_returns_space_if_not_ewpm
|
138
|
+
# assert_equal '', @tg.word_space
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|