Skip to content

Commit 108decf

Browse files
committed
More work on data transfer...
1 parent 6a29fe1 commit 108decf

File tree

6 files changed

+205
-9
lines changed

6 files changed

+205
-9
lines changed

src/Blazor.Extensions.WebUSB.JS/src/USBManager.ts

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { USBDeviceFound, USBRequestDeviceOptions, ParseUSBDevice, USBConfiguration, USBInterface } from "./USBTypes";
1+
import { USBDeviceFound, USBRequestDeviceOptions, ParseUSBDevice, USBConfiguration, USBInterface, USBDirection, USBInTransferResult, USBOutTransferResult, USBTransferStatus } from "./USBTypes";
22

33
type DotNetReferenceType = {
44
invokeMethod<T>(methodIdentifier: string, ...args: any[]): T,
@@ -7,7 +7,10 @@ type DotNetReferenceType = {
77

88
export class USBManager {
99
private usb: any = (<any>navigator).usb; // The WebUSB API root object
10-
private _foundDevices: any[] = []; // All devices found on the last request
10+
// All devices found on the last request
11+
// We keep a list of the most recent object because we can't serialize the "real" USBDevice to send back to C#
12+
// TODO: Find a better way to maintain it and keep consistent with the C# side...
13+
private _foundDevices: any[] = [];
1114

1215
public GetDevices = async (): Promise<USBDeviceFound[]> => {
1316
let devices = await this.usb.getDevices();
@@ -77,31 +80,114 @@ export class USBManager {
7780
});
7881
}
7982

80-
public SelectConfiguration = (device: USBDeviceFound, config: USBConfiguration): Promise<USBDeviceFound> => {
83+
public CloseDevice = (device: USBDeviceFound): Promise<USBDeviceFound> => {
8184
let usbDevice = this.GetUSBDevice(device);
8285
return new Promise<USBDeviceFound>((resolve, reject) => {
8386
if (!usbDevice) return reject("Device not connected");
84-
usbDevice.selectConfiguration(config.configurationValue)
87+
usbDevice.close()
8588
.then(() => {
8689
resolve(ParseUSBDevice(usbDevice));
8790
})
8891
.catch(err => reject(err));
8992
});
9093
}
9194

92-
public ClaimInterface = (device: USBDeviceFound, usbInterface: USBInterface): Promise<USBDeviceFound> => {
95+
public ResetDevice = (device: USBDeviceFound): Promise<USBDeviceFound> => {
9396
let usbDevice = this.GetUSBDevice(device);
9497
return new Promise<USBDeviceFound>((resolve, reject) => {
9598
if (!usbDevice) return reject("Device not connected");
99+
usbDevice.reset()
100+
.then(() => {
101+
resolve(ParseUSBDevice(usbDevice));
102+
})
103+
.catch(err => reject(err));
104+
});
105+
}
106+
107+
public SelectConfiguration = (device: USBDeviceFound, configurationValue: number): Promise<USBDeviceFound> => {
108+
let usbDevice = this.GetUSBDevice(device);
109+
return new Promise<USBDeviceFound>((resolve, reject) => {
110+
if (!usbDevice) return reject("Device not connected");
111+
usbDevice.selectConfiguration(configurationValue)
112+
.then(() => {
113+
resolve(ParseUSBDevice(usbDevice));
114+
})
115+
.catch(err => reject(err));
116+
});
117+
}
96118

97-
usbDevice.claimInterface(usbInterface.interfaceNumber)
119+
public ClaimInterface = (device: USBDeviceFound, interfaceNumber: number): Promise<USBDeviceFound> => {
120+
let usbDevice = this.GetUSBDevice(device);
121+
return new Promise<USBDeviceFound>((resolve, reject) => {
122+
if (!usbDevice) return reject("Device not connected");
123+
124+
usbDevice.claimInterface(interfaceNumber)
125+
.then(() => {
126+
resolve(ParseUSBDevice(usbDevice));
127+
})
128+
.catch(err => reject(err));
129+
});
130+
}
131+
132+
public ReleaseInterface = (device: USBDeviceFound, interfaceNumber: number): Promise<USBDeviceFound> => {
133+
let usbDevice = this.GetUSBDevice(device);
134+
return new Promise<USBDeviceFound>((resolve, reject) => {
135+
if (!usbDevice) return reject("Device not connected");
136+
137+
usbDevice.releaseInterface(interfaceNumber)
98138
.then(() => {
99139
resolve(ParseUSBDevice(usbDevice));
100140
})
101141
.catch(err => reject(err));
102142
});
103143
}
104144

145+
public SelectAlternateInterface = (device: USBDeviceFound, interfaceNumber: number, alternateSetting: number): Promise<USBDeviceFound> => {
146+
let usbDevice = this.GetUSBDevice(device);
147+
return new Promise<USBDeviceFound>((resolve, reject) => {
148+
if (!usbDevice) return reject("Device not connected");
149+
150+
usbDevice.selectAlternateInterface(interfaceNumber, alternateSetting)
151+
.then(() => {
152+
resolve(ParseUSBDevice(usbDevice));
153+
})
154+
.catch(err => reject(err));
155+
});
156+
}
157+
158+
public ClearHalt = (device: USBDeviceFound, direction: USBDirection, endpointNumber: number): Promise<USBDeviceFound> => {
159+
let usbDevice = this.GetUSBDevice(device);
160+
return new Promise<USBDeviceFound>((resolve, reject) => {
161+
if (!usbDevice) return reject("Device not connected");
162+
163+
usbDevice.clearHalt(direction, endpointNumber)
164+
.then(() => {
165+
resolve(ParseUSBDevice(usbDevice));
166+
})
167+
.catch(err => reject(err));
168+
});
169+
}
170+
171+
public TransferIn = (device: USBDeviceFound, endpointNumber: number, length: number): Promise<USBInTransferResult> => {
172+
return new Promise<USBInTransferResult>((resolve, reject) => {
173+
reject("Not implemented");
174+
});
175+
}
176+
177+
public TransferOut = (device: USBDeviceFound, endpointNumber: number, data: ArrayBuffer): Promise<USBOutTransferResult> => {
178+
let usbDevice = this.GetUSBDevice(device);
179+
return new Promise<USBOutTransferResult>((resolve, reject) => {
180+
if (!usbDevice) return reject("Device not connected");
181+
console.log(data);
182+
usbDevice.transferOut(endpointNumber, data)
183+
.then(out => {
184+
console.log(out);
185+
resolve({ bytesWritten: out.bytesWritten, status: out.status });
186+
})
187+
.catch(err => reject(err));
188+
});
189+
}
190+
105191
private GetUSBDevice = (device: USBDeviceFound): any => {
106192
return this._foundDevices.find(
107193
d => d.vendorId == device.vendorId &&

src/Blazor.Extensions.WebUSB.JS/src/USBTypes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ export interface USBAlternateInterface { alternateSetting: number, interfaceClas
2323
export interface USBDeviceFilter { vendorId: number, productId: number, classCode: any, subClassCode: any, protocolCode: any, serialNumber: string }
2424
export interface USBRequestDeviceOptions { filters: USBDeviceFilter[] }
2525
export interface USBEndpoint { endpointNumber: number, direction: USBDirection, type: USBEndpointType, packetSize: number }
26+
export interface USBInTransferResult { data: number[], status: USBTransferStatus }
27+
export interface USBOutTransferResult { bytesWritten: number, status: USBTransferStatus }
28+
2629
export enum USBDirection { "in", "out" }
2730
export enum USBEndpointType { "bulk", "interrupt", "isochronous" }
31+
export enum USBTransferStatus { "ok", "stall", "babble" }
2832

2933
export function ParseUSBDevice(rawDevice: any): USBDeviceFound {
3034
return {

src/Blazor.Extensions.WebUSB/USBConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace Blazor.Extensions.WebUSB
44
{
55
public class USBConfiguration
66
{
7-
public byte ConfigurationValue { get; private set; }
7+
public byte ConfigurationValue { get; internal set; }
88
public string ConfigurationName { get; private set; }
99
public List<USBInterface> Interfaces { get; private set; }
1010
}

src/Blazor.Extensions.WebUSB/USBDevice.Methods.cs

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,107 @@ namespace Blazor.Extensions.WebUSB
88
public static class USBDeviceMethods
99
{
1010
private const string OPEN_DEVICE_METHOD = "BlazorExtensions.WebUSB.OpenDevice";
11+
private const string CLOSE_DEVICE_METHOD = "BlazorExtensions.WebUSB.CloseDevice";
12+
private const string RESET_DEVICE_METHOD = "BlazorExtensions.WebUSB.ResetDevice";
1113
private const string SELECT_CONFIGURATION_METHOD = "BlazorExtensions.WebUSB.SelectConfiguration";
1214
private const string CLAIM_INTERFACE_METHOD = "BlazorExtensions.WebUSB.ClaimInterface";
15+
private const string CLEAR_HALT_METHOD = "BlazorExtensions.WebUSB.ClearHalt";
16+
private const string RELEASE_INTERFACE_METHOD = "BlazorExtensions.WebUSB.ReleaseInterface";
17+
private const string SELECT_ALTERNATE_INTERFACE_METHOD = "BlazorExtensions.WebUSB.SelectAlternateInterface";
18+
private const string TRANSFER_OUT_METHOD = "BlazorExtensions.WebUSB.TransferOut";
19+
private const string TRANSFER_IN_METHOD = "BlazorExtensions.WebUSB.TransferIn";
1320

1421
internal static void AttachUSB(this USBDevice device, USB usb) => device.USB = usb;
1522
public static Task<USBDevice> Open(this USBDevice device) => JSRuntime.Current.InvokeAsync<USBDevice>(OPEN_DEVICE_METHOD, device);
23+
public static Task<USBDevice> Close(this USBDevice device) => JSRuntime.Current.InvokeAsync<USBDevice>(CLOSE_DEVICE_METHOD, device);
24+
public static Task<USBDevice> Reset(this USBDevice device) => JSRuntime.Current.InvokeAsync<USBDevice>(RESET_DEVICE_METHOD, device);
1625
public static Task<USBDevice> SelectConfiguration(this USBDevice device, USBConfiguration configuration)
1726
{
1827
if (configuration == null) throw new ArgumentNullException(nameof(configuration));
1928

29+
return device.SelectConfiguration(configuration.ConfigurationValue);
30+
}
31+
32+
public static Task<USBDevice> SelectConfiguration(this USBDevice device, byte configuration)
33+
{
2034
return JSRuntime.Current.InvokeAsync<USBDevice>(SELECT_CONFIGURATION_METHOD, device, configuration);
2135
}
2236

2337
public static Task<USBDevice> ClaimInterface(this USBDevice device, USBInterface usbInterface)
2438
{
2539
if (usbInterface == null) throw new ArgumentNullException(nameof(usbInterface));
2640

27-
return JSRuntime.Current.InvokeAsync<USBDevice>(CLAIM_INTERFACE_METHOD, device, usbInterface);
41+
return device.ClaimInterface(usbInterface.InterfaceNumber);
42+
}
43+
44+
public static Task<USBDevice> ClaimInterface(this USBDevice device, byte interfaceNumber)
45+
{
46+
return JSRuntime.Current.InvokeAsync<USBDevice>(CLAIM_INTERFACE_METHOD, device, interfaceNumber);
2847
}
2948

3049
public static Task<USBDevice> ClaimBulkInterface(this USBDevice device)
3150
{
3251
var bulkInterface = device.Configuration.Interfaces.FirstOrDefault(i => i.Alternates.Any(a => a.Endpoints.Any(e => e.Type == USBEndpointType.Bulk)));
3352
if (bulkInterface == null) throw new InvalidOperationException("This devices doesn't have a Bulk interface");
34-
return device.ClaimInterface(bulkInterface);
53+
return device.ClaimInterface(bulkInterface.InterfaceNumber);
54+
}
55+
56+
public static Task<USBDevice> ReleaseInterface(this USBDevice device, USBInterface usbInterface)
57+
{
58+
if (usbInterface == null) throw new ArgumentNullException(nameof(usbInterface));
59+
60+
return device.ReleaseInterface(usbInterface.InterfaceNumber);
61+
}
62+
63+
public static Task<USBDevice> ReleaseInterface(this USBDevice device, byte interfaceNumber)
64+
{
65+
return JSRuntime.Current.InvokeAsync<USBDevice>(RELEASE_INTERFACE_METHOD, device, interfaceNumber);
66+
}
67+
68+
public static Task<USBDevice> SelectAlternateInterface(this USBDevice device, USBInterface usbInterface, USBAlternateInterface usbAlternateInterface)
69+
{
70+
if (usbInterface == null) throw new ArgumentNullException(nameof(usbInterface));
71+
if (usbAlternateInterface == null) throw new ArgumentNullException(nameof(usbAlternateInterface));
72+
73+
return device.SelectAlternateInterface(usbInterface.InterfaceNumber, usbAlternateInterface.AlternateSetting);
74+
}
75+
76+
public static Task<USBDevice> SelectAlternateInterface(this USBDevice device, byte interfaceNumber, byte alternateSetting)
77+
{
78+
return JSRuntime.Current.InvokeAsync<USBDevice>(SELECT_ALTERNATE_INTERFACE_METHOD, device, interfaceNumber, alternateSetting);
79+
}
80+
81+
public static Task<USBDevice> ClearHalt(this USBDevice device, USBEndpoint endpoint)
82+
{
83+
if (endpoint == null) throw new ArgumentNullException(nameof(endpoint));
84+
85+
return device.ClearHalt(endpoint.Direction, endpoint.EndpointNumber);
86+
}
87+
88+
public static Task<USBDevice> ClearHalt(this USBDevice device, string direction, byte endpointNumber)
89+
{
90+
return JSRuntime.Current.InvokeAsync<USBDevice>(CLEAR_HALT_METHOD, device, direction, endpointNumber);
91+
}
92+
93+
public static Task<USBInTransferResult> TransferIn(this USBDevice device, USBEndpoint endpoint, long length)
94+
{
95+
if (endpoint == null) throw new ArgumentNullException(nameof(endpoint));
96+
return device.TransferIn(endpoint.EndpointNumber, length);
97+
}
98+
99+
public static Task<USBInTransferResult> TransferIn(this USBDevice device, byte endpointNumber, long length)
100+
{
101+
return JSRuntime.Current.InvokeAsync<USBInTransferResult>(TRANSFER_IN_METHOD, device, endpointNumber, length);
102+
}
103+
104+
public static Task<USBOutTransferResult> TransferOut(this USBDevice device, USBEndpoint endpoint, byte[] data)
105+
{
106+
return device.TransferOut(endpoint.EndpointNumber, data);
107+
}
108+
109+
public static Task<USBOutTransferResult> TransferOut(this USBDevice device, byte endpointNumber, byte[] data)
110+
{
111+
return JSRuntime.Current.InvokeAsync<USBOutTransferResult>(TRANSFER_OUT_METHOD, device, endpointNumber, data);
35112
}
36113
}
37114
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
namespace Blazor.Extensions.WebUSB
2+
{
3+
public static class USBTransferStatus
4+
{
5+
public const string OK = "ok";
6+
public const string Stall = "stall";
7+
public const string Babble = "babble";
8+
}
9+
10+
public abstract class USBTransferResult
11+
{
12+
public string Status { get; private set; }
13+
}
14+
15+
public class USBInTransferResult : USBTransferResult
16+
{
17+
public byte[] Data { get; set; }
18+
}
19+
20+
public class USBOutTransferResult : USBTransferResult
21+
{
22+
public long BytesWritten { get; private set; }
23+
}
24+
}

test/Blazor.Extensions.WebUSB.Test/Pages/TestPage.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,13 @@ protected async Task RequestDevices()
5656
{
5757
device = await device.Open();
5858
device = await device.SelectConfiguration(device.Configuration);
59+
// device = await device.SelectConfiguration(1);
5960
device = await device.ClaimBulkInterface();
6061
this._logger.LogInformation(device);
62+
63+
var outResult = await device.TransferOut(2, new byte[] { 1, 2, 3 });
64+
this._logger.LogInformation("Write response:");
65+
this._logger.LogInformation(outResult);
6166
}
6267
}
6368

0 commit comments

Comments
 (0)