beaglebone 1.0.4
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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +6 -0
- data/beaglebone.gemspec +12 -0
- data/examples/ain.rb +92 -0
- data/examples/gpio.rb +196 -0
- data/examples/i2c.rb +110 -0
- data/examples/pwm.rb +63 -0
- data/examples/shiftregister.rb +12 -0
- data/examples/spi.rb +62 -0
- data/examples/uart.rb +64 -0
- data/lib/beaglebone/ain.rb +480 -0
- data/lib/beaglebone/beaglebone.rb +287 -0
- data/lib/beaglebone/gpio.rb +598 -0
- data/lib/beaglebone/i2c.rb +186 -0
- data/lib/beaglebone/pwm.rb +479 -0
- data/lib/beaglebone/shiftregister.rb +21 -0
- data/lib/beaglebone/spi.rb +322 -0
- data/lib/beaglebone/uart.rb +388 -0
- data/lib/beaglebone.rb +8 -0
- metadata +63 -0
@@ -0,0 +1,598 @@
|
|
1
|
+
# == gpio.rb
|
2
|
+
# This file contains the GPIO methods
|
3
|
+
|
4
|
+
module Beaglebone #:nodoc:
|
5
|
+
# GPIO
|
6
|
+
# procedural methods for GPIO control
|
7
|
+
# == Summary
|
8
|
+
# #pin_mode is called to initialize a pin.
|
9
|
+
# Further basic functionality is available with #digital_read and #digital_write
|
10
|
+
module GPIO
|
11
|
+
class << self
|
12
|
+
# GPIO modes
|
13
|
+
MODES = [ :IN, :OUT ]
|
14
|
+
# GPIO states
|
15
|
+
STATES = { :HIGH => 1, :LOW => 0 }
|
16
|
+
# Edge trigger options
|
17
|
+
EDGES = [ :NONE, :RISING, :FALLING, :BOTH ]
|
18
|
+
|
19
|
+
# Initialize a GPIO pin
|
20
|
+
#
|
21
|
+
# @param pin should be a symbol representing the header pin
|
22
|
+
# @param mode should specify the mode of the pin, either :IN or :OUT
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# GPIO.pin_mode(:P9_12, :OUT)
|
26
|
+
# GPIO.pin_mode(:P9_11, :IN)
|
27
|
+
def pin_mode(pin, mode)
|
28
|
+
|
29
|
+
#make sure a valid mode was passed
|
30
|
+
check_valid_mode(mode)
|
31
|
+
|
32
|
+
#make sure a valid pin was passed and that it supports GPIO
|
33
|
+
Beaglebone::check_valid_pin(pin, :gpio)
|
34
|
+
|
35
|
+
#get info from PINS hash
|
36
|
+
pininfo = PINS[pin]
|
37
|
+
|
38
|
+
#if pin is enabled for something else, disable it
|
39
|
+
if Beaglebone::get_pin_status(pin) && Beaglebone::get_pin_status(pin, :type) != :gpio
|
40
|
+
Beaglebone::disable_pin(pin)
|
41
|
+
end
|
42
|
+
|
43
|
+
#export pin unless its an on board LED, if it isn't already exported
|
44
|
+
if pininfo[:led]
|
45
|
+
raise StandardError, "LEDs only support OUT mode: #{pin.to_s}" unless mode == :OUT
|
46
|
+
File.open("#{gpio_directory(pin)}/trigger", 'w') { |f| f.write('gpio') }
|
47
|
+
else
|
48
|
+
File.open('/sys/class/gpio/export', 'w') { |f| f.write pininfo[:gpio] }
|
49
|
+
#check to see if pin is GPIO enabled in /sys/class/gpio/
|
50
|
+
raise StandardError, "GPIO was unable to initalize pin: #{pin.to_s}" unless enabled?(pin)
|
51
|
+
end unless Beaglebone::get_pin_status(pin, :type) == :gpio
|
52
|
+
|
53
|
+
#set pin mode
|
54
|
+
unless pininfo[:led]
|
55
|
+
set_gpio_mode(pin, mode)
|
56
|
+
dir = read_gpio_direction(pin)
|
57
|
+
raise StandardError, "GPIO was unable to set mode: #{pin.to_s} to #{mode.to_s} (#{dir})" if mode != dir
|
58
|
+
end
|
59
|
+
|
60
|
+
Beaglebone::set_pin_status(pin, :mode, mode)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Sets a pin's output state
|
64
|
+
#
|
65
|
+
# @param pin should be a symbol representing the header pin
|
66
|
+
# @param state should be a symbol representin the state, :HIGH or :LOW
|
67
|
+
#
|
68
|
+
# @example
|
69
|
+
# GPIO.digital_write(:P9_12, :HIGH)
|
70
|
+
# GPIO.digital_write(:P9_12, :LOW)
|
71
|
+
def digital_write(pin, state)
|
72
|
+
check_valid_state(state)
|
73
|
+
check_gpio_enabled(pin)
|
74
|
+
|
75
|
+
raise StandardError, "PIN not in GPIO OUT mode: #{pin}" unless get_gpio_mode(pin) == :OUT
|
76
|
+
|
77
|
+
fd = get_value_fd(pin)
|
78
|
+
fd.write STATES[state.to_sym.upcase].to_s
|
79
|
+
fd.flush
|
80
|
+
Beaglebone::set_pin_status(pin, :state, state)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Reads a pin's input state and return that value
|
84
|
+
#
|
85
|
+
# @param pin should be a symbol representing the header pin, i.e. :P9_11
|
86
|
+
#
|
87
|
+
# @return [Symbol] :HIGH or :LOW
|
88
|
+
#
|
89
|
+
# @example
|
90
|
+
# GPIO.digital_read(:P9_11) => :HIGH
|
91
|
+
def digital_read(pin)
|
92
|
+
check_gpio_enabled(pin)
|
93
|
+
|
94
|
+
raise StandardError, "PIN not in GPIO IN mode: #{pin}" unless get_gpio_mode(pin) == :IN
|
95
|
+
|
96
|
+
fd = get_value_fd(pin)
|
97
|
+
fd.rewind
|
98
|
+
value = fd.read.to_s.strip
|
99
|
+
state = STATES.key(value.to_i)
|
100
|
+
|
101
|
+
Beaglebone::set_pin_status(pin, :state, state)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Runs a callback on an edge trigger event
|
105
|
+
# This creates a new thread that runs in the background
|
106
|
+
#
|
107
|
+
# @param callback A method to call when the edge trigger is detected. This method should take 3 arguments, the pin, the edge, and the counter
|
108
|
+
# @param pin should be a symbol representing the header pin, i.e. :P9_11
|
109
|
+
# @param edge should be a symbol representing the trigger type, e.g. :RISING, :FALLING, :BOTH
|
110
|
+
# @param timeout is optional and specifies a time window to wait
|
111
|
+
# @param repeats is optional and specifies the number of times the callback will be run
|
112
|
+
#
|
113
|
+
# @example
|
114
|
+
# GPIO.run_on_edge(lambda { |pin,edge,count| puts "[#{count}] #{pin} -- #{edge}" }, :P9_11, :RISING)
|
115
|
+
def run_on_edge(callback, pin, edge, timeout = nil, repeats=nil)
|
116
|
+
|
117
|
+
raise StandardError, "Already waiting for trigger on pin: #{pin}" if Beaglebone::get_pin_status(pin, :trigger)
|
118
|
+
raise StandardError, "Already waiting for trigger on pin: #{pin}" if Beaglebone::get_pin_status(pin, :thread)
|
119
|
+
|
120
|
+
thread = Thread.new(callback, pin, edge, timeout, repeats) do |c, p, e, t, r|
|
121
|
+
begin
|
122
|
+
count = 0
|
123
|
+
loop do
|
124
|
+
|
125
|
+
state = wait_for_edge(p, e, t, false)
|
126
|
+
|
127
|
+
c.call(p, state, count) if c
|
128
|
+
count += 1
|
129
|
+
break if r && count >= r
|
130
|
+
end
|
131
|
+
rescue => ex
|
132
|
+
puts ex
|
133
|
+
puts ex.backtrace
|
134
|
+
ensure
|
135
|
+
cleanup_edge_trigger(p)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
Beaglebone::set_pin_status(pin, :thread, thread)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Runs a callback one time on an edge trigger event
|
143
|
+
# this is a convenience method for run_on_edge
|
144
|
+
# @see #run_on_edge
|
145
|
+
def run_once_on_edge(callback, pin, edge, timeout = nil)
|
146
|
+
run_on_edge(callback, pin, edge, timeout, 1)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Stops any threads waiting for data on specified pin
|
150
|
+
#
|
151
|
+
# @param pin should be a symbol representing the header pin, i.e. :P9_11
|
152
|
+
def stop_edge_wait(pin)
|
153
|
+
thread = Beaglebone::get_pin_status(pin, :thread)
|
154
|
+
|
155
|
+
thread.exit if thread
|
156
|
+
thread.join if thread
|
157
|
+
end
|
158
|
+
|
159
|
+
# Wait for an edge trigger
|
160
|
+
# Returns the type that triggered the event, e.g. :RISING, :FALLING, :BOTH
|
161
|
+
#
|
162
|
+
# @returns [Symbol] :RISING, :FALLING, or :BOTH
|
163
|
+
#
|
164
|
+
# @param pin should be a symbol representing the header pin, i.e. :P9_11
|
165
|
+
# @param edge should be a symbol representing the trigger type, e.g. :RISING, :FALLING, :BOTH
|
166
|
+
# @param timeout is optional and specifies a time window to wait
|
167
|
+
# @param disable is optional. If set, edge trigger detection is cleared on return
|
168
|
+
#
|
169
|
+
# @example
|
170
|
+
# wait_for_edge(:P9_11, :RISING, 30) => :RISING
|
171
|
+
def wait_for_edge(pin, edge, timeout = nil, disable=true)
|
172
|
+
check_valid_edge(edge)
|
173
|
+
raise ArgumentError, "Cannot wait for edge trigger NONE: #{pin}" if edge.to_sym.upcase == :NONE
|
174
|
+
|
175
|
+
check_gpio_enabled(pin)
|
176
|
+
raise StandardError, "PIN not in GPIO IN mode: #{pin}" unless get_gpio_mode(pin) == :IN
|
177
|
+
|
178
|
+
#ensure we're the only ones waiting for this trigger
|
179
|
+
if Beaglebone::get_pin_status(pin, :thread) && Beaglebone::get_pin_status(pin, :thread) != Thread.current
|
180
|
+
raise StandardError, "Already waiting for trigger on pin: #{pin}"
|
181
|
+
end
|
182
|
+
|
183
|
+
if Beaglebone::get_pin_status(pin, :trigger) && Beaglebone::get_pin_status(pin, :thread) != Thread.current
|
184
|
+
raise StandardError, "Already waiting for trigger on pin: #{pin}"
|
185
|
+
end
|
186
|
+
|
187
|
+
set_gpio_edge(pin, edge)
|
188
|
+
|
189
|
+
fd = get_value_fd(pin)
|
190
|
+
fd.read
|
191
|
+
|
192
|
+
#select will return fd into the error set "es" if it recieves an interrupt
|
193
|
+
_, _, es = IO.select(nil, nil, [fd], timeout)
|
194
|
+
|
195
|
+
set_gpio_edge(pin, :NONE) if disable
|
196
|
+
|
197
|
+
es ? digital_read(pin) : nil
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
# Resets all the GPIO pins that we have used and unexport them
|
202
|
+
def cleanup
|
203
|
+
get_gpio_pins.each { |x| disable_gpio_pin(x) }
|
204
|
+
end
|
205
|
+
|
206
|
+
# Returns true if specified pin is enabled in GPIO mode, else false
|
207
|
+
def enabled?(pin)
|
208
|
+
|
209
|
+
return true if Beaglebone::get_pin_status(pin, :type) == :gpio
|
210
|
+
|
211
|
+
return false unless valid?(pin)
|
212
|
+
if Dir.exists?(gpio_directory(pin))
|
213
|
+
|
214
|
+
Beaglebone::set_pin_status(pin, :type, :gpio)
|
215
|
+
return true
|
216
|
+
end
|
217
|
+
|
218
|
+
false
|
219
|
+
end
|
220
|
+
|
221
|
+
# Sends data to a shift register
|
222
|
+
#
|
223
|
+
# @param latch_pin should be a symbol representing the header pin, i.e. :P9_12
|
224
|
+
# @param clock_pin should be a symbol representing the header pin, i.e. :P9_12
|
225
|
+
# @param data_pin should be a symbol representing the header pin, i.e. :P9_12
|
226
|
+
# @param data Integer value to write to the shift register
|
227
|
+
# @param lsb optional, send least significant bit first if set
|
228
|
+
#
|
229
|
+
# @example
|
230
|
+
# GPIO.shift_out(:P9_11, :P9_12, :P9_13, 255)
|
231
|
+
def shift_out(latch_pin, clock_pin, data_pin, data, lsb=nil)
|
232
|
+
raise ArgumentError, "data must be > 0 (#{date}" if data < 0
|
233
|
+
digital_write(latch_pin, :LOW)
|
234
|
+
|
235
|
+
binary = data.to_s(2)
|
236
|
+
pad = 8 - (binary.size % 8 )
|
237
|
+
binary = (' ' * pad) + binary
|
238
|
+
|
239
|
+
binary.reverse! if lsb
|
240
|
+
|
241
|
+
binary.each_char do |bit|
|
242
|
+
digital_write(clock_pin, :LOW)
|
243
|
+
digital_write(data_pin, bit == '0' ? :LOW : :HIGH)
|
244
|
+
digital_write(clock_pin, :HIGH)
|
245
|
+
end
|
246
|
+
digital_write(latch_pin, :HIGH)
|
247
|
+
end
|
248
|
+
|
249
|
+
# Returns last known state from +pin+, reads state if unknown
|
250
|
+
# @returns [Symbol] :HIGH or :LOW
|
251
|
+
def get_gpio_state(pin)
|
252
|
+
check_gpio_enabled(pin)
|
253
|
+
|
254
|
+
state = Beaglebone::get_pin_status(pin, :state)
|
255
|
+
return state if state
|
256
|
+
|
257
|
+
digital_read(pin)
|
258
|
+
end
|
259
|
+
|
260
|
+
# Returns mode from +pin+, reads mode if unknown
|
261
|
+
# @returns [Symbol] :IN or :OUT
|
262
|
+
def get_gpio_mode(pin)
|
263
|
+
check_gpio_enabled(pin)
|
264
|
+
|
265
|
+
mode = Beaglebone::get_pin_status(pin, :mode)
|
266
|
+
return mode if mode
|
267
|
+
|
268
|
+
read_gpio_direction(pin)
|
269
|
+
end
|
270
|
+
|
271
|
+
# Set GPIO mode on an initialized pin
|
272
|
+
#
|
273
|
+
# @param pin should be a symbol representing the header pin
|
274
|
+
# @param mode should specify the mode of the pin, either :IN or :OUT
|
275
|
+
#
|
276
|
+
# @example
|
277
|
+
# GPIO.set_gpio_mode(:P9_12, :OUT)
|
278
|
+
# GPIO.set_gpio_mode(:P9_11, :IN)
|
279
|
+
def set_gpio_mode(pin, mode)
|
280
|
+
Beaglebone::check_valid_pin(pin, :gpio)
|
281
|
+
check_valid_mode(mode)
|
282
|
+
check_gpio_enabled(pin)
|
283
|
+
|
284
|
+
File.open("#{gpio_directory(pin)}/direction", 'w') { |f| f.write mode.to_s.downcase }
|
285
|
+
Beaglebone::set_pin_status(pin, :mode, mode)
|
286
|
+
end
|
287
|
+
|
288
|
+
# Set GPIO edge trigger type on an initialized pin
|
289
|
+
#
|
290
|
+
# @param pin should be a symbol representing the header pin
|
291
|
+
# @param edge should be a symbol representing the trigger type, e.g. :RISING, :FALLING, :BOTH
|
292
|
+
# @param force is optional, if set will set the mode even if already set
|
293
|
+
#
|
294
|
+
# @example
|
295
|
+
# GPIO.set_gpio_edge(:P9_11, :RISING)
|
296
|
+
def set_gpio_edge(pin, edge, force=nil)
|
297
|
+
check_valid_edge(edge)
|
298
|
+
Beaglebone::check_valid_pin(pin, :gpio)
|
299
|
+
|
300
|
+
raise StandardError, "PIN not in GPIO IN mode: #{pin}" unless get_gpio_mode(pin) == :IN
|
301
|
+
|
302
|
+
return if get_gpio_edge(pin) == edge && !force
|
303
|
+
|
304
|
+
File.open("#{gpio_directory(pin)}/edge", 'w') { |f| f.write edge.to_s.downcase }
|
305
|
+
testedge = read_gpio_edge(pin)
|
306
|
+
if testedge != edge.to_s.downcase
|
307
|
+
Beaglebone::delete_pin_status(pin, :trigger)
|
308
|
+
raise StandardError, "GPIO was unable to set edge: #{pin.to_s} to #{edge.to_s}"
|
309
|
+
end
|
310
|
+
|
311
|
+
if edge.to_sym == :NONE
|
312
|
+
Beaglebone::delete_pin_status(pin, :trigger)
|
313
|
+
else
|
314
|
+
Beaglebone::set_pin_status(pin, :trigger, edge.to_sym)
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
|
319
|
+
# Returns the GPIO edge trigger type on an initialized pin
|
320
|
+
# @return [Symbol] :NONE, :RISING, :FALLING, or :BOTH
|
321
|
+
def get_gpio_edge(pin)
|
322
|
+
check_gpio_enabled(pin)
|
323
|
+
|
324
|
+
edge = Beaglebone::get_pin_status(pin, :trigger)
|
325
|
+
return edge if edge
|
326
|
+
|
327
|
+
read_gpio_edge(pin)
|
328
|
+
end
|
329
|
+
|
330
|
+
# Return an array of GPIO pins in use
|
331
|
+
#
|
332
|
+
# @return [Array<Symbol>]
|
333
|
+
#
|
334
|
+
# @example
|
335
|
+
# GPIO.get_gpio_pins => [:P9_12, :P9_13]
|
336
|
+
def get_gpio_pins
|
337
|
+
Beaglebone.pinstatus.clone.select { |x,y| x if y[:type] == :gpio && !PINS[x][:led] }.keys
|
338
|
+
end
|
339
|
+
|
340
|
+
# Disable a GPIO pin
|
341
|
+
#
|
342
|
+
# @param pin should be a symbol representing the header pin
|
343
|
+
def disable_gpio_pin(pin)
|
344
|
+
|
345
|
+
Beaglebone::check_valid_pin(pin, :gpio)
|
346
|
+
|
347
|
+
pininfo = PINS[pin]
|
348
|
+
|
349
|
+
close_value_fd(pin)
|
350
|
+
|
351
|
+
#close any running threads
|
352
|
+
stop_edge_wait(pin)
|
353
|
+
|
354
|
+
#write to unexport to disable gpio
|
355
|
+
File.open('/sys/class/gpio/unexport', 'w') { |f| f.write(pininfo[:gpio]) }
|
356
|
+
|
357
|
+
#remove status from hash so following enabled? call checks actual system
|
358
|
+
Beaglebone::delete_pin_status(pin)
|
359
|
+
|
360
|
+
#check to see if pin is GPIO enabled in /sys/class/gpio/
|
361
|
+
raise StandardError, "GPIO was unable to uninitalize pin: #{pin.to_s}" if enabled?(pin)
|
362
|
+
|
363
|
+
end
|
364
|
+
|
365
|
+
private
|
366
|
+
|
367
|
+
#ensure edge type is valid
|
368
|
+
def check_valid_edge(edge)
|
369
|
+
raise ArgumentError, "No such edge: #{edge.to_s}" unless EDGES.include?(edge)
|
370
|
+
end
|
371
|
+
|
372
|
+
#read gpio edge file
|
373
|
+
def read_gpio_edge(pin)
|
374
|
+
check_gpio_enabled(pin)
|
375
|
+
File.open("#{gpio_directory(pin)}/edge", 'r').read.to_s.strip
|
376
|
+
end
|
377
|
+
|
378
|
+
#check if pin is valid to use as gpio pin
|
379
|
+
def valid?(pin)
|
380
|
+
#check to see if pin exists
|
381
|
+
pin = pin.to_sym.upcase
|
382
|
+
|
383
|
+
return false unless PINS[pin]
|
384
|
+
return false unless PINS[pin][:gpio]
|
385
|
+
|
386
|
+
true
|
387
|
+
end
|
388
|
+
|
389
|
+
#set edge trigger to none
|
390
|
+
def cleanup_edge_trigger(pin)
|
391
|
+
if Beaglebone::get_pin_status(pin, :thread) == Thread.current
|
392
|
+
set_gpio_edge(pin, :NONE)
|
393
|
+
Beaglebone::delete_pin_status(pin, :thread)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
#convenience method for getting gpio dir in /sys
|
398
|
+
def gpio_directory(pin)
|
399
|
+
raise StandardError, 'Invalid Pin' unless valid?(pin)
|
400
|
+
#led's are in a special place
|
401
|
+
if PINS[pin][:led]
|
402
|
+
"/sys/class/leds/beaglebone:green:#{pin.to_s.downcase}"
|
403
|
+
else
|
404
|
+
#normal gpio pins
|
405
|
+
"/sys/class/gpio/gpio#{PINS[pin][:gpio]}"
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
#read gpio direction file
|
410
|
+
def read_gpio_direction(pin)
|
411
|
+
check_gpio_enabled(pin)
|
412
|
+
|
413
|
+
Beaglebone::set_pin_status(pin, :mode, File.open("#{gpio_directory(pin)}/direction", 'r').read.to_s.strip.to_sym.upcase)
|
414
|
+
end
|
415
|
+
|
416
|
+
#return the open value fd, or open if needed
|
417
|
+
def get_value_fd(pin)
|
418
|
+
check_gpio_enabled(pin)
|
419
|
+
|
420
|
+
fd = Beaglebone::get_pin_status(pin, :fd_value)
|
421
|
+
return fd if fd
|
422
|
+
|
423
|
+
pininfo = PINS[pin]
|
424
|
+
|
425
|
+
#leds aren't normal gpio pins, we can toggle them on and off however.
|
426
|
+
if pininfo[:led]
|
427
|
+
fd = File.open("#{gpio_directory(pin)}/brightness", 'w+')
|
428
|
+
else
|
429
|
+
fd = File.open("#{gpio_directory(pin)}/value", 'w+')
|
430
|
+
end
|
431
|
+
|
432
|
+
Beaglebone::set_pin_status(pin, :fd_value, fd)
|
433
|
+
end
|
434
|
+
|
435
|
+
#close value fd if open
|
436
|
+
def close_value_fd(pin)
|
437
|
+
fd = Beaglebone::get_pin_status(pin, :fd_value)
|
438
|
+
fd.close if fd
|
439
|
+
Beaglebone::delete_pin_status(pin, :fd_value)
|
440
|
+
end
|
441
|
+
|
442
|
+
#ensure state is valid
|
443
|
+
def check_valid_state(state)
|
444
|
+
#check to see if mode is valid
|
445
|
+
state = state.to_sym.upcase
|
446
|
+
raise ArgumentError, "No such state: #{state.to_s}" unless STATES.include?(state)
|
447
|
+
end
|
448
|
+
|
449
|
+
#ensure mode is valid
|
450
|
+
def check_valid_mode(mode)
|
451
|
+
#check to see if mode is valid
|
452
|
+
mode = mode.to_sym.upcase
|
453
|
+
raise ArgumentError, "No such mode: #{mode.to_s}" unless MODES.include?(mode)
|
454
|
+
end
|
455
|
+
|
456
|
+
#ensure gpio pin is enabled
|
457
|
+
def check_gpio_enabled(pin)
|
458
|
+
Beaglebone::check_valid_pin(pin, :gpio)
|
459
|
+
raise StandardError, "PIN not GPIO enabled: #{pin}" unless enabled?(pin)
|
460
|
+
end
|
461
|
+
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
465
|
+
# Object Oriented GPIO Implementation.
|
466
|
+
# This treats the pin as an object.
|
467
|
+
class GPIOPin
|
468
|
+
|
469
|
+
# Initialize a GPIO pin
|
470
|
+
# Return's a GPIOPin object, setting the pin mode on initialization
|
471
|
+
#
|
472
|
+
# @param mode should specify the mode of the pin, either :IN or :OUT
|
473
|
+
#
|
474
|
+
# @return [GPIOPin]
|
475
|
+
#
|
476
|
+
# @example
|
477
|
+
# p9_12 = GPIOPin.new(:P9_12, :OUT)
|
478
|
+
# p9_11 = GPIOPin.new(:P9_11, :IN)
|
479
|
+
def initialize(pin, mode)
|
480
|
+
@pin = pin
|
481
|
+
|
482
|
+
GPIO::pin_mode(@pin, mode)
|
483
|
+
end
|
484
|
+
|
485
|
+
# Sets a pin's output state
|
486
|
+
#
|
487
|
+
# @param state should be a symbol representin the state, :HIGH or :LOW
|
488
|
+
#
|
489
|
+
# @example
|
490
|
+
# p9_12 = GPIOPin.new(:P9_12, :OUT)
|
491
|
+
# p9_12.digital_write(:HIGH)
|
492
|
+
# p9_12.digital_write(:LOW)
|
493
|
+
def digital_write(state)
|
494
|
+
GPIO::digital_write(@pin, state)
|
495
|
+
end
|
496
|
+
|
497
|
+
# Reads a pin's input state and return that value
|
498
|
+
#
|
499
|
+
# @return [Symbol] :HIGH or :LOW
|
500
|
+
#
|
501
|
+
# @example
|
502
|
+
# p9_11 = GPIOPin.new(:P9_12, :OUT)
|
503
|
+
# p9_11.digital_read => :HIGH
|
504
|
+
def digital_read
|
505
|
+
GPIO::digital_read(@pin)
|
506
|
+
end
|
507
|
+
|
508
|
+
# Runs a callback on an edge trigger event
|
509
|
+
# This creates a new thread that runs in the background
|
510
|
+
#
|
511
|
+
# @param callback A method to call when the edge trigger is detected. This method should take 3 arguments, the pin, the edge, and the counter
|
512
|
+
# @param edge should be a symbol representing the trigger type, e.g. :RISING, :FALLING, :BOTH
|
513
|
+
# @param timeout is optional and specifies a time window to wait
|
514
|
+
# @param repeats is optional and specifies the number of times the callback will be run
|
515
|
+
#
|
516
|
+
# @example
|
517
|
+
# p9_11 = GPIOPin.new(:P9_11, :IN)
|
518
|
+
# p9_11.run_on_edge(lambda { |pin,edge,count| puts "[#{count}] #{pin} -- #{edge}" }, :P9_11, :RISING) def run_on_edge(callback, edge, timeout=nil, repeats=nil)
|
519
|
+
def run_on_edge(callback, edge, timeout=nil, repeats=nil)
|
520
|
+
GPIO::run_on_edge(callback, @pin, edge, timeout, repeats)
|
521
|
+
end
|
522
|
+
|
523
|
+
# Runs a callback one time on an edge trigger event
|
524
|
+
# this is a convenience method for run_on_edge
|
525
|
+
# @see #run_on_edge
|
526
|
+
def run_once_on_edge(callback, edge, timeout=nil)
|
527
|
+
GPIO::run_once_on_edge(callback, @pin, edge, timeout)
|
528
|
+
end
|
529
|
+
|
530
|
+
# Stops any threads waiting for data on this pin
|
531
|
+
#
|
532
|
+
def stop_edge_wait
|
533
|
+
GPIO::stop_edge_wait(@pin)
|
534
|
+
end
|
535
|
+
|
536
|
+
# Wait for an edge trigger
|
537
|
+
# Returns the type that triggered the event, e.g. :RISING, :FALLING, :BOTH
|
538
|
+
#
|
539
|
+
# @return [Symbol] :RISING, :FALLING, or :BOTH
|
540
|
+
#
|
541
|
+
# @param edge should be a symbol representing the trigger type, e.g. :RISING, :FALLING, :BOTH
|
542
|
+
# @param timeout is optional and specifies a time window to wait
|
543
|
+
#
|
544
|
+
# @example
|
545
|
+
# p9_11 = GPIOPin.new(:P9_11, :IN)
|
546
|
+
# p9_11.wait_for_edge(:RISING, 30) => :RISING
|
547
|
+
def wait_for_edge(edge, timeout=nil)
|
548
|
+
GPIO::wait_for_edge(@pin, edge, timeout)
|
549
|
+
end
|
550
|
+
|
551
|
+
# Returns last known state from +pin+, reads state if unknown
|
552
|
+
# @return [Symbol] :HIGH or :LOW
|
553
|
+
def get_gpio_state
|
554
|
+
GPIO::get_gpio_state(@pin)
|
555
|
+
end
|
556
|
+
|
557
|
+
# Returns mode from pin, reads mode if unknown
|
558
|
+
# @return [Symbol] :IN or :OUT
|
559
|
+
def get_gpio_mode
|
560
|
+
GPIO::get_gpio_mode(@pin)
|
561
|
+
end
|
562
|
+
|
563
|
+
# Returns the GPIO edge trigger type
|
564
|
+
# @return [Symbol] :NONE, :RISING, :FALLING, or :BOTH
|
565
|
+
def get_gpio_edge
|
566
|
+
GPIO::get_gpio_edge(@pin)
|
567
|
+
end
|
568
|
+
|
569
|
+
|
570
|
+
# Set GPIO mode on an initialized pin
|
571
|
+
#
|
572
|
+
# @param mode should specify the mode of the pin, either :IN or :OUT
|
573
|
+
#
|
574
|
+
# @example
|
575
|
+
# p9_12.set_gpio_mode(:OUT)
|
576
|
+
# p9_11.set_gpio_mode(:IN)
|
577
|
+
def set_gpio_mode(mode)
|
578
|
+
GPIO::set_gpio_mode(@pin, mode)
|
579
|
+
end
|
580
|
+
|
581
|
+
# Set GPIO edge trigger type
|
582
|
+
#
|
583
|
+
# @param edge should be a symbol representing the trigger type, e.g. :RISING, :FALLING, :BOTH
|
584
|
+
# @param force is optional, if set will set the mode even if already set
|
585
|
+
#
|
586
|
+
# @example
|
587
|
+
# p9_11.set_gpio_edge(:RISING)
|
588
|
+
def set_gpio_edge(edge, force=nil)
|
589
|
+
GPIO::set_gpio_edge(@pin, edge, force)
|
590
|
+
end
|
591
|
+
|
592
|
+
# Disable GPIO pin
|
593
|
+
def disable_gpio_pin
|
594
|
+
GPIO::disable_gpio_pin(@pin)
|
595
|
+
end
|
596
|
+
|
597
|
+
end
|
598
|
+
end
|