diff --git a/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs b/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs
index a11c8a3e32..f45d662e27 100644
--- a/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs
+++ b/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs
@@ -91,6 +91,30 @@ public void IsPinOpenOnInputTest()
}
}
+ [Fact]
+ public void SharedControllerManagesItsOwnPinsTest()
+ {
+ using (GpioController controller = new GpioController(GetTestNumberingScheme(), GetTestDriver()))
+ {
+ // Open pin in input mode (default)
+ Assert.False(controller.IsPinOpen(LedPin));
+ controller.OpenPin(LedPin, PinMode.Input);
+ Assert.True(controller.IsPinOpen(LedPin));
+
+ var sharedController = new SharedGpioController(controller);
+ sharedController.OpenPin(10, PinMode.Input);
+ Assert.True(sharedController.IsPinOpen(10));
+ Assert.True(controller.IsPinOpen(10));
+
+ sharedController.ClosePin(10);
+ Assert.False(sharedController.IsPinOpen(10));
+ Assert.False(controller.IsPinOpen(10));
+
+ controller.ClosePin(LedPin);
+ Assert.False(controller.IsPinOpen(LedPin));
+ }
+ }
+
[Fact]
public void IsPinOpenOnOutputTest()
{
@@ -112,6 +136,21 @@ public void IsPinOpenOnOutputTest()
}
}
+ [Fact]
+ public void CanClosePinsViaDisposableTest()
+ {
+ using (GpioController controller = new GpioController(GetTestNumberingScheme(), GetTestDriver()))
+ {
+ Assert.False(controller.IsPinOpen(LedPin));
+
+ var openPin = controller.OpenPinAsDisposable(LedPin, PinMode.Output);
+ Assert.True(controller.IsPinOpen(LedPin));
+
+ openPin.Dispose();
+ Assert.False(controller.IsPinOpen(LedPin));
+ }
+ }
+
[Fact]
public void ThrowsIfWritingOnInputPin()
{
@@ -270,6 +309,52 @@ void Callback(object sender, PinValueChangedEventArgs e)
}
}
+ [Fact]
+ public void AddCallbackDisposeCallbackTest()
+ {
+ int risingEventOccurredCount = 0, fallingEventOccurredCount = 0;
+ using (GpioController controller = new GpioController(GetTestNumberingScheme(), GetTestDriver()))
+ {
+ controller.OpenPin(InputPin, PinMode.Input);
+ controller.OpenPin(OutputPin, PinMode.Output);
+ controller.Write(OutputPin, PinValue.Low);
+
+ controller.RegisterCallbackForPinValueChangedEvent(InputPin, PinEventTypes.Rising, (o, e) =>
+ {
+ risingEventOccurredCount++;
+ });
+ var callbackToDispose = controller.RegisterCallbackForPinValueChangedEventAsDisposable(InputPin, PinEventTypes.Rising, Callback);
+ controller.RegisterCallbackForPinValueChangedEvent(InputPin, PinEventTypes.Rising, (o, e) =>
+ {
+ risingEventOccurredCount++;
+ if (fallingEventOccurredCount == 4)
+ {
+ callbackToDispose.Dispose();
+ }
+ });
+ controller.RegisterCallbackForPinValueChangedEvent(InputPin, PinEventTypes.Falling, (o, e) =>
+ {
+ fallingEventOccurredCount++;
+ });
+
+ for (int i = 0; i < 10; i++)
+ {
+ controller.Write(OutputPin, PinValue.High);
+ Thread.Sleep(WaitMilliseconds);
+ controller.Write(OutputPin, PinValue.Low);
+ Thread.Sleep(WaitMilliseconds);
+ }
+
+ Assert.Equal(25, risingEventOccurredCount);
+ Assert.Equal(10, fallingEventOccurredCount);
+
+ void Callback(object sender, PinValueChangedEventArgs e)
+ {
+ risingEventOccurredCount++;
+ }
+ }
+ }
+
[Fact]
public void AddCallbackRemoveAllCallbackTest()
{
diff --git a/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs b/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs
index 190bbee0a1..5dba50e798 100644
--- a/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs
+++ b/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs
@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Device.Gpio.Drivers;
+using System.Disposables;
using System.IO;
using System.Text.RegularExpressions;
using System.Threading;
@@ -15,7 +16,7 @@ namespace System.Device.Gpio
///
/// Represents a general-purpose I/O (GPIO) controller.
///
- public sealed class GpioController : IDisposable
+ public sealed class GpioController : IGpioController
{
// Constants used to check the hardware on linux
private const string CpuInfoPath = "/proc/cpuinfo";
@@ -52,14 +53,10 @@ public GpioController(PinNumberingScheme numberingScheme, GpioDriver driver)
_openPins = new HashSet();
}
- ///
- /// The numbering scheme used to represent pins provided by the controller.
- ///
+ ///
public PinNumberingScheme NumberingScheme { get; }
- ///
- /// The number of pins provided by the controller.
- ///
+ ///
public int PinCount => _driver.PinCount;
///
@@ -72,10 +69,7 @@ private int GetLogicalPinNumber(int pinNumber)
return (NumberingScheme == PinNumberingScheme.Logical) ? pinNumber : _driver.ConvertPinNumberToLogicalNumberingScheme(pinNumber);
}
- ///
- /// Opens a pin in order for it to be ready to use.
- ///
- /// The pin number in the controller's numbering scheme.
+ ///
public void OpenPin(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -88,21 +82,14 @@ public void OpenPin(int pinNumber)
_openPins.Add(logicalPinNumber);
}
- ///
- /// Opens a pin and sets it to a specific mode.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The mode to be set.
+ ///
public void OpenPin(int pinNumber, PinMode mode)
{
OpenPin(pinNumber);
SetPinMode(pinNumber, mode);
}
- ///
- /// Closes an open pin.
- ///
- /// The pin number in the controller's numbering scheme.
+ ///
public void ClosePin(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -115,11 +102,7 @@ public void ClosePin(int pinNumber)
_openPins.Remove(logicalPinNumber);
}
- ///
- /// Sets the mode to a pin.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The mode to be set.
+ ///
public void SetPinMode(int pinNumber, PinMode mode)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -136,11 +119,7 @@ public void SetPinMode(int pinNumber, PinMode mode)
_driver.SetPinMode(logicalPinNumber, mode);
}
- ///
- /// Gets the mode of a pin.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The mode of the pin.
+ ///
public PinMode GetPinMode(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -152,34 +131,21 @@ public PinMode GetPinMode(int pinNumber)
return _driver.GetPinMode(logicalPinNumber);
}
- ///
- /// Checks if a specific pin is open.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The status if the pin is open or closed.
+ ///
public bool IsPinOpen(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
return _openPins.Contains(logicalPinNumber);
}
- ///
- /// Checks if a pin supports a specific mode.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The mode to check.
- /// The status if the pin supports the mode.
+ ///
public bool IsPinModeSupported(int pinNumber, PinMode mode)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
return _driver.IsPinModeSupported(logicalPinNumber, mode);
}
- ///
- /// Reads the current value of a pin.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The value of the pin.
+ ///
public PinValue Read(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -191,11 +157,7 @@ public PinValue Read(int pinNumber)
return _driver.Read(logicalPinNumber);
}
- ///
- /// Writes a value to a pin.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The value to be written to the pin.
+ ///
public void Write(int pinNumber, PinValue value)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -212,13 +174,7 @@ public void Write(int pinNumber, PinValue value)
_driver.Write(logicalPinNumber, value);
}
- ///
- /// Blocks execution until an event of type eventType is received or a period of time has expired.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The event types to wait for.
- /// The time to wait for the event.
- /// A structure that contains the result of the waiting operation.
+ ///
public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
{
using (CancellationTokenSource tokenSource = new CancellationTokenSource(timeout))
@@ -227,13 +183,7 @@ public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes,
}
}
- ///
- /// Blocks execution until an event of type eventType is received or a cancellation is requested.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The event types to wait for.
- /// The cancellation token of when the operation should stop waiting for an event.
- /// A structure that contains the result of the waiting operation.
+ ///
public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, CancellationToken cancellationToken)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -245,13 +195,7 @@ public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes,
return _driver.WaitForEvent(logicalPinNumber, eventTypes, cancellationToken);
}
- ///
- /// Async call to wait until an event of type eventType is received or a period of time has expired.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The event types to wait for.
- /// The time to wait for the event.
- /// A task representing the operation of getting the structure that contains the result of the waiting operation.
+ ///
public async ValueTask WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
{
using (CancellationTokenSource tokenSource = new CancellationTokenSource(timeout))
@@ -260,13 +204,7 @@ public async ValueTask WaitForEventAsync(int pinNumber, PinE
}
}
- ///
- /// Async call until an event of type eventType is received or a cancellation is requested.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The event types to wait for.
- /// The cancellation token of when the operation should stop waiting for an event.
- /// A task representing the operation of getting the structure that contains the result of the waiting operation
+ ///
public ValueTask WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, CancellationToken token)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -278,12 +216,7 @@ public ValueTask WaitForEventAsync(int pinNumber, PinEventTy
return _driver.WaitForEventAsync(logicalPinNumber, eventTypes, token);
}
- ///
- /// Adds a callback that will be invoked when pinNumber has an event of type eventType.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The event types to wait for.
- /// The callback method that will be invoked.
+ ///
public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -295,11 +228,7 @@ public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes
_driver.AddCallbackForPinValueChangedEvent(logicalPinNumber, eventTypes, callback);
}
- ///
- /// Removes a callback that was being invoked for pin at pinNumber.
- ///
- /// The pin number in the controller's numbering scheme.
- /// The callback method that will be invoked.
+ ///
public void UnregisterCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
@@ -328,10 +257,7 @@ public void Dispose()
Dispose(true);
}
- ///
- /// Write the given pins with the given values.
- ///
- /// The pin/value pairs to write.
+ ///
public void Write(ReadOnlySpan pinValuePairs)
{
for (int i = 0; i < pinValuePairs.Length; i++)
@@ -340,10 +266,7 @@ public void Write(ReadOnlySpan pinValuePairs)
}
}
- ///
- /// Read the given pins with the given pin numbers.
- ///
- /// The pin/value pairs to read.
+ ///
public void Read(Span pinValuePairs)
{
for (int i = 0; i < pinValuePairs.Length; i++)
diff --git a/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs b/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs
new file mode 100644
index 0000000000..7dd2d2f131
--- /dev/null
+++ b/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Device.Gpio
+{
+ ///
+ /// Represents the interface of a general-purpose I/O (GPIO) controller.
+ ///
+ public interface IGpioController : IDisposable
+ {
+ ///
+ /// The numbering scheme used to represent pins provided by the controller.
+ ///
+ PinNumberingScheme NumberingScheme { get; }
+
+ ///
+ /// The number of pins provided by the controller.
+ ///
+ int PinCount { get; }
+
+ ///
+ /// Opens a pin in order for it to be ready to use.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ void OpenPin(int pinNumber);
+
+ ///
+ /// Opens a pin and sets it to a specific mode.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The mode to be set.
+ void OpenPin(int pinNumber, PinMode mode);
+
+ ///
+ /// Closes an open pin.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ void ClosePin(int pinNumber);
+
+ ///
+ /// Sets the mode to a pin.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The mode to be set.
+ void SetPinMode(int pinNumber, PinMode mode);
+
+ ///
+ /// Gets the mode of a pin.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The mode of the pin.
+ PinMode GetPinMode(int pinNumber);
+
+ ///
+ /// Checks if a specific pin is open.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The status if the pin is open or closed.
+ bool IsPinOpen(int pinNumber);
+
+ ///
+ /// Checks if a pin supports a specific mode.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The mode to check.
+ /// The status if the pin supports the mode.
+ bool IsPinModeSupported(int pinNumber, PinMode mode);
+
+ ///
+ /// Reads the current value of a pin.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The value of the pin.
+ PinValue Read(int pinNumber);
+
+ ///
+ /// Writes a value to a pin.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The value to be written to the pin.
+ void Write(int pinNumber, PinValue value);
+
+ ///
+ /// Blocks execution until an event of type eventType is received or a period of time has expired.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The event types to wait for.
+ /// The time to wait for the event.
+ /// A structure that contains the result of the waiting operation.
+ WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout);
+
+ ///
+ /// Blocks execution until an event of type eventType is received or a cancellation is requested.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The event types to wait for.
+ /// The cancellation token of when the operation should stop waiting for an event.
+ /// A structure that contains the result of the waiting operation.
+ WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, CancellationToken cancellationToken);
+
+ ///
+ /// Async call to wait until an event of type eventType is received or a period of time has expired.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The event types to wait for.
+ /// The time to wait for the event.
+ /// A task representing the operation of getting the structure that contains the result of the waiting operation.
+ ValueTask WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout);
+
+ ///
+ /// Async call until an event of type eventType is received or a cancellation is requested.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The event types to wait for.
+ /// The cancellation token of when the operation should stop waiting for an event.
+ /// A task representing the operation of getting the structure that contains the result of the waiting operation
+ ValueTask WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, CancellationToken token);
+
+ ///
+ /// Adds a callback that will be invoked when pinNumber has an event of type eventType.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The event types to wait for.
+ /// The callback method that will be invoked.
+ void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback);
+
+ ///
+ /// Removes a callback that was being invoked for pin at pinNumber.
+ ///
+ /// The pin number in the controller's numbering scheme.
+ /// The callback method that will be invoked.
+ void UnregisterCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback);
+
+ ///
+ /// Write the given pins with the given values.
+ ///
+ /// The pin/value pairs to write.
+ void Write(ReadOnlySpan pinValuePairs);
+
+ ///
+ /// Read the given pins with the given pin numbers.
+ ///
+ /// The pin/value pairs to read.
+ void Read(Span pinValuePairs);
+ }
+}
diff --git a/src/System.Device.Gpio/System/Device/Gpio/IGpioControllerExtensions.cs b/src/System.Device.Gpio/System/Device/Gpio/IGpioControllerExtensions.cs
new file mode 100644
index 0000000000..682e92ccca
--- /dev/null
+++ b/src/System.Device.Gpio/System/Device/Gpio/IGpioControllerExtensions.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Disposables;
+
+namespace System.Device.Gpio
+{
+ ///
+ /// Extensions for interface.
+ ///
+ public static class IGpioControllerExtensions
+ {
+ ///
+ /// Opens a pin in order for it to be ready to use.
+ ///
+ /// The GPioController.
+ /// The pin number in the controller's numbering scheme.
+ /// A disposable that will close the pin if disposed.
+ public static IDisposable OpenPinAsDisposable(this IGpioController controller, int pinNumber)
+ {
+ controller.OpenPin(pinNumber);
+ return Disposable.Create(() => controller.ClosePin(pinNumber));
+ }
+
+ ///
+ /// Opens a pin and sets it to a specific mode.
+ ///
+ /// The GPioController.
+ /// The pin number in the controller's numbering scheme.
+ /// The mode to be set.
+ /// A disposable that will close the pin if disposed.
+ public static IDisposable OpenPinAsDisposable(this IGpioController controller, int pinNumber, PinMode mode)
+ {
+ controller.OpenPin(pinNumber, mode);
+ return Disposable.Create(() => controller.ClosePin(pinNumber));
+ }
+
+ ///
+ /// Adds a callback that will be invoked when pinNumber has an event of type eventType.
+ ///
+ /// The GPioController.
+ /// The pin number in the controller's numbering scheme.
+ /// The event types to wait for.
+ /// The callback method that will be invoked.
+ /// A disposable object that will remove the added callback
+ public static IDisposable RegisterCallbackForPinValueChangedEventAsDisposable(this IGpioController controller, int pinNumber,
+ PinEventTypes eventTypes, PinChangeEventHandler callback)
+ {
+ controller.RegisterCallbackForPinValueChangedEvent(pinNumber, eventTypes, callback);
+ return Disposable.Create(() => controller.UnregisterCallbackForPinValueChangedEvent(pinNumber, callback));
+ }
+ }
+}
diff --git a/src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs b/src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs
new file mode 100644
index 0000000000..cbb921166f
--- /dev/null
+++ b/src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Disposables;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace System.Device.Gpio
+{
+ ///
+ /// Represents a shared view of general-purpose I/O (GPIO) controller.
+ ///
+ public sealed class SharedGpioController : IGpioController
+ {
+ private readonly List _openPins = new List();
+ private readonly IGpioController _controller;
+
+ ///
+ /// Initializes a new instance of the class that will use the logical pin numbering scheme as default.
+ ///
+ public SharedGpioController(IGpioController controller)
+ {
+ _controller = controller;
+ }
+
+ ///
+ public void Dispose()
+ {
+ foreach (var openPin in _openPins)
+ {
+ _controller.ClosePin(openPin);
+ }
+
+ _openPins.Clear();
+ }
+
+ ///
+ public PinNumberingScheme NumberingScheme => _controller.NumberingScheme;
+
+ ///
+ public int PinCount => _controller.PinCount;
+
+ ///
+ public void OpenPin(int pinNumber)
+ {
+ _controller.OpenPin(pinNumber);
+ _openPins.Add(pinNumber);
+ }
+
+ ///
+ public void OpenPin(int pinNumber, PinMode mode)
+ {
+ _controller.OpenPin(pinNumber, mode);
+ _openPins.Add(pinNumber);
+ }
+
+ ///
+ public void ClosePin(int pinNumber)
+ {
+ if (_openPins.Remove(pinNumber))
+ {
+ _controller.ClosePin(pinNumber);
+ }
+ }
+
+ ///
+ public void SetPinMode(int pinNumber, PinMode mode)
+ {
+ _controller.SetPinMode(pinNumber, mode);
+ }
+
+ ///
+ public PinMode GetPinMode(int pinNumber)
+ {
+ return _controller.GetPinMode(pinNumber);
+ }
+
+ ///
+ public bool IsPinOpen(int pinNumber)
+ {
+ return _openPins.Contains(pinNumber);
+ }
+
+ ///
+ public bool IsPinModeSupported(int pinNumber, PinMode mode)
+ {
+ return _controller.IsPinModeSupported(pinNumber, mode);
+ }
+
+ ///
+ public PinValue Read(int pinNumber)
+ {
+ return _controller.Read(pinNumber);
+ }
+
+ ///
+ public void Write(int pinNumber, PinValue value)
+ {
+ _controller.Write(pinNumber, value);
+ }
+
+ ///
+ public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
+ {
+ return _controller.WaitForEvent(pinNumber, eventTypes, timeout);
+ }
+
+ ///
+ public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, CancellationToken cancellationToken)
+ {
+ return _controller.WaitForEvent(pinNumber, eventTypes, cancellationToken);
+ }
+
+ ///
+ public ValueTask WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
+ {
+ return _controller.WaitForEventAsync(pinNumber, eventTypes, timeout);
+ }
+
+ ///
+ public ValueTask WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, CancellationToken token)
+ {
+ return _controller.WaitForEventAsync(pinNumber, eventTypes, token);
+ }
+
+ ///
+ public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback)
+ {
+ _controller.RegisterCallbackForPinValueChangedEvent(pinNumber, eventTypes, callback);
+ }
+
+ ///
+ public void UnregisterCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback)
+ {
+ _controller.UnregisterCallbackForPinValueChangedEvent(pinNumber, callback);
+ }
+
+ ///
+ public void Write(ReadOnlySpan pinValuePairs)
+ {
+ _controller.Write(pinValuePairs);
+ }
+
+ ///
+ public void Read(Span pinValuePairs)
+ {
+ _controller.Read(pinValuePairs);
+ }
+ }
+}
diff --git a/src/System.Device.Gpio/System/Disposables/Disposable.cs b/src/System.Device.Gpio/System/Disposables/Disposable.cs
new file mode 100644
index 0000000000..dcd503b1f6
--- /dev/null
+++ b/src/System.Device.Gpio/System/Disposables/Disposable.cs
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Disposables
+{
+ ///
+ /// Utility to create disposable objects
+ ///
+ public static class Disposable
+ {
+ private class AnonymousDisposable : IDisposable
+ {
+ private readonly Action _onDispose;
+
+ public AnonymousDisposable(Action onDispose)
+ {
+ _onDispose = onDispose ?? throw new ArgumentNullException(nameof(onDispose));
+ }
+
+ public void Dispose()
+ {
+ _onDispose();
+ }
+ }
+
+ ///
+ /// Creates a disposable object.
+ ///
+ /// The action to perform on disposal
+ /// The disposable object
+ public static IDisposable Create(Action onDispose)
+ {
+ return new AnonymousDisposable(onDispose);
+ }
+ }
+}