pi_piper 2.0.beta.4 → 2.0.0
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 +10 -0
- data/Gemfile +3 -3
- data/Gemfile.lock +39 -26
- data/LICENCE.md +23 -0
- data/README.md +53 -16
- data/Rakefile +4 -22
- data/examples/2_bit_counter/2_bit_counter.rb +21 -0
- data/examples/7-segment/7-segment.rb +37 -0
- data/examples/dsl_switch/dsl_switch.rb +15 -0
- data/examples/elro/README.md +75 -0
- data/examples/elro/docs/elro-dips.jpg +0 -0
- data/examples/elro/docs/elro-switch.jpg +0 -0
- data/examples/elro/docs/setup.jpg +0 -0
- data/examples/elro/docs/wireplan.jpg +0 -0
- data/examples/elro/docs/wrl10534.jpg +0 -0
- data/examples/elro/elro.rb +15 -0
- data/examples/elro/lib/elro_switch.rb +51 -0
- data/examples/elro/lib/elro_util.rb +64 -0
- data/examples/elro/spec/elro_spec.rb +35 -0
- data/examples/elro/spec/elro_util_spec.rb +51 -0
- data/examples/elro/spec/spec_helper.rb +6 -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 +49 -0
- data/examples/simple_switch/circuit.png +0 -0
- data/examples/simple_switch/simple_switch.rb +10 -0
- data/lib/pi_piper.rb +5 -3
- data/lib/pi_piper/bcm2835.rb +84 -14
- data/lib/pi_piper/i2c.rb +0 -1
- data/lib/pi_piper/libbcm2835.so +0 -0
- data/lib/pi_piper/pin.rb +102 -63
- data/lib/pi_piper/pin_error.rb +3 -0
- data/lib/pi_piper/pin_values.rb +35 -0
- data/lib/pi_piper/platform.rb +5 -5
- data/lib/pi_piper/pwm.rb +95 -0
- data/lib/pi_piper/spi.rb +30 -45
- data/lib/pi_piper/stub_driver.rb +124 -0
- data/lib/pi_piper/version.rb +3 -0
- data/pi_piper.gemspec +24 -29
- data/spec/bcm2835_spec.rb +132 -0
- data/spec/i2c_spec.rb +62 -0
- data/spec/pin_spec.rb +140 -0
- data/spec/pwm_spec.rb +83 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/spi_spec.rb +38 -0
- data/spec/stub_driver_spec.rb +140 -0
- metadata +100 -26
- data/Manifest +0 -14
- data/lib/pi_piper/libbcm2835.img +0 -0
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
|
3
|
+
|
4
|
+
require 'pi_piper'
|
5
|
+
require 'elro_switch'
|
6
|
+
|
7
|
+
exit(0) unless ARGV[0]
|
8
|
+
|
9
|
+
device = ARGV[0].to_i
|
10
|
+
switch_on = ARGV[1]
|
11
|
+
key = [0,0,0,0,1]
|
12
|
+
|
13
|
+
pin = PiPiper::Pin.new(:pin => 17, :direction => :out)
|
14
|
+
elro = ElroSwitch.new(device, key, pin)
|
15
|
+
elro.switch(switch_on == "1")
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'elro_util'
|
2
|
+
|
3
|
+
# ElroSwitch is a little tool written to send trigger-events from a RaspberryPi
|
4
|
+
# to an Elro remote controlled switch.
|
5
|
+
#
|
6
|
+
# It works perfectly with PiPiper: https://github.com/jwhitehorn/pi_piper
|
7
|
+
#
|
8
|
+
# See README.md for more information.
|
9
|
+
#
|
10
|
+
# == CREDITS
|
11
|
+
# Written by Torsten Mangner (https://github.com/alphaone).
|
12
|
+
# This library is mostly a (heavily refactored) port from this python script
|
13
|
+
# http://pastebin.com/aRipYrZ6
|
14
|
+
# by Heiko H.,
|
15
|
+
# which is a port from a C++ snippet
|
16
|
+
# http://www.jer00n.nl/433send.cpp
|
17
|
+
# written by J. Lukas,
|
18
|
+
# and influenced by this Arduino source code
|
19
|
+
# http://gathering.tweakers.net/forum/view_message/34919677
|
20
|
+
# written by Piepersnijder.
|
21
|
+
class ElroSwitch
|
22
|
+
include ElroUtil
|
23
|
+
|
24
|
+
# devices: according to dipswitches on your Elro receivers
|
25
|
+
# or
|
26
|
+
# a numeric A = 1, B = 2, C = 4, D = 8, E = 16
|
27
|
+
# key: according to dipswitches on your Elro receivers
|
28
|
+
# pin: an object that responses to #update_value(bool) (like PiPiper::Pin)
|
29
|
+
def initialize(device, key, pin)
|
30
|
+
raise ArgumentError.new("key has to be of size 5") unless key.size == 5
|
31
|
+
raise ArgumentError.new("device has to be Numeric or Array") unless (device.is_a?(Numeric) or device.is_a?(Array))
|
32
|
+
raise ArgumentError.new("device has to be of size 5") if (device.is_a?(Array) and device.size != 5)
|
33
|
+
raise ArgumentError.new("device has to be between 0 and 31") if (device.is_a?(Numeric) and !((0..31) === device))
|
34
|
+
raise ArgumentError.new("pin has no method :update_value") unless pin.respond_to?(:update_value)
|
35
|
+
@key = key
|
36
|
+
@device = device
|
37
|
+
@pin = pin
|
38
|
+
end
|
39
|
+
|
40
|
+
def switch(switch)
|
41
|
+
sequence = []
|
42
|
+
sequence << ElroUtil.sequence_for_key(@key)
|
43
|
+
sequence << ElroUtil.sequence_for_device(@device)
|
44
|
+
sequence << ElroUtil.sequence_for_onoff(switch)
|
45
|
+
sequence << ElroUtil.sequence_for_static_part
|
46
|
+
|
47
|
+
pulses = ElroUtil.pulses_from_sequence(sequence.flatten)
|
48
|
+
ElroUtil.send_pulses(@pin, pulses)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# ElroUtil will do the hard work for ElroSwitch
|
2
|
+
#
|
3
|
+
# == WARNING
|
4
|
+
# The Raspberry is not build to be the fastest hardware in the world.
|
5
|
+
# Ruby (MRI) is not fastest programming language (but still the best).
|
6
|
+
# The Elro Switch expects the 1280 signals for each switch-event to be
|
7
|
+
# transmitted with a frequency of 300 microseconds (but as I have observed
|
8
|
+
# will still operate while using frequencies from ≈100 to ≈600 microseconds
|
9
|
+
# per signal).
|
10
|
+
#
|
11
|
+
# This implementation (using PiPiper) reaches a frequency of around
|
12
|
+
# 500 microseconds on an RaspberryPi without any wait or sleep.
|
13
|
+
#
|
14
|
+
# Other implementation (in python or C) need to time their signals to
|
15
|
+
# not be too fast.
|
16
|
+
#
|
17
|
+
# Keep that in mind, if this code will run on faster hardware or faster Rubies.
|
18
|
+
module ElroUtil
|
19
|
+
|
20
|
+
DIP_OFF = 142
|
21
|
+
DIP_ON = 136
|
22
|
+
REPEAT = 10 # Number of transmissions
|
23
|
+
|
24
|
+
def ElroUtil.sequence_for_key(key)
|
25
|
+
key.map { |dip| (dip == 1) ? DIP_ON : DIP_OFF }
|
26
|
+
end
|
27
|
+
|
28
|
+
def ElroUtil.sequence_for_device(device)
|
29
|
+
if device.is_a?(Array)
|
30
|
+
device.map { |dip| dip == 1 ? DIP_ON : DIP_OFF }
|
31
|
+
elsif device.is_a?(Numeric)
|
32
|
+
ElroUtil.convert_to_bits(device, 5).reverse.map { |b| b ? DIP_ON : DIP_OFF }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def ElroUtil.sequence_for_onoff(switch_on)
|
37
|
+
switch_on ? [DIP_ON, DIP_OFF] : [DIP_OFF, DIP_ON]
|
38
|
+
end
|
39
|
+
|
40
|
+
def ElroUtil.sequence_for_static_part
|
41
|
+
[128, 0, 0, 0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def ElroUtil.pulses_from_sequence(sequence)
|
45
|
+
sequence.map { |part| ElroUtil.convert_to_bits(part, 8) }.flatten
|
46
|
+
end
|
47
|
+
|
48
|
+
def ElroUtil.send_pulses(pin, pulses, verbose=false)
|
49
|
+
pin.update_value(false)
|
50
|
+
start_time = Time.now
|
51
|
+
REPEAT.times do
|
52
|
+
pulses.each { |b| pin.update_value(b) }
|
53
|
+
end
|
54
|
+
end_time = Time.now
|
55
|
+
if verbose
|
56
|
+
puts "avg %.0f microsecs per pulse" % ((end_time - start_time) / (10 * 16 * 8) * 1_000_000)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def ElroUtil.convert_to_bits(num, length)
|
61
|
+
sprintf("%0#{length}d", num.to_s(2)).split("").map {|b| b.to_i & 1 == 1}
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElroSwitch do
|
4
|
+
|
5
|
+
let(:pin) {double("pi_piper_pin", :update_value => nil)}
|
6
|
+
|
7
|
+
it "does not allow wrong key length" do
|
8
|
+
expect {ElroSwitch.new(1, [0,0,1,0,1,0], pin)}.to raise_error ArgumentError
|
9
|
+
end
|
10
|
+
|
11
|
+
it "does expect a Numeric or a List as device" do
|
12
|
+
expect {ElroSwitch.new([0,0,0,0,0], [0,1,0,1,0], pin)}.not_to raise_error ArgumentError
|
13
|
+
expect {ElroSwitch.new(15, [0,1,0,1,0], pin)}.not_to raise_error ArgumentError
|
14
|
+
expect {ElroSwitch.new("x", [0,1,0,1,0], pin)}.to raise_error ArgumentError
|
15
|
+
end
|
16
|
+
|
17
|
+
it "does expect a numeric device to be between 0 and 31" do
|
18
|
+
expect {ElroSwitch.new(-1, [0,1,0,1,0], pin)}.to raise_error ArgumentError
|
19
|
+
expect {ElroSwitch.new( 0, [0,1,0,1,0], pin)}.not_to raise_error ArgumentError
|
20
|
+
expect {ElroSwitch.new(31, [0,1,0,1,0], pin)}.not_to raise_error ArgumentError
|
21
|
+
expect {ElroSwitch.new(32, [0,1,0,1,0], pin)}.to raise_error ArgumentError
|
22
|
+
end
|
23
|
+
|
24
|
+
it "does not allow wrong device length" do
|
25
|
+
expect {ElroSwitch.new([0,0,0,0], [0,1,0,1,0], pin)}.to raise_error ArgumentError
|
26
|
+
end
|
27
|
+
|
28
|
+
it "sends pulses on switch" do
|
29
|
+
pin.should_receive(:update_value).exactly(16 * 8 * 10 + 1).times
|
30
|
+
|
31
|
+
elro = ElroSwitch.new(1, [0,0,1,0,1], pin)
|
32
|
+
elro.switch(true)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ElroUtil do
|
4
|
+
|
5
|
+
it "generates correct sequence for key" do
|
6
|
+
ElroUtil.sequence_for_key([0,0,1,0,1]).should ==
|
7
|
+
[142, 142, 136, 142, 136]
|
8
|
+
end
|
9
|
+
|
10
|
+
it "generates correct sequence for device" do
|
11
|
+
ElroUtil.sequence_for_device(7).should ==
|
12
|
+
[136, 136, 136, 142, 142]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "generates correct sequence for device as array" do
|
16
|
+
ElroUtil.sequence_for_device([1,1,1,0,0]).should ==
|
17
|
+
[136, 136, 136, 142, 142]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "generates correct sequence for on/off" do
|
21
|
+
ElroUtil.sequence_for_onoff(true).should ==
|
22
|
+
[136, 142]
|
23
|
+
ElroUtil.sequence_for_onoff(false).should ==
|
24
|
+
[142, 136]
|
25
|
+
end
|
26
|
+
|
27
|
+
it "generates correct sequence for static part" do
|
28
|
+
ElroUtil.sequence_for_static_part.should ==
|
29
|
+
[128, 0, 0, 0]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "converts numbers to bits" do
|
33
|
+
ElroUtil.convert_to_bits(7, 8).should == [false, false, false, false, false, true, true, true]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "converts sequence to bit pulses" do
|
37
|
+
ElroUtil.pulses_from_sequence([136, 142]).should ==
|
38
|
+
[
|
39
|
+
true, false, false, false, true, false, false, false,
|
40
|
+
true, false, false, false, true, true, true, false
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "sends pulses" do
|
45
|
+
pin = double("pi_piper_pin")
|
46
|
+
pin.should_receive(:update_value).exactly(40 + 1).times
|
47
|
+
|
48
|
+
ElroUtil.send_pulses(pin, [true, false, false, true])
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
Binary file
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'pi_piper'
|
2
|
+
#port of the Adafruit MCP3008 interface code found @ http://learn.adafruit.com/send-raspberry-pi-data-to-cosm/python-script
|
3
|
+
|
4
|
+
def read_adc(adc_pin, clockpin, adc_in, adc_out, cspin)
|
5
|
+
cspin.on
|
6
|
+
clockpin.off
|
7
|
+
cspin.off
|
8
|
+
|
9
|
+
command_out = adc_pin
|
10
|
+
command_out |= 0x18
|
11
|
+
command_out <<= 3
|
12
|
+
|
13
|
+
(0..4).each do
|
14
|
+
adc_in.update_value((command_out & 0x80) > 0)
|
15
|
+
command_out <<= 1
|
16
|
+
clockpin.on
|
17
|
+
clockpin.off
|
18
|
+
end
|
19
|
+
result = 0
|
20
|
+
|
21
|
+
(0..11).each do
|
22
|
+
clockpin.on
|
23
|
+
clockpin.off
|
24
|
+
result <<= 1
|
25
|
+
adc_out.read
|
26
|
+
if adc_out.on?
|
27
|
+
result |= 0x1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
cspin.on
|
32
|
+
|
33
|
+
result >> 1
|
34
|
+
end
|
35
|
+
|
36
|
+
clock = PiPiper::Pin.new :pin => 18, :direction => :out
|
37
|
+
adc_out = PiPiper::Pin.new :pin => 23
|
38
|
+
adc_in = PiPiper::Pin.new :pin => 24, :direction => :out
|
39
|
+
cs = PiPiper::Pin.new :pin => 25, :direction => :out
|
40
|
+
|
41
|
+
adc_pin = 0
|
42
|
+
|
43
|
+
loop do
|
44
|
+
value = read_adc(adc_pin, clock, adc_in, adc_out, cs)
|
45
|
+
invert = 1023 - value
|
46
|
+
mvolts = invert * (3300.0 / 1023.0)
|
47
|
+
if mvolts < 2700
|
48
|
+
temp = (mvolts - 380.0) / (2320.0 / 84.0)
|
49
|
+
else
|
50
|
+
temp = (mvolts - 2700.0) / (390.0 / 92.0) + 84.0
|
51
|
+
end
|
52
|
+
temp_f = (temp * 9.0 / 5.0) + 32
|
53
|
+
puts "Value = #{value}, invert = #{invert}, mvolts = #{mvolts}, temp = #{temp} C | #{temp_f} F"
|
54
|
+
sleep 1
|
55
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'pi_piper'
|
2
|
+
#special thanks to Jeremy Blythe, and his article @ http://jeremyblythe.blogspot.com/2012/09/raspberry-pi-hardware-spi-analog-inputs.html
|
3
|
+
#it greatly helped in getting the MCP3008 setup with SPI
|
4
|
+
|
5
|
+
adc_num = 0
|
6
|
+
|
7
|
+
loop do
|
8
|
+
value = 0
|
9
|
+
PiPiper::Spi.begin do |spi|
|
10
|
+
raw = spi.write [1, (8+adc_num)<<4, 0]
|
11
|
+
value = ((raw[1]&3) << 8) + raw[2]
|
12
|
+
end
|
13
|
+
|
14
|
+
invert = 1023 - value
|
15
|
+
mvolts = invert * (3300.0 / 1023.0)
|
16
|
+
if mvolts < 2700
|
17
|
+
temp = (mvolts - 380.0) / (2320.0 / 84.0)
|
18
|
+
else
|
19
|
+
temp = (mvolts - 2700.0) / (390.0 / 92.0) + 84.0
|
20
|
+
end
|
21
|
+
temp_f = (temp * 9.0 / 5.0) + 32
|
22
|
+
puts "Value = #{value}, invert = #{invert}, mvolts = #{mvolts}, temp = #{temp} C | #{temp_f} F"
|
23
|
+
sleep 1
|
24
|
+
end
|
Binary file
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'pi_piper'
|
2
|
+
|
3
|
+
unit = 0.1
|
4
|
+
dot = unit
|
5
|
+
dash = unit * 3
|
6
|
+
inter_element_gap = unit
|
7
|
+
short_gap = unit * 3
|
8
|
+
medium_gap = unit * 7
|
9
|
+
|
10
|
+
#http://en.wikipedia.org/wiki/Morse_code
|
11
|
+
character_timing = { "a" => [dot, dash], "b" => [dash, dot, dot, dot], "c" => [dash, dot, dash, dot],
|
12
|
+
"d" => [dash, dot, dot], "e" => [dot], "f" => [dot, dot, dash, dot],
|
13
|
+
"g" => [dash, dash, dot], "h" => [dot, dot, dot, dot], "i" => [dot, dot],
|
14
|
+
"j" => [dot, dash, dash, dash], "k" => [dash, dot, dash], "l" => [dot, dash, dot, dot],
|
15
|
+
"m" => [dash, dash], "n" => [dash, dot], "o" => [dash, dash, dash],
|
16
|
+
"p" => [dot, dash, dash, dot], "q" => [dash, dash, dot, dash], "r" => [dot, dash, dot],
|
17
|
+
"s" => [dot, dot, dot], "t" => [dash], "u" => [dot, dot, dash],
|
18
|
+
"v" => [dot, dot, dot, dash], "w" => [dot, dash, dash], "x" => [dash, dot, dot, dash],
|
19
|
+
"y" => [dash, dot, dash, dash], "z" => [dash, dash, dot, dot],
|
20
|
+
"0" => [dash, dash, dash, dash, dash], "1" => [dot, dash, dash, dash, dash],
|
21
|
+
"2" => [dot, dot, dash, dash, dash], "3" => [dot, dot, dot, dash, dash],
|
22
|
+
"4" => [dot, dot, dot, dot, dash], "5" => [dot, dot, dot, dot, dot],
|
23
|
+
"6" => [dash, dot, dot, dot, dot], "7" => [dash, dash, dot, dot, dot],
|
24
|
+
"8" => [dash, dash, dash, dot, dot], "9" => [dash, dash, dash, dash, dot]
|
25
|
+
}
|
26
|
+
|
27
|
+
pin = PiPiper::Pin.new(:pin => 17, :direction => :out)
|
28
|
+
pin.off
|
29
|
+
|
30
|
+
loop do
|
31
|
+
puts "Please type something"
|
32
|
+
something = gets.chomp.downcase
|
33
|
+
|
34
|
+
something.each_char do |letter|
|
35
|
+
if letter == " "
|
36
|
+
pin.off
|
37
|
+
sleep medium_gap
|
38
|
+
else
|
39
|
+
character_timing[letter].each do |timing|
|
40
|
+
pin.on
|
41
|
+
sleep timing
|
42
|
+
pin.off
|
43
|
+
sleep inter_element_gap
|
44
|
+
end
|
45
|
+
sleep short_gap - inter_element_gap
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
Binary file
|
data/lib/pi_piper.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'eventmachine'
|
2
|
-
Dir[File.dirname(__FILE__) + '/pi_piper/*.rb'].each {|file| require file
|
2
|
+
Dir[File.dirname(__FILE__) + '/pi_piper/*.rb'].each {|file| require file unless file.end_with?('bcm2835.rb') }
|
3
3
|
|
4
4
|
module PiPiper
|
5
5
|
extend self
|
@@ -11,7 +11,7 @@ module PiPiper
|
|
11
11
|
# Options hash. Options include `:pin`, `:invert` and `:trigger`.
|
12
12
|
#
|
13
13
|
def watch(options, &block)
|
14
|
-
Thread.new do
|
14
|
+
new_thread = Thread.new do
|
15
15
|
pin = PiPiper::Pin.new(options)
|
16
16
|
loop do
|
17
17
|
pin.wait_for_change
|
@@ -21,7 +21,9 @@ module PiPiper
|
|
21
21
|
pin.instance_exec &block
|
22
22
|
end
|
23
23
|
end
|
24
|
-
end
|
24
|
+
end
|
25
|
+
new_thread.abort_on_exception = true
|
26
|
+
new_thread
|
25
27
|
end
|
26
28
|
|
27
29
|
#Defines an event block to be executed after a pin either goes high or low.
|
data/lib/pi_piper/bcm2835.rb
CHANGED
@@ -5,7 +5,8 @@ module PiPiper
|
|
5
5
|
# It serves as an FFI library for PiPiper::SPI & PiPiper::I2C.
|
6
6
|
module Bcm2835
|
7
7
|
extend FFI::Library
|
8
|
-
ffi_lib File.dirname(__FILE__) + '/libbcm2835.
|
8
|
+
ffi_lib File.dirname(__FILE__) + '/libbcm2835.so'
|
9
|
+
@pins = []
|
9
10
|
|
10
11
|
SPI_MODE0 = 0
|
11
12
|
SPI_MODE1 = 1
|
@@ -20,27 +21,97 @@ module PiPiper
|
|
20
21
|
attach_function :init, :bcm2835_init, [], :uint8
|
21
22
|
attach_function :close, :bcm2835_close, [], :uint8
|
22
23
|
|
24
|
+
# Sets the Function Select register for the given pin, which configures the pin as Input, Output or one of the 6 alternate functions.
|
25
|
+
attach_function :gpio_select_function, :bcm2835_gpio_fsel, [:uint8, :uint8], :void
|
26
|
+
# attach_function :gpio_set, :bcm2835_gpio_set, [:uint8], :void
|
27
|
+
# attach_function :gpio_clear, :bcm2835_gpio_clr, [:uint8], :void
|
28
|
+
# attach_function :gpio_level, :bcm2835_gpio_lev, [:uint8], :uint8
|
29
|
+
|
23
30
|
#pin support...
|
24
|
-
attach_function :pin_set_pud,
|
31
|
+
attach_function :pin_set_pud, :bcm2835_gpio_set_pud, [:uint8, :uint8], :void
|
25
32
|
|
26
33
|
def self.pin_input(pin)
|
27
|
-
|
28
|
-
|
34
|
+
export(pin)
|
35
|
+
pin_direction(pin, 'in')
|
29
36
|
end
|
30
|
-
|
37
|
+
|
31
38
|
def self.pin_set(pin, value)
|
32
|
-
|
39
|
+
raise PiPiper::PinError, "Pin #{pin} not exported" unless exported?(pin)
|
40
|
+
File.write("/sys/class/gpio/gpio#{pin}/value", value)
|
33
41
|
end
|
34
|
-
|
35
|
-
def
|
36
|
-
|
37
|
-
|
42
|
+
|
43
|
+
def self.pin_output(pin)
|
44
|
+
export(pin)
|
45
|
+
pin_direction(pin, 'out')
|
38
46
|
end
|
39
|
-
|
47
|
+
|
40
48
|
def self.pin_read(pin)
|
49
|
+
raise PiPiper::PinError, "Pin #{pin} not exported" unless exported?(pin)
|
41
50
|
File.read("/sys/class/gpio/gpio#{pin}/value").to_i
|
42
51
|
end
|
43
52
|
|
53
|
+
#PWM support...
|
54
|
+
attach_function :pwm_clock, :bcm2835_pwm_set_clock, [:uint32], :void
|
55
|
+
attach_function :pwm_mode, :bcm2835_pwm_set_mode, [:uint8, :uint8, :uint8], :void
|
56
|
+
attach_function :pwm_range, :bcm2835_pwm_set_range, [:uint8, :uint32], :void
|
57
|
+
attach_function :pwm_data, :bcm2835_pwm_set_data, [:uint8, :uint32], :void
|
58
|
+
|
59
|
+
def self.pin_direction(pin, direction)
|
60
|
+
raise PiPiper::PinError, "Pin #{pin} not exported" unless exported?(pin)
|
61
|
+
File.write("/sys/class/gpio/gpio#{pin}/direction", direction)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.export(pin)
|
65
|
+
File.write('/sys/class/gpio/export', pin)
|
66
|
+
@pins << pin unless @pins.include?(pin)
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.unexport_pin(pin)
|
70
|
+
File.write('/sys/class/gpio/unexport', pin)
|
71
|
+
@pins.delete(pin)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.unexport_all
|
75
|
+
@pins.dup.each { |pin| unexport_pin(pin) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.exported_pins
|
79
|
+
@pins
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.exported?(pin)
|
83
|
+
@pins.include?(pin)
|
84
|
+
end
|
85
|
+
|
86
|
+
# Support "none", "rising", "falling", or "both"
|
87
|
+
def self.pin_set_edge(pin, trigger)
|
88
|
+
raise PiPiper::PinError, "Pin #{pin} not exported" unless exported?(pin)
|
89
|
+
File.write("/sys/class/gpio/gpio#{pin}/edge", trigger)
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.pin_wait_for(pin, trigger)
|
93
|
+
pin_set_edge(pin, trigger)
|
94
|
+
|
95
|
+
fd = File.open("/sys/class/gpio/gpio#{pin}/value", "r")
|
96
|
+
value = nil
|
97
|
+
loop do
|
98
|
+
fd.read
|
99
|
+
IO.select(nil, nil, [fd], nil)
|
100
|
+
last_value = value
|
101
|
+
value = self.pin_read(pin)
|
102
|
+
if last_value != value
|
103
|
+
next if trigger == :rising and value == 0
|
104
|
+
next if trigger == :falling and value == 1
|
105
|
+
break
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
#NOTE to use: chmod 666 /dev/spidev0.0
|
111
|
+
def self.spidev_out(array)
|
112
|
+
File.open('/dev/spidev0.0', 'wb'){|f| f.write(array.pack('C*')) }
|
113
|
+
end
|
114
|
+
|
44
115
|
#SPI support...
|
45
116
|
attach_function :spi_begin, :bcm2835_spi_begin, [], :uint8
|
46
117
|
attach_function :spi_end, :bcm2835_spi_end, [], :uint8
|
@@ -65,11 +136,11 @@ module PiPiper
|
|
65
136
|
[100.kilohertz,
|
66
137
|
399.3610.kilohertz,
|
67
138
|
1.666.megahertz,
|
68
|
-
1.689.megahertz]
|
139
|
+
1.689.megahertz]
|
69
140
|
end
|
70
141
|
|
71
142
|
def self.spi_transfer_bytes(data)
|
72
|
-
data_out = FFI::MemoryPointer.new(data.count)
|
143
|
+
data_out = FFI::MemoryPointer.new(data.count)
|
73
144
|
data_in = FFI::MemoryPointer.new(data.count)
|
74
145
|
(0..data.count-1).each { |i| data_out.put_uint8(i, data[i]) }
|
75
146
|
|
@@ -91,6 +162,5 @@ module PiPiper
|
|
91
162
|
|
92
163
|
(0..bytes-1).map { |i| data_in.get_uint8(i) }
|
93
164
|
end
|
94
|
-
|
95
165
|
end
|
96
166
|
end
|