Skip to content

Commit 481b165

Browse files
authored
Move to fully native implementation (#2)
1 parent 2231cf0 commit 481b165

40 files changed

+280
-1894
lines changed

.editorconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[*.cs]
2+
3+
4+
# S4200: Native methods should be wrapped
5+
# OK to call directly native methods in nanoFramework
6+
dotnet_diagnostic.S4200.severity = none

System.Device.Gpio/GpioController.cs

Lines changed: 194 additions & 127 deletions
Large diffs are not rendered by default.

Windows.Devices.Gpio/GpioPin.cs renamed to System.Device.Gpio/GpioPin.cs

Lines changed: 40 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,61 +3,49 @@
33
// See LICENSE file in the project root for full license information.
44
//
55

6-
using System;
76
using System.Runtime.CompilerServices;
87

9-
namespace Windows.Devices.Gpio
8+
namespace System.Device.Gpio
109
{
11-
// This should be a TypedEventHandler "EventHandler<GpioPinValueChangedEventArgs>"
12-
#pragma warning disable 1591
13-
public delegate void GpioPinValueChangedEventHandler(
14-
Object sender,
15-
GpioPinValueChangedEventArgs e);
16-
10+
// This should be a TypedEventHandler "EventHandler<PinValueChangedEventArgs>"
11+
#pragma warning disable 1591
12+
public delegate void PinValueChangedEventHandler(
13+
object sender,
14+
PinValueChangedEventArgs e);
1715

1816
/// <summary>
1917
/// Represents a general-purpose I/O (GPIO) pin.
2018
/// </summary>
21-
public sealed class Gpio​Pin : IGpioPin, IDisposable
19+
public sealed class Gpio​Pin : IDisposable
2220
{
23-
private static GpioPinEventListener s_eventListener;
21+
private static readonly GpioPinEventListener s_gpioPinEventManager = new GpioPinEventListener();
2422

2523
// this is used as the lock object
2624
// a lock is required because multiple threads can access the GpioPin
27-
private object _syncLock;
25+
private readonly object _syncLock = new object();
2826

2927
private readonly int _pinNumber;
30-
private GpioPinDriveMode _driveMode = GpioPinDriveMode.Input;
28+
private PinMode _driveMode = PinMode.Input;
3129
private TimeSpan _debounceTimeout = TimeSpan.Zero;
32-
private GpioPinValueChangedEventHandler _callbacks = null;
33-
private GpioPinValue _lastOutputValue = GpioPinValue.Low;
30+
private PinValueChangedEventHandler _callbacks = null;
31+
private PinValue _lastOutputValue = PinValue.Low;
3432

3533
#pragma warning disable 0414
3634
// this field is used in native so it must be kept here despite "not being used"
37-
private GpioPinValue _lastInputValue = GpioPinValue.Low;
35+
private PinValue _lastInputValue = PinValue.Low;
3836
#pragma warning restore 0414
3937

4038
internal GpioPin(int pinNumber)
4139
{
4240
_pinNumber = pinNumber;
43-
44-
_syncLock = new object();
45-
46-
lock (_syncLock)
47-
{
48-
if (s_eventListener == null)
49-
{
50-
s_eventListener = new GpioPinEventListener();
51-
}
52-
}
5341
}
5442

5543
internal bool Init()
5644
{
5745
if(NativeInit(_pinNumber))
5846
{
5947
// add the pin to the event listener in order to receive the callbacks from the native interrupts
60-
s_eventListener.AddPin(this);
48+
s_gpioPinEventManager.AddPin(this);
6149

6250
return true;
6351
}
@@ -93,31 +81,11 @@ public TimeSpan DebounceTimeout
9381
/// <value>
9482
/// The pin number of the GPIO pin.
9583
/// </value>
96-
public int PinNumber {
97-
get
98-
{
99-
lock (_syncLock)
100-
{
101-
// check if pin has been disposed
102-
if (!_disposedValue) { return _pinNumber; }
103-
104-
throw new ObjectDisposedException();
105-
}
106-
}
107-
}
108-
109-
/// <summary>
110-
/// Gets the sharing mode in which the general-purpose I/O (GPIO) pin is open.
111-
/// </summary>
112-
/// <value>
113-
/// The sharing mode in which the GPIO pin is open.
114-
/// </value>
115-
public GpioSharingMode SharingMode
84+
public int PinNumber
11685
{
11786
get
11887
{
119-
// at this time pins can't be shared, use is exclusive exclusive (pun intended!)
120-
return GpioSharingMode.Exclusive;
88+
return _pinNumber;
12189
}
12290
}
12391

@@ -126,7 +94,7 @@ public GpioSharingMode SharingMode
12694
/// </summary>
12795
/// <returns>An enumeration value that indicates the current drive mode for the GPIO pin.
12896
/// The drive mode specifies whether the pin is configured as an input or an output, and determines how values are driven onto the pin.</returns>
129-
public GpioPinDriveMode GetDriveMode()
97+
public PinMode GetDriveMode()
13098
{
13199
lock (_syncLock)
132100
{
@@ -142,11 +110,11 @@ public GpioPinDriveMode GetDriveMode()
142110
/// </summary>
143111
/// <param name="driveMode">The drive mode that you want to check for support.</param>
144112
/// <returns>
145-
/// True if the GPIO pin supports the drive mode that driveMode specifies; otherwise false.
113+
/// <see langword="true"/> if the GPIO pin supports the drive mode that driveMode specifies; otherwise false.
146114
/// If you specify a drive mode for which this method returns false when you call <see cref="SetDriveMode"/>, <see cref="SetDriveMode"/> generates an exception.
147115
/// </returns>
148116

149-
public bool IsDriveModeSupported(GpioPinDriveMode driveMode)
117+
public bool IsDriveModeSupported(PinMode driveMode)
150118
{
151119
lock (_syncLock)
152120
{
@@ -166,10 +134,10 @@ public bool IsDriveModeSupported(GpioPinDriveMode driveMode)
166134
/// <remarks>The following exceptions can be thrown by this method:
167135
/// <list type="bullet">
168136
/// <item><term>E_INVALIDARG : The GPIO pin does not support the specified drive mode.</term></item>
169-
/// <item><term>E_ACCESSDENIED : The pin is open in shared read-only mode.Close the pin and reopen it in exclusive mode to change the drive mode of the pin.</term></item>
137+
/// <item><term>E_ACCESSDENIED : The pin is open in shared read-only mode. Close the pin and reopen it in exclusive mode to change the drive mode of the pin.</term></item>
170138
/// </list>
171139
/// </remarks>
172-
public void SetDriveMode(GpioPinDriveMode value)
140+
public void SetDriveMode(PinMode value)
173141
{
174142
lock (_syncLock)
175143
{
@@ -191,7 +159,7 @@ public void SetDriveMode(GpioPinDriveMode value)
191159
/// </summary>
192160
/// <returns>The current value of the GPIO pin. If the pin is configured as an output, this value is the last value written to the pin.</returns>
193161
[MethodImpl(MethodImplOptions.InternalCall)]
194-
public extern GpioPinValue Read();
162+
public extern PinValue Read();
195163

196164
/// <summary>
197165
/// Drives the specified value onto the general purpose I/O (GPIO) pin according to the current drive mode for the pin
@@ -206,7 +174,7 @@ public void SetDriveMode(GpioPinDriveMode value)
206174
/// <item><term>E_ACCESSDENIED : The GPIO pin is open in shared read-only mode. To write to the pin, close the pin and reopen the pin in exclusive mode.</term></item>
207175
/// </list>
208176
/// </remarks>
209-
public void Write(GpioPinValue value)
177+
public void Write(PinValue value)
210178
{
211179
lock (_syncLock)
212180
{
@@ -220,17 +188,17 @@ public void Write(GpioPinValue value)
220188
WriteNative(value);
221189

222190
// trigger the pin value changed event, if any is set
223-
GpioPinValueChangedEventHandler callbacks = _callbacks;
191+
PinValueChangedEventHandler callbacks = _callbacks;
224192

225-
if (_lastOutputValue == GpioPinValue.Low)
193+
if (_lastOutputValue == PinValue.Low)
226194
{
227195
// last value is now LOW, so it was HIGH
228-
callbacks?.Invoke(this, new GpioPinValueChangedEventArgs(GpioPinEdge.FallingEdge));
196+
callbacks?.Invoke(this, new PinValueChangedEventArgs(PinEventTypes.Falling, _pinNumber));
229197
}
230198
else
231199
{
232200
// last value is now HIGH, so it was LOW
233-
callbacks?.Invoke(this, new GpioPinValueChangedEventArgs(GpioPinEdge.RisingEdge));
201+
callbacks?.Invoke(this, new PinValueChangedEventArgs(PinEventTypes.Rising, _pinNumber));
234202
}
235203
}
236204
}
@@ -239,7 +207,7 @@ public void Write(GpioPinValue value)
239207
/// <summary>
240208
/// Occurs when the value of the general-purpose I/O (GPIO) pin changes, either because of an external stimulus when the pin is configured as an input, or when a value is written to the pin when the pin in configured as an output.
241209
/// </summary>
242-
public event GpioPinValueChangedEventHandler ValueChanged
210+
public event PinValueChangedEventHandler ValueChanged
243211
{
244212
add
245213
{
@@ -251,7 +219,7 @@ public event GpioPinValueChangedEventHandler ValueChanged
251219
}
252220

253221
var callbacksOld = _callbacks;
254-
var callbacksNew = (GpioPinValueChangedEventHandler)Delegate.Combine(callbacksOld, value);
222+
var callbacksNew = (PinValueChangedEventHandler)Delegate.Combine(callbacksOld, value);
255223

256224
try
257225
{
@@ -276,7 +244,7 @@ public event GpioPinValueChangedEventHandler ValueChanged
276244
}
277245

278246
var callbacksOld = _callbacks;
279-
var callbacksNew = (GpioPinValueChangedEventHandler)Delegate.Remove(callbacksOld, value);
247+
var callbacksNew = (PinValueChangedEventHandler)Delegate.Remove(callbacksOld, value);
280248

281249
try
282250
{
@@ -296,9 +264,9 @@ public event GpioPinValueChangedEventHandler ValueChanged
296264
/// Handles internal events and re-dispatches them to the publicly subscribed delegates.
297265
/// </summary>
298266
/// <param name="edge">The state transition for this event.</param>
299-
internal void OnPinChangedInternal(GpioPinEdge edge)
267+
internal void OnPinChangedInternal(PinEventTypes edge)
300268
{
301-
GpioPinValueChangedEventHandler callbacks = null;
269+
PinValueChangedEventHandler callbacks = null;
302270

303271
lock (_syncLock)
304272
{
@@ -308,18 +276,16 @@ internal void OnPinChangedInternal(GpioPinEdge edge)
308276
}
309277
}
310278

311-
callbacks?.Invoke(this, new GpioPinValueChangedEventArgs(edge));
279+
callbacks?.Invoke(this, new PinValueChangedEventArgs(edge, _pinNumber));
312280
}
313281

314282
/// <summary>
315283
/// Toggles the output of the general purpose I/O (GPIO) pin if the pin is configured as an output.
316284
/// </summary>
317-
/// <remarks>
318-
/// This method is exclusive of nanoFramework and it's not available in the UWP API.
319-
/// </remarks>
320285
[MethodImpl(MethodImplOptions.InternalCall)]
286+
#pragma warning disable S4200 // OK to call native methods directly in nanoFramework
321287
public extern void Toggle();
322-
288+
#pragma warning restore S4200 // Native methods should be wrapped
323289

324290
#region IDisposable Support
325291

@@ -331,8 +297,8 @@ private void Dispose(bool disposing)
331297
{
332298
if (disposing)
333299
{
334-
// remove the pin from the event listner
335-
s_eventListener.RemovePin(_pinNumber);
300+
// remove the pin from the event listener
301+
s_gpioPinEventManager.RemovePin(_pinNumber);
336302
}
337303

338304
DisposeNative();
@@ -368,10 +334,10 @@ public void Dispose()
368334
#region external calls to native implementations
369335

370336
[MethodImpl(MethodImplOptions.InternalCall)]
371-
private extern bool NativeIsDriveModeSupported(GpioPinDriveMode driveMode);
337+
private extern bool NativeIsDriveModeSupported(PinMode driveMode);
372338

373339
[MethodImpl(MethodImplOptions.InternalCall)]
374-
private extern void NativeSetDriveMode(GpioPinDriveMode driveMode);
340+
private extern void NativeSetDriveMode(PinMode driveMode);
375341

376342
[MethodImpl(MethodImplOptions.InternalCall)]
377343
private extern bool NativeInit(int pinNumber);
@@ -380,7 +346,7 @@ public void Dispose()
380346
private extern void NativeSetDebounceTimeout();
381347

382348
[MethodImpl(MethodImplOptions.InternalCall)]
383-
private extern void WriteNative(GpioPinValue value);
349+
private extern void WriteNative(PinValue value);
384350

385351
[MethodImpl(MethodImplOptions.InternalCall)]
386352
internal extern void NativeSetAlternateFunction(int alternateFunction);

Windows.Devices.Gpio/GpioPinEvent.cs renamed to System.Device.Gpio/GpioPinEvent.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55

66
using nanoFramework.Runtime.Events;
77

8-
namespace Windows.Devices.Gpio
8+
namespace System.Device.Gpio
99
{
1010
internal class GpioPinEvent : BaseEvent
1111
{
1212
public int PinNumber;
13-
public GpioPinEdge Edge;
13+
public PinEventTypes EventType;
1414
}
1515
}

Windows.Devices.Gpio/GpioPinEventListener.cs renamed to System.Device.Gpio/GpioPinEventListener.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@
44
//
55

66
using nanoFramework.Runtime.Events;
7-
using System;
87
using System.Collections;
98

10-
namespace Windows.Devices.Gpio
9+
namespace System.Device.Gpio
1110
{
1211
internal class GpioPinEventListener : IEventProcessor, IEventListener
1312
{
1413
// Map of pin numbers to GpioPin objects.
15-
private ArrayList _pinMap = new ArrayList();
14+
private static readonly ArrayList _pinMap = new ArrayList();
1615

1716
public GpioPinEventListener()
1817
{
@@ -26,7 +25,7 @@ public BaseEvent ProcessEvent(uint data1, uint data2, DateTime time)
2625
{
2726
// Data1 is packed by PostManagedEvent, so we need to unpack the high word.
2827
PinNumber = (int)(data1 >> 16),
29-
Edge = (data2 == 0) ? GpioPinEdge.FallingEdge : GpioPinEdge.RisingEdge,
28+
EventType = (data2 == 0) ? PinEventTypes.Falling : PinEventTypes.Rising,
3029
};
3130
}
3231

@@ -47,7 +46,7 @@ public bool OnEvent(BaseEvent ev)
4746
// Avoid calling this under a lock to prevent a potential lock inversion.
4847
if (pin != null)
4948
{
50-
pin.OnPinChangedInternal(pinEvent.Edge);
49+
pin.OnPinChangedInternal(pinEvent.EventType);
5150
}
5251

5352
return true;

System.Device.Gpio/PinValueChangedEventArgs.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using nanoFramework.Runtime.Events;
6+
57
namespace System.Device.Gpio
68
{
79
/// <summary>
810
/// Arguments passed in when an event is triggered by the GPIO.
911
/// </summary>
10-
public class PinValueChangedEventArgs
12+
public class PinValueChangedEventArgs : BaseEvent
1113
{
1214
/// <summary>
1315
/// Initializes a new instance of the <see cref="PinValueChangedEventArgs"/> class.

Windows.Devices.Gpio/Properties/AssemblyInfo.cs renamed to System.Device.Gpio/Properties/AssemblyInfo.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
// General Information about an assembly is controlled through the following
66
// set of attributes. Change these attribute values to modify the information
77
// associated with an assembly.
8-
[assembly: AssemblyTitle("Windows.Devices.Gpio")]
8+
[assembly: AssemblyTitle("System.Device.Gpio")]
99
[assembly: AssemblyCompany("nanoFramework Contributors")]
10-
[assembly: AssemblyProduct("Windows.Devices.Gpio")]
10+
[assembly: AssemblyProduct("System.Device.Gpio")]
1111
[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")]
1212

1313
////////////////////////////////////////////////////////////////

0 commit comments

Comments
 (0)