cheeky-dreams 0.0.4 → 0.0.5
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.
- data/VERSION +1 -1
- data/cheeky-dreams.gemspec +4 -2
- data/lib/cheeky-dreams.rb +180 -112
- data/spec/cheeky-dreams_spec.rb +371 -239
- data/spec/off.rb +10 -0
- data/spec/small-test.rb +16 -0
- data/spec/support/collecting_auditor.rb +7 -7
- data/spec/support/stub_driver.rb +1 -1
- data/spec/support/stub_effect.rb +2 -2
- metadata +13 -11
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.5
|
data/cheeky-dreams.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "cheeky-dreams"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["simon"]
|
12
|
-
s.date = "2011-11-
|
12
|
+
s.date = "2011-11-17"
|
13
13
|
s.description = "For controlling dream cheeky usb light"
|
14
14
|
s.email = "simojenki@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -28,6 +28,8 @@ Gem::Specification.new do |s|
|
|
28
28
|
"cheeky-dreams.gemspec",
|
29
29
|
"lib/cheeky-dreams.rb",
|
30
30
|
"spec/cheeky-dreams_spec.rb",
|
31
|
+
"spec/off.rb",
|
32
|
+
"spec/small-test.rb",
|
31
33
|
"spec/spec_helper.rb",
|
32
34
|
"spec/support/collecting_auditor.rb",
|
33
35
|
"spec/support/stub_driver.rb",
|
data/lib/cheeky-dreams.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
require 'thread'
|
2
2
|
|
3
3
|
module CheekyDreams
|
4
|
-
|
5
|
-
|
6
|
-
[
|
7
|
-
[
|
8
|
-
|
4
|
+
|
5
|
+
COLOURS = {
|
6
|
+
:off => [0, 0, 0],
|
7
|
+
:red => [255, 0, 0],
|
8
|
+
:green => [0, 255, 0],
|
9
|
+
:blue => [0, 0, 255],
|
10
|
+
:yellow => [255,255,0],
|
11
|
+
:aqua => [0,255,255],
|
12
|
+
:purple => [255,0,255],
|
13
|
+
:grey => [192,192,192],
|
14
|
+
:white => [255,255,255]
|
15
|
+
}
|
9
16
|
|
10
17
|
def rgb_between a, b, ratio
|
11
18
|
[
|
@@ -15,58 +22,84 @@ module CheekyDreams
|
|
15
22
|
]
|
16
23
|
end
|
17
24
|
|
25
|
+
def sleep_until time
|
26
|
+
zzz_time = time - Time.now
|
27
|
+
sleep(zzz_time) if zzz_time > 0
|
28
|
+
end
|
29
|
+
|
18
30
|
def position_between a, b, ratio
|
19
31
|
return b if ratio >= 1.0
|
20
32
|
(((b - a) * ratio) + a).floor
|
21
33
|
end
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
}
|
34
|
-
|
35
|
-
def rgb_for colour
|
36
|
-
case colour
|
37
|
-
when Symbol
|
38
|
-
raise "Unknown colour '#{colour}'" unless COLOURS.has_key?(colour)
|
39
|
-
COLOURS[colour]
|
40
|
-
when Array
|
41
|
-
raise "Invalid rgb #{colour}" unless colour.length == 3 && colour.all? { |c| c.is_a? Fixnum }
|
42
|
-
rgb(colour[0], colour[1], colour[2])
|
35
|
+
def rgb *rgb_args
|
36
|
+
raise 'Cannot give rgb for nil!' unless rgb_args
|
37
|
+
args = rgb_args.flatten
|
38
|
+
if args.length == 1 && args[0].is_a?(Symbol)
|
39
|
+
raise "Unknown colour '#{args[0]}'" unless COLOURS.has_key?(args[0])
|
40
|
+
COLOURS[args[0]]
|
41
|
+
elsif (args.length == 3 && args.all? { |c| c.is_a? Numeric })
|
42
|
+
r, g, b = args[0].floor, args[1].floor, args[2].floor
|
43
|
+
[r, g, b].each { |c| raise "Invalid rgb value #{r}, #{g}, #{b}" if c < 0 || c > 255}
|
44
|
+
[r, g, b]
|
43
45
|
else
|
44
|
-
raise "
|
46
|
+
raise "Invalid rgb #{args}"
|
45
47
|
end
|
46
48
|
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
|
50
|
+
class FilteringAuditor
|
51
|
+
def initialize auditor, including
|
52
|
+
@auditor, @including = auditor, Set.new(including)
|
53
|
+
end
|
54
|
+
|
55
|
+
def audit type, message
|
56
|
+
@auditor.audit(type, message) if @including.include?(type)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class StdIOAuditor
|
61
|
+
def initialize out = STDOUT, err = STDERR
|
62
|
+
@out, @err = out, err
|
63
|
+
end
|
64
|
+
|
65
|
+
def audit type, message
|
66
|
+
case type
|
67
|
+
when :error
|
68
|
+
@err.puts "#{type} - #{message}"
|
69
|
+
else
|
70
|
+
@out.puts "#{type} - #{message}"
|
53
71
|
end
|
54
|
-
end
|
72
|
+
end
|
55
73
|
end
|
56
74
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
75
|
+
def filtering including, auditor
|
76
|
+
FilteringAuditor.new auditor, including
|
77
|
+
end
|
78
|
+
|
79
|
+
def audit_to *auditors
|
80
|
+
CompositeAuditor.new *auditors
|
81
|
+
end
|
82
|
+
|
83
|
+
class CompositeAuditor
|
84
|
+
def initialize *auditors
|
85
|
+
@auditors = auditors
|
86
|
+
end
|
87
|
+
|
88
|
+
def audit type, message
|
89
|
+
@auditors.each { |auditor| auditor.audit type, message }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def stdio_audit out = STDOUT, err = STDERR
|
94
|
+
StdIOAuditor.new(out, err)
|
95
|
+
end
|
96
|
+
|
97
|
+
def dev_null
|
98
|
+
Dev::Null.new
|
62
99
|
end
|
63
100
|
|
64
101
|
def stdout_driver
|
65
|
-
|
66
|
-
def go rgb
|
67
|
-
puts rgb
|
68
|
-
end
|
69
|
-
end.new
|
102
|
+
Dev::IO.new
|
70
103
|
end
|
71
104
|
|
72
105
|
def ansi_driver
|
@@ -80,10 +113,58 @@ module CheekyDreams
|
|
80
113
|
end
|
81
114
|
|
82
115
|
def find_dream_cheeky_usb_device
|
83
|
-
|
116
|
+
Dev::DreamCheeky.new(File.dirname(Dir.glob('/sys/devices/**/red').first))
|
117
|
+
end
|
118
|
+
|
119
|
+
def off
|
120
|
+
solid :off
|
121
|
+
end
|
122
|
+
|
123
|
+
def solid colour
|
124
|
+
Effects::Solid.new(colour)
|
125
|
+
end
|
126
|
+
|
127
|
+
def cycle colours, freq = 1
|
128
|
+
Effects::Cycle.new(colours, freq)
|
129
|
+
end
|
130
|
+
|
131
|
+
def fade from, to, steps = 10, freq = 1
|
132
|
+
Effects::Fade.new from, to, steps, freq
|
133
|
+
end
|
134
|
+
|
135
|
+
def fade_to to, steps = 10, freq = 1
|
136
|
+
Effects::FadeTo.new to, steps, freq
|
137
|
+
end
|
138
|
+
|
139
|
+
def func freq = 1, &block
|
140
|
+
Effects::Func.new freq, &block
|
141
|
+
end
|
142
|
+
|
143
|
+
def throb freq, from, to
|
144
|
+
Effects::Throb.new freq, from, to
|
84
145
|
end
|
85
146
|
|
86
|
-
|
147
|
+
def crazy freq = 1, new_effect_freq = 2
|
148
|
+
Effects::Crazy.new(freq, new_effect_freq)
|
149
|
+
end
|
150
|
+
|
151
|
+
module Dev
|
152
|
+
class Null
|
153
|
+
def audit type, message
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class IO
|
158
|
+
def initialize io = $stdout
|
159
|
+
@io, @last = io, nil
|
160
|
+
end
|
161
|
+
|
162
|
+
def go rgb
|
163
|
+
@io.puts "[#{rgb.join(',')}]" unless rgb == @last
|
164
|
+
@last = rgb
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
87
168
|
class DreamCheeky
|
88
169
|
attr_reader :path
|
89
170
|
def initialize path, max_threshold = 50
|
@@ -105,7 +186,7 @@ module CheekyDreams
|
|
105
186
|
end
|
106
187
|
end
|
107
188
|
|
108
|
-
module
|
189
|
+
module Effects
|
109
190
|
class Effect
|
110
191
|
include CheekyDreams
|
111
192
|
include Math
|
@@ -138,11 +219,12 @@ module CheekyDreams
|
|
138
219
|
@r_centre, @r_amp = centre_and_amp from[0], to[0]
|
139
220
|
@g_centre, @g_amp = centre_and_amp from[1], to[1]
|
140
221
|
@b_centre, @b_amp = centre_and_amp from[2], to[2]
|
141
|
-
@
|
222
|
+
@sin_freq = 3.14 / freq.to_f
|
223
|
+
@count = (1.57 / @sin_freq).floor
|
142
224
|
end
|
143
225
|
|
144
226
|
def next current_colour
|
145
|
-
x = sin(
|
227
|
+
x = sin(@sin_freq * @count)
|
146
228
|
r = x * r_amp + r_centre
|
147
229
|
g = x * g_amp + g_centre
|
148
230
|
b = x * b_amp + b_centre
|
@@ -151,7 +233,7 @@ module CheekyDreams
|
|
151
233
|
# [v, 0, 0]
|
152
234
|
|
153
235
|
@count += 1
|
154
|
-
[r, g, b]
|
236
|
+
[r.floor, g.floor, b.floor]
|
155
237
|
end
|
156
238
|
|
157
239
|
private
|
@@ -166,6 +248,21 @@ module CheekyDreams
|
|
166
248
|
end
|
167
249
|
end
|
168
250
|
|
251
|
+
class Crazy < Effect
|
252
|
+
def initialize freq, new_effect_freq
|
253
|
+
super freq
|
254
|
+
@new_effect_freq = new_effect_freq
|
255
|
+
@count, @effect = 0, nil
|
256
|
+
end
|
257
|
+
|
258
|
+
def next current_colour
|
259
|
+
if @count % @new_effect_freq == 0
|
260
|
+
@effect = FadeTo.new([rand(255), rand(255), rand(255)], @new_effect_freq, freq)
|
261
|
+
end
|
262
|
+
@count += 1
|
263
|
+
@effect.next current_colour
|
264
|
+
end
|
265
|
+
end
|
169
266
|
|
170
267
|
class Func < Effect
|
171
268
|
def initialize freq, &block
|
@@ -174,14 +271,14 @@ module CheekyDreams
|
|
174
271
|
end
|
175
272
|
|
176
273
|
def next current_colour = nil
|
177
|
-
|
274
|
+
rgb(@block.yield(current_colour))
|
178
275
|
end
|
179
276
|
end
|
180
277
|
|
181
278
|
class Solid < Effect
|
182
279
|
def initialize colour
|
183
|
-
super 1
|
184
|
-
@rgb =
|
280
|
+
super 0.1
|
281
|
+
@rgb = rgb(colour)
|
185
282
|
end
|
186
283
|
|
187
284
|
def next current_colour = nil
|
@@ -196,14 +293,14 @@ module CheekyDreams
|
|
196
293
|
end
|
197
294
|
|
198
295
|
def next current_colour = nil
|
199
|
-
|
296
|
+
rgb(@cycle.next)
|
200
297
|
end
|
201
298
|
end
|
202
299
|
|
203
300
|
class Fade < Effect
|
204
301
|
def initialize from, to, steps, freq
|
205
302
|
super freq
|
206
|
-
@rgb_from, @rgb_to =
|
303
|
+
@rgb_from, @rgb_to = rgb(from), rgb(to)
|
207
304
|
@fade = [@rgb_from]
|
208
305
|
(1..(steps-1)).each { |i| @fade << rgb_between(@rgb_from, @rgb_to, i / steps.to_f) }
|
209
306
|
@fade << @rgb_to
|
@@ -226,10 +323,7 @@ module CheekyDreams
|
|
226
323
|
end
|
227
324
|
|
228
325
|
def next current_colour
|
229
|
-
unless @fade
|
230
|
-
@fade = Fade.new(current_colour, @to, @steps, freq)
|
231
|
-
@fade.next current_colour
|
232
|
-
end
|
326
|
+
@fade = Fade.new(current_colour, @to, @steps, freq) unless @fade
|
233
327
|
@fade.next current_colour
|
234
328
|
end
|
235
329
|
end
|
@@ -238,85 +332,59 @@ end
|
|
238
332
|
|
239
333
|
class Light
|
240
334
|
|
241
|
-
include CheekyDreams
|
242
|
-
|
243
335
|
attr_accessor :freq, :auditor
|
244
336
|
|
337
|
+
include CheekyDreams
|
338
|
+
|
245
339
|
def initialize driver
|
246
|
-
@driver, @freq, @auditor = driver,
|
247
|
-
@lock = Mutex.new
|
248
|
-
@effect = nil
|
340
|
+
@driver, @freq, @auditor, @effect = driver, 50, dev_null, solid(:off)
|
341
|
+
@lock, @wake_up = Mutex.new, ConditionVariable.new
|
249
342
|
@on = false
|
250
343
|
end
|
251
344
|
|
252
|
-
def cycle colours, freq = 1
|
253
|
-
go(Effect::Cycle.new(colours, freq))
|
254
|
-
end
|
255
|
-
|
256
|
-
def solid colour
|
257
|
-
go(Effect::Solid.new(colour))
|
258
|
-
end
|
259
|
-
|
260
|
-
def fade from, to, steps = 10, freq = 1
|
261
|
-
go Effect::Fade.new from, to, steps, freq
|
262
|
-
end
|
263
|
-
|
264
|
-
def fade_to to, steps = 10, freq = 1
|
265
|
-
go Effect::FadeTo.new to, steps, freq
|
266
|
-
end
|
267
|
-
|
268
|
-
def func freq = 1, &block
|
269
|
-
go Effect::Func.new freq, &block
|
270
|
-
end
|
271
|
-
|
272
|
-
def throb freq, amplitude, centre
|
273
|
-
go Effect::Throb.new freq, amplitude, centre
|
274
|
-
end
|
275
|
-
|
276
345
|
def go effect
|
277
346
|
@lock.synchronize {
|
278
347
|
case effect
|
279
348
|
when Symbol
|
280
|
-
@effect =
|
349
|
+
@effect = solid(effect)
|
281
350
|
when Array
|
282
|
-
@effect =
|
283
|
-
when
|
351
|
+
@effect = solid(effect)
|
352
|
+
when CheekyDreams::Effects::Effect
|
284
353
|
@effect = effect
|
285
354
|
else
|
286
355
|
raise "Im sorry dave, I'm afraid I can't do that. #{effect}"
|
287
356
|
end
|
288
357
|
}
|
358
|
+
wakeup
|
289
359
|
turn_on unless @on
|
290
360
|
end
|
291
361
|
|
362
|
+
def off
|
363
|
+
@on = false
|
364
|
+
end
|
365
|
+
|
292
366
|
private
|
293
367
|
def turn_on
|
294
|
-
@on = true
|
295
|
-
Thread.new do
|
296
|
-
|
297
|
-
last_colour = nil
|
298
|
-
next_colour_time = nil
|
368
|
+
@on, current_effect = true, nil
|
369
|
+
@run_thread = Thread.new do
|
370
|
+
last_colour = COLOURS[:off]
|
299
371
|
while @on
|
372
|
+
start = Time.now
|
373
|
+
@lock.synchronize { current_effect = @effect }
|
300
374
|
begin
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
end
|
306
|
-
}
|
307
|
-
if current_effect
|
308
|
-
if Time.now > next_colour_time
|
309
|
-
new_colour = current_effect.next(last_colour)
|
310
|
-
@driver.go new_colour
|
311
|
-
last_colour = new_colour
|
312
|
-
next_colour_time = Time.now + (1 / current_effect.freq.to_f)
|
313
|
-
end
|
314
|
-
end
|
375
|
+
new_colour = current_effect.next last_colour
|
376
|
+
@driver.go new_colour
|
377
|
+
@auditor.audit :colour_change, new_colour.to_s
|
378
|
+
last_colour = new_colour
|
315
379
|
rescue => e
|
316
|
-
auditor.
|
380
|
+
auditor.audit :error, e.message
|
317
381
|
end
|
318
|
-
|
319
|
-
end
|
382
|
+
sleep_until (start + (1 / current_effect.freq.to_f))
|
383
|
+
end
|
320
384
|
end
|
321
385
|
end
|
386
|
+
|
387
|
+
def wakeup
|
388
|
+
@run_thread.run if @run_thread
|
389
|
+
end
|
322
390
|
end
|