taopaipai 0.1.0
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 +7 -0
- data/.gitignore +17 -0
- data/.ruby-version +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +84 -0
- data/Rakefile +11 -0
- data/lib/taopaipai.rb +12 -0
- data/lib/taopaipai/gpio.rb +36 -0
- data/lib/taopaipai/io.rb +44 -0
- data/lib/taopaipai/pin.rb +108 -0
- data/lib/taopaipai/version.rb +3 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/taopaipai/gpio_spec.rb +56 -0
- data/spec/taopaipai/io_spec.rb +47 -0
- data/spec/taopaipai/pin_spec.rb +178 -0
- data/spec/taopaipai_spec.rb +12 -0
- data/taopaipai.gemspec +30 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 76f89d4892efbdd72aefc83bfd68819b30bfab61
|
4
|
+
data.tar.gz: 807a87eea219ffe3dfbe0d3b64665c752aad8c8f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a998207c3dd4cf59d99f042e704f4ae64fb3e0a03d384b660bd0684be5c2c5b15a68a188ced48cf110efd84fe109c616b947525b0ab0e88ec6817c0ce2b5fc99
|
7
|
+
data.tar.gz: 3665259d4c536930a17994913e9f3ef66c83f84baee45fa7f237852392d264df34ec39c56753b83a46700411c221bc4add5659d74c384a78459482e7f88f8b3b
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p353
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Jef Mathiot
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Taopaipai
|
2
|
+
|
3
|
+
A dead-simple, dependency-less gem to control Raspberry GPIO pins using Linux User Space. No
|
4
|
+
root-access is required as Taopaipai handles pins reservation using the filsystem.
|
5
|
+
|
6
|
+
[](https://travis-ci.org/servebox/taopaipai)
|
7
|
+
[](https://coveralls.io/r/servebox/taopaipai)
|
8
|
+
[](https://codeclimate.com/github/servebox/taopaipai)
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'taopaipai'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install taopaipai
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
GPIO pins are exposed through the `Taopaipai.gpio` method :
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require 'taopaipai'
|
30
|
+
|
31
|
+
pin = Taopaipai.gpio.pin(17, direction: :out, value: 0)
|
32
|
+
|
33
|
+
# Write 1 to the pin 17
|
34
|
+
pin.value(1)
|
35
|
+
|
36
|
+
# Read from the pin 27
|
37
|
+
Taopaipai.gpio.pin(27, direction: :in).value
|
38
|
+
# => 0
|
39
|
+
```
|
40
|
+
|
41
|
+
Notice that Taopaipai memoizes the pin states so that it never writes again to a pin unless its
|
42
|
+
value or direction changed.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
# Writes for the first time
|
46
|
+
pin = Taopaipai.gpio.pin(17, direction: :out, value: 1)
|
47
|
+
|
48
|
+
# Does not write anything
|
49
|
+
1000.times do
|
50
|
+
pin.value(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Back to 0 !
|
54
|
+
pin(17).value(0)
|
55
|
+
|
56
|
+
# Change the pin's direction and read its value
|
57
|
+
pin.direction(:in).value
|
58
|
+
```
|
59
|
+
|
60
|
+
To free pins so that other modules may use them :
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
Taopaipai.gpio.release
|
64
|
+
```
|
65
|
+
|
66
|
+
## Other useful projects
|
67
|
+
|
68
|
+
Taopaipai was meant to be the simplest approach to control GPIO using ruby code, without the need
|
69
|
+
for native extensions or FFI. If you need more powerful control over Raspberry Pi IO, you may have
|
70
|
+
a look at these useful projects:
|
71
|
+
|
72
|
+
* [WiringPi](https://github.com/WiringPi/WiringPi) (C/C++): Arduino wiring-like WiringPi
|
73
|
+
Library for the Raspberry Pi
|
74
|
+
* [WiringPi-Ruby](https://github.com/WiringPi/WiringPi-Ruby): Ruby wrapper around the WiringPi
|
75
|
+
library
|
76
|
+
* [PiPiper](https://github.com/jwhitehorn/pi_piper): Event driven Raspberry Pi GPIO programming in Ruby
|
77
|
+
|
78
|
+
## Contributing
|
79
|
+
|
80
|
+
1. Fork it ( http://github.com/servebox/taopaipai/fork )
|
81
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
82
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
83
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
84
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/taopaipai.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Taopaipai
|
2
|
+
class GPIO
|
3
|
+
|
4
|
+
BASE_PATH = '/sys/class/gpio'
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@io = IO.new(BASE_PATH)
|
8
|
+
@registry = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def pin(number, options={})
|
12
|
+
pin = @registry[pin_key(number)]
|
13
|
+
if pin
|
14
|
+
[:direction, :value].each do |option|
|
15
|
+
pin.send option, options[option] if options.has_key?(option)
|
16
|
+
end
|
17
|
+
pin
|
18
|
+
else
|
19
|
+
@registry[pin_key(number)] = Pin.new(@io, options.merge(number: number)).apply!
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def release
|
24
|
+
@registry.values.each do |pin|
|
25
|
+
pin.unexport
|
26
|
+
end
|
27
|
+
@registry = {}
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def pin_key(number)
|
33
|
+
"gpio#{number}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/taopaipai/io.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module Taopaipai
|
2
|
+
class IO
|
3
|
+
def initialize(base_path)
|
4
|
+
@base_path = base_path
|
5
|
+
end
|
6
|
+
|
7
|
+
def export(pin)
|
8
|
+
write_to_file('export', pin.to_s)
|
9
|
+
end
|
10
|
+
|
11
|
+
def unexport(pin)
|
12
|
+
write_to_file('unexport', pin.to_s)
|
13
|
+
end
|
14
|
+
|
15
|
+
def direction(pin, direction)
|
16
|
+
write_to_file("gpio#{pin}/direction", direction)
|
17
|
+
end
|
18
|
+
|
19
|
+
def read(pin)
|
20
|
+
File.open(relative("gpio#{pin}/value"), 'r'){|f| f.read }
|
21
|
+
end
|
22
|
+
|
23
|
+
def write(pin, value)
|
24
|
+
write_to_file("gpio#{pin}/value", value)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def write_to_file(path, content, last_attempt = false)
|
29
|
+
begin
|
30
|
+
File.open(relative(path), 'w'){|f| f.write(content) }
|
31
|
+
rescue => e
|
32
|
+
unless last_attempt
|
33
|
+
write_to_file(path, content, true)
|
34
|
+
else
|
35
|
+
raise e
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def relative(path)
|
41
|
+
"#{@base_path}/#{path}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Taopaipai
|
2
|
+
class Pin
|
3
|
+
|
4
|
+
def initialize(io, options={})
|
5
|
+
@io = io
|
6
|
+
@state = PinState.new(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply!
|
10
|
+
export.apply_direction.apply_value
|
11
|
+
end
|
12
|
+
|
13
|
+
def direction(direction)
|
14
|
+
@state.changing :direction, direction do
|
15
|
+
apply_direction
|
16
|
+
end
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
20
|
+
def value(value = nil)
|
21
|
+
if @state.out?
|
22
|
+
@state.changing :value, value do
|
23
|
+
apply_value
|
24
|
+
end
|
25
|
+
self
|
26
|
+
else
|
27
|
+
@state.value = @io.read(@state.number)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def unexport
|
32
|
+
@io.unexport(@state.number) if @state.unexport!
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def export
|
37
|
+
@io.export(@state.number) if @state.export!
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def apply_direction
|
44
|
+
@io.direction(@state.number, @state.direction)
|
45
|
+
self
|
46
|
+
end
|
47
|
+
|
48
|
+
def apply_value
|
49
|
+
if @state.out? && @state.value
|
50
|
+
@io.write(@state.number, @state.value)
|
51
|
+
end
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
class PinState
|
58
|
+
attr_reader :number, :direction, :value
|
59
|
+
|
60
|
+
def initialize(options={})
|
61
|
+
@number = options[:number]
|
62
|
+
self.direction = options[:direction]
|
63
|
+
self.value = options[:value]
|
64
|
+
end
|
65
|
+
|
66
|
+
def changing(attribute, update)
|
67
|
+
if send(attribute) != update
|
68
|
+
send "#{attribute}=", update
|
69
|
+
yield if block_given?
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def direction=(direction)
|
74
|
+
direction = direction.to_s.to_sym
|
75
|
+
unless [:in, :out].include?(direction)
|
76
|
+
raise "Invalid direction \"#{direction}\", should be one of \"in\", \"out\""
|
77
|
+
end
|
78
|
+
@direction = direction
|
79
|
+
end
|
80
|
+
|
81
|
+
def value=(v)
|
82
|
+
v = v.to_i
|
83
|
+
unless (0..1).include?(v)
|
84
|
+
raise "Invalid value \"#{v}\", should be one of 0, 1"
|
85
|
+
end
|
86
|
+
@value = v
|
87
|
+
end
|
88
|
+
|
89
|
+
def in?
|
90
|
+
direction == :in
|
91
|
+
end
|
92
|
+
|
93
|
+
def out?
|
94
|
+
direction == :out
|
95
|
+
end
|
96
|
+
|
97
|
+
def export!
|
98
|
+
return false if @exported
|
99
|
+
@exported = true
|
100
|
+
end
|
101
|
+
|
102
|
+
def unexport!
|
103
|
+
return false unless @exported
|
104
|
+
@exported = false
|
105
|
+
true
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
|
4
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
+
SimpleCov::Formatter::HTMLFormatter,
|
6
|
+
Coveralls::SimpleCov::Formatter
|
7
|
+
]
|
8
|
+
|
9
|
+
SimpleCov.start do
|
10
|
+
add_filter '/spec/'
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'taopaipai'
|
14
|
+
require 'minitest'
|
15
|
+
require 'minitest/spec'
|
16
|
+
require 'minitest/autorun'
|
17
|
+
require 'minitest/pride'
|
18
|
+
require 'minitest-implicit-subject'
|
19
|
+
require 'mocha/setup'
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Taopaipai::GPIO do
|
4
|
+
|
5
|
+
before do
|
6
|
+
Taopaipai::IO.expects(:new).with('/sys/class/gpio').returns(@io = mock)
|
7
|
+
@gpio = subject.new
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'retrieving pin' do
|
11
|
+
|
12
|
+
def expect_pin_creation
|
13
|
+
@gpio.pin(17, direction: :in).must_equal @pin
|
14
|
+
end
|
15
|
+
|
16
|
+
before do
|
17
|
+
Taopaipai::Pin.expects(:new).once.with(@io, direction: :in, number: 17).returns(@pin = mock)
|
18
|
+
@pin.expects(:apply!).returns(@pin)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'creates and applies a new pin if it does not exist' do
|
22
|
+
expect_pin_creation
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'reuse the same pin over and over again' do
|
26
|
+
expect_pin_creation
|
27
|
+
@gpio.pin(17).must_equal @pin
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'changes existing pins on the fly using the given options' do
|
31
|
+
expect_pin_creation
|
32
|
+
@pin.expects(:direction).with(:out)
|
33
|
+
@pin.expects(:value).with(1)
|
34
|
+
@gpio.pin(17, direction: :out, value: 1).must_equal @pin
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'release pins' do
|
39
|
+
pin_sequence = sequence('pins')
|
40
|
+
|
41
|
+
Taopaipai::Pin.expects(:new).in_sequence(pin_sequence).
|
42
|
+
with(@io, direction: :in, number: 17).returns(@first = mock)
|
43
|
+
@first.expects(:apply!).in_sequence(pin_sequence).returns(@first)
|
44
|
+
Taopaipai::Pin.expects(:new).in_sequence(pin_sequence).
|
45
|
+
with(@io, direction: :in, number: 27).returns(@last = mock)
|
46
|
+
@last.expects(:apply!).in_sequence(pin_sequence).returns(@last)
|
47
|
+
|
48
|
+
@first.expects(:unexport).in_sequence(pin_sequence)
|
49
|
+
@last.expects(:unexport).in_sequence(pin_sequence)
|
50
|
+
|
51
|
+
@gpio.pin(17, direction: :in)
|
52
|
+
@gpio.pin(27, direction: :in)
|
53
|
+
@gpio.release.must_equal @gpio
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe Taopaipai::IO do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@base_path = 'tmp/sys/class/gpio'
|
8
|
+
FileUtils.rm_f @base_path
|
9
|
+
FileUtils.mkdir_p "#{@base_path}/gpio17"
|
10
|
+
FileUtils.touch "#{@base_path}/gpio17/direction"
|
11
|
+
FileUtils.touch "#{@base_path}/gpio17/value"
|
12
|
+
end
|
13
|
+
|
14
|
+
def expects_content(path, content)
|
15
|
+
File.open(path, 'r'){|file| file.read}.must_equal content
|
16
|
+
end
|
17
|
+
|
18
|
+
def io
|
19
|
+
subject.new(@base_path)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'exports pin' do
|
23
|
+
io.export(17)
|
24
|
+
expects_content "#{@base_path}/export", "17"
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'unexports pin' do
|
28
|
+
io.unexport(17)
|
29
|
+
expects_content "#{@base_path}/unexport", "17"
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'changes pin direction' do
|
33
|
+
io.direction(17, :in)
|
34
|
+
expects_content "#{@base_path}/gpio17/direction", "in"
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'reads pin value' do
|
38
|
+
File.open("#{@base_path}/gpio17/value", 'w'){|file| file.write "1" }
|
39
|
+
io.read(17).must_equal "1"
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'reads pin value' do
|
43
|
+
io.write(17, "0")
|
44
|
+
expects_content "#{@base_path}/gpio17/value", "0"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Taopaipai::Pin do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@io = mock()
|
7
|
+
@pin = subject.new(@io, number: 17, direction: :out, value: 1)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'exports the pin then applies the direction and value' do
|
11
|
+
io_sequence = sequence('io')
|
12
|
+
@io.expects(:export).with(17).in_sequence(io_sequence)
|
13
|
+
@io.expects(:direction).with(17, :out).in_sequence(io_sequence)
|
14
|
+
@io.expects(:write).with(17, 1).in_sequence(io_sequence)
|
15
|
+
@pin.apply!.must_equal @pin
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'on applying direction' do
|
19
|
+
|
20
|
+
it 'writes to the io' do
|
21
|
+
@io.expects(:direction).with(17, :in)
|
22
|
+
@pin.direction(:in).must_equal @pin
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'does not do anything if direction stays the same' do
|
26
|
+
@io.expects(:direction).never
|
27
|
+
@pin.direction(:out).must_equal @pin
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'on applying value' do
|
33
|
+
|
34
|
+
it 'writes to the io' do
|
35
|
+
@io.expects(:write).with(17, 0)
|
36
|
+
@pin.value(0).must_equal @pin
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'does not do anything if direction stays the same' do
|
40
|
+
@io.expects(:value).never
|
41
|
+
@pin.value(1).must_equal @pin
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'reads the value' do
|
47
|
+
@io.expects(:direction).with(17, :in)
|
48
|
+
@io.expects(:read).returns 0
|
49
|
+
@pin.direction(:in)
|
50
|
+
@pin.value.must_equal 0
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'exporting pin' do
|
54
|
+
|
55
|
+
it 'exports the pin only once' do
|
56
|
+
@io.expects(:export).with(17)
|
57
|
+
2.times do @pin.export.must_equal @pin end
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'does not unexport the pin if not exported' do
|
61
|
+
@io.expects(:unexport).never
|
62
|
+
@pin.unexport.must_equal @pin
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'unexports the pin if exported' do
|
66
|
+
export = sequence('export')
|
67
|
+
@io.expects(:export).in_sequence(export).with(17)
|
68
|
+
@io.expects(:unexport).in_sequence(export).with(17)
|
69
|
+
2.times do @pin.export.must_equal @pin end
|
70
|
+
2.times do @pin.unexport.must_equal @pin end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
describe Taopaipai::PinState do
|
77
|
+
|
78
|
+
describe 'assigning direction' do
|
79
|
+
|
80
|
+
before do
|
81
|
+
@state = subject.new(number: 17, direction: :out)
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'raises and error if direction is invalid' do
|
85
|
+
[nil, :none, "none"].each do |dir|
|
86
|
+
err = ->{ @state.direction = dir }.must_raise RuntimeError
|
87
|
+
err.message.must_match /Invalid direction "#{dir}"/
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'assigns the direction' do
|
92
|
+
@state.direction = :in
|
93
|
+
@state.direction.must_equal :in
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'assigning value' do
|
99
|
+
|
100
|
+
before do
|
101
|
+
@state = subject.new(number: 17, direction: :out)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'assigns the value' do
|
105
|
+
@state.value = 1
|
106
|
+
@state.value.must_equal 1
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'raises an error if value is invalid' do
|
110
|
+
[-1, 2].each do |v|
|
111
|
+
err = ->{@state.value = v}.must_raise RuntimeError
|
112
|
+
err.message.must_match /Invalid value "#{v}"/
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'assigns pin number, direction and value on initialization' do
|
119
|
+
subject.new(number: 17, direction: :out).number.must_equal 17
|
120
|
+
subject.new(number: 17, direction: :out).direction.must_equal :out
|
121
|
+
subject.new(number: 17, direction: :in).direction.must_equal :in
|
122
|
+
subject.new(number: 17, direction: :out).value.must_equal 0
|
123
|
+
subject.new(number: 17, direction: :out, value: 1).value.must_equal 1
|
124
|
+
end
|
125
|
+
|
126
|
+
describe 'on checking direction' do
|
127
|
+
|
128
|
+
before do
|
129
|
+
@state = subject.new(number: 17, direction: :out)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'indicates an out pin' do
|
133
|
+
@state.in?.must_equal false
|
134
|
+
@state.out?.must_equal true
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'indicates an in pin' do
|
138
|
+
@state.direction = :in
|
139
|
+
@state.in?.must_equal true
|
140
|
+
@state.out?.must_equal false
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'marks the pin exported once' do
|
146
|
+
state = subject.new(number: 17, direction: :out)
|
147
|
+
state.export!.must_equal true
|
148
|
+
state.export!.must_equal false
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'marks the pin unexported' do
|
152
|
+
state = subject.new(number: 17, direction: :out)
|
153
|
+
state.export!
|
154
|
+
state.unexport!.must_equal true
|
155
|
+
state.unexport!.must_equal false
|
156
|
+
end
|
157
|
+
|
158
|
+
describe 'on changing attribute' do
|
159
|
+
|
160
|
+
before do
|
161
|
+
@state = subject.new(number: 17, direction: :out)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'yields given block if value changed' do
|
165
|
+
changed = false
|
166
|
+
@state.changing :direction, :in do
|
167
|
+
changed = true
|
168
|
+
end
|
169
|
+
changed.must_equal true
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'assigns the value to the attribute' do
|
173
|
+
@state.changing :direction, :in
|
174
|
+
@state.direction.must_equal :in
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
data/taopaipai.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'taopaipai/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "taopaipai"
|
8
|
+
spec.version = Taopaipai::VERSION
|
9
|
+
spec.authors = ["Jef Mathiot"]
|
10
|
+
spec.email = ["jeff.mathiot@gmail.com"]
|
11
|
+
spec.summary = %q{Access Raspberry Pi GPIO from Linux User Space.}
|
12
|
+
spec.description = %q{Access Raspberry Pi PGIO from Linux User Space.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "mocha"
|
24
|
+
spec.add_development_dependency "coveralls"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0.7"
|
26
|
+
spec.add_development_dependency "minitest-implicit-subject", "~> 1.4.0"
|
27
|
+
spec.add_development_dependency "rb-readline", "~> 0.5.0"
|
28
|
+
spec.add_development_dependency "guard-minitest", "~> 2.1.3"
|
29
|
+
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: taopaipai
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jef Mathiot
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mocha
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: coveralls
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 5.0.7
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 5.0.7
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest-implicit-subject
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.4.0
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.4.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rb-readline
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ~>
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.5.0
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.5.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: guard-minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 2.1.3
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ~>
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 2.1.3
|
125
|
+
description: Access Raspberry Pi PGIO from Linux User Space.
|
126
|
+
email:
|
127
|
+
- jeff.mathiot@gmail.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- .gitignore
|
133
|
+
- .ruby-version
|
134
|
+
- .travis.yml
|
135
|
+
- Gemfile
|
136
|
+
- Guardfile
|
137
|
+
- LICENSE.txt
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- lib/taopaipai.rb
|
141
|
+
- lib/taopaipai/gpio.rb
|
142
|
+
- lib/taopaipai/io.rb
|
143
|
+
- lib/taopaipai/pin.rb
|
144
|
+
- lib/taopaipai/version.rb
|
145
|
+
- spec/spec_helper.rb
|
146
|
+
- spec/taopaipai/gpio_spec.rb
|
147
|
+
- spec/taopaipai/io_spec.rb
|
148
|
+
- spec/taopaipai/pin_spec.rb
|
149
|
+
- spec/taopaipai_spec.rb
|
150
|
+
- taopaipai.gemspec
|
151
|
+
homepage: ''
|
152
|
+
licenses:
|
153
|
+
- MIT
|
154
|
+
metadata: {}
|
155
|
+
post_install_message:
|
156
|
+
rdoc_options: []
|
157
|
+
require_paths:
|
158
|
+
- lib
|
159
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - '>='
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
requirements: []
|
170
|
+
rubyforge_project:
|
171
|
+
rubygems_version: 2.0.14
|
172
|
+
signing_key:
|
173
|
+
specification_version: 4
|
174
|
+
summary: Access Raspberry Pi GPIO from Linux User Space.
|
175
|
+
test_files:
|
176
|
+
- spec/spec_helper.rb
|
177
|
+
- spec/taopaipai/gpio_spec.rb
|
178
|
+
- spec/taopaipai/io_spec.rb
|
179
|
+
- spec/taopaipai/pin_spec.rb
|
180
|
+
- spec/taopaipai_spec.rb
|