pi_piper 2.0.beta.4 → 2.0.0

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.
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