Skip to content

Add support for the MCP23008 I/O extender used by the Adafruit I2C/SPI Serial backpack #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 8, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions Raspberry.IO.Components/Expanders/Mcp23008/Mcp23008I2cConnection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#region References

using Raspberry.IO.InterIntegratedCircuit;

#endregion

namespace Raspberry.IO.Components.Expanders.Mcp23008
{
/// <summary>
/// Represents a I2C connection to a MCP23008 I/O Expander.
/// </summary>
/// <remarks>See <see cref="http://www.adafruit.com/datasheets/MCP23008.pdf"/> for more information.</remarks>
public class Mcp23008I2cConnection
{
#region Fields

private readonly I2cDeviceConnection connection;

#endregion

#region Instance Management

/// <summary>
/// Initializes a new instance of the <see cref="Mcp23008I2cConnection"/> class.
/// </summary>
/// <param name="connection">The connection.</param>
public Mcp23008I2cConnection(I2cDeviceConnection connection)
{
this.connection = connection;
}

#endregion

#region Methods

/// <summary>
/// Sets the direction.
/// </summary>
/// <param name="pin">The pin.</param>
/// <param name="direction">The direction.</param>
public void SetDirection(Mcp23008Pin pin, Mcp23008PinDirection direction)
{
var register = Register.IODIR;

connection.WriteByte((byte)register);
var directions = connection.ReadByte();

var bit = (byte)((int)pin & 0xFF);
var newDirections = (direction == Mcp23008PinDirection.Input)
? directions | bit
: directions & ~bit;

connection.Write(new[] { (byte)register, (byte)newDirections });
}

/// <summary>
/// Sets the polarity.
/// </summary>
/// <param name="pin">The pin.</param>
/// <param name="polarity">The polarity.</param>
public void SetPolarity(Mcp23008Pin pin, Mcp23008PinPolarity polarity)
{
var register = Register.IPOL;

connection.WriteByte((byte)register);
var polarities = connection.ReadByte();

var bit = (byte)((int)pin & 0xFF);
var newPolarities = (polarity == Mcp23008PinPolarity.Inverted)
? polarities | bit
: polarities & ~bit;

connection.Write(new[] { (byte)register, (byte)newPolarities });
}

/// <summary>
/// Sets the resistor.
/// </summary>
/// <param name="pin">The pin.</param>
/// <param name="resistor">The resistor.</param>
public void SetResistor(Mcp23008Pin pin, Mcp23008PinResistor resistor)
{
var register = Register.GPPU;

connection.WriteByte((byte)register);
var resistors = connection.ReadByte();

var bit = (byte)((int)pin & 0xFF);
var newResistors = (resistor == Mcp23008PinResistor.PullUp)
? resistors | bit
: resistors & ~bit;

connection.Write(new[] { (byte)register, (byte)newResistors });
}

/// <summary>
/// Sets the pin status.
/// </summary>
/// <param name="pin">The pin.</param>
/// <param name="enabled">if set to <c>true</c>, pin is enabled.</param>
public void SetPinStatus(Mcp23008Pin pin, bool enabled)
{
var register = Register.GPIO;

connection.WriteByte((byte)register);
var status = connection.ReadByte();

var bit = (byte)((int)pin & 0xFF);
var newStatus = enabled
? status | bit
: status & ~bit;

connection.Write((byte)register, (byte)newStatus);
}


/// <summary>
/// Gets the pin status.
/// </summary>
/// <param name="pin">The pin.</param>
/// <returns>The pin status.</returns>
public bool GetPinStatus(Mcp23008Pin pin)
{
var register = Register.GPIO;

connection.WriteByte((byte)register);
var status = connection.ReadByte();

var bit = (byte)((int)pin & 0xFF);
return (status & bit) != 0x00;
}

/// <summary>
/// Toogles the specified pin.
/// </summary>
/// <param name="pin">The pin.</param>
public void Toogle(Mcp23008Pin pin)
{
var register = Register.GPIO;

connection.WriteByte((byte)register);
var status = connection.ReadByte();

var bit = (byte)((int)pin & 0xFF);
var bitEnabled = (status & bit) != 0x00;
var newBitEnabled = !bitEnabled;

var newStatus = newBitEnabled
? status | bit
: status & ~bit;

connection.Write((byte)register, (byte)newStatus);
}

#endregion

#region Private Helpers

private enum Register
{
IODIR = 0x00,
IPOL = 0x01,
GPINTEN = 0x02,
DEFVAL = 0x03,
INTCON = 0x04,
IOCON = 0x05,
GPPU = 0x06,
INTF = 0x07,
INTCAP = 0x08,
GPIO = 0x09,
OLAT = 0x0A
}

#endregion

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#region References

using System;

#endregion

namespace Raspberry.IO.Components.Expanders.Mcp23008
{
/// <summary>
/// Represents a binary intput pin on a MCP23017 I/O expander.
/// </summary>
public class Mcp23008InputBinaryPin : IInputBinaryPin
{
#region Fields

private readonly Mcp23008I2cConnection connection;
private readonly Mcp23008Pin pin;

/// <summary>
/// The default timeout (5 seconds).
/// </summary>
public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(5);

#endregion

#region Instance Management

/// <summary>
/// Initializes a new instance of the <see cref="Mcp23008InputBinaryPin"/> class.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="pin">The pin.</param>
/// <param name="resistor">The resistor.</param>
/// <param name="polarity">The polarity.</param>
public Mcp23008InputBinaryPin(Mcp23008I2cConnection connection, Mcp23008Pin pin,
Mcp23008PinResistor resistor = Mcp23008PinResistor.None,
Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
{
this.connection = connection;
this.pin = pin;

connection.SetDirection(pin, Mcp23008PinDirection.Input);
connection.SetResistor(pin, resistor);
connection.SetPolarity(pin, polarity);
}

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose(){}

#endregion

#region Methods

/// <summary>
/// Reads the state of the pin.
/// </summary>
/// <returns>
/// <c>true</c> if the pin is in high state; otherwise, <c>false</c>.
/// </returns>
public bool Read()
{
return connection.GetPinStatus(pin);
}

/// <summary>
/// Waits for the specified pin to be in the specified state.
/// </summary>
/// <param name="waitForUp">if set to <c>true</c> waits for the pin to be up. Default value is <c>true</c>.</param>
/// <param name="timeout">The timeout. Default value is <see cref="TimeSpan.Zero"/>.</param>
/// <remarks>If <c>timeout</c> is set to <see cref="TimeSpan.Zero"/>, a default timeout is used instead.</remarks>
public void Wait(bool waitForUp = true, TimeSpan timeout = new TimeSpan())
{
var startWait = DateTime.UtcNow;
if (timeout == TimeSpan.Zero)
timeout = DefaultTimeout;

while (Read() != waitForUp)
{
if (DateTime.UtcNow - startWait >= timeout)
throw new TimeoutException("A timeout occurred while waiting for pin status to change");
}
}

#endregion

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System;

namespace Raspberry.IO.Components.Expanders.Mcp23008
{
/// <summary>
/// Represents a binary output pin on a MCP23008 I/O expander.
/// </summary>
public class Mcp23008OutputBinaryPin : IOutputBinaryPin
{
#region Properties

private readonly Mcp23008I2cConnection connection;
private readonly Mcp23008Pin pin;

#endregion

#region Instance Management

/// <summary>
/// Initializes a new instance of the <see cref="Mcp23008OutputBinaryPin"/> class.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="pin">The pin.</param>
/// <param name="resistor">The resistor.</param>
/// <param name="polarity">The polarity.</param>
public Mcp23008OutputBinaryPin(Mcp23008I2cConnection connection, Mcp23008Pin pin,
Mcp23008PinResistor resistor = Mcp23008PinResistor.None,
Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
{
this.connection = connection;
this.pin = pin;

connection.SetDirection(pin, Mcp23008PinDirection.Output);
connection.SetResistor(pin, resistor);
connection.SetPolarity(pin, polarity);
}

/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose(){}

#endregion

#region Methods

/// <summary>
/// Writes the value of the pin.
/// </summary>
/// <param name="state">if set to <c>true</c>, pin is set to high state.</param>
public void Write(bool state)
{
connection.SetPinStatus(pin, state);
}

#endregion
}
}
14 changes: 14 additions & 0 deletions Raspberry.IO.Components/Expanders/Mcp23008/Mcp23008Pin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Raspberry.IO.Components.Expanders.Mcp23008
{
public enum Mcp23008Pin
{
Pin0 = 0x0001,
Pin1 = 0x0002,
Pin2 = 0x0004,
Pin3 = 0x0008,
Pin4 = 0x0010,
Pin5 = 0x0020,
Pin6 = 0x0040,
Pin7 = 0x0080
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Raspberry.IO.Components.Expanders.Mcp23008
{
public enum Mcp23008PinDirection
{
Input,
Output
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace Raspberry.IO.Components.Expanders.Mcp23008
{
/// <summary>
/// Provides extension methods for MCP23008 pins.
/// </summary>
public static class Mcp23008PinExtensionMethods
{
#region Methods

/// <summary>
/// Creates an output binary pin.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="pin">The pin.</param>
/// <param name="resistor">The resistor.</param>
/// <param name="polarity">The polarity.</param>
/// <returns>The pin.</returns>
public static Mcp23008OutputBinaryPin Out(this Mcp23008I2cConnection connection, Mcp23008Pin pin, Mcp23008PinResistor resistor = Mcp23008PinResistor.None, Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
{
return new Mcp23008OutputBinaryPin(connection, pin, resistor, polarity);
}

/// <summary>
/// Creates an input binary pin.
/// </summary>
/// <param name="connection">The connection.</param>
/// <param name="pin">The pin.</param>
/// <param name="resistor">The resistor.</param>
/// <param name="polarity">The polarity.</param>
/// <returns>The pin.</returns>
public static Mcp23008InputBinaryPin In(this Mcp23008I2cConnection connection, Mcp23008Pin pin, Mcp23008PinResistor resistor = Mcp23008PinResistor.None, Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
{
return new Mcp23008InputBinaryPin(connection, pin, resistor, polarity);
}

#endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Raspberry.IO.Components.Expanders.Mcp23008
{
public enum Mcp23008PinPolarity
{
Normal,
Inverted
}
}
Loading