Skip to content
Closed
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
85 changes: 85 additions & 0 deletions src/System.Device.Gpio.Tests/GpioControllerTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -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()
{
Expand Down Expand Up @@ -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()
{
Expand Down
119 changes: 21 additions & 98 deletions src/System.Device.Gpio/System/Device/Gpio/GpioController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -15,7 +16,7 @@ namespace System.Device.Gpio
/// <summary>
/// Represents a general-purpose I/O (GPIO) controller.
/// </summary>
public sealed class GpioController : IDisposable
public sealed class GpioController : IGpioController
{
// Constants used to check the hardware on linux
private const string CpuInfoPath = "/proc/cpuinfo";
Expand Down Expand Up @@ -52,14 +53,10 @@ public GpioController(PinNumberingScheme numberingScheme, GpioDriver driver)
_openPins = new HashSet<int>();
}

/// <summary>
/// The numbering scheme used to represent pins provided by the controller.
/// </summary>
/// <inheritdoc/>
public PinNumberingScheme NumberingScheme { get; }

/// <summary>
/// The number of pins provided by the controller.
/// </summary>
/// <inheritdoc/>
public int PinCount => _driver.PinCount;

/// <summary>
Expand All @@ -72,10 +69,7 @@ private int GetLogicalPinNumber(int pinNumber)
return (NumberingScheme == PinNumberingScheme.Logical) ? pinNumber : _driver.ConvertPinNumberToLogicalNumberingScheme(pinNumber);
}

/// <summary>
/// Opens a pin in order for it to be ready to use.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <inheritdoc/>
public void OpenPin(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -88,21 +82,14 @@ public void OpenPin(int pinNumber)
_openPins.Add(logicalPinNumber);
}

/// <summary>
/// Opens a pin and sets it to a specific mode.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="mode">The mode to be set.</param>
/// <inheritdoc/>
public void OpenPin(int pinNumber, PinMode mode)
{
OpenPin(pinNumber);
SetPinMode(pinNumber, mode);
}

/// <summary>
/// Closes an open pin.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <inheritdoc/>
public void ClosePin(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -115,11 +102,7 @@ public void ClosePin(int pinNumber)
_openPins.Remove(logicalPinNumber);
}

/// <summary>
/// Sets the mode to a pin.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="mode">The mode to be set.</param>
/// <inheritdoc/>
public void SetPinMode(int pinNumber, PinMode mode)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -136,11 +119,7 @@ public void SetPinMode(int pinNumber, PinMode mode)
_driver.SetPinMode(logicalPinNumber, mode);
}

/// <summary>
/// Gets the mode of a pin.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <returns>The mode of the pin.</returns>
/// <inheritdoc/>
public PinMode GetPinMode(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -152,34 +131,21 @@ public PinMode GetPinMode(int pinNumber)
return _driver.GetPinMode(logicalPinNumber);
}

/// <summary>
/// Checks if a specific pin is open.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <returns>The status if the pin is open or closed.</returns>
/// <inheritdoc/>
public bool IsPinOpen(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
return _openPins.Contains(logicalPinNumber);
}

/// <summary>
/// Checks if a pin supports a specific mode.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="mode">The mode to check.</param>
/// <returns>The status if the pin supports the mode.</returns>
/// <inheritdoc/>
public bool IsPinModeSupported(int pinNumber, PinMode mode)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
return _driver.IsPinModeSupported(logicalPinNumber, mode);
}

/// <summary>
/// Reads the current value of a pin.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <returns>The value of the pin.</returns>
/// <inheritdoc/>
public PinValue Read(int pinNumber)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -191,11 +157,7 @@ public PinValue Read(int pinNumber)
return _driver.Read(logicalPinNumber);
}

/// <summary>
/// Writes a value to a pin.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="value">The value to be written to the pin.</param>
/// <inheritdoc/>
public void Write(int pinNumber, PinValue value)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -212,13 +174,7 @@ public void Write(int pinNumber, PinValue value)
_driver.Write(logicalPinNumber, value);
}

/// <summary>
/// Blocks execution until an event of type eventType is received or a period of time has expired.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="eventTypes">The event types to wait for.</param>
/// <param name="timeout">The time to wait for the event.</param>
/// <returns>A structure that contains the result of the waiting operation.</returns>
/// <inheritdoc/>
public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
{
using (CancellationTokenSource tokenSource = new CancellationTokenSource(timeout))
Expand All @@ -227,13 +183,7 @@ public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes,
}
}

/// <summary>
/// Blocks execution until an event of type eventType is received or a cancellation is requested.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="eventTypes">The event types to wait for.</param>
/// <param name="cancellationToken">The cancellation token of when the operation should stop waiting for an event.</param>
/// <returns>A structure that contains the result of the waiting operation.</returns>
/// <inheritdoc/>
public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes, CancellationToken cancellationToken)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -245,13 +195,7 @@ public WaitForEventResult WaitForEvent(int pinNumber, PinEventTypes eventTypes,
return _driver.WaitForEvent(logicalPinNumber, eventTypes, cancellationToken);
}

/// <summary>
/// Async call to wait until an event of type eventType is received or a period of time has expired.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="eventTypes">The event types to wait for.</param>
/// <param name="timeout">The time to wait for the event.</param>
/// <returns>A task representing the operation of getting the structure that contains the result of the waiting operation.</returns>
/// <inheritdoc/>
public async ValueTask<WaitForEventResult> WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, TimeSpan timeout)
{
using (CancellationTokenSource tokenSource = new CancellationTokenSource(timeout))
Expand All @@ -260,13 +204,7 @@ public async ValueTask<WaitForEventResult> WaitForEventAsync(int pinNumber, PinE
}
}

/// <summary>
/// Async call until an event of type eventType is received or a cancellation is requested.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="eventTypes">The event types to wait for.</param>
/// <param name="token">The cancellation token of when the operation should stop waiting for an event.</param>
/// <returns>A task representing the operation of getting the structure that contains the result of the waiting operation</returns>
/// <inheritdoc/>
public ValueTask<WaitForEventResult> WaitForEventAsync(int pinNumber, PinEventTypes eventTypes, CancellationToken token)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -278,12 +216,7 @@ public ValueTask<WaitForEventResult> WaitForEventAsync(int pinNumber, PinEventTy
return _driver.WaitForEventAsync(logicalPinNumber, eventTypes, token);
}

/// <summary>
/// Adds a callback that will be invoked when pinNumber has an event of type eventType.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="eventTypes">The event types to wait for.</param>
/// <param name="callback">The callback method that will be invoked.</param>
/// <inheritdoc/>
public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes eventTypes, PinChangeEventHandler callback)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand All @@ -295,11 +228,7 @@ public void RegisterCallbackForPinValueChangedEvent(int pinNumber, PinEventTypes
_driver.AddCallbackForPinValueChangedEvent(logicalPinNumber, eventTypes, callback);
}

/// <summary>
/// Removes a callback that was being invoked for pin at pinNumber.
/// </summary>
/// <param name="pinNumber">The pin number in the controller's numbering scheme.</param>
/// <param name="callback">The callback method that will be invoked.</param>
/// <inheritdoc/>
public void UnregisterCallbackForPinValueChangedEvent(int pinNumber, PinChangeEventHandler callback)
{
int logicalPinNumber = GetLogicalPinNumber(pinNumber);
Expand Down Expand Up @@ -328,10 +257,7 @@ public void Dispose()
Dispose(true);
}

/// <summary>
/// Write the given pins with the given values.
/// </summary>
/// <param name="pinValuePairs">The pin/value pairs to write.</param>
/// <inheritdoc/>
public void Write(ReadOnlySpan<PinValuePair> pinValuePairs)
{
for (int i = 0; i < pinValuePairs.Length; i++)
Expand All @@ -340,10 +266,7 @@ public void Write(ReadOnlySpan<PinValuePair> pinValuePairs)
}
}

/// <summary>
/// Read the given pins with the given pin numbers.
/// </summary>
/// <param name="pinValuePairs">The pin/value pairs to read.</param>
/// <inheritdoc/>
public void Read(Span<PinValuePair> pinValuePairs)
{
for (int i = 0; i < pinValuePairs.Length; i++)
Expand Down
Loading