module I2C::Drivers::MCP230xx
Driver class for the Microchip MPC230xx IO-Expanders.
The interface is mostly compatible to the interface of the WiringPi gem. PWM is not supported though. On the other hand a more rubyesque interface is also provided.
Public Class Methods
Creates an instance representing exactly one MCP230xx
on one I2C-bus.
@todo This implementation currently assumes
that all registers of the same type are on a continuos address range. Implement a (less efficient) case for other situations.
@param device [IO, String] I2C-device file
(usually /dev/i2c-0). Or an intantiated io class that supports the necessary operations (#read, #write and #ioctl).
@param address [Integer] Device address on the bus.
# File lib/i2c/drivers/mcp230xx.rb, line 41 def initialize(device, address) if device.kind_of?(String) @device = ::I2C.create(device) else [ :read, :write ].each do |m| raise IncompatibleDeviceException, "Missing #{m} method in device object." unless device.respond_to?(m) end @device = device end @address = address @iodir = Array.new max_port_no.times { @iodir << 0xFF } # Direction is input initially @device.write(@address, port_count, iodir[0], *@iodir) @data = Array.new max_port_no.times { @data << 0xFF } @unpack_string = "C" * port_count @data = @device.read(@address, port_count, gpio[0]).unpack(@unpack_string) @dir = @device.read(@address, port_count, iodir[0]).unpack(@unpack_string) end
Public Instance Methods
Reads a IO-pin value. @param pin [Integer] Pin number to set. @return [Integer] Pin value. Either HIGH or LOW.
# File lib/i2c/drivers/mcp230xx.rb, line 104 def [](pin) check_pin(pin) # Raises if the pin is not valid index = port_for_pin(pin) @data = @device.read(@address, port_count, gpio[0]).unpack(@unpack_string) index = port_for_pin(pin) (@data[index[0]] >> index[1]) & 0x01 end
Sets a IO-pin value. @param pin [Integer] Pin number to set. @param value [Integer] Pin value. Either HIGH or LOW.
# File lib/i2c/drivers/mcp230xx.rb, line 90 def []=(pin, value) check_pin(pin) # Raises if the pin is not valid raise ArgumentError, 'invalid value' unless [0,1].include?(value) index = port_for_pin(pin) @data[index[0]] = set_bit_value(@data[index[0]], index[1], value) @device.write(@address, gpio[0], *@data) end
private
Checks a pin number for validity. Raises an exception if not valid. Returns nil otherwise. @param pin [Integer] IO pin number. @return nil Raises an exception in all other cases.
# File lib/i2c/drivers/mcp230xx.rb, line 121 def check_pin(pin) raise ArgumentError, "Pin not 0-#{max_pin_no}" unless (0..max_pin_no).include?(pin) nil end
Checks a port number for validity. Raises an exception if not valid. Returns nil otherwise. @param no [Integer] IO port number. @return nil Raises an exception in all other cases.
# File lib/i2c/drivers/mcp230xx.rb, line 130 def check_port(no) raise ArgumentError, "Only Ports 0-#{max_port_no} available." unless (0..max_port_no).include?(no) nil end
Sets the mode of a IO-pin. @param pin [Integer] Pin number to set. @param pin_mode [Integer] Pin mode. Either INPUT or OUTPUT.
# File lib/i2c/drivers/mcp230xx.rb, line 78 def mode(pin, pin_mode) check_pin(pin) # Raises if the pin is not valid raise ArgumentError, 'invalid value' unless [0,1].include?(pin_mode) index = port_for_pin(pin) @dir[index[0]] = set_bit_value(@dir[index[0]], index[1], pin_mode) @device.write(@address, iodir[0], *@dir) end
Reads the mode of a IO-pin. @param pin [Integer] Pin number to check. @return [Integer] Pin mode. Either INPUT or OUTPUT.
# File lib/i2c/drivers/mcp230xx.rb, line 67 def mode?(pin) check_pin(pin) # Raises if the pin is not valid @dir = @device.read(@address, port_count, iodir[0]).unpack(@unpack_string) index = port_for_pin(pin) (@dir[index[0]] >> index[1]) & 0x01 end
Returns a port no, index in port pair for a pin number.
E.g. Pin 14 is the is bit 7 of port 1. So the method returns [1,7].
@param pin [Integer] Pin number, begining at 0. @return [Array<Integer, Integer>] Port number and index in the port
of the passed continuos pin number.
# File lib/i2c/drivers/mcp230xx.rb, line 142 def port_for_pin(pin) check_pin(pin) [pin / 8, pin % 8] end
Sets a bit in a byte to a defied state not touching the other bits.
@param byte [Integer] Byte to manipulate (LSB). @param bit [Integer] Bit number to manipulate. @param value [Integer] 1 or 0; the new value of the bit. @return [Integer] The new byte
# File lib/i2c/drivers/mcp230xx.rb, line 153 def set_bit_value(byte, bit, value) [byte, bit, value].each do |p| raise ArgumentError, "Arguments must be Integer" unless p.kind_of? Integer end raise ArgumentError, "Only bits 0..7 are available." unless bit < 8 raise ArgumentError, "Value needs to be 0 or 1." unless (value == 0) or (value == 1) mask = 0x00 mask = (0x01 << bit) case value when 0 byte = (byte & ((~mask) & 0xFF)) & 0xFF when 1 byte = (byte | mask) & 0xFF else raise ArgumentError, "Bit not 0-7." end byte end