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

new(device, address) click to toggle source

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

[](pin) click to toggle source

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
Also aliased as: read
[]=(pin, value) click to toggle source

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
Also aliased as: write
check_pin(pin) click to toggle source
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
check_port(no) click to toggle source

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
mode(pin, pin_mode) click to toggle source

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
mode?(pin) click to toggle source

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
port_for_pin(pin) click to toggle source

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
read(pin)

Alias for a WiringPi compatible naming.

Alias for: []
set_bit_value(byte, bit, value) click to toggle source

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
write(pin, value)

Alias for a WiringPi compatible naming.

Alias for: []=