# -*- ruby -*- # vim: set noet sta sw=4 ts=4 : require 'socket' require 'configurability' require 'loggability' require 'pathname' # A representation of a GPIO pin. # Manages basic reads/writes (HIGH/LOW). # class GPIO extend Configurability, Loggability # Default read timeout. TIMEOUT = 0.5 # The sysfs path. BASE = Pathname( "/sys/class/gpio" ) # Loggability API log_as :gpio ### Instance a new GPIO at +pin+. It will be automatically exported. ### def initialize( pin ) @pin = pin @paths = { export: BASE + "export", unexport: BASE + "unexport", edge: BASE + "gpio#{pin}" + "edge", direction: BASE + "gpio#{pin}" + "direction", value: BASE + "gpio#{pin}" + "value" } self.export rescue nil end # The GPIO PIN number. attr_reader :pin ### Mark this pin as either input or output. ### def mode( dir ) case dir.to_sym when :in, :out self.set( :direction ) { dir.to_s } else raise "Mode must be :in or :out." end end ### Hint at voltage measurement capture. ### def edge( mode ) case mode.to_sym when :none, :rising, :falling, :both self.set( :edge ) { mode.to_s } else raise "Edge must be one of: :none, :rising, :falling, or :both" end end ### Tell the operating system to make this gpio available to sysfs. ### def export self.set( :export ) { self.pin } end ### Remove this gpio from sysfs. ### def unexport self.set( :unexport ) { self.pin } end ### Write a single +val+ to the GPIO. ### def write( val ) self.set( :value ) { val } end ### Read a single value from the GPIO, with an optional timeout. ### def read( timeout=TIMEOUT ) io = @paths[ :value ].open ready = IO.select( [io], nil, nil, timeout ) return unless ready # timeout rv = io.read( 1 ).to_i self.log.debug "Read %p from GPIO %d" % [ rv, self.pin ] return rv ensure io.close end ######### protected ######### ### Generic write helper. ### def set( path, &block ) @paths[ path ].open( 'w' ) do |f| self.log.debug "Writing %p to %p of GPIO %d" % [ block.yield, path, self.pin ] f.puts( block.yield ) end end end