From e1760e69cb945390ed3d718721c670b40e3d60ad Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 26 Aug 2020 14:47:44 +0100 Subject: [PATCH 1/2] adding disposable, shared controller interface and gpiocontroller interface --- .../GpioControllerTestBase.cs | 85 ++++++++++ .../System/Device/Gpio/GpioController.cs | 129 ++++----------- .../System/Device/Gpio/IGpioController.cs | 153 +++++++++++++++++ .../Device/Gpio/SharedGpioController.cs | 156 ++++++++++++++++++ .../System/Disposables/Disposable.cs | 37 +++++ 5 files changed, 459 insertions(+), 101 deletions(-) create mode 100644 src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs create mode 100644 src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs create mode 100644 src/System.Device.Gpio/System/Disposables/Disposable.cs diff --git a/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs b/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs index a11c8a3e32..df229a51fb 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.OpenPin(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.RegisterCallbackForPinValueChangedEvent(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..010f000245 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,11 +69,8 @@ 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) + /// + public IDisposable OpenPin(int pinNumber) { int logicalPinNumber = GetLogicalPinNumber(pinNumber); if (_openPins.Contains(logicalPinNumber)) @@ -86,23 +80,18 @@ public void OpenPin(int pinNumber) _driver.OpenPin(logicalPinNumber); _openPins.Add(logicalPinNumber); + return Disposable.Create(() => ClosePin(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. - public void OpenPin(int pinNumber, PinMode mode) + /// + public IDisposable OpenPin(int pinNumber, PinMode mode) { OpenPin(pinNumber); SetPinMode(pinNumber, mode); + return Disposable.Create(() => ClosePin(pinNumber)); } - /// - /// Closes an open pin. - /// - /// The pin number in the controller's numbering scheme. + /// public void ClosePin(int pinNumber) { int logicalPinNumber = GetLogicalPinNumber(pinNumber); @@ -115,11 +104,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 +121,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 +133,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 +159,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 +176,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 +185,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 +197,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 +206,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,13 +218,8 @@ 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) + /// + public IDisposable RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback) { int logicalPinNumber = GetLogicalPinNumber(pinNumber); if (!_openPins.Contains(logicalPinNumber)) @@ -293,13 +228,11 @@ public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes } _driver.AddCallbackForPinValueChangedEvent(logicalPinNumber, eventTypes, callback); + + return Disposable.Create(() => UnregisterCallbackForPinValueChangedEvent(pinNumber, 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 +261,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 +270,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..e81a91d3f5 --- /dev/null +++ b/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs @@ -0,0 +1,153 @@ +// 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. + /// A disposable that will close the pin if disposed. + IDisposable 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. + /// A disposable that will close the pin if disposed. + IDisposable 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. + /// A disposable object that will remove the added callback + IDisposable 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/SharedGpioController.cs b/src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs new file mode 100644 index 0000000000..6e2f0cee4e --- /dev/null +++ b/src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs @@ -0,0 +1,156 @@ +// 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 IDisposable OpenPin(int pinNumber) + { + _controller.OpenPin(pinNumber); + _openPins.Add(pinNumber); + return Disposable.Create(() => ClosePin(pinNumber)); + } + + /// + public IDisposable OpenPin(int pinNumber, PinMode mode) + { + _controller.OpenPin(pinNumber, mode); + _openPins.Add(pinNumber); + return Disposable.Create(() => ClosePin(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 IDisposable RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback) + { + _controller.RegisterCallbackForPinValueChangedEvent(pinNumber, eventTypes, callback); + + return Disposable.Create(() => UnregisterCallbackForPinValueChangedEvent(pinNumber, 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); + } + } +} From 67d5b1ca257a15069618fb1d6c77fab7fd55a295 Mon Sep 17 00:00:00 2001 From: Diego Date: Wed, 26 Aug 2020 17:45:32 +0100 Subject: [PATCH 2/2] add new api as extensions instead of breaking changes --- .../GpioControllerTestBase.cs | 4 +- .../System/Device/Gpio/GpioController.cs | 10 ++-- .../System/Device/Gpio/IGpioController.cs | 9 ++-- .../Device/Gpio/IGpioControllerExtensions.cs | 54 +++++++++++++++++++ .../Device/Gpio/SharedGpioController.cs | 10 ++-- 5 files changed, 65 insertions(+), 22 deletions(-) create mode 100644 src/System.Device.Gpio/System/Device/Gpio/IGpioControllerExtensions.cs diff --git a/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs b/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs index df229a51fb..f45d662e27 100644 --- a/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs +++ b/src/System.Device.Gpio.Tests/GpioControllerTestBase.cs @@ -143,7 +143,7 @@ public void CanClosePinsViaDisposableTest() { Assert.False(controller.IsPinOpen(LedPin)); - var openPin = controller.OpenPin(LedPin, PinMode.Output); + var openPin = controller.OpenPinAsDisposable(LedPin, PinMode.Output); Assert.True(controller.IsPinOpen(LedPin)); openPin.Dispose(); @@ -323,7 +323,7 @@ public void AddCallbackDisposeCallbackTest() { risingEventOccurredCount++; }); - var callbackToDispose = controller.RegisterCallbackForPinValueChangedEvent(InputPin, PinEventTypes.Rising, Callback); + var callbackToDispose = controller.RegisterCallbackForPinValueChangedEventAsDisposable(InputPin, PinEventTypes.Rising, Callback); controller.RegisterCallbackForPinValueChangedEvent(InputPin, PinEventTypes.Rising, (o, e) => { risingEventOccurredCount++; diff --git a/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs b/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs index 010f000245..5dba50e798 100644 --- a/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs +++ b/src/System.Device.Gpio/System/Device/Gpio/GpioController.cs @@ -70,7 +70,7 @@ private int GetLogicalPinNumber(int pinNumber) } /// - public IDisposable OpenPin(int pinNumber) + public void OpenPin(int pinNumber) { int logicalPinNumber = GetLogicalPinNumber(pinNumber); if (_openPins.Contains(logicalPinNumber)) @@ -80,15 +80,13 @@ public IDisposable OpenPin(int pinNumber) _driver.OpenPin(logicalPinNumber); _openPins.Add(logicalPinNumber); - return Disposable.Create(() => ClosePin(pinNumber)); } /// - public IDisposable OpenPin(int pinNumber, PinMode mode) + public void OpenPin(int pinNumber, PinMode mode) { OpenPin(pinNumber); SetPinMode(pinNumber, mode); - return Disposable.Create(() => ClosePin(pinNumber)); } /// @@ -219,7 +217,7 @@ public ValueTask WaitForEventAsync(int pinNumber, PinEventTy } /// - public IDisposable RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback) + public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback) { int logicalPinNumber = GetLogicalPinNumber(pinNumber); if (!_openPins.Contains(logicalPinNumber)) @@ -228,8 +226,6 @@ public IDisposable RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEve } _driver.AddCallbackForPinValueChangedEvent(logicalPinNumber, eventTypes, callback); - - return Disposable.Create(() => UnregisterCallbackForPinValueChangedEvent(pinNumber, callback)); } /// diff --git a/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs b/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs index e81a91d3f5..7dd2d2f131 100644 --- a/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs +++ b/src/System.Device.Gpio/System/Device/Gpio/IGpioController.cs @@ -26,16 +26,14 @@ public interface IGpioController : IDisposable /// Opens a pin in order for it to be ready to use. /// /// The pin number in the controller's numbering scheme. - /// A disposable that will close the pin if disposed. - IDisposable OpenPin(int pinNumber); + 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. - /// A disposable that will close the pin if disposed. - IDisposable OpenPin(int pinNumber, PinMode mode); + void OpenPin(int pinNumber, PinMode mode); /// /// Closes an open pin. @@ -128,8 +126,7 @@ public interface IGpioController : IDisposable /// 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 - IDisposable RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback); + void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback); /// /// Removes a callback that was being invoked for pin at pinNumber. 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 index 6e2f0cee4e..cbb921166f 100644 --- a/src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs +++ b/src/System.Device.Gpio/System/Device/Gpio/SharedGpioController.cs @@ -43,19 +43,17 @@ public void Dispose() public int PinCount => _controller.PinCount; /// - public IDisposable OpenPin(int pinNumber) + public void OpenPin(int pinNumber) { _controller.OpenPin(pinNumber); _openPins.Add(pinNumber); - return Disposable.Create(() => ClosePin(pinNumber)); } /// - public IDisposable OpenPin(int pinNumber, PinMode mode) + public void OpenPin(int pinNumber, PinMode mode) { _controller.OpenPin(pinNumber, mode); _openPins.Add(pinNumber); - return Disposable.Create(() => ClosePin(pinNumber)); } /// @@ -128,11 +126,9 @@ public ValueTask WaitForEventAsync(int pinNumber, PinEventTy } /// - public IDisposable RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback) + public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback) { _controller.RegisterCallbackForPinValueChangedEvent(pinNumber, eventTypes, callback); - - return Disposable.Create(() => UnregisterCallbackForPinValueChangedEvent(pinNumber, callback)); } ///