Skip to content

Commit 5a27dd8

Browse files
authored
Adding managed System.Device.Gpio (#1)
1 parent a6a4ae1 commit 5a27dd8

18 files changed

+821
-4
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-Windows.Devices.Gpio&metric=alert_status)](https://sonarcloud.io/dashboard?id=nanoframework_lib-Windows.Devices.Gpio) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-Windows.Devices.Gpio&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=nanoframework_lib-Windows.Devices.Gpio) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.Windows.Devices.Gpio.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Windows.Devices.Gpio/) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/master/CONTRIBUTING.md) [![Discord](https://img.shields.io/discord/478725473862549535.svg?logo=discord&logoColor=white&label=Discord&color=7289DA)](https://discord.gg/gCyBu8T)
1+
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-System.Device.Gpio&metric=alert_status)](https://sonarcloud.io/dashboard?id=nanoframework_lib-System.Device.Gpio) [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=nanoframework_lib-System.Device.Gpio&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=nanoframework_lib-System.Device.Gpio) [![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) [![NuGet](https://img.shields.io/nuget/dt/nanoFramework.System.Device.Gpio.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.System.Device.Gpio/) [![#yourfirstpr](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](https://github.com/nanoframework/Home/blob/master/CONTRIBUTING.md) [![Discord](https://img.shields.io/discord/478725473862549535.svg?logo=discord&logoColor=white&label=Discord&color=7289DA)](https://discord.gg/gCyBu8T)
22

33
![nanoFramework logo](https://github.com/nanoframework/Home/blob/master/resources/logo/nanoFramework-repo-logo.png)
44

55
-----
66

7-
### Welcome to the **nanoFramework** Windows.Devices.Gpio Library repository!
7+
### Welcome to the **nanoFramework** System.Device.Gpio Library repository!
88

99
## Build status
1010

1111
| Component | Build Status | NuGet Package |
1212
|:-|---|---|
13-
| Windows.Devices.Gpio | [![Build Status](https://dev.azure.com/nanoframework/Windows.Devices.Gpio/_apis/build/status/nanoframework.lib-Windows.Devices.Gpio?branchName=develop)](https://dev.azure.com/nanoframework/Windows.Devices.Gpio/_build/latest?definitionId=16?branchName=master) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.Windows.Devices.Gpio.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.Windows.Devices.Gpio/) |
14-
| Windows.Devices.Gpio (preview) | [![Build Status](https://dev.azure.com/nanoframework/Windows.Devices.Gpio/_apis/build/status/nanoframework.lib-Windows.Devices.Gpio?branchName=develop)](https://dev.azure.com/nanoframework/Windows.Devices.Gpio/_build/latest?definitionId=16?branchName=develop) | [![](https://badgen.net/badge/NuGet/preview/D7B023?icon=https://simpleicons.now.sh/azuredevops/fff)](https://dev.azure.com/nanoframework/feed/_packaging?_a=package&feed=sandbox&package=nanoFramework.Windows.Devices.Gpio&protocolType=NuGet&view=overview) |
13+
| System.Device.Gpio | [![Build Status](https://dev.azure.com/nanoframework/System.Device.Gpio/_apis/build/status/nanoframework.lib-System.Device.Gpio?branchName=develop)](https://dev.azure.com/nanoframework/System.Device.Gpio/_build/latest?definitionId=16?branchName=master) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.System.Device.Gpio.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.System.Device.Gpio/) |
14+
| System.Device.Gpio (preview) | [![Build Status](https://dev.azure.com/nanoframework/System.Device.Gpio/_apis/build/status/nanoframework.lib-System.Device.Gpio?branchName=develop)](https://dev.azure.com/nanoframework/System.Device.Gpio/_build/latest?definitionId=16?branchName=develop) | [![](https://badgen.net/badge/NuGet/preview/D7B023?icon=https://simpleicons.now.sh/azuredevops/fff)](https://dev.azure.com/nanoframework/feed/_packaging?_a=package&feed=sandbox&package=nanoFramework.System.Device.Gpio&protocolType=NuGet&view=overview) |
1515

1616
## Feedback and documentation
1717

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections;
6+
using System.IO;
7+
8+
namespace System.Device.Gpio
9+
{
10+
/// <summary>
11+
/// Represents a general-purpose I/O (GPIO) controller.
12+
/// </summary>
13+
public sealed class GpioController : IDisposable
14+
{
15+
private Windows.Devices.Gpio.GpioController _controller;
16+
private static Windows.Devices.Gpio.GpioPin[] _gpioPins;
17+
private static PinEventTypes[] _gpioEvents;
18+
private static PinChangeEventHandler[] _gpioPinChange;
19+
private static PinEventTypes[] _gpioEventsHappening;
20+
21+
// this is used as the lock object
22+
// a lock is required because multiple threads can access the GPIO controller
23+
static object _syncLock;
24+
25+
/// <summary>
26+
/// Initializes a new instance of the System.Device.Gpio.GpioController class that
27+
/// will use the logical pin numbering scheme as default.
28+
/// </summary>
29+
public GpioController()
30+
{
31+
GetController();
32+
}
33+
34+
/// <summary>
35+
/// Initializes a new instance of the System.Device.Gpio.GpioController class that
36+
/// will use the specified numbering scheme. The controller will default to use the
37+
/// driver that best applies given the platform the program is executing on.
38+
/// </summary>
39+
/// <param name="numberingScheme">The numbering scheme used to represent pins provided by the controller.</param>
40+
public GpioController(PinNumberingScheme numberingScheme) : this()
41+
{
42+
NumberingScheme = numberingScheme;
43+
}
44+
45+
private void GetController()
46+
{
47+
if (_syncLock == null)
48+
{
49+
_syncLock = new object();
50+
}
51+
52+
lock (_syncLock)
53+
{
54+
_controller = Windows.Devices.Gpio.GpioController.GetDefault();
55+
if (_gpioPins == null)
56+
{
57+
_gpioPins = new Windows.Devices.Gpio.GpioPin[_controller.PinCount];
58+
_gpioEvents = new PinEventTypes[_controller.PinCount];
59+
_gpioEventsHappening = new PinEventTypes[_controller.PinCount];
60+
_gpioPinChange = new PinChangeEventHandler[_controller.PinCount];
61+
}
62+
}
63+
}
64+
65+
/// <summary>
66+
/// The numbering scheme used to represent pins provided by the controller.
67+
/// </summary>
68+
public PinNumberingScheme NumberingScheme { get; internal set; }
69+
70+
/// <summary>
71+
/// The number of pins provided by the controller.
72+
/// </summary>
73+
public int PinCount => _controller.PinCount;
74+
75+
/// <summary>
76+
/// Closes an open pin.
77+
/// </summary>
78+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
79+
public void ClosePin(int pinNumber)
80+
{
81+
82+
if (_gpioPins[pinNumber] != null)
83+
{
84+
_gpioPins[pinNumber].Dispose();
85+
_gpioPins[pinNumber] = null;
86+
}
87+
else
88+
{
89+
throw new IOException($"Port {pinNumber} is not open");
90+
}
91+
}
92+
93+
/// <summary>
94+
/// Dispose the controller
95+
/// </summary>
96+
public void Dispose()
97+
{
98+
for (int i = 0; i < _gpioPins.Length; i++)
99+
{
100+
ClosePin(i);
101+
}
102+
}
103+
104+
/// <summary>
105+
/// Gets the mode of a pin.
106+
/// </summary>
107+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
108+
/// <returns>The mode of the pin.</returns>
109+
public PinMode GetPinMode(int pinNumber)
110+
{
111+
if (_gpioPins[pinNumber] == null)
112+
{
113+
throw new IOException($"Port {pinNumber} is not open");
114+
}
115+
116+
// It is safe to cast, enums are the same
117+
return (PinMode)_gpioPins[pinNumber].GetDriveMode();
118+
}
119+
120+
/// <summary>
121+
/// Checks if a pin supports a specific mode.
122+
/// </summary>
123+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
124+
/// <param name="mode">The mode to check.</param>
125+
/// <returns>The status if the pin supports the mode.</returns>
126+
public bool IsPinModeSupported(int pinNumber, PinMode mode) => _gpioPins[pinNumber].IsDriveModeSupported((Windows.Devices.Gpio.GpioPinDriveMode)mode);
127+
128+
/// <summary>
129+
/// Checks if a specific pin is open.
130+
/// </summary>
131+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
132+
/// <returns>The status if the pin is open or closed.</returns>
133+
public bool IsPinOpen(int pinNumber) => _gpioPins[pinNumber] != null;
134+
135+
/// <summary>
136+
/// Opens a pin in order for it to be ready to use.
137+
/// </summary>
138+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
139+
public void OpenPin(int pinNumber)
140+
{
141+
if (IsPinOpen(pinNumber))
142+
{
143+
throw new IOException($"Pin {pinNumber} already open");
144+
}
145+
146+
_gpioPins[pinNumber] = _controller.OpenPin(pinNumber);
147+
}
148+
149+
/// <summary>
150+
/// Opens a pin and sets it to a specific mode.
151+
/// </summary>
152+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
153+
/// <param name="mode">The mode to be set.</param>
154+
public void OpenPin(int pinNumber, PinMode mode)
155+
{
156+
OpenPin(pinNumber);
157+
SetPinMode(pinNumber, mode);
158+
}
159+
160+
/// <summary>
161+
/// Reads the current value of a pin.
162+
/// </summary>
163+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
164+
/// <returns>The value of the pin.</returns>
165+
public PinValue Read(int pinNumber) => _gpioPins[pinNumber].Read() == Windows.Devices.Gpio.GpioPinValue.High ? PinValue.High : PinValue.Low;
166+
167+
/// <summary>
168+
/// Adds a callback that will be invoked when pinNumber has an event of type eventType.
169+
/// </summary>
170+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
171+
/// <param name="eventTypes">The event types to wait for.</param>
172+
/// <param name="callback">The callback method that will be invoked.</param>
173+
public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback)
174+
{
175+
_gpioEvents[pinNumber] = eventTypes;
176+
_gpioPinChange[pinNumber] = callback;
177+
_gpioPins[pinNumber].ValueChanged += GpioControllerValueChanged;
178+
}
179+
180+
private void GpioControllerValueChanged(object sender, Windows.Devices.Gpio.GpioPinValueChangedEventArgs e)
181+
{
182+
var gpioPinNumber = ((Windows.Devices.Gpio.GpioPin)sender).PinNumber;
183+
if ((e.Edge == Windows.Devices.Gpio.GpioPinEdge.FallingEdge) && (_gpioEvents[gpioPinNumber] == PinEventTypes.Falling))
184+
{
185+
_gpioPinChange[gpioPinNumber].Invoke(this, new PinValueChangedEventArgs(PinEventTypes.Falling, gpioPinNumber));
186+
}
187+
188+
if ((e.Edge == Windows.Devices.Gpio.GpioPinEdge.RisingEdge) && (_gpioEvents[gpioPinNumber] == PinEventTypes.Rising))
189+
{
190+
_gpioPinChange[gpioPinNumber].Invoke(this, new PinValueChangedEventArgs(PinEventTypes.Rising, gpioPinNumber));
191+
}
192+
}
193+
194+
/// <summary>
195+
/// Sets the mode to a pin.
196+
/// </summary>
197+
/// <param name="pinNumber">The pin number in the controller's numbering scheme</param>
198+
/// <param name="mode">The mode to be set.</param>
199+
public void SetPinMode(int pinNumber, PinMode mode)
200+
{
201+
if (!IsPinOpen(pinNumber))
202+
{
203+
throw new IOException($"Pin {pinNumber} needs to be open");
204+
}
205+
206+
// Safe cast, same enum on nanoFramework
207+
_gpioPins[pinNumber].SetDriveMode((Windows.Devices.Gpio.GpioPinDriveMode)mode);
208+
}
209+
210+
/// <summary>
211+
/// Removes a callback that was being invoked for pin at pinNumber.
212+
/// </summary>
213+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
214+
/// <param name="callback">The callback method that will be invoked.</param>
215+
public void UnregisterCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback)
216+
{
217+
_gpioEvents[pinNumber] = PinEventTypes.None;
218+
_gpioPins[pinNumber].ValueChanged -= GpioControllerValueChanged;
219+
}
220+
221+
/// <summary>
222+
/// Blocks execution until an event of type eventType is received or a period of
223+
/// time has expired.
224+
/// </summary>
225+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
226+
/// <param name="eventTypes">The event types to wait for.</param>
227+
/// <param name="timeout">The time to wait for the event.</param>
228+
/// <returns>A structure that contains the result of the waiting operation.</returns>
229+
public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
230+
{
231+
_gpioEvents[pinNumber] = eventTypes;
232+
_gpioEventsHappening[pinNumber] = PinEventTypes.None;
233+
_gpioPins[pinNumber].ValueChanged += GpioControllerWaitForEvents;
234+
DateTime dtTimeout = DateTime.UtcNow.Add(timeout);
235+
while (DateTime.UtcNow < dtTimeout)
236+
{
237+
if (_gpioEventsHappening[pinNumber] != PinEventTypes.None)
238+
{
239+
break;
240+
}
241+
}
242+
_gpioPins[pinNumber].ValueChanged -= GpioControllerWaitForEvents;
243+
244+
if (_gpioEventsHappening[pinNumber] != PinEventTypes.None)
245+
{
246+
return new WaitForEventResult() { EventTypes = _gpioEventsHappening[pinNumber], TimedOut = false };
247+
}
248+
249+
return new WaitForEventResult() { EventTypes = PinEventTypes.None, TimedOut = true };
250+
}
251+
252+
private void GpioControllerWaitForEvents(object sender, Windows.Devices.Gpio.GpioPinValueChangedEventArgs e)
253+
{
254+
var gpioPinNumber = ((Windows.Devices.Gpio.GpioPin)sender).PinNumber;
255+
_gpioEventsHappening[gpioPinNumber] = e.Edge == Windows.Devices.Gpio.GpioPinEdge.FallingEdge ? PinEventTypes.Rising : PinEventTypes.Falling;
256+
}
257+
258+
/// <summary>
259+
/// Writes a value to a pin.
260+
/// </summary>
261+
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
262+
/// <param name="value">The value to be written to the pin.</param>
263+
public void Write(int pinNumber, PinValue value)
264+
{
265+
_gpioPins[pinNumber].Write(value == PinValue.High ? Windows.Devices.Gpio.GpioPinValue.High : Windows.Devices.Gpio.GpioPinValue.Low);
266+
}
267+
}
268+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace System.Device.Gpio
6+
{
7+
/// <summary>
8+
/// Delegate that defines the structure for callbacks when a pin value changed event occurs.
9+
/// </summary>
10+
/// <param name="sender">The sender of the event.</param>
11+
/// <param name="pinValueChangedEventArgs">The pin value changed arguments from the event.</param>
12+
public delegate void PinChangeEventHandler(object sender, PinValueChangedEventArgs pinValueChangedEventArgs);
13+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace System.Device.Gpio
6+
{
7+
/// <summary>
8+
/// Event types that can be triggered by the GPIO.
9+
/// Also used to report the received event types back.
10+
/// </summary>
11+
[Flags]
12+
public enum PinEventTypes
13+
{
14+
/// <summary>
15+
/// None.
16+
/// </summary>
17+
None = 0,
18+
19+
/// <summary>
20+
/// Triggered when pin value goes from low to high.
21+
/// </summary>
22+
Rising = 1,
23+
24+
/// <summary>
25+
/// Triggered when a pin value goes from high to low.
26+
/// </summary>
27+
Falling = 2
28+
}
29+
}

System.Device.Gpio/PinMode.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace System.Device.Gpio
6+
{
7+
/// <summary>
8+
/// Pin modes supported by the GPIO controllers and drivers.
9+
/// </summary>
10+
public enum PinMode
11+
{
12+
/// <summary>
13+
/// Configures the GPIO pin in floating mode, with high impedance.
14+
/// </summary>
15+
Input,
16+
17+
/// <summary>
18+
/// Configures the GPIO pin as high impedance with a pull-down resistor to ground.
19+
/// </summary>
20+
InputPullDown,
21+
22+
/// <summary>
23+
/// Configures the GPIO pin as high impedance with a pull-up resistor to the voltage charge connection (VCC).
24+
/// </summary>
25+
InputPullUp,
26+
27+
/// <summary>
28+
/// Configures the GPIO pin in strong drive mode, with low impedance.
29+
/// </summary>
30+
Output,
31+
32+
/// <summary>
33+
/// Configures the GPIO in open drain mode.
34+
/// </summary>
35+
OutputOpenDrain,
36+
37+
/// <summary>
38+
/// Configures the GPIO pin in open drain mode with resistive pull-up mode.
39+
/// </summary>
40+
OutputOpenDrainPullUp,
41+
42+
/// <summary>
43+
/// Configures the GPIO pin in open collector mode.
44+
/// </summary>
45+
OutputOpenSource,
46+
47+
/// <summary>
48+
/// Configures the GPIO pin in open collector mode with resistive pull-down mode.
49+
/// </summary>
50+
OutputOpenSourcePullDown
51+
}
52+
}

0 commit comments

Comments
 (0)