taopaipai 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/servebox/taopaipai.png)](https://travis-ci.org/servebox/taopaipai)
|
7
|
+
[![Coverage Status](https://coveralls.io/repos/servebox/taopaipai/badge.png)](https://coveralls.io/r/servebox/taopaipai)
|
8
|
+
[![Code Climate](https://codeclimate.com/github/servebox/taopaipai.png)](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
|