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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +3 -3
  6. data/Gemfile.lock +39 -26
  7. data/LICENCE.md +23 -0
  8. data/README.md +53 -16
  9. data/Rakefile +4 -22
  10. data/examples/2_bit_counter/2_bit_counter.rb +21 -0
  11. data/examples/7-segment/7-segment.rb +37 -0
  12. data/examples/dsl_switch/dsl_switch.rb +15 -0
  13. data/examples/elro/README.md +75 -0
  14. data/examples/elro/docs/elro-dips.jpg +0 -0
  15. data/examples/elro/docs/elro-switch.jpg +0 -0
  16. data/examples/elro/docs/setup.jpg +0 -0
  17. data/examples/elro/docs/wireplan.jpg +0 -0
  18. data/examples/elro/docs/wrl10534.jpg +0 -0
  19. data/examples/elro/elro.rb +15 -0
  20. data/examples/elro/lib/elro_switch.rb +51 -0
  21. data/examples/elro/lib/elro_util.rb +64 -0
  22. data/examples/elro/spec/elro_spec.rb +35 -0
  23. data/examples/elro/spec/elro_util_spec.rb +51 -0
  24. data/examples/elro/spec/spec_helper.rb +6 -0
  25. data/examples/mcp3008/circuit.png +0 -0
  26. data/examples/mcp3008/mcp3008.rb +55 -0
  27. data/examples/mcp3008_spi/mcp3008_spi.rb +24 -0
  28. data/examples/morse_code/circuit.png +0 -0
  29. data/examples/morse_code/morse_code.rb +49 -0
  30. data/examples/simple_switch/circuit.png +0 -0
  31. data/examples/simple_switch/simple_switch.rb +10 -0
  32. data/lib/pi_piper.rb +5 -3
  33. data/lib/pi_piper/bcm2835.rb +84 -14
  34. data/lib/pi_piper/i2c.rb +0 -1
  35. data/lib/pi_piper/libbcm2835.so +0 -0
  36. data/lib/pi_piper/pin.rb +102 -63
  37. data/lib/pi_piper/pin_error.rb +3 -0
  38. data/lib/pi_piper/pin_values.rb +35 -0
  39. data/lib/pi_piper/platform.rb +5 -5
  40. data/lib/pi_piper/pwm.rb +95 -0
  41. data/lib/pi_piper/spi.rb +30 -45
  42. data/lib/pi_piper/stub_driver.rb +124 -0
  43. data/lib/pi_piper/version.rb +3 -0
  44. data/pi_piper.gemspec +24 -29
  45. data/spec/bcm2835_spec.rb +132 -0
  46. data/spec/i2c_spec.rb +62 -0
  47. data/spec/pin_spec.rb +140 -0
  48. data/spec/pwm_spec.rb +83 -0
  49. data/spec/spec_helper.rb +7 -0
  50. data/spec/spi_spec.rb +38 -0
  51. data/spec/stub_driver_spec.rb +140 -0
  52. metadata +100 -26
  53. data/Manifest +0 -14
  54. data/lib/pi_piper/libbcm2835.img +0 -0
@@ -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
@@ -0,0 +1,6 @@
1
+ require 'rspec'
2
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'elro_switch')
3
+
4
+ RSpec.configure do |config|
5
+ # ...
6
+ end
@@ -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
@@ -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
@@ -0,0 +1,10 @@
1
+ require 'pi_piper'
2
+
3
+ puts "Press the switch to get started"
4
+
5
+ PiPiper.watch :pin => 17, :invert => true do |pin|
6
+ puts "Pin changed from #{pin.last_value} to #{pin.value}"
7
+ end
8
+
9
+ PiPiper.wait
10
+
@@ -1,5 +1,5 @@
1
1
  require 'eventmachine'
2
- Dir[File.dirname(__FILE__) + '/pi_piper/*.rb'].each {|file| require file }#unless file.end_with?('bcm2835.rb') }
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.abort_on_exception = true
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.
@@ -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.img'
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, :bcm2835_gpio_set_pud, [:uint8, :uint8], :void
31
+ attach_function :pin_set_pud, :bcm2835_gpio_set_pud, [:uint8, :uint8], :void
25
32
 
26
33
  def self.pin_input(pin)
27
- File.open("/sys/class/gpio/export", "w") { |f| f.write("#{pin}") }
28
- File.open("/sys/class/gpio/gpio#{pin}/direction", "w") { |f| f.write("in") }
34
+ export(pin)
35
+ pin_direction(pin, 'in')
29
36
  end
30
-
37
+
31
38
  def self.pin_set(pin, value)
32
- File.open("/sys/class/gpio/gpio#{pin}/value", 'w') {|f| f.write("#{value}") }
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 Bcm2835.pin_output(pin)
36
- File.open("/sys/class/gpio/export", "w") { |f| f.write("#{pin}") }
37
- File.open("/sys/class/gpio/gpio#{pin}/direction", "w") { |f| f.write("out") }
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