usblamp 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +24 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE.md +674 -0
- data/MANIFEST +24 -0
- data/README.md +60 -0
- data/Rakefile +10 -0
- data/bin/usblamp +5 -0
- data/lib/usblamp/cli/blink.rb +20 -0
- data/lib/usblamp/cli/fadein.rb +20 -0
- data/lib/usblamp/cli.rb +57 -0
- data/lib/usblamp/color.rb +67 -0
- data/lib/usblamp/controller.rb +110 -0
- data/lib/usblamp/version.rb +5 -0
- data/lib/usblamp.rb +15 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/usblamp/cli_spec.rb +44 -0
- data/spec/usblamp/color_spec.rb +90 -0
- data/spec/usblamp/controller_spec.rb +152 -0
- data/task/manifest.rake +9 -0
- data/task/rspec.rake +6 -0
- data/task/rubocop.rake +5 -0
- data/usblamp.gemspec +27 -0
- metadata +153 -0
data/MANIFEST
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
.gitignore
|
2
|
+
.rubocop.yml
|
3
|
+
.travis.yml
|
4
|
+
Gemfile
|
5
|
+
LICENSE.md
|
6
|
+
MANIFEST
|
7
|
+
README.md
|
8
|
+
Rakefile
|
9
|
+
bin/usblamp
|
10
|
+
lib/usblamp.rb
|
11
|
+
lib/usblamp/cli.rb
|
12
|
+
lib/usblamp/cli/blink.rb
|
13
|
+
lib/usblamp/cli/fadein.rb
|
14
|
+
lib/usblamp/color.rb
|
15
|
+
lib/usblamp/controller.rb
|
16
|
+
lib/usblamp/version.rb
|
17
|
+
spec/spec_helper.rb
|
18
|
+
spec/usblamp/cli_spec.rb
|
19
|
+
spec/usblamp/color_spec.rb
|
20
|
+
spec/usblamp/controller_spec.rb
|
21
|
+
task/manifest.rake
|
22
|
+
task/rspec.rake
|
23
|
+
task/rubocop.rake
|
24
|
+
usblamp.gemspec
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#WebMail Notifier with Ruby (Dream Cheeky)
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/PierreRambaud/usblamp.png?branch=master)](https://travis-ci.org/PierreRambaud/usblamp)
|
4
|
+
|
5
|
+
Ruby script to power the Dreamcheeky USB webmail notifier gadget. <http://www.dreamcheeky.com/webmail-notifier>
|
6
|
+
|
7
|
+
##Requirements
|
8
|
+
|
9
|
+
- Ruby 1.9.2 or newer
|
10
|
+
|
11
|
+
##Installation
|
12
|
+
|
13
|
+
Assuming RubyGems isn't down you can install the Gem as following:
|
14
|
+
|
15
|
+
```
|
16
|
+
$ gem install usblamp
|
17
|
+
```
|
18
|
+
|
19
|
+
##Usage
|
20
|
+
|
21
|
+
```
|
22
|
+
Usage: usblamp [COMMAND] [OPTIONS]
|
23
|
+
|
24
|
+
Options:
|
25
|
+
|
26
|
+
-v, --version Shows the current version
|
27
|
+
-r, --red Red
|
28
|
+
-g, --green Green
|
29
|
+
-b, --blue Blue
|
30
|
+
-c, --color Color
|
31
|
+
-h, --help Display this help message.
|
32
|
+
|
33
|
+
Available commands:
|
34
|
+
|
35
|
+
fadein Fade in effect
|
36
|
+
blink Blink effect
|
37
|
+
```
|
38
|
+
|
39
|
+
##Troubleshooting
|
40
|
+
|
41
|
+
Should be run as root unless the necessary udev rules are set.
|
42
|
+
Create the file `/etc/udev/rules.d/42-usblamp.rules`
|
43
|
+
And add this content by replacing `got` by your username:
|
44
|
+
```
|
45
|
+
SUBSYSTEM !="usb_device", ACTION !="add", GOTO="datalogger_rules_end"
|
46
|
+
SYSFS{idVendor} =="1d34", SYSFS{idProduct} =="0004", SYMLINK+="datalogger"
|
47
|
+
MODE="0666", OWNER="got", GROUP="root"
|
48
|
+
LABEL="datalogger_rules_end"
|
49
|
+
```
|
50
|
+
|
51
|
+
## Running tests
|
52
|
+
|
53
|
+
Install dependencies:
|
54
|
+
|
55
|
+
`$ bundle install`
|
56
|
+
|
57
|
+
To run tests:
|
58
|
+
`$ bundle exec rake`
|
59
|
+
|
60
|
+
|
data/Rakefile
ADDED
data/bin/usblamp
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
Usblamp::CLI.slop.command 'blink' do
|
3
|
+
banner 'Usage: usblamp blink [OPTIONS]'
|
4
|
+
description 'Blink effect'
|
5
|
+
separator "\nOptions:\n"
|
6
|
+
|
7
|
+
Usblamp::CLI.slop.options.each do |c|
|
8
|
+
next if c.long == 'version'
|
9
|
+
options << c
|
10
|
+
end
|
11
|
+
|
12
|
+
on :t=, :times=, 'Times', as: Integer, default: 2
|
13
|
+
|
14
|
+
run do |opts, _args|
|
15
|
+
lamp = Usblamp::Controller.new
|
16
|
+
lamp.open
|
17
|
+
lamp.switch_off
|
18
|
+
lamp.blink(opts[:t], lamp.parse(opts))
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
Usblamp::CLI.slop.command 'fadein' do
|
3
|
+
banner 'Usage: usblamp fadein [OPTIONS]'
|
4
|
+
description 'Fade in effect'
|
5
|
+
separator "\nOptions:\n"
|
6
|
+
|
7
|
+
Usblamp::CLI.slop.options.each do |c|
|
8
|
+
next if c.long == 'version'
|
9
|
+
options << c
|
10
|
+
end
|
11
|
+
|
12
|
+
on :d=, :delay=, 'Delay', as: Integer, default: 2
|
13
|
+
|
14
|
+
run do |opts, _args|
|
15
|
+
lamp = Usblamp::Controller.new
|
16
|
+
lamp.open
|
17
|
+
lamp.switch_off
|
18
|
+
lamp.fade_in(opts[:d], lamp.parse(opts))
|
19
|
+
end
|
20
|
+
end
|
data/lib/usblamp/cli.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module Usblamp
|
3
|
+
# CLI mode
|
4
|
+
module CLI
|
5
|
+
##
|
6
|
+
# Hash containing the default Slop options.
|
7
|
+
#
|
8
|
+
# @return [Hash]
|
9
|
+
#
|
10
|
+
SLOP_OPTIONS = {
|
11
|
+
strict: true,
|
12
|
+
help: true,
|
13
|
+
banner: 'Usage: usblamp [COMMAND] [OPTIONS]'
|
14
|
+
}
|
15
|
+
|
16
|
+
##
|
17
|
+
# @return [Slop]
|
18
|
+
#
|
19
|
+
def self.slop
|
20
|
+
@slop ||= default_slop
|
21
|
+
end
|
22
|
+
|
23
|
+
##
|
24
|
+
# @return [Slop]
|
25
|
+
#
|
26
|
+
def self.default_slop
|
27
|
+
Slop.new(SLOP_OPTIONS.dup) do
|
28
|
+
separator "\nOptions:\n"
|
29
|
+
|
30
|
+
on :v, :version, 'Shows the current version' do
|
31
|
+
puts CLI.version_information
|
32
|
+
end
|
33
|
+
|
34
|
+
on :r=, :red=, 'Red', as: Integer
|
35
|
+
on :g=, :green=, 'Green', as: Integer
|
36
|
+
on :b=, :blue=, 'Blue', as: Integer
|
37
|
+
on :c=, :color=, 'Color'
|
38
|
+
|
39
|
+
run do |opts, _args|
|
40
|
+
lamp = Controller.new
|
41
|
+
lamp.open
|
42
|
+
lamp.switch_off
|
43
|
+
lamp.send_color(lamp.parse(opts))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Returns a String containing some platform/version related information.
|
50
|
+
#
|
51
|
+
# @return [String]
|
52
|
+
#
|
53
|
+
def self.version_information
|
54
|
+
"usblamp v#{VERSION} on #{RUBY_DESCRIPTION}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Usblamp module
|
3
|
+
module Usblamp
|
4
|
+
# Color class
|
5
|
+
class Color
|
6
|
+
attr_accessor :red, :green, :blue
|
7
|
+
MAX_VALUE = 0x40
|
8
|
+
|
9
|
+
def initialize(red = nil, green = nil, blue = nil)
|
10
|
+
set(red, green, blue)
|
11
|
+
end
|
12
|
+
|
13
|
+
def set(red, green = nil, blue = nil)
|
14
|
+
if red.is_a?(String) && green.nil? && blue.nil?
|
15
|
+
if ['#', '_'].include?(red[0])
|
16
|
+
return define_from_hex(red)
|
17
|
+
else
|
18
|
+
return define_from_string(red)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
red = 0 if red.nil?
|
23
|
+
green = 0 if green.nil?
|
24
|
+
blue = 0 if blue.nil?
|
25
|
+
|
26
|
+
@red = define_value(red)
|
27
|
+
@green = define_value(green)
|
28
|
+
@blue = define_value(blue)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def define_value(integer)
|
34
|
+
[[0, integer.to_i].max, MAX_VALUE].min
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_from_hex(string)
|
38
|
+
string = string.gsub(/[#_]/, '')
|
39
|
+
fail ArgumentError, 'Wrong length for hexadecimal string' unless
|
40
|
+
[3, 6].include?(string.length.to_i)
|
41
|
+
|
42
|
+
return set(string[0..1].to_i(16),
|
43
|
+
string[2..3].to_i(16),
|
44
|
+
string[4..5].to_i(16)
|
45
|
+
) if string.length == 6
|
46
|
+
|
47
|
+
set((string[0] * 2).to_i(16),
|
48
|
+
(string[1] * 2).to_i(16),
|
49
|
+
(string[2] * 2).to_i(16)
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def define_from_string(string)
|
54
|
+
return set(MAX_VALUE, 0, 0) if string == 'red'
|
55
|
+
return set(0, MAX_VALUE, 0) if string == 'green'
|
56
|
+
return set(0, 0, MAX_VALUE) if string == 'blue'
|
57
|
+
return set(MAX_VALUE, MAX_VALUE, MAX_VALUE) if string == 'white'
|
58
|
+
return set(MAX_VALUE, 0, MAX_VALUE) if string == 'magenta'
|
59
|
+
return set(0, MAX_VALUE, MAX_VALUE) if string == 'cyan'
|
60
|
+
return set(MAX_VALUE, MAX_VALUE, 0) if string == 'yellow'
|
61
|
+
return set(MAX_VALUE / 2, MAX_VALUE / 2, MAX_VALUE / 2) if
|
62
|
+
string == 'purple'
|
63
|
+
|
64
|
+
set(0, 0, 0)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Usblamp module
|
3
|
+
module Usblamp
|
4
|
+
# Controller class
|
5
|
+
class Controller
|
6
|
+
attr_accessor :device, :color
|
7
|
+
|
8
|
+
VENDOR_ID = 0x1d34
|
9
|
+
PRODUCT_ID = 0x0004
|
10
|
+
INIT_PACKET1 = [0x1F, 0x01, 0x29, 0x00, 0xB8, 0x54, 0x2C, 0x03]
|
11
|
+
INIT_PACKET2 = [0x00, 0x01, 0x29, 0x00, 0xB8, 0x54, 0x2C, 0x04]
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@device = nil
|
15
|
+
@color = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def open
|
19
|
+
usb = LIBUSB::Context.new
|
20
|
+
device = usb.devices(idVendor: VENDOR_ID, idProduct: PRODUCT_ID).first
|
21
|
+
|
22
|
+
fail 'Could no find a supported device.' if device.nil?
|
23
|
+
@device = device.open
|
24
|
+
@device.detach_kernel_driver(0) if @device.kernel_driver_active?(0)
|
25
|
+
@device.claim_interface(0)
|
26
|
+
send(INIT_PACKET1)
|
27
|
+
send(INIT_PACKET2)
|
28
|
+
end
|
29
|
+
|
30
|
+
def send(data)
|
31
|
+
return true if @device
|
32
|
+
.control_transfer(
|
33
|
+
bmRequestType: LIBUSB::REQUEST_TYPE_CLASS |
|
34
|
+
LIBUSB::RECIPIENT_INTERFACE,
|
35
|
+
bRequest: LIBUSB::REQUEST_SET_CONFIGURATION,
|
36
|
+
wValue: 0x81,
|
37
|
+
wIndex: LIBUSB::ENDPOINT_OUT,
|
38
|
+
dataOut: data.map(&:chr).reduce(:+),
|
39
|
+
timeout: 10) == 8
|
40
|
+
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def send_color(color)
|
45
|
+
fail TypeError, 'Parameter must be an instance of Color' unless
|
46
|
+
color.is_a?(Color)
|
47
|
+
|
48
|
+
@color = color
|
49
|
+
data = [color.red,
|
50
|
+
color.green,
|
51
|
+
color.blue,
|
52
|
+
0x00,
|
53
|
+
0x00,
|
54
|
+
0x00,
|
55
|
+
0x00,
|
56
|
+
0x05]
|
57
|
+
send(data)
|
58
|
+
end
|
59
|
+
|
60
|
+
def switch_off
|
61
|
+
send_color(Color.new('black'))
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(args)
|
65
|
+
color = Color.new(args[:c]) unless args[:c].nil?
|
66
|
+
color = Color.new(args[:r], args[:g], args[:b]) if args[:c].nil?
|
67
|
+
color
|
68
|
+
end
|
69
|
+
|
70
|
+
def fade_in(delay, new_color)
|
71
|
+
delay = delay.to_i
|
72
|
+
color = Color.new
|
73
|
+
max_value = [new_color.red, new_color.green, new_color.blue].max
|
74
|
+
(0..max_value).each do |i|
|
75
|
+
sleep((delay.to_f * 1000.to_f / max_value.to_f + 1.to_f) / 1000.to_f)
|
76
|
+
color.red = transition(i,
|
77
|
+
@color.red,
|
78
|
+
new_color.red,
|
79
|
+
max_value)
|
80
|
+
color.green = transition(i,
|
81
|
+
@color.green,
|
82
|
+
new_color.green,
|
83
|
+
max_value)
|
84
|
+
color.blue = transition(i,
|
85
|
+
@color.blue,
|
86
|
+
new_color.blue,
|
87
|
+
max_value)
|
88
|
+
send_color(color)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def blink(times, new_color)
|
93
|
+
(1..times).each do
|
94
|
+
send_color(new_color)
|
95
|
+
sleep 0.5
|
96
|
+
switch_off
|
97
|
+
sleep 0.5
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def transition(index, start_point, end_point, maximum)
|
104
|
+
(((start_point.to_f + (end_point.to_f - start_point.to_f)) *
|
105
|
+
(index.to_f + 1.to_f)
|
106
|
+
) / maximum.to_f
|
107
|
+
).to_i
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/lib/usblamp.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'slop'
|
3
|
+
require 'libusb'
|
4
|
+
|
5
|
+
unless $LOAD_PATH.include?(File.expand_path('../', __FILE__))
|
6
|
+
$LOAD_PATH.unshift(File.expand_path('../', __FILE__))
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'usblamp/color'
|
10
|
+
require 'usblamp/controller'
|
11
|
+
require 'usblamp/version'
|
12
|
+
|
13
|
+
require 'usblamp/cli'
|
14
|
+
require 'usblamp/cli/fadein'
|
15
|
+
require 'usblamp/cli/blink'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'usblamp/cli'
|
4
|
+
require 'slop'
|
5
|
+
|
6
|
+
# Usblamp tests
|
7
|
+
module Usblamp
|
8
|
+
# CLI tests
|
9
|
+
module CLI
|
10
|
+
describe 'CLI' do
|
11
|
+
it 'should return options' do
|
12
|
+
options = CLI.slop
|
13
|
+
expect(options).to be_a(::Slop)
|
14
|
+
expect(options.config[:strict]).to be_truthy
|
15
|
+
expect(options.config[:banner])
|
16
|
+
.to eq('Usage: usblamp [COMMAND] [OPTIONS]')
|
17
|
+
expect(options.to_s)
|
18
|
+
.to match(/-v, --version(\s+)Shows the current version/)
|
19
|
+
expect(options.to_s)
|
20
|
+
.to match(/-h, --help(\s+)Display this help message./)
|
21
|
+
|
22
|
+
version = options.fetch_option(:v)
|
23
|
+
expect(version.short).to eq('v')
|
24
|
+
expect(version.long).to eq('version')
|
25
|
+
expect { version.call }.to output(/usblamp v.* on ruby/).to_stdout
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should retrieve version information' do
|
29
|
+
expect(CLI.version_information).to eq(
|
30
|
+
"usblamp v#{VERSION} on #{RUBY_DESCRIPTION}"
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should change color' do
|
35
|
+
controller = double(open: true,
|
36
|
+
switch_off: true,
|
37
|
+
parse: { c: 'blue' },
|
38
|
+
send_color: true)
|
39
|
+
allow(Controller).to receive(:new).and_return(controller)
|
40
|
+
expect(CLI.slop.parse(c: 'blue')).to eq(c: 'blue')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'usblamp/color'
|
4
|
+
|
5
|
+
# Usblamp module
|
6
|
+
module Usblamp
|
7
|
+
describe 'Color' do
|
8
|
+
before(:each) do
|
9
|
+
@color = Color.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should test initialize with color' do
|
13
|
+
color = Color.new(10, 11, 12)
|
14
|
+
expect(color.red).to eq(10)
|
15
|
+
expect(color.green).to eq(11)
|
16
|
+
expect(color.blue).to eq(12)
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should test const' do
|
20
|
+
expect(Color::MAX_VALUE).to eq(0x40)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should set' do
|
24
|
+
@color.set(10, 11, 12)
|
25
|
+
expect(@color.red).to eq(10)
|
26
|
+
expect(@color.green).to eq(11)
|
27
|
+
expect(@color.blue).to eq(12)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should set from hex' do
|
31
|
+
@color.set('#112233')
|
32
|
+
expect(@color.red).to eq(17)
|
33
|
+
expect(@color.green).to eq(34)
|
34
|
+
expect(@color.blue).to eq(51)
|
35
|
+
@color.set('_112233')
|
36
|
+
expect(@color.red).to eq(17)
|
37
|
+
expect(@color.green).to eq(34)
|
38
|
+
expect(@color.blue).to eq(51)
|
39
|
+
@color.set('#123')
|
40
|
+
expect(@color.red).to eq(17)
|
41
|
+
expect(@color.green).to eq(34)
|
42
|
+
expect(@color.blue).to eq(51)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should set from string' do
|
46
|
+
@color.set('red')
|
47
|
+
expect(@color.red).to eq(64)
|
48
|
+
expect(@color.green).to eq(0)
|
49
|
+
expect(@color.blue).to eq(0)
|
50
|
+
@color.set('green')
|
51
|
+
expect(@color.red).to eq(0)
|
52
|
+
expect(@color.green).to eq(64)
|
53
|
+
expect(@color.blue).to eq(0)
|
54
|
+
@color.set('blue')
|
55
|
+
expect(@color.red).to eq(0)
|
56
|
+
expect(@color.green).to eq(0)
|
57
|
+
expect(@color.blue).to eq(64)
|
58
|
+
@color.set('white')
|
59
|
+
expect(@color.red).to eq(64)
|
60
|
+
expect(@color.green).to eq(64)
|
61
|
+
expect(@color.blue).to eq(64)
|
62
|
+
@color.set('magenta')
|
63
|
+
expect(@color.red).to eq(64)
|
64
|
+
expect(@color.green).to eq(0)
|
65
|
+
expect(@color.blue).to eq(64)
|
66
|
+
@color.set('cyan')
|
67
|
+
expect(@color.red).to eq(0)
|
68
|
+
expect(@color.green).to eq(64)
|
69
|
+
expect(@color.blue).to eq(64)
|
70
|
+
@color.set('yellow')
|
71
|
+
expect(@color.red).to eq(64)
|
72
|
+
expect(@color.green).to eq(64)
|
73
|
+
expect(@color.blue).to eq(0)
|
74
|
+
@color.set('purple')
|
75
|
+
expect(@color.red).to eq(32)
|
76
|
+
expect(@color.green).to eq(32)
|
77
|
+
expect(@color.blue).to eq(32)
|
78
|
+
@color.set('nothing')
|
79
|
+
expect(@color.red).to eq(0)
|
80
|
+
expect(@color.green).to eq(0)
|
81
|
+
expect(@color.blue).to eq(0)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should raise error when undefined color' do
|
85
|
+
expect { @color.set('#FF') }.to raise_error ArgumentError
|
86
|
+
expect { @color.set('#FFFF') }.to raise_error ArgumentError
|
87
|
+
expect { @color.set('#FFFFF') }.to raise_error ArgumentError
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'libusb'
|
4
|
+
require 'usblamp/controller'
|
5
|
+
|
6
|
+
# Usblamp module
|
7
|
+
module Usblamp
|
8
|
+
describe 'Controller' do
|
9
|
+
before(:each) do
|
10
|
+
@controller = Controller.new
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should test init' do
|
14
|
+
expect(@controller.device).to be(nil)
|
15
|
+
expect(@controller.color).to be(nil)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should test const' do
|
19
|
+
expect(Controller::VENDOR_ID).to eq(0x1d34)
|
20
|
+
expect(Controller::PRODUCT_ID).to eq(0x0004)
|
21
|
+
expect(Controller::INIT_PACKET1)
|
22
|
+
.to eq([31, 1, 41, 0, 184, 84, 44, 3])
|
23
|
+
expect(Controller::INIT_PACKET2)
|
24
|
+
.to eq([0, 1, 41, 0, 184, 84, 44, 4])
|
25
|
+
expect(@controller.device).to eq(nil)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should raise when no supported devices found' do
|
29
|
+
device = double(devices: [])
|
30
|
+
allow(LIBUSB::Context).to receive(:new).and_return(device)
|
31
|
+
expect { @controller.open }.to raise_error(RuntimeError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should open device' do
|
35
|
+
handle = spy(open: true,
|
36
|
+
kernel_driver_active?: true,
|
37
|
+
detach_kernel_driver: true,
|
38
|
+
control_transfer: 8)
|
39
|
+
device = double(devices: [double(open: handle)])
|
40
|
+
allow(LIBUSB::Context).to receive(:new).and_return(device)
|
41
|
+
expect(@controller.open).to be_truthy
|
42
|
+
expect(handle).to have_received(:claim_interface).with(0)
|
43
|
+
expect(handle).to have_received(:control_transfer)
|
44
|
+
.with(bmRequestType: 33,
|
45
|
+
bRequest: 9,
|
46
|
+
wValue: 129,
|
47
|
+
wIndex: 0,
|
48
|
+
dataOut: [31, 1, 41, 0, 184, 84, 44, 3].map(&:chr).reduce(:+),
|
49
|
+
timeout: 10)
|
50
|
+
expect(handle).to have_received(:control_transfer)
|
51
|
+
.with(bmRequestType: 33,
|
52
|
+
bRequest: 9,
|
53
|
+
wValue: 129,
|
54
|
+
wIndex: 0,
|
55
|
+
dataOut: [0, 1, 41, 0, 184, 84, 44, 4].map(&:chr).reduce(:+),
|
56
|
+
timeout: 10)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should fail send transfer' do
|
60
|
+
device = double(control_transfer: 5)
|
61
|
+
@controller.device = device
|
62
|
+
expect(@controller.send([0])).to be_falsy
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should test send_color parameter' do
|
66
|
+
expect { @controller.send_color('fake') }
|
67
|
+
.to raise_error(TypeError, 'Parameter must be an instance of Color')
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should send color' do
|
71
|
+
device = spy(control_transfer: 8)
|
72
|
+
@controller.device = device
|
73
|
+
expect(@controller.send_color(Color.new('blue'))).to be_truthy
|
74
|
+
expect(device).to have_received(:control_transfer)
|
75
|
+
.with(bmRequestType: 33,
|
76
|
+
bRequest: 9,
|
77
|
+
wValue: 129,
|
78
|
+
wIndex: 0,
|
79
|
+
dataOut: [0, 0, 64, 0, 0, 0, 0, 5].map(&:chr).reduce(:+),
|
80
|
+
timeout: 10)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should switch off' do
|
84
|
+
device = spy(control_transfer: 8)
|
85
|
+
@controller.device = device
|
86
|
+
expect(@controller.switch_off).to be_truthy
|
87
|
+
expect(device).to have_received(:control_transfer)
|
88
|
+
.with(bmRequestType: 33,
|
89
|
+
bRequest: 9,
|
90
|
+
wValue: 129,
|
91
|
+
wIndex: 0,
|
92
|
+
dataOut: "\x00\x00\x00\x00\x00\x00\x00\x05",
|
93
|
+
timeout: 10)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'should parse args to create color' do
|
97
|
+
args = { c: 'red' }
|
98
|
+
result = @controller.parse(args)
|
99
|
+
expect(result).to be_a(Color)
|
100
|
+
expect(result.red).to eq(64)
|
101
|
+
expect(result.green).to eq(0)
|
102
|
+
expect(result.blue).to eq(0)
|
103
|
+
|
104
|
+
args = { r: 10, g: 10, b: 10 }
|
105
|
+
result = @controller.parse(args)
|
106
|
+
expect(result).to be_a(Color)
|
107
|
+
expect(result.red).to eq(10)
|
108
|
+
expect(result.green).to eq(10)
|
109
|
+
expect(result.blue).to eq(10)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should fade in' do
|
113
|
+
device = spy(control_transfer: 8)
|
114
|
+
@controller.color = Color.new('black')
|
115
|
+
@controller.device = device
|
116
|
+
allow(@controller).to receive(:sleep).and_return(true)
|
117
|
+
expect(@controller.fade_in(2, Color.new('blue'))).to be_truthy
|
118
|
+
(1..64).each do |i|
|
119
|
+
expect(device).to have_received(:control_transfer)
|
120
|
+
.with(bmRequestType: 33,
|
121
|
+
bRequest: 9,
|
122
|
+
wValue: 129,
|
123
|
+
wIndex: 0,
|
124
|
+
dataOut: [0, 0, i, 0, 0, 0, 0, 5].map(&:chr).reduce(:+),
|
125
|
+
timeout: 10)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should blink' do
|
130
|
+
device = spy(control_transfer: 8)
|
131
|
+
@controller.device = device
|
132
|
+
allow(@controller).to receive(:sleep).and_return(true)
|
133
|
+
expect(@controller.blink(2, Color.new('blue'))).to be_truthy
|
134
|
+
(1..2).each do
|
135
|
+
expect(device).to have_received(:control_transfer).twice
|
136
|
+
.with(bmRequestType: 33,
|
137
|
+
bRequest: 9,
|
138
|
+
wValue: 129,
|
139
|
+
wIndex: 0,
|
140
|
+
dataOut: [0, 0, 64, 0, 0, 0, 0, 5].map(&:chr).reduce(:+),
|
141
|
+
timeout: 10)
|
142
|
+
expect(device).to have_received(:control_transfer).twice
|
143
|
+
.with(bmRequestType: 33,
|
144
|
+
bRequest: 9,
|
145
|
+
wValue: 129,
|
146
|
+
wIndex: 0,
|
147
|
+
dataOut: [0, 0, 0, 0, 0, 0, 0, 5].map(&:chr).reduce(:+),
|
148
|
+
timeout: 10)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|