Skip to content

Commit 1670315

Browse files
Improvements in API (#8)
1 parent 03cb7dd commit 1670315

11 files changed

+264
-96
lines changed

System.Device.UsbStream/Properties/AssemblyInfo.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@
2020
/////////////////////////////////////////////////////////////////
2121
// This attribute is mandatory when building Interop libraries //
2222
// update this whenever the native assembly signature changes //
23-
[assembly: AssemblyNativeVersion("1.0.0.0")]
23+
[assembly: AssemblyNativeVersion("100.0.0.1")]
2424
/////////////////////////////////////////////////////////////////

System.Device.UsbStream/System.Device.UsbStream.nfproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,12 @@
4444
</NFMDP_PE_ExcludeClassByName>
4545
</ItemGroup>
4646
<ItemGroup>
47+
<Compile Include="UsbClient.cs" />
48+
<Compile Include="UsbDeviceEventListener.cs" />
49+
<Compile Include="UsbStreamDataReceivedEventHandler.cs" />
4750
<Compile Include="UsbStream.cs" />
4851
<Compile Include="Properties\AssemblyInfo.cs" />
52+
<Compile Include="UsbStreamDataReceivedEventArgs.cs" />
4953
</ItemGroup>
5054
<ItemGroup>
5155
<Reference Include="mscorlib">
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) .NET Foundation and Contributors
2+
// See LICENSE file in the project root for full license information.
3+
4+
namespace System.Device.Usb
5+
{
6+
/// <summary>
7+
/// Provides static methods for the creation of USB client instances.
8+
/// </summary>
9+
public partial class UsbClient
10+
{
11+
/// <summary>
12+
/// Creates an USB Stream from a WinUSB device that will use the specified name as the device description.
13+
/// </summary>
14+
/// <param name="classId"><see cref="Guid"/> for the device class that will be used by WinUSB device.</param>
15+
/// <param name="name">Name to be used as device description.</param>
16+
/// <returns>A new UsbStream that was created with the specified name.</returns>
17+
public static UsbStream CreateUsbStream(
18+
Guid classId,
19+
string name)
20+
{
21+
return new UsbStream(
22+
classId,
23+
name);
24+
}
25+
}
26+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright (c) .NET Foundation and Contributors
2+
// See LICENSE file in the project root for full license information.
3+
4+
using nanoFramework.Runtime.Events;
5+
6+
namespace System.Device.Usb
7+
{
8+
internal class UsbDeviceEventListener : IEventProcessor, IEventListener
9+
{
10+
// Map of UsbStream objects
11+
private readonly UsbStream _usbStream;
12+
13+
public UsbDeviceEventListener(UsbStream usbStream)
14+
{
15+
EventSink.AddEventProcessor(EventCategory.Usb, this);
16+
EventSink.AddEventListener(EventCategory.Usb, this);
17+
18+
_usbStream = usbStream;
19+
}
20+
21+
public BaseEvent ProcessEvent(uint data1, uint data2, DateTime time)
22+
{
23+
return new UsbDeviceEvent()
24+
{
25+
// Data1 is packed by PostManagedEvent, so we need to unpack the high word.
26+
EventType = (UsbEventType)(data1 & 0xFF),
27+
28+
// Data2 - Low 8 bits are the interface index
29+
InterfaceIndex = (ushort)(data2 & 0xff)
30+
};
31+
}
32+
33+
public void InitializeForEventSource()
34+
{
35+
// This method has to exist
36+
}
37+
38+
public bool OnEvent(BaseEvent ev)
39+
{
40+
if (ev is UsbDeviceEvent myEvent)
41+
{
42+
switch (myEvent.EventType)
43+
{
44+
case UsbEventType.DeviceDisconnected:
45+
46+
// call internal event handler
47+
_usbStream.OnUsbDeviceConnectionChangedInternal(false);
48+
break;
49+
50+
case UsbEventType.DeviceConnected:
51+
// call internal event handler
52+
_usbStream.OnUsbDeviceConnectionChangedInternal(true);
53+
break;
54+
55+
case UsbEventType.DataAvailable:
56+
// fire event, if subscribed
57+
_usbStream.OnUsbStreamDataReceivedInternal();
58+
break;
59+
}
60+
}
61+
62+
return true;
63+
}
64+
}
65+
}

System.Device.UsbStream/UsbStream.cs

Lines changed: 118 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,47 @@ namespace System.Device.Usb
1212
/// </summary>
1313
public sealed class UsbStream : System.IO.Stream
1414
{
15+
private static bool _streamCreated = false;
16+
1517
#pragma warning disable IDE0052 // required at native code
1618
private readonly int _streamIndex;
1719
#pragma warning restore IDE0052 // Remove unread private members
1820

21+
[System.Diagnostics.DebuggerBrowsable(Diagnostics.DebuggerBrowsableState.Never)]
22+
private readonly UsbDeviceEventListener _useDeviceEventListener;
23+
1924
private bool _disposed;
2025
private int _writeTimeout = Timeout.Infinite;
2126
private int _readTimeout = Timeout.Infinite;
2227

28+
// default threshold is 1
29+
private int _receivedBytesThreshold = 1;
30+
private int _bufferSize = 256;
31+
32+
/// <summary>
33+
/// Event occurs when the connection state of the USB device changes.
34+
/// </summary>
35+
public event UsbDeviceConnectionChangedEventHandler UsbDeviceConnectionChanged;
36+
37+
/// <summary>
38+
/// Gets a value indicating whether the USB device is connected or not.
39+
/// </summary>
40+
public static extern bool IsConnected
41+
{
42+
[MethodImpl(MethodImplOptions.InternalCall)]
43+
get;
44+
}
45+
46+
/// <summary>
47+
/// Gets the number of bytes of data in the receive buffer.
48+
/// </summary>
49+
/// <returns>The number of bytes of data in the receive buffer.</returns>
50+
public extern int BytesToRead
51+
{
52+
[MethodImpl(MethodImplOptions.InternalCall)]
53+
get;
54+
}
55+
2356
/// <inheritdoc/>
2457
public override bool CanRead => true;
2558

@@ -37,6 +70,37 @@ public sealed class UsbStream : System.IO.Stream
3770
/// <exception cref="PlatformNotSupportedException">This is not support in .NET nanoFramework.</exception>
3871
public override long Position { get => throw new PlatformNotSupportedException(); set => throw new PlatformNotSupportedException(); }
3972

73+
/// <summary>
74+
/// Gets or sets the size of the <see cref="UsbStream"/> input buffer.
75+
/// </summary>
76+
/// <value>The size of the input buffer. The default is 256.</value>
77+
/// <exception cref="ArgumentOutOfRangeException">The <see cref="ReadBufferSize"/> value is less than or equal to zero.</exception>
78+
/// <remarks>
79+
/// <para>
80+
/// - There is only one work buffer which is used for transmission and reception.
81+
/// </para>
82+
/// <para>
83+
/// - When the <see cref="UsbStream"/> is <see cref="UsbClient.CreateUsbStream(Guid, string)"/> the driver will try to allocate the requested memory for the buffer. On failure to do so, an <see cref="OutOfMemoryException"/> exception will be throw and the <see cref="UsbClient.CreateUsbStream(Guid, string)"/> operation will fail.
84+
/// </para>
85+
/// </remarks>
86+
public int ReadBufferSize
87+
{
88+
get
89+
{
90+
return _bufferSize;
91+
}
92+
93+
set
94+
{
95+
if (value <= 0)
96+
{
97+
throw new ArgumentOutOfRangeException();
98+
}
99+
100+
_bufferSize = value;
101+
}
102+
}
103+
40104
/// <summary>
41105
/// Gets or sets the number of milliseconds before a time-out occurs when a read operation does not finish.
42106
/// </summary>
@@ -54,6 +118,22 @@ public override int ReadTimeout
54118
}
55119
}
56120

121+
/// <summary>
122+
/// Gets or sets the number of bytes in the internal input buffer before a <see cref="DataReceived"/> event occurs.
123+
/// </summary>
124+
/// <value>The number of bytes in the internal input buffer before a <see cref="DataReceived"/> event is fired. The default is 1.</value>
125+
/// <exception cref="ArgumentOutOfRangeException">The <see cref="ReceivedBytesThreshold"/> value is less than or equal
126+
/// to zero.</exception>
127+
public int ReceivedBytesThreshold
128+
{
129+
get => _receivedBytesThreshold;
130+
131+
set
132+
{
133+
NativeReceivedBytesThreshold(value);
134+
}
135+
}
136+
57137
/// <summary>
58138
/// Gets or sets the number of milliseconds before a time-out occurs when a write operation does not finish.
59139
/// </summary>
@@ -75,11 +155,20 @@ internal UsbStream(
75155
Guid classId,
76156
string name)
77157
{
158+
// at this time there is support for a single instance of the UsbStream
159+
if (_streamCreated)
160+
{
161+
throw new InvalidOperationException();
162+
}
163+
78164
// need to convert GUID to proper format to help processing at native end
79165
_streamIndex = NativeOpen(
80166
$"{{{classId}}}",
81167
name);
82168

169+
_useDeviceEventListener = new UsbDeviceEventListener(this);
170+
171+
_streamCreated = true;
83172
_disposed = false;
84173
}
85174

@@ -97,6 +186,7 @@ protected override void Dispose(bool disposing)
97186
NativeClose();
98187

99188
_disposed = true;
189+
_streamCreated = false;
100190
}
101191
}
102192

@@ -107,7 +197,8 @@ protected override void Dispose(bool disposing)
107197
/// <inheritdoc/>
108198
/// <exception cref="ObjectDisposedException">This <see cref="UsbStream"/> has been disposed.</exception>
109199
/// <exception cref="InvalidOperationException">If the USB device is not connected.</exception>
110-
/// <remarks>Device connectivity can be checked with </remarks>
200+
/// <exception cref="TimeoutException">No bytes were available to read.</exception>
201+
/// <remarks>Device connectivity can be checked with <see cref="IsConnected"/>. </remarks>
111202
public override int Read(
112203
byte[] buffer,
113204
int offset,
@@ -122,6 +213,7 @@ public override int Read(
122213
/// <inheritdoc/>
123214
/// <exception cref="NotImplementedException"></exception>
124215
/// <exception cref="InvalidOperationException">If the USB device is not connected.</exception>
216+
/// <exception cref="TimeoutException">No bytes were available to read.</exception>
125217
public override int Read(SpanByte buffer)
126218
{
127219
return Read(
@@ -143,6 +235,7 @@ public override long Seek(
143235
/// <inheritdoc/>
144236
/// <exception cref="ObjectDisposedException">This <see cref="UsbStream"/> has been disposed.</exception>
145237
/// <exception cref="InvalidOperationException">If the USB device is not connected.</exception>
238+
/// <exception cref="TimeoutException">The operation did not complete before the time-out period ended.</exception>
146239
public override void Write(
147240
byte[] buffer,
148241
int offset,
@@ -163,6 +256,27 @@ private static void CheckValidTimeout(int value)
163256
}
164257
}
165258

259+
#region event and delegate related methods
260+
261+
/// <summary>
262+
/// Indicates that data has been received through the <see cref="UsbClient"/> object.
263+
/// </summary>
264+
public event UsbStreamDataReceivedEventHandler DataReceived;
265+
266+
internal void OnUsbDeviceConnectionChangedInternal(bool isConnected)
267+
{
268+
// fire event, if subscribed
269+
UsbDeviceConnectionChanged?.Invoke(this, new DeviceConnectionEventArgs(isConnected));
270+
}
271+
272+
internal void OnUsbStreamDataReceivedInternal()
273+
{
274+
// fire event, if subscribed
275+
DataReceived?.Invoke(this, new UsbStreamDataReceivedEventArgs());
276+
}
277+
278+
#endregion
279+
166280
#region Native Methods
167281

168282
[MethodImpl(MethodImplOptions.InternalCall)]
@@ -177,6 +291,9 @@ private static void CheckValidTimeout(int value)
177291
[MethodImpl(MethodImplOptions.InternalCall)]
178292
private extern int NativeRead(byte[] buffer, int offset, int count);
179293

294+
[MethodImpl(MethodImplOptions.InternalCall)]
295+
internal extern void NativeReceivedBytesThreshold(int value);
296+
180297
#endregion
181298
}
182299
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) .NET Foundation and Contributors
2+
// See LICENSE file in the project root for full license information.
3+
4+
namespace System.Device.Usb
5+
{
6+
/// <summary>
7+
/// Provides data for the <see cref="UsbStream.DataReceived"/> event.
8+
/// </summary>
9+
public class UsbStreamDataReceivedEventArgs : EventArgs
10+
{
11+
internal UsbStreamDataReceivedEventArgs()
12+
{
13+
}
14+
}
15+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright (c) .NET Foundation and Contributors
2+
// See LICENSE file in the project root for full license information.
3+
4+
namespace System.Device.Usb
5+
{
6+
/// <summary>
7+
/// Represents the method that will handle the <see cref="UsbStream.DataReceived"/> event of a <see cref="UsbStream"/> object.
8+
/// </summary>
9+
/// <param name="sender">The sender of the event, which is the <see cref="UsbStream"/> object.</param>
10+
/// <param name="e">A <see cref="UsbStreamDataReceivedEventArgs"/> object that contains the event data.</param>
11+
public delegate void UsbStreamDataReceivedEventHandler(
12+
object sender,
13+
UsbStreamDataReceivedEventArgs e);
14+
}

0 commit comments

Comments
 (0)