Module: I2C::Drivers::MCP230xx

Defined in:
lib/i2c/drivers/mcp230xx.rb

Overview

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.

Instance Method Summary collapse

Instance Method Details

#[](pin) ⇒ Integer Also known as: read

Reads a IO-pin value.

Parameters:

  • pin (Integer)

    Pin number to set.

Returns:

  • (Integer)

    Pin value. Either HIGH or LOW.



105
106
107
108
109
110
111
112
# File 'lib/i2c/drivers/mcp230xx.rb', line 105

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

#[]=(pin, value) ⇒ Object Also known as: write

Sets a IO-pin value.

Parameters:

  • pin (Integer)

    Pin number to set.

  • value (Integer)

    Pin value. Either HIGH or LOW.

Raises:

  • (ArgumentError)


91
92
93
94
95
96
97
# File 'lib/i2c/drivers/mcp230xx.rb', line 91

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

#check_pin(pin) ⇒ Object

Checks a pin number for validity. Raises an exception if not valid. Returns nil otherwise.

Parameters:

  • pin (Integer)

    IO pin number.

Returns:

  • nil Raises an exception in all other cases.

Raises:

  • (ArgumentError)


122
123
124
125
# File 'lib/i2c/drivers/mcp230xx.rb', line 122

def check_pin(pin)
  raise ArgumentError, "Pin not 0-#{max_pin_no}" unless (0..max_pin_no).include?(pin)
  nil
end

#check_port(no) ⇒ Object

Checks a port number for validity. Raises an exception if not valid. Returns nil otherwise.

Parameters:

  • no (Integer)

    IO port number.

Returns:

  • nil Raises an exception in all other cases.

Raises:

  • (ArgumentError)


131
132
133
134
# File 'lib/i2c/drivers/mcp230xx.rb', line 131

def check_port(no)
  raise ArgumentError, "Only Ports 0-#{max_port_no} available." unless (0..max_port_no).include?(no)
  nil
end

#initialize(device, address) ⇒ Object

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.

Creates an instance representing exactly one MCP230xx on one I2C-bus.

Parameters:

  • device (IO, String)

    I2C-device file (usually /dev/i2c-0). Or an intantiated io class that supports the necessary operations (#read, #write and #ioctl).

  • address (Integer)

    Device address on the bus.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/i2c/drivers/mcp230xx.rb', line 42

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

#mode(pin, pin_mode) ⇒ Object

Sets the mode of a IO-pin.

Parameters:

  • pin (Integer)

    Pin number to set.

  • pin_mode (Integer)

    Pin mode. Either INPUT or OUTPUT.

Raises:

  • (ArgumentError)


79
80
81
82
83
84
85
86
# File 'lib/i2c/drivers/mcp230xx.rb', line 79

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) ⇒ Integer

Reads the mode of a IO-pin.

Parameters:

  • pin (Integer)

    Pin number to check.

Returns:

  • (Integer)

    Pin mode. Either INPUT or OUTPUT.



68
69
70
71
72
73
74
# File 'lib/i2c/drivers/mcp230xx.rb', line 68

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) ⇒ Array<Integer, Integer>

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].

Parameters:

  • pin (Integer)

    Pin number, begining at 0.

Returns:

  • (Array<Integer, Integer>)

    Port number and index in the port of the passed continuos pin number.



143
144
145
146
# File 'lib/i2c/drivers/mcp230xx.rb', line 143

def port_for_pin(pin)
  check_pin(pin)
  [pin / 8, pin % 8]
end

#set_bit_value(byte, bit, value) ⇒ Integer

Sets a bit in a byte to a defied state not touching the other bits.

Parameters:

  • byte (Integer)

    Byte to manipulate (LSB).

  • bit (Integer)

    Bit number to manipulate.

  • value (Integer)

    1 or 0; the new value of the bit.

Returns:

  • (Integer)

    The new byte

Raises:

  • (ArgumentError)


154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/i2c/drivers/mcp230xx.rb', line 154

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