pi_piper 1.3.2 → 1.9.9
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 +4 -4
- data/.gitignore +4 -0
- data/.rspec +3 -0
- data/.travis.yml +8 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +65 -0
- data/Manifest +5 -0
- data/README.md +54 -8
- data/Rakefile +24 -14
- data/examples/2_bit_counter/2_bit_counter.rb +22 -0
- data/examples/7-segment/7-segment.rb +37 -0
- data/examples/dsl_switch/dsl_switch.rb +15 -0
- data/examples/mcp3008/circuit.png +0 -0
- data/examples/mcp3008/mcp3008.rb +55 -0
- data/examples/mcp3008_spi/mcp3008_spi.rb +24 -0
- data/examples/morse_code/circuit.png +0 -0
- data/examples/morse_code/morse_code.rb +43 -0
- data/examples/simple_switch/circuit.png +0 -0
- data/examples/simple_switch/simple_switch.rb +10 -0
- data/lib/pi_piper.rb +38 -5
- data/lib/pi_piper/bcm2835.rb +85 -3
- data/lib/pi_piper/frequency.rb +19 -0
- data/lib/pi_piper/i2c.rb +51 -0
- data/lib/pi_piper/libbcm2835.so +0 -0
- data/lib/pi_piper/pin.rb +129 -38
- data/lib/pi_piper/pin_error.rb +3 -0
- data/lib/pi_piper/pin_values.rb +10 -0
- data/lib/pi_piper/platform.rb +25 -0
- data/lib/pi_piper/spi.rb +47 -43
- data/lib/pi_piper/stub_driver.rb +107 -0
- data/pi_piper.gemspec +18 -7
- data/spec/i2c_spec.rb +83 -0
- data/spec/pin_spec.rb +149 -0
- data/spec/pull_mode_spec.rb +70 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/spi_spec.rb +44 -0
- data/spec/stub_driver_spec.rb +140 -0
- metadata +107 -14
- data/lib/pi_piper/libbcm2835.img +0 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
module PiPiper
|
2
|
+
|
3
|
+
#Hardware abstraction manager. Not intended for direct use.
|
4
|
+
class Platform
|
5
|
+
@@driver = nil
|
6
|
+
|
7
|
+
#gets the current platform driver. Defaults to BCM2835.
|
8
|
+
def self.driver
|
9
|
+
unless @@driver
|
10
|
+
require 'pi_piper/bcm2835'
|
11
|
+
PiPiper::Bcm2835.init
|
12
|
+
@@driver = PiPiper::Bcm2835
|
13
|
+
at_exit do
|
14
|
+
Bcm2835.release_pins
|
15
|
+
Bcm2835.close
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@@driver
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.driver=(instance)
|
22
|
+
@@driver = instance
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/pi_piper/spi.rb
CHANGED
@@ -28,39 +28,9 @@
|
|
28
28
|
#++
|
29
29
|
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
31
|
module PiPiper
|
35
32
|
# class for SPI interfaces on the Raspberry Pi
|
36
33
|
class Spi
|
37
|
-
# 65536 = 256us = 4kHz
|
38
|
-
CLOCK_DIVIDER_65536 = 0
|
39
|
-
# 32768 = 126us = 8kHz
|
40
|
-
CLOCK_DIVIDER_32768 = 32768
|
41
|
-
# 16384 = 64us = 15.625kHz
|
42
|
-
CLOCK_DIVIDER_16384 = 16384
|
43
|
-
# 8192 = 32us = 31.25kHz
|
44
|
-
CLOCK_DIVIDER_8192 = 8192
|
45
|
-
# 4096 = 16us = 62.5kHz
|
46
|
-
CLOCK_DIVIDER_4096 = 4096
|
47
|
-
# 2048 = 8us = 125kHz
|
48
|
-
CLOCK_DIVIDER_2048 = 2048
|
49
|
-
# 1024 = 4us = 250kHz
|
50
|
-
CLOCK_DIVIDER_1024 = 1024
|
51
|
-
# 512 = 2us = 500kHz
|
52
|
-
CLOCK_DIVIDER_512 = 512
|
53
|
-
# 256 = 1us = 1MHz
|
54
|
-
CLOCK_DIVIDER_256 = 256
|
55
|
-
# 128 = 500ns = = 2MHz
|
56
|
-
CLOCK_DIVIDER_128 = 128
|
57
|
-
# 64 = 250ns = 4MHz
|
58
|
-
CLOCK_DIVIDER_64 = 64
|
59
|
-
# 32 = 125ns = 8MHz
|
60
|
-
CLOCK_DIVIDER_32 = 32
|
61
|
-
# 16 = 50ns = 20MHz
|
62
|
-
CLOCK_DIVIDER_16 = 16
|
63
|
-
|
64
34
|
# Least signifigant bit first, e.g. 4 = 0b001
|
65
35
|
LSBFIRST = 0
|
66
36
|
# Most signifigant bit first, e.g. 4 = 0b100
|
@@ -75,18 +45,24 @@ module PiPiper
|
|
75
45
|
# No CS, control it yourself
|
76
46
|
CHIP_SELECT_NONE = 3
|
77
47
|
|
48
|
+
# SPI Modes
|
49
|
+
SPI_MODE0 = 0
|
50
|
+
SPI_MODE1 = 1
|
51
|
+
SPI_MODE2 = 2
|
52
|
+
SPI_MODE3 = 3
|
53
|
+
|
78
54
|
#Sets the SPI mode. Defaults to mode (0,0).
|
79
55
|
def self.set_mode(cpol, cpha)
|
80
56
|
mode = SPI_MODE0 #default
|
81
57
|
mode = SPI_MODE1 if cpol == 0 and cpha == 1
|
82
58
|
mode = SPI_MODE2 if cpol == 1 and cpha == 0
|
83
59
|
mode = SPI_MODE3 if cpol == 1 and cpha == 1
|
84
|
-
|
60
|
+
Platform.driver.spi_set_data_mode mode
|
85
61
|
end
|
86
62
|
|
87
63
|
#Begin an SPI block. All SPI communications should be wrapped in a block.
|
88
64
|
def self.begin(chip=nil, &block)
|
89
|
-
|
65
|
+
Platform.driver.spi_begin
|
90
66
|
chip = CHIP_SELECT_0 if !chip && block_given?
|
91
67
|
spi = new(chip)
|
92
68
|
|
@@ -99,11 +75,39 @@ module PiPiper
|
|
99
75
|
|
100
76
|
# Not needed when #begin is called with a block
|
101
77
|
def self.end
|
102
|
-
|
78
|
+
Platform.driver.spi_end
|
103
79
|
end
|
104
80
|
|
105
|
-
|
106
|
-
|
81
|
+
# Uses /dev/spidev0.0 to write to the SPI
|
82
|
+
# NOTE: Requires that you have /dev/spidev0.0
|
83
|
+
# see: http://learn.adafruit.com/adafruit-raspberry-pi-educational-linux-distro/overview
|
84
|
+
# most likely requires `chmod 666 /dev/spidev0.0`
|
85
|
+
#
|
86
|
+
# @example Writing red, green, blue to a string of WS2801 pixels
|
87
|
+
# PiPiper::Spi.spidev_out([255,0,0,0,255,0,0,0,255])
|
88
|
+
#
|
89
|
+
def self.spidev_out(array)
|
90
|
+
Platform.driver.spidev_out(array)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Sets the SPI clock frequency
|
94
|
+
def clock(frequency)
|
95
|
+
options = {4000 => 0, #4 kHz
|
96
|
+
8000 => 32768, #8 kHz
|
97
|
+
15625 => 16384, #15.625 kHz
|
98
|
+
31250 => 8192, #31.25 kHz
|
99
|
+
62500 => 4096, #62.5 kHz
|
100
|
+
125000 => 2048, #125 kHz
|
101
|
+
250000 => 1024, #250 kHz
|
102
|
+
500000 => 512, #500 kHz
|
103
|
+
1000000 => 256, #1 MHz
|
104
|
+
2000000 => 128, #2 MHz
|
105
|
+
4000000 => 64, #4 MHz
|
106
|
+
8000000 => 32, #8 MHz
|
107
|
+
20000000 => 16 #20 MHz
|
108
|
+
}
|
109
|
+
divider = options[frequency]
|
110
|
+
Platform.driver.spi_clock(divider)
|
107
111
|
end
|
108
112
|
|
109
113
|
def bit_order(order=MSBFIRST)
|
@@ -115,7 +119,7 @@ module PiPiper
|
|
115
119
|
end
|
116
120
|
end
|
117
121
|
|
118
|
-
|
122
|
+
Platform.driver.spi_bit_order(order)
|
119
123
|
end
|
120
124
|
|
121
125
|
# Activate a specific chip so that communication can begin
|
@@ -137,13 +141,13 @@ module PiPiper
|
|
137
141
|
# @yield
|
138
142
|
# @param [optional, CHIP_SELECT_*] chip the chip select line options
|
139
143
|
def chip_select(chip=CHIP_SELECT_0)
|
140
|
-
chip = @chip if @chip
|
141
|
-
|
144
|
+
chip = @chip if @chip
|
145
|
+
Platform.driver.spi_chip_select(chip)
|
142
146
|
if block_given?
|
143
147
|
begin
|
144
148
|
yield
|
145
149
|
ensure
|
146
|
-
|
150
|
+
Platform.driver.spi_chip_select(CHIP_SELECT_NONE)
|
147
151
|
end
|
148
152
|
end
|
149
153
|
end
|
@@ -162,7 +166,7 @@ module PiPiper
|
|
162
166
|
chip = @chip if @chip
|
163
167
|
chip = CHIP_SELECT_0 unless chip
|
164
168
|
|
165
|
-
|
169
|
+
Platform.driver.spi_chip_select_polarity(chip, active_low ? 0 : 1)
|
166
170
|
end
|
167
171
|
|
168
172
|
# Read from the bus
|
@@ -182,7 +186,7 @@ module PiPiper
|
|
182
186
|
if count
|
183
187
|
write([0xFF] * count)
|
184
188
|
else
|
185
|
-
enable {
|
189
|
+
enable { Platform.driver.spi_transfer(0) }
|
186
190
|
end
|
187
191
|
end
|
188
192
|
|
@@ -208,9 +212,9 @@ module PiPiper
|
|
208
212
|
enable do
|
209
213
|
case data
|
210
214
|
when Numeric
|
211
|
-
|
215
|
+
Platform.driver.spi_transfer(data)
|
212
216
|
when Enumerable
|
213
|
-
|
217
|
+
Platform.driver.spi_transfer_bytes(data)
|
214
218
|
else
|
215
219
|
raise ArgumentError.new("#{data.class} is not valid data. Use Numeric or an Enumerable of numbers")
|
216
220
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# @description driver that can be used either with tests or with rails or other frameworks for development
|
2
|
+
require_relative 'pin_values'
|
3
|
+
|
4
|
+
module PiPiper
|
5
|
+
|
6
|
+
class NullLogger
|
7
|
+
def debug(*) end
|
8
|
+
end
|
9
|
+
|
10
|
+
module StubDriver
|
11
|
+
include PiPiper::PinValues
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def new(options = {})
|
15
|
+
opts = {
|
16
|
+
:logger => NullLogger.new
|
17
|
+
}.merge(options)
|
18
|
+
|
19
|
+
@logger = opts[:logger]
|
20
|
+
|
21
|
+
@pins = {}
|
22
|
+
@spi = {data:[], chip_select:0,}
|
23
|
+
|
24
|
+
self
|
25
|
+
end
|
26
|
+
alias_method :reset, :new
|
27
|
+
|
28
|
+
def pin_input(pin_number)
|
29
|
+
#@pins[pin_number] = { direction: :in }
|
30
|
+
pin(pin_number)[:direction] = :in
|
31
|
+
@logger.debug("Pin ##{pin_number} -> Input")
|
32
|
+
end
|
33
|
+
|
34
|
+
def pin_output(pin_number)
|
35
|
+
#@pins[pin_number] = { direction: :in }
|
36
|
+
pin(pin_number)[:direction] = :out
|
37
|
+
@logger.debug("Pin ##{pin_number} -> Output")
|
38
|
+
end
|
39
|
+
|
40
|
+
def pin_direction(pin_number)
|
41
|
+
pin(pin_number)[:direction] if @pins[pin_number]
|
42
|
+
end
|
43
|
+
|
44
|
+
def pin_set(pin_number, value)
|
45
|
+
pin(pin_number)[:value] = value
|
46
|
+
@logger.debug("Pin ##{pin_number} -> #{value}")
|
47
|
+
end
|
48
|
+
|
49
|
+
def pin_set_pud(pin_number, value)
|
50
|
+
pin(pin_number)[:pud] = value
|
51
|
+
@logger.debug("PinPUD ##{pin_number} -> #{value}")
|
52
|
+
end
|
53
|
+
|
54
|
+
def spidev_out(array)
|
55
|
+
@spi[:data] = array
|
56
|
+
@logger.debug("SPIDEV -> #{array.pack('C*')}")
|
57
|
+
end
|
58
|
+
|
59
|
+
def spi_begin
|
60
|
+
@logger.debug("SPI Begin")
|
61
|
+
@spi[:data] = []
|
62
|
+
end
|
63
|
+
|
64
|
+
def spi_transfer_bytes(data)
|
65
|
+
@logger.debug("SPI CS#{@spi[:chip_select]} <- #{data.to_s}")
|
66
|
+
@spi[:data] = Array(data)
|
67
|
+
end
|
68
|
+
|
69
|
+
def spi_chip_select(chip = nil)
|
70
|
+
chip = chip || @spi[:chip_select]
|
71
|
+
@logger.debug("SPI Chip Select = #{chip}")
|
72
|
+
@spi[:chip_select] = chip
|
73
|
+
end
|
74
|
+
|
75
|
+
def pin_read(pin_number)
|
76
|
+
val = pin(pin_number)[:value]
|
77
|
+
val ||= case pin(pin_number)[:pud]
|
78
|
+
when GPIO_PUD_UP then GPIO_HIGH
|
79
|
+
when GPIO_PUD_DOWN then GPIO_LOW
|
80
|
+
else nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def release_pins
|
85
|
+
@pins.keys.each { |pin_number| release_pin(pin_number) }
|
86
|
+
end
|
87
|
+
|
88
|
+
def release_pin(pin_number)
|
89
|
+
@pins.delete(pin_number)
|
90
|
+
end
|
91
|
+
|
92
|
+
def method_missing(meth, *args, &block)
|
93
|
+
puts "Needs Implementation: StubDriver##{meth}"
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def pin(pin_number)
|
99
|
+
@pins[pin_number] ||= {}
|
100
|
+
end
|
101
|
+
|
102
|
+
## The following methods are only for testing and are not available on any platforms
|
103
|
+
def spi_data
|
104
|
+
@spi[:data]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/pi_piper.gemspec
CHANGED
@@ -1,16 +1,20 @@
|
|
1
|
-
#
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pi_piper/version'
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
7
|
s.name = "pi_piper"
|
5
|
-
s.version =
|
8
|
+
s.version = PiPiper::VERSION
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["Jason Whitehorn"]
|
9
|
-
s.date = "2013-09-
|
12
|
+
s.date = "2013-09-14"
|
10
13
|
s.description = "Event driven Raspberry Pi GPIO library"
|
11
14
|
s.email = "jason.whitehorn@gmail.com"
|
12
|
-
s.extra_rdoc_files = ["README.md", "lib/pi_piper.rb", "lib/pi_piper/bcm2835.rb", "lib/pi_piper/libbcm2835.
|
13
|
-
s.files
|
15
|
+
s.extra_rdoc_files = ["README.md", "lib/pi_piper.rb", "lib/pi_piper/bcm2835.rb", "lib/pi_piper/frequency.rb", "lib/pi_piper/i2c.rb", "lib/pi_piper/libbcm2835.so", "lib/pi_piper/pin.rb", "lib/pi_piper/platform.rb", "lib/pi_piper/spi.rb"]
|
16
|
+
s.files = `git ls-files -z`.split("\x0")
|
17
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
14
18
|
s.homepage = "http://github.com/jwhitehorn/pi_piper"
|
15
19
|
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Pi_piper", "--main", "README.md"]
|
16
20
|
s.require_paths = ["lib"]
|
@@ -18,15 +22,22 @@ Gem::Specification.new do |s|
|
|
18
22
|
s.rubygems_version = "2.0.0"
|
19
23
|
s.summary = "Event driven Raspberry Pi GPIO library"
|
20
24
|
|
21
|
-
if s.respond_to? :specification_version
|
25
|
+
if s.respond_to? :specification_version
|
22
26
|
s.specification_version = 4
|
23
27
|
|
24
|
-
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0')
|
28
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0')
|
25
29
|
s.add_runtime_dependency(%q<ffi>, [">= 0"])
|
30
|
+
s.add_runtime_dependency(%q<eventmachine>, ["= 1.0.9"])
|
26
31
|
else
|
27
32
|
s.add_dependency(%q<ffi>, [">= 0"])
|
33
|
+
s.add_dependency(%q<eventmachine>, ["= 1.0.9"])
|
28
34
|
end
|
29
35
|
else
|
30
36
|
s.add_dependency(%q<ffi>, [">= 0"])
|
37
|
+
s.add_dependency(%q<eventmachine>, ["= 1.0.9"])
|
31
38
|
end
|
39
|
+
|
40
|
+
s.add_development_dependency 'rspec'
|
41
|
+
s.add_development_dependency 'mocha'
|
42
|
+
s.add_development_dependency 'simplecov'
|
32
43
|
end
|
data/spec/i2c_spec.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe 'I2C' do
|
4
|
+
describe 'clock setting' do
|
5
|
+
it 'should check driver settings' do
|
6
|
+
Platform.driver = StubDriver.new.tap do |d|
|
7
|
+
expect(d).to receive(:i2c_allowed_clocks).and_return([100.kilohertz])
|
8
|
+
end
|
9
|
+
|
10
|
+
I2C.clock = 100.kilohertz
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should accept 100 kHz' do
|
14
|
+
Platform.driver = StubDriver.new.tap do |d|
|
15
|
+
expect(d).to receive(:i2c_allowed_clocks).and_return([100.kilohertz])
|
16
|
+
expect(d).to receive(:i2c_set_clock).with(100.kilohertz)
|
17
|
+
end
|
18
|
+
|
19
|
+
I2C.clock = 100.kilohertz
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should not accept 200 kHz' do
|
23
|
+
Platform.driver = StubDriver.new.tap do |d|
|
24
|
+
expect(d).to receive(:i2c_allowed_clocks).and_return([100.kilohertz])
|
25
|
+
end
|
26
|
+
|
27
|
+
expect { I2C.clock = 200.kilohertz }.to raise_error(RuntimeError)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'when in block' do
|
32
|
+
it 'should call i2c_begin' do
|
33
|
+
driver = StubDriver.new
|
34
|
+
expect(driver).to receive(:i2c_begin)
|
35
|
+
|
36
|
+
Platform.driver = driver
|
37
|
+
I2C.begin do
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should call i2c_end' do
|
42
|
+
driver = StubDriver.new
|
43
|
+
expect(driver).to receive(:i2c_end)
|
44
|
+
|
45
|
+
Platform.driver = driver
|
46
|
+
I2C.begin do
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should call i2c_end even after raise' do
|
51
|
+
driver = StubDriver.new
|
52
|
+
expect(driver).to receive(:i2c_end)
|
53
|
+
|
54
|
+
Platform.driver = driver
|
55
|
+
begin
|
56
|
+
I2C.begin { raise 'OMG' }
|
57
|
+
rescue
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'write operation' do
|
62
|
+
it 'should set address' do
|
63
|
+
Platform.driver = StubDriver.new.tap do |d|
|
64
|
+
expect(d).to receive(:i2c_set_address).with(4)
|
65
|
+
end
|
66
|
+
|
67
|
+
I2C.begin do
|
68
|
+
write to: 4, data: [1, 2, 3, 4]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should pass data to driver' do
|
73
|
+
Platform.driver = StubDriver.new.tap do |d|
|
74
|
+
expect(d).to receive(:i2c_transfer_bytes).with([1, 2, 3, 4])
|
75
|
+
end
|
76
|
+
|
77
|
+
I2C.begin do
|
78
|
+
write to: 4, data: [1, 2, 3, 4]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/spec/pin_spec.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include PiPiper
|
3
|
+
|
4
|
+
describe 'Pin' do
|
5
|
+
it 'should export pin for input' do
|
6
|
+
Platform.driver = StubDriver.new.tap do |d|
|
7
|
+
expect(d).to receive(:pin_input).with(4)
|
8
|
+
end
|
9
|
+
Pin.new pin: 4, direction: :in
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should export pin for output' do
|
13
|
+
Platform.driver = StubDriver.new.tap do |d|
|
14
|
+
expect(d).to receive(:pin_output).with(4)
|
15
|
+
end
|
16
|
+
|
17
|
+
Pin.new pin: 4, direction: :out
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should read start value on construction' do
|
21
|
+
Platform.driver = StubDriver.new.tap do |d|
|
22
|
+
expect(d).to receive(:pin_read).with(4).and_return(0)
|
23
|
+
end
|
24
|
+
|
25
|
+
Pin.new pin: 4, direction: :in
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should detect on?' do
|
29
|
+
Platform.driver = StubDriver.new.tap do |d|
|
30
|
+
expect(d).to receive(:pin_read).with(4).and_return(1)
|
31
|
+
end
|
32
|
+
|
33
|
+
pin = Pin.new pin: 4, direction: :in
|
34
|
+
expect(pin.on?).to be(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should detect off?' do
|
38
|
+
Platform.driver = StubDriver.new.tap do |d|
|
39
|
+
expect(d).to receive(:pin_read).with(4).and_return(0)
|
40
|
+
end
|
41
|
+
|
42
|
+
pin = Pin.new pin: 4, direction: :in
|
43
|
+
expect(pin.off?).to be(true)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should invert true' do
|
47
|
+
Platform.driver = StubDriver.new.tap do |d|
|
48
|
+
expect(d).to receive(:pin_read).with(4).and_return(1)
|
49
|
+
end
|
50
|
+
|
51
|
+
pin = Pin.new pin: 4, direction: :in, invert: true
|
52
|
+
expect(pin.on?).to be(false)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should invert true' do
|
56
|
+
Platform.driver = StubDriver.new.tap do |d|
|
57
|
+
expect(d).to receive(:pin_read).with(4).and_return(0)
|
58
|
+
end
|
59
|
+
|
60
|
+
pin = Pin.new pin: 4, direction: :in, invert: true
|
61
|
+
expect(pin.off?).to be(false)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should write high' do
|
65
|
+
Platform.driver = StubDriver.new.tap do |d|
|
66
|
+
expect(d).to receive(:pin_set).with(4, 1)
|
67
|
+
end
|
68
|
+
|
69
|
+
pin = Pin.new pin: 4, direction: :out
|
70
|
+
pin.on
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should write low' do
|
74
|
+
Platform.driver = StubDriver.new.tap do |d|
|
75
|
+
expect(d).to receive(:pin_set).with(4, 0)
|
76
|
+
end
|
77
|
+
|
78
|
+
pin = Pin.new pin: 4, direction: :out
|
79
|
+
pin.off
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should not write high on direction in' do
|
83
|
+
Platform.driver = StubDriver.new.tap do |d|
|
84
|
+
expect(d).not_to receive(:pin_set)
|
85
|
+
end
|
86
|
+
|
87
|
+
pin = Pin.new pin: 4, direction: :in
|
88
|
+
pin.on
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should not write low on direction in' do
|
92
|
+
Platform.driver = StubDriver.new.tap do |d|
|
93
|
+
expect(d).not_to receive(:pin_set)
|
94
|
+
end
|
95
|
+
|
96
|
+
pin = Pin.new pin: 4, direction: :in
|
97
|
+
pin.off
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'should detect high to low change' do
|
101
|
+
Platform.driver = StubDriver.new.tap do |d|
|
102
|
+
value = 1
|
103
|
+
# begins low, then high, low, high, low...
|
104
|
+
allow(d).to receive(:pin_read) { value ^= 1 }
|
105
|
+
end
|
106
|
+
|
107
|
+
pin = Pin.new pin: 4, direction: :in
|
108
|
+
expect(pin.off?).to be(true)
|
109
|
+
pin.read
|
110
|
+
expect(pin.off?).to be(false)
|
111
|
+
expect(pin.changed?).to be(true)
|
112
|
+
end
|
113
|
+
|
114
|
+
xit 'should wait for change' do
|
115
|
+
pending
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'given a pin is released' do
|
119
|
+
it 'should actually release it' do
|
120
|
+
Platform.driver = StubDriver.new.tap do |driver|
|
121
|
+
expect(driver).to receive(:release_pin).with(4)
|
122
|
+
end
|
123
|
+
|
124
|
+
pin = Pin.new(pin: 4, direction: :in)
|
125
|
+
pin.release
|
126
|
+
expect(pin.released?).to be(true)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should not mark unreleased pins as released' do
|
130
|
+
pin = Pin.new(pin: 4, direction: :in)
|
131
|
+
expect(pin.released?).to be(false)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should not continue to use the pin' do
|
135
|
+
Platform.driver = StubDriver.new.tap do |driver|
|
136
|
+
expect(driver).to receive(:release_pin).with(4)
|
137
|
+
end
|
138
|
+
|
139
|
+
pin = Pin.new(pin: 4, direction: :in)
|
140
|
+
pin.release
|
141
|
+
|
142
|
+
expect { pin.read }.to raise_error(PinError, 'Pin 4 already released')
|
143
|
+
expect { pin.on }.to raise_error(PinError, 'Pin 4 already released')
|
144
|
+
expect { pin.off }.to raise_error(PinError, 'Pin 4 already released')
|
145
|
+
expect { pin.pull!(:up) }.to(
|
146
|
+
raise_error(PinError, 'Pin 4 already released'))
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|