pi_piper 1.3.2 → 1.9.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|