pi_piper 1.1.2 → 1.2

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.
data/Manifest CHANGED
@@ -2,5 +2,7 @@ Manifest
2
2
  README.md
3
3
  Rakefile
4
4
  lib/pi_piper.rb
5
+ lib/pi_piper/bcm2835.rb
6
+ lib/pi_piper/libbcm2835.img
5
7
  lib/pi_piper/pin.rb
6
- pi_piper.gemspec
8
+ lib/pi_piper/spi.rb
data/README.md CHANGED
@@ -4,7 +4,7 @@ Pi Piper brings event driven programming to the Raspberry Pi's GPIO pins. To get
4
4
 
5
5
  sudo gem install pi_piper
6
6
 
7
- Sample usage:
7
+ ### GPIO
8
8
  ```ruby
9
9
  require 'pi_piper'
10
10
 
@@ -26,6 +26,31 @@ sleep 1
26
26
  pin.off
27
27
  ```
28
28
 
29
+ ### SPI
30
+ Starting with version 1.2, PiPiper offers SPI support. Before utilizing SPI, ensure that you have Mike McCauley's [bcm2835 library](http://www.open.com.au/mikem/bcm2835/index.html) installed:
31
+
32
+ ls /usr/local/lib/libbcm2835.so
33
+
34
+ If that file is not present, and you try to utilize the PiPiper::Spi class, you will receive an error similar to:
35
+
36
+ LoadError: Could not open library '/usr/local/lib/libbcm2835.so': /usr/local/lib/libbcm2835.so: cannot open shared object file: No such file or directory
37
+ from /var/lib/gems/1.9.1/gems/ffi-1.3.1/lib/ffi/library.rb:123:in `block in ffi_lib'
38
+ from /var/lib/gems/1.9.1/gems/ffi-1.3.1/lib/ffi/library.rb:90:in `map'
39
+ from /var/lib/gems/1.9.1/gems/ffi-1.3.1/lib/ffi/library.rb:90:in `ffi_lib'
40
+ from /var/lib/gems/1.9.1/gems/pi_piper-1.2/lib/pi_piper/bcm2835.rb:6:in `<module:Bcm2835>'
41
+ from /var/lib/gems/1.9.1/gems/pi_piper-1.2/lib/pi_piper/bcm2835.rb:4:in `<module:PiPiper>'
42
+ from /var/lib/gems/1.9.1/gems/pi_piper-1.2/lib/pi_piper/bcm2835.rb:3:in `<top (required)>'
43
+ from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
44
+ from /usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
45
+ from /var/lib/gems/1.9.1/gems/pi_piper-1.2/lib/pi_piper/spi.rb:261:in `initialize'
46
+ from (irb):2:in `new'
47
+ from (irb):2
48
+ from /usr/bin/irb:12:in `<main>'
49
+
50
+ For those uninterested in SPI support, the bcm2835 is a "soft" requirement and is lazy loaded. If you never intended to use PiPiper::Spi, you shouldn't have to worry about this requirement.
51
+
52
+
53
+
29
54
  ## Example projects
30
55
 
31
56
  Looking for more examples/sample code for Pi Piper? Then check out the following example projects, complete with circuit diagrams:
@@ -33,6 +58,7 @@ Looking for more examples/sample code for Pi Piper? Then check out the following
33
58
  * [Project 1: Morse Code](https://github.com/jwhitehorn/pi_piper/wiki/Project-1:-Morse-Code)
34
59
  * [Project 2: Simple Switch](https://github.com/jwhitehorn/pi_piper/wiki/Project-2:-Simple-Switch)
35
60
  * [Project 3: 2-bit counter](https://github.com/jwhitehorn/pi_piper/wiki/Project-3:-2-bit-counter)
61
+ * [Project 4: MCP3008](https://github.com/jwhitehorn/pi_piper/wiki/Project-4:-MCP3008)
36
62
 
37
63
  ## License
38
64
 
data/Rakefile CHANGED
@@ -2,13 +2,13 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('pi_piper', '1.1.2') do |p|
5
+ Echoe.new('pi_piper', '1.2') do |p|
6
6
  p.description = "Event driven Raspberry Pi GPIO library"
7
7
  p.url = "http://github.com/jwhitehorn/pi_piper"
8
8
  p.author = "Jason Whitehorn"
9
9
  p.email = "jason.whitehorn@gmail.com"
10
10
  p.ignore_pattern = ["examples/**/*"]
11
- p.development_dependencies = []
11
+ p.development_dependencies = ['ffi']
12
12
  end
13
13
 
14
14
  Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/lib/pi_piper.rb CHANGED
@@ -1,4 +1,8 @@
1
1
  Dir[File.dirname(__FILE__) + '/pi_piper/*.rb'].each {|file| require file }
2
+ at_exit do
3
+ PiPiper::Bcm2835.close
4
+ end
5
+ PiPiper::Bcm2835.init
2
6
 
3
7
  module PiPiper
4
8
 
@@ -0,0 +1,38 @@
1
+ require 'ffi'
2
+
3
+ module PiPiper
4
+ module Bcm2835
5
+ extend FFI::Library
6
+ ffi_lib File.dirname(__FILE__) + '/libbcm2835.img'
7
+
8
+ SPI_MODE0 = 0
9
+ SPI_MODE1 = 1
10
+ SPI_MODE2 = 2
11
+ SPI_MODE3 = 3
12
+
13
+ attach_function :init, :bcm2835_init, [], :uint8
14
+ attach_function :close, :bcm2835_close, [], :uint8
15
+
16
+ attach_function :spi_begin, :bcm2835_spi_begin, [], :uint8
17
+ attach_function :spi_end, :bcm2835_spi_end, [], :uint8
18
+ attach_function :spi_transfer, :bcm2835_spi_transfer, [:uint8], :uint8
19
+ attach_function :spi_transfernb, :bcm2835_spi_transfernb, [:pointer, :pointer, :uint], :void
20
+ attach_function :spi_clock, :bcm2835_spi_setClockDivider, [:uint8], :void
21
+ attach_function :spi_bit_order, :bcm2835_spi_setBitOrder, [:uint8], :void
22
+ attach_function :spi_chip_select, :bcm2835_spi_chipSelect, [:uint8], :void
23
+ attach_function :spi_set_data_mode, :bcm2835_spi_setDataMode, [:uint8], :void
24
+ attach_function :spi_chip_select_polarity,
25
+ :bcm2835_spi_setChipSelectPolarity, [:uint8, :uint8], :void
26
+
27
+ def self.spi_transfer_bytes(data)
28
+ data_out = FFI::MemoryPointer.new(data.count)
29
+ data_in = FFI::MemoryPointer.new(data.count)
30
+ (0..data.count-1).each { |i| data_out.put_uint8(i, data[i]) }
31
+
32
+ spi_transfernb(data_out, data_in, data.count)
33
+
34
+ (0..data.count-1).map { |i| data_in.get_uint8(i) }
35
+ end
36
+
37
+ end
38
+ end
Binary file
@@ -0,0 +1,229 @@
1
+ =begin
2
+ Modifications Copyright 2013, Jason Whitehorn and released under the terms
3
+ of the license included in README.md
4
+
5
+ Based on works, Copyright (c) 2012 Joshua Nussbaum
6
+
7
+ MIT License
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining
10
+ a copy of this software and associated documentation files (the
11
+ "Software"), to deal in the Software without restriction, including
12
+ without limitation the rights to use, copy, modify, merge, publish,
13
+ distribute, sublicense, and/or sell copies of the Software, and to
14
+ permit persons to whom the Software is furnished to do so, subject to
15
+ the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be
18
+ included in all copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
+ =end
28
+
29
+ module PiPiper
30
+ class Spi
31
+ # 65536 = 256us = 4kHz
32
+ CLOCK_DIVIDER_65536 = 0
33
+ # 32768 = 126us = 8kHz
34
+ CLOCK_DIVIDER_32768 = 32768
35
+ # 16384 = 64us = 15.625kHz
36
+ CLOCK_DIVIDER_16384 = 16384
37
+ # 8192 = 32us = 31.25kHz
38
+ CLOCK_DIVIDER_8192 = 8192
39
+ # 4096 = 16us = 62.5kHz
40
+ CLOCK_DIVIDER_4096 = 4096
41
+ # 2048 = 8us = 125kHz
42
+ CLOCK_DIVIDER_2048 = 2048
43
+ # 1024 = 4us = 250kHz
44
+ CLOCK_DIVIDER_1024 = 1024
45
+ # 512 = 2us = 500kHz
46
+ CLOCK_DIVIDER_512 = 512
47
+ # 256 = 1us = 1MHz
48
+ CLOCK_DIVIDER_256 = 256
49
+ # 128 = 500ns = = 2MHz
50
+ CLOCK_DIVIDER_128 = 128
51
+ # 64 = 250ns = 4MHz
52
+ CLOCK_DIVIDER_64 = 64
53
+ # 32 = 125ns = 8MHz
54
+ CLOCK_DIVIDER_32 = 32
55
+ # 16 = 50ns = 20MHz
56
+ CLOCK_DIVIDER_16 = 16
57
+
58
+ # Least signifigant bit first, e.g. 4 = 0b001
59
+ LSBFIRST = 0
60
+ # Most signifigant bit first, e.g. 4 = 0b100
61
+ MSBFIRST = 1
62
+
63
+ # Select Chip 0
64
+ CHIP_SELECT_0 = 0
65
+ # Select Chip 1
66
+ CHIP_SELECT_1 = 1
67
+ # Select both chips (ie pins CS1 and CS2 are asserted)
68
+ CHIP_SELECT_BOTH = 2
69
+ # No CS, control it yourself
70
+ CHIP_SELECT_NONE = 3
71
+
72
+ def self.set_mode(cpol, cpha)
73
+ mode = SPI_MODE0 #default
74
+ mode = SPI_MODE1 if cpol == 0 and cpha == 1
75
+ mode = SPI_MODE2 if cpol == 1 and cpha == 0
76
+ mode = SPI_MODE3 if cpol == 1 and cpha == 1
77
+ Bcma2835.spi_set_data_mode mode
78
+ end
79
+
80
+ def self.begin(chip=nil)
81
+ Bcm2835.spi_begin
82
+ chip = CHIP_SELECT_0 if !chip && block_given?
83
+ spi = new(chip)
84
+
85
+ if block_given?
86
+ begin
87
+ yield(spi)
88
+ ensure
89
+ self.end
90
+ end
91
+ else
92
+ spi
93
+ end
94
+ end
95
+
96
+ # Not needed when #begin is called with a block
97
+ def self.end
98
+ Bcm2835.spi_end
99
+ end
100
+
101
+ def clock(divider)
102
+ Bcm2835.spi_clock(divider)
103
+ end
104
+
105
+ def bit_order(order=MSBFIRST)
106
+ if order.is_a?(Range)
107
+ if order.begin < order.end
108
+ order = LSBFIRST
109
+ else
110
+ order = MSBFIRST
111
+ end
112
+ end
113
+
114
+ Bcm2835.spi_bit_order(order)
115
+ end
116
+
117
+ # Activate a specific chip so that communication can begin
118
+ #
119
+ # When a block is provided, the chip is automatically deactivated after the block completes.
120
+ # When a block is not provided, the user is responsible for calling chip_select(CHIP_SELECT_NONE)
121
+ #
122
+ # @example With block (preferred)
123
+ # spi.chip_select do
124
+ # spi.write(0xFF)
125
+ # end
126
+ #
127
+ # @example Without block
128
+ # spi.chip_select(CHIP_SELECT_0)
129
+ # spi.write(0xFF)
130
+ # spi.write(0x22)
131
+ # spi.chip_select(CHIP_SELECT_NONE)
132
+ #
133
+ # @yield
134
+ # @param [optional, CHIP_SELECT_*] chip the chip select line options
135
+ def chip_select(chip=CHIP_SELECT_0)
136
+ chip = @chip if @chip
137
+ Bcm2835.spi_chip_select(chip)
138
+ if block_given?
139
+ begin
140
+ yield
141
+ ensure
142
+ Bcm2835.spi_chip_select(CHIP_SELECT_NONE)
143
+ end
144
+ end
145
+ end
146
+
147
+ # Configure the active state of the chip select line
148
+ #
149
+ # The default state for most chips is active low.
150
+ #
151
+ # "active low" means the clock line is kept high during idle, and goes low when communicating.
152
+ #
153
+ # "active high" means the clock line is kept low during idle, and goes high when communicating.
154
+ #
155
+ # @param [Boolean] active_low true for active low, false for active high
156
+ # @param [optional, CHIP_SELECT_*] chip one of CHIP_SELECT_*
157
+ def chip_select_active_low(active_low, chip=nil)
158
+ chip = @chip if @chip
159
+ chip = CHIP_SELECT_0 unless chip
160
+
161
+ Bcm2835.spi_chip_select_polarity(chip, active_low ? 0 : 1)
162
+ end
163
+
164
+ # Read from the bus
165
+ #
166
+ # @example Read a single byte
167
+ # byte = spi.read
168
+ #
169
+ # @example Read array of bytes
170
+ # array = spi.read(3)
171
+ #
172
+ #
173
+ # @param [optional, Number] count the number of bytes to read.
174
+ # When count is provided, an array is returned.
175
+ # When count is nil, a single byte is returned.
176
+ # @return [Number|Array] data that was read from the bus
177
+ def read(count=nil)
178
+ if count
179
+ write([0xFF] * count)
180
+ else
181
+ enable { Bcm2835.spi_transfer(0) }
182
+ end
183
+ end
184
+
185
+ # Write to the bus
186
+ #
187
+ # @example Write a single byte
188
+ # spi.write(0x22)
189
+ #
190
+ # @example Write multiple bytes
191
+ # spi.write(0x22, 0x33, 0x44)
192
+ #
193
+ # @return [Number|Array|String] data that came out of MISO during write
194
+ def write(*args)
195
+ case args.count
196
+ when 0
197
+ raise ArgumentError.new("missing arguments")
198
+ when 1
199
+ data = args.first
200
+ else
201
+ data = args
202
+ end
203
+
204
+ enable do
205
+ case data
206
+ when Numeric
207
+ Bcm2835.spi_transfer(data)
208
+ when Enumerable
209
+ Bcm2835.spi_transfer_bytes(data)
210
+ else
211
+ raise ArgumentError.new("#{data.class} is not valid data. Use Numeric or an Enumerable of numbers")
212
+ end
213
+ end
214
+ end
215
+
216
+ private
217
+ def initialize(chip)
218
+ @chip = chip
219
+ end
220
+
221
+ def enable(&block)
222
+ if @chip
223
+ chip_select(&block)
224
+ else
225
+ yield
226
+ end
227
+ end
228
+ end
229
+ end
data/pi_piper.gemspec CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "pi_piper"
5
- s.version = "1.1.2"
5
+ s.version = "1.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Jason Whitehorn"]
9
- s.date = "2013-01-20"
9
+ s.date = "2013-01-21"
10
10
  s.description = "Event driven Raspberry Pi GPIO library"
11
11
  s.email = "jason.whitehorn@gmail.com"
12
- s.extra_rdoc_files = ["README.md", "lib/pi_piper.rb", "lib/pi_piper/pin.rb"]
13
- s.files = ["Manifest", "README.md", "Rakefile", "lib/pi_piper.rb", "lib/pi_piper/pin.rb", "pi_piper.gemspec"]
12
+ s.extra_rdoc_files = ["README.md", "lib/pi_piper.rb", "lib/pi_piper/bcm2835.rb", "lib/pi_piper/libbcm2835.img", "lib/pi_piper/pin.rb", "lib/pi_piper/spi.rb"]
13
+ s.files = ["Manifest", "README.md", "Rakefile", "lib/pi_piper.rb", "lib/pi_piper/bcm2835.rb", "lib/pi_piper/libbcm2835.img", "lib/pi_piper/pin.rb", "lib/pi_piper/spi.rb", "pi_piper.gemspec"]
14
14
  s.homepage = "http://github.com/jwhitehorn/pi_piper"
15
15
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Pi_piper", "--main", "README.md"]
16
16
  s.require_paths = ["lib"]
@@ -22,8 +22,11 @@ Gem::Specification.new do |s|
22
22
  s.specification_version = 3
23
23
 
24
24
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
+ s.add_development_dependency(%q<ffi>, [">= 0"])
25
26
  else
27
+ s.add_dependency(%q<ffi>, [">= 0"])
26
28
  end
27
29
  else
30
+ s.add_dependency(%q<ffi>, [">= 0"])
28
31
  end
29
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pi_piper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: '1.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-20 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2013-01-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: Event driven Raspberry Pi GPIO library
15
31
  email: jason.whitehorn@gmail.com
16
32
  executables: []
@@ -18,13 +34,19 @@ extensions: []
18
34
  extra_rdoc_files:
19
35
  - README.md
20
36
  - lib/pi_piper.rb
37
+ - lib/pi_piper/bcm2835.rb
38
+ - lib/pi_piper/libbcm2835.img
21
39
  - lib/pi_piper/pin.rb
40
+ - lib/pi_piper/spi.rb
22
41
  files:
23
42
  - Manifest
24
43
  - README.md
25
44
  - Rakefile
26
45
  - lib/pi_piper.rb
46
+ - lib/pi_piper/bcm2835.rb
47
+ - lib/pi_piper/libbcm2835.img
27
48
  - lib/pi_piper/pin.rb
49
+ - lib/pi_piper/spi.rb
28
50
  - pi_piper.gemspec
29
51
  homepage: http://github.com/jwhitehorn/pi_piper
30
52
  licenses: []