Skip to content

Commit 1b491be

Browse files
committed
Merge pull request #46 from dgt0011/development
Add support for the MCP23008 I/O extender used by the Adafruit I2C/SPI Serial backpack
2 parents 288a016 + 84419ef commit 1b491be

14 files changed

+624
-0
lines changed
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
#region References
2+
3+
using Raspberry.IO.InterIntegratedCircuit;
4+
5+
#endregion
6+
7+
namespace Raspberry.IO.Components.Expanders.Mcp23008
8+
{
9+
/// <summary>
10+
/// Represents a I2C connection to a MCP23008 I/O Expander.
11+
/// </summary>
12+
/// <remarks>See <see cref="http://www.adafruit.com/datasheets/MCP23008.pdf"/> for more information.</remarks>
13+
public class Mcp23008I2cConnection
14+
{
15+
#region Fields
16+
17+
private readonly I2cDeviceConnection connection;
18+
19+
#endregion
20+
21+
#region Instance Management
22+
23+
/// <summary>
24+
/// Initializes a new instance of the <see cref="Mcp23008I2cConnection"/> class.
25+
/// </summary>
26+
/// <param name="connection">The connection.</param>
27+
public Mcp23008I2cConnection(I2cDeviceConnection connection)
28+
{
29+
this.connection = connection;
30+
}
31+
32+
#endregion
33+
34+
#region Methods
35+
36+
/// <summary>
37+
/// Sets the direction.
38+
/// </summary>
39+
/// <param name="pin">The pin.</param>
40+
/// <param name="direction">The direction.</param>
41+
public void SetDirection(Mcp23008Pin pin, Mcp23008PinDirection direction)
42+
{
43+
var register = Register.IODIR;
44+
45+
connection.WriteByte((byte)register);
46+
var directions = connection.ReadByte();
47+
48+
var bit = (byte)((int)pin & 0xFF);
49+
var newDirections = (direction == Mcp23008PinDirection.Input)
50+
? directions | bit
51+
: directions & ~bit;
52+
53+
connection.Write(new[] { (byte)register, (byte)newDirections });
54+
}
55+
56+
/// <summary>
57+
/// Sets the polarity.
58+
/// </summary>
59+
/// <param name="pin">The pin.</param>
60+
/// <param name="polarity">The polarity.</param>
61+
public void SetPolarity(Mcp23008Pin pin, Mcp23008PinPolarity polarity)
62+
{
63+
var register = Register.IPOL;
64+
65+
connection.WriteByte((byte)register);
66+
var polarities = connection.ReadByte();
67+
68+
var bit = (byte)((int)pin & 0xFF);
69+
var newPolarities = (polarity == Mcp23008PinPolarity.Inverted)
70+
? polarities | bit
71+
: polarities & ~bit;
72+
73+
connection.Write(new[] { (byte)register, (byte)newPolarities });
74+
}
75+
76+
/// <summary>
77+
/// Sets the resistor.
78+
/// </summary>
79+
/// <param name="pin">The pin.</param>
80+
/// <param name="resistor">The resistor.</param>
81+
public void SetResistor(Mcp23008Pin pin, Mcp23008PinResistor resistor)
82+
{
83+
var register = Register.GPPU;
84+
85+
connection.WriteByte((byte)register);
86+
var resistors = connection.ReadByte();
87+
88+
var bit = (byte)((int)pin & 0xFF);
89+
var newResistors = (resistor == Mcp23008PinResistor.PullUp)
90+
? resistors | bit
91+
: resistors & ~bit;
92+
93+
connection.Write(new[] { (byte)register, (byte)newResistors });
94+
}
95+
96+
/// <summary>
97+
/// Sets the pin status.
98+
/// </summary>
99+
/// <param name="pin">The pin.</param>
100+
/// <param name="enabled">if set to <c>true</c>, pin is enabled.</param>
101+
public void SetPinStatus(Mcp23008Pin pin, bool enabled)
102+
{
103+
var register = Register.GPIO;
104+
105+
connection.WriteByte((byte)register);
106+
var status = connection.ReadByte();
107+
108+
var bit = (byte)((int)pin & 0xFF);
109+
var newStatus = enabled
110+
? status | bit
111+
: status & ~bit;
112+
113+
connection.Write((byte)register, (byte)newStatus);
114+
}
115+
116+
117+
/// <summary>
118+
/// Gets the pin status.
119+
/// </summary>
120+
/// <param name="pin">The pin.</param>
121+
/// <returns>The pin status.</returns>
122+
public bool GetPinStatus(Mcp23008Pin pin)
123+
{
124+
var register = Register.GPIO;
125+
126+
connection.WriteByte((byte)register);
127+
var status = connection.ReadByte();
128+
129+
var bit = (byte)((int)pin & 0xFF);
130+
return (status & bit) != 0x00;
131+
}
132+
133+
/// <summary>
134+
/// Toogles the specified pin.
135+
/// </summary>
136+
/// <param name="pin">The pin.</param>
137+
public void Toogle(Mcp23008Pin pin)
138+
{
139+
var register = Register.GPIO;
140+
141+
connection.WriteByte((byte)register);
142+
var status = connection.ReadByte();
143+
144+
var bit = (byte)((int)pin & 0xFF);
145+
var bitEnabled = (status & bit) != 0x00;
146+
var newBitEnabled = !bitEnabled;
147+
148+
var newStatus = newBitEnabled
149+
? status | bit
150+
: status & ~bit;
151+
152+
connection.Write((byte)register, (byte)newStatus);
153+
}
154+
155+
#endregion
156+
157+
#region Private Helpers
158+
159+
private enum Register
160+
{
161+
IODIR = 0x00,
162+
IPOL = 0x01,
163+
GPINTEN = 0x02,
164+
DEFVAL = 0x03,
165+
INTCON = 0x04,
166+
IOCON = 0x05,
167+
GPPU = 0x06,
168+
INTF = 0x07,
169+
INTCAP = 0x08,
170+
GPIO = 0x09,
171+
OLAT = 0x0A
172+
}
173+
174+
#endregion
175+
176+
}
177+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#region References
2+
3+
using System;
4+
5+
#endregion
6+
7+
namespace Raspberry.IO.Components.Expanders.Mcp23008
8+
{
9+
/// <summary>
10+
/// Represents a binary intput pin on a MCP23017 I/O expander.
11+
/// </summary>
12+
public class Mcp23008InputBinaryPin : IInputBinaryPin
13+
{
14+
#region Fields
15+
16+
private readonly Mcp23008I2cConnection connection;
17+
private readonly Mcp23008Pin pin;
18+
19+
/// <summary>
20+
/// The default timeout (5 seconds).
21+
/// </summary>
22+
public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(5);
23+
24+
#endregion
25+
26+
#region Instance Management
27+
28+
/// <summary>
29+
/// Initializes a new instance of the <see cref="Mcp23008InputBinaryPin"/> class.
30+
/// </summary>
31+
/// <param name="connection">The connection.</param>
32+
/// <param name="pin">The pin.</param>
33+
/// <param name="resistor">The resistor.</param>
34+
/// <param name="polarity">The polarity.</param>
35+
public Mcp23008InputBinaryPin(Mcp23008I2cConnection connection, Mcp23008Pin pin,
36+
Mcp23008PinResistor resistor = Mcp23008PinResistor.None,
37+
Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
38+
{
39+
this.connection = connection;
40+
this.pin = pin;
41+
42+
connection.SetDirection(pin, Mcp23008PinDirection.Input);
43+
connection.SetResistor(pin, resistor);
44+
connection.SetPolarity(pin, polarity);
45+
}
46+
47+
/// <summary>
48+
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
49+
/// </summary>
50+
public void Dispose(){}
51+
52+
#endregion
53+
54+
#region Methods
55+
56+
/// <summary>
57+
/// Reads the state of the pin.
58+
/// </summary>
59+
/// <returns>
60+
/// <c>true</c> if the pin is in high state; otherwise, <c>false</c>.
61+
/// </returns>
62+
public bool Read()
63+
{
64+
return connection.GetPinStatus(pin);
65+
}
66+
67+
/// <summary>
68+
/// Waits for the specified pin to be in the specified state.
69+
/// </summary>
70+
/// <param name="waitForUp">if set to <c>true</c> waits for the pin to be up. Default value is <c>true</c>.</param>
71+
/// <param name="timeout">The timeout. Default value is <see cref="TimeSpan.Zero"/>.</param>
72+
/// <remarks>If <c>timeout</c> is set to <see cref="TimeSpan.Zero"/>, a default timeout is used instead.</remarks>
73+
public void Wait(bool waitForUp = true, TimeSpan timeout = new TimeSpan())
74+
{
75+
var startWait = DateTime.UtcNow;
76+
if (timeout == TimeSpan.Zero)
77+
timeout = DefaultTimeout;
78+
79+
while (Read() != waitForUp)
80+
{
81+
if (DateTime.UtcNow - startWait >= timeout)
82+
throw new TimeoutException("A timeout occurred while waiting for pin status to change");
83+
}
84+
}
85+
86+
#endregion
87+
88+
}
89+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using System;
2+
3+
namespace Raspberry.IO.Components.Expanders.Mcp23008
4+
{
5+
/// <summary>
6+
/// Represents a binary output pin on a MCP23008 I/O expander.
7+
/// </summary>
8+
public class Mcp23008OutputBinaryPin : IOutputBinaryPin
9+
{
10+
#region Properties
11+
12+
private readonly Mcp23008I2cConnection connection;
13+
private readonly Mcp23008Pin pin;
14+
15+
#endregion
16+
17+
#region Instance Management
18+
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="Mcp23008OutputBinaryPin"/> class.
21+
/// </summary>
22+
/// <param name="connection">The connection.</param>
23+
/// <param name="pin">The pin.</param>
24+
/// <param name="resistor">The resistor.</param>
25+
/// <param name="polarity">The polarity.</param>
26+
public Mcp23008OutputBinaryPin(Mcp23008I2cConnection connection, Mcp23008Pin pin,
27+
Mcp23008PinResistor resistor = Mcp23008PinResistor.None,
28+
Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
29+
{
30+
this.connection = connection;
31+
this.pin = pin;
32+
33+
connection.SetDirection(pin, Mcp23008PinDirection.Output);
34+
connection.SetResistor(pin, resistor);
35+
connection.SetPolarity(pin, polarity);
36+
}
37+
38+
/// <summary>
39+
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
40+
/// </summary>
41+
public void Dispose(){}
42+
43+
#endregion
44+
45+
#region Methods
46+
47+
/// <summary>
48+
/// Writes the value of the pin.
49+
/// </summary>
50+
/// <param name="state">if set to <c>true</c>, pin is set to high state.</param>
51+
public void Write(bool state)
52+
{
53+
connection.SetPinStatus(pin, state);
54+
}
55+
56+
#endregion
57+
}
58+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
namespace Raspberry.IO.Components.Expanders.Mcp23008
2+
{
3+
public enum Mcp23008Pin
4+
{
5+
Pin0 = 0x0001,
6+
Pin1 = 0x0002,
7+
Pin2 = 0x0004,
8+
Pin3 = 0x0008,
9+
Pin4 = 0x0010,
10+
Pin5 = 0x0020,
11+
Pin6 = 0x0040,
12+
Pin7 = 0x0080
13+
}
14+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Raspberry.IO.Components.Expanders.Mcp23008
2+
{
3+
public enum Mcp23008PinDirection
4+
{
5+
Input,
6+
Output
7+
}
8+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
namespace Raspberry.IO.Components.Expanders.Mcp23008
2+
{
3+
/// <summary>
4+
/// Provides extension methods for MCP23008 pins.
5+
/// </summary>
6+
public static class Mcp23008PinExtensionMethods
7+
{
8+
#region Methods
9+
10+
/// <summary>
11+
/// Creates an output binary pin.
12+
/// </summary>
13+
/// <param name="connection">The connection.</param>
14+
/// <param name="pin">The pin.</param>
15+
/// <param name="resistor">The resistor.</param>
16+
/// <param name="polarity">The polarity.</param>
17+
/// <returns>The pin.</returns>
18+
public static Mcp23008OutputBinaryPin Out(this Mcp23008I2cConnection connection, Mcp23008Pin pin, Mcp23008PinResistor resistor = Mcp23008PinResistor.None, Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
19+
{
20+
return new Mcp23008OutputBinaryPin(connection, pin, resistor, polarity);
21+
}
22+
23+
/// <summary>
24+
/// Creates an input binary pin.
25+
/// </summary>
26+
/// <param name="connection">The connection.</param>
27+
/// <param name="pin">The pin.</param>
28+
/// <param name="resistor">The resistor.</param>
29+
/// <param name="polarity">The polarity.</param>
30+
/// <returns>The pin.</returns>
31+
public static Mcp23008InputBinaryPin In(this Mcp23008I2cConnection connection, Mcp23008Pin pin, Mcp23008PinResistor resistor = Mcp23008PinResistor.None, Mcp23008PinPolarity polarity = Mcp23008PinPolarity.Normal)
32+
{
33+
return new Mcp23008InputBinaryPin(connection, pin, resistor, polarity);
34+
}
35+
36+
#endregion
37+
}
38+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Raspberry.IO.Components.Expanders.Mcp23008
2+
{
3+
public enum Mcp23008PinPolarity
4+
{
5+
Normal,
6+
Inverted
7+
}
8+
}

0 commit comments

Comments
 (0)