cheeky-dreams 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.5
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "cheeky-dreams"
8
- s.version = "0.0.4"
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-02"
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
- def rgb r, g, b
6
- [r, g, b].each { |c| raise "Invalid rgb value #{r}, #{g}, #{b}" if c < 0 || c > 255}
7
- [r, g, b]
8
- end
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
- COLOURS = {
24
- :off => [0, 0, 0],
25
- :red => [255, 0, 0],
26
- :green => [0, 255, 0],
27
- :blue => [0, 0, 255],
28
- :yellow => [255,255,0],
29
- :aqua => [0,255,255],
30
- :purple => [255,0,255],
31
- :grey => [192,192,192],
32
- :white => [255,255,255]
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 "Unsupported colour type #{colour}"
46
+ raise "Invalid rgb #{args}"
45
47
  end
46
48
  end
47
-
48
- def stderr_auditor
49
- Class.new do
50
- def unhandled_error e
51
- STDERR.puts e.message
52
- STDERR.puts e.backtrace.join("\n")
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.new
72
+ end
55
73
  end
56
74
 
57
- def dev_null_auditor
58
- Class.new do
59
- def unhandled_error e
60
- end
61
- end.new
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
- Class.new do
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
- Device::DreamCheeky.new(File.dirname(Dir.glob('/sys/devices/**/red').first))
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
- module Device
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 Effect
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
- @count = 1
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(freq * @count)
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
- rgb_for(@block.yield(current_colour))
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 = rgb_for(colour)
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
- rgb_for(@cycle.next)
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 = rgb_for(from), rgb_for(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, 100, dev_null_auditor
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 = Effect::Solid.new(effect)
349
+ @effect = solid(effect)
281
350
  when Array
282
- @effect = Effect::Solid.new(effect)
283
- when Effect::Effect
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
- current_effect = nil
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
- @lock.synchronize {
302
- if @effect && current_effect != @effect
303
- current_effect = @effect
304
- next_colour_time = Time.at(0)
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.unhandled_error e
380
+ auditor.audit :error, e.message
317
381
  end
318
- sleep (1 / freq.to_f)
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