├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── examples └── led.rb ├── gpio.gemspec └── lib ├── gpio └── version.rb └── ruby-gpio.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | .bundle 4 | .config 5 | .yardoc 6 | Gemfile.lock 7 | InstalledFiles 8 | _yardoc 9 | coverage 10 | doc/ 11 | lib/bundler/man 12 | pkg 13 | rdoc 14 | spec/reports 15 | test/tmp 16 | test/version_tmp 17 | tmp 18 | *.bundle 19 | *.so 20 | *.o 21 | *.a 22 | mkmf.log 23 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | # Specify your gem's dependencies in gpio.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Chang Sau Sheong 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby-GPIO 2 | 3 | A Ruby DSL to interface with the Raspberry Pi GPIO. It wraps around the Linux sysfs-based GPIO interface and provides features to set pins as input or output, pull pins to high or low, and also to asynchronously watch for changes to a pin, then trigger a handler to react to it. 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | gem 'ruby-gpio' 10 | 11 | And then execute: 12 | 13 | $ bundle 14 | 15 | Or install it yourself as: 16 | 17 | $ gem install ruby-gpio 18 | 19 | ## Usage 20 | 21 | Example: 22 | 23 | ```ruby 24 | require 'ruby-gpio' 25 | 26 | # blue, yellow and led are labels, 22, 23 and 27 are GPIO pin numbers 27 | GPIO.access(blue: 23, yellow: 27, led: 22) do 28 | blue.as :in # set pin GPIO23, labeled blue, as an input pin 29 | yellow.as :in 30 | led.as :out 31 | 32 | # watch GPIO23 and turn the led on when it is set to high 33 | # use async to watch the pin asynchronously 34 | blue.async.watch_for(1) do 35 | led.on 36 | end 37 | # watch GPIO27 and turn the led off when it is set to high 38 | yellow.async.watch_for(1) do 39 | led.off 40 | end 41 | 42 | # sleep is only necessary if you're watching pins 43 | sleep 44 | end 45 | ``` 46 | 47 | ## Contributing 48 | 49 | 1. Fork it ( https://github.com/sausheong/ruby-gpio/fork ) 50 | 2. Create your feature branch (`git checkout -b my-new-feature`) 51 | 3. Commit your changes (`git commit -am 'Add some feature'`) 52 | 4. Push to the branch (`git push origin my-new-feature`) 53 | 5. Create a new Pull Request 54 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | 3 | -------------------------------------------------------------------------------- /examples/led.rb: -------------------------------------------------------------------------------- 1 | require 'ruby-gpio' 2 | 3 | # blue, yellow and led are labels, 22, 23 and 27 are GPIO pin numbers 4 | GPIO.access(blue: 23, yellow: 27, led: 22) do 5 | blue.as :in # set pin GPIO23, labeled blue, as an input pin 6 | yellow.as :in 7 | led.as :out 8 | 9 | # watch GPIO23 and turn the led on when it is pulled high 10 | # use async to watch the pin asynchronously 11 | blue.async.watch_for(1) do 12 | led.on 13 | end 14 | # watch GPIO27 and turn the led off when it is pulled high 15 | yellow.async.watch_for(1) do 16 | led.off 17 | end 18 | 19 | # sleep is only necessary if you're watching pins 20 | sleep 21 | end -------------------------------------------------------------------------------- /gpio.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'gpio/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "ruby-gpio" 8 | spec.version = Gpio::VERSION 9 | spec.authors = ["Chang Sau Sheong"] 10 | spec.email = ["sausheong@gmail.com"] 11 | spec.summary = %q{A Ruby DSL to interface with the Raspberry Pi GPIO.} 12 | spec.description = %q{Wraps around the Linux sysfs GPIO interface to control GPIO pins. Also watches pins and trigger handlers accordingly.} 13 | spec.homepage = "https://github.com/sausheong/ruby-gpio" 14 | spec.license = "MIT" 15 | 16 | spec.files = `git ls-files -z`.split("\x0") 17 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 18 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 19 | spec.require_paths = ["lib"] 20 | 21 | spec.add_development_dependency "bundler", "~> 1.6" 22 | spec.add_development_dependency "rake" 23 | spec.add_runtime_dependency "concurrent-ruby", "~> 0.8.0" 24 | spec.add_runtime_dependency "concurrent-ruby-ext", "~> 0.8.0" 25 | end 26 | -------------------------------------------------------------------------------- /lib/gpio/version.rb: -------------------------------------------------------------------------------- 1 | module Gpio 2 | VERSION = "0.0.2" 3 | end 4 | -------------------------------------------------------------------------------- /lib/ruby-gpio.rb: -------------------------------------------------------------------------------- 1 | require "gpio/version" 2 | 3 | require 'concurrent/async' 4 | 5 | class Hash 6 | def method_missing(name, *args, &block) 7 | return self[name.to_sym] 8 | end 9 | end 10 | 11 | 12 | module GPIO 13 | class Pin 14 | include Concurrent::Async 15 | attr_accessor :name, :number, :direction 16 | 17 | def initialize(name, number) 18 | init_mutex 19 | @name = name 20 | @number = number 21 | end 22 | 23 | # set input or output 24 | # gpio_num is the GPIO pin number, dir is the direction - either :out or :in 25 | def as(dir=:out) 26 | @direction = dir.to_s 27 | GPIO.write "gpio#{@number}/direction", @direction 28 | end 29 | 30 | # send a high value to the pin 31 | def on 32 | GPIO.write "gpio#{@number}/value", "1" 33 | end 34 | 35 | # send a low value to the pin 36 | def off 37 | GPIO.write "gpio#{@number}/value", "0" 38 | end 39 | 40 | # send a PWM (pulse width modulation) signal to the pin 41 | def pwm(value) 42 | GPIO.write "gpio#{@number}/value", value 43 | end 44 | 45 | # read from the pin 46 | def read 47 | GPIO.read @number 48 | end 49 | 50 | # watch the pin for change and trigger the block once 51 | def watch_once_for(value, &block) 52 | watching = true 53 | while watching 54 | if read == value 55 | GPIO.instance_eval &block 56 | watching = false 57 | end 58 | end 59 | end 60 | 61 | # watch the pin for change and trigger the block over and over again 62 | def watch_for(value, &block) 63 | while true 64 | if read == value 65 | GPIO.instance_eval &block 66 | end 67 | end 68 | end 69 | 70 | end 71 | 72 | class << self 73 | # main entry for the DSL 74 | def access(hash, &block) 75 | @pins = {} # a hash of available pins 76 | # set up pins 77 | hash.each do |k, v| 78 | @pins[k] = Pin.new(k.to_s, v) 79 | export v 80 | end 81 | begin 82 | instance_eval &block 83 | ensure 84 | # make sure all pins are unexported before we end the program 85 | hash.each do |k, v| 86 | unexport v 87 | end 88 | end 89 | end 90 | 91 | # method missing used to return the pin named earlier in the hash parameter to access 92 | def method_missing(name, *args, &block) 93 | if @pins.keys.include?(name) 94 | return @pins[name] 95 | end 96 | end 97 | 98 | def export(gpio_num) 99 | write "export", gpio_num 100 | end 101 | 102 | def unexport(gpio_num) 103 | write "unexport", gpio_num 104 | end 105 | 106 | def read(gpio_num) 107 | File.read("/sys/class/gpio/gpio#{gpio_num}/value").to_i 108 | end 109 | 110 | def write(command, value) 111 | File.open("/sys/class/gpio/#{command}", "w") do |f| 112 | f.write value 113 | end 114 | end 115 | end 116 | end 117 | --------------------------------------------------------------------------------