cw 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|